@@ -34,7 +34,7 @@ pub struct Node<T> {
3434 // The value stored at this node.
3535 //
3636 // See `Node::at` for why an `UnsafeCell` is necessary.
37- value : Option < UnsafeCell < T > > ,
37+ pub ( crate ) value : Option < UnsafeCell < T > > ,
3838
3939 // A parameter name remapping, stored at nodes that hold values.
4040 pub ( crate ) remapping : ParamRemapping ,
@@ -71,6 +71,52 @@ pub(crate) enum NodeType {
7171unsafe impl < T : Send > Send for Node < T > { }
7272unsafe impl < T : Sync > Sync for Node < T > { }
7373
74+ /// Tracks the current node and its parent during insertion.
75+ struct InsertState < ' node , T > {
76+ parent : & ' node mut Node < T > ,
77+ child : Option < usize > ,
78+ }
79+
80+ impl < ' node , T > InsertState < ' node , T > {
81+ /// Returns a reference to the parent node for the traversal.
82+ fn parent ( & self ) -> Option < & Node < T > > {
83+ match self . child {
84+ None => None ,
85+ Some ( _) => Some ( self . parent ) ,
86+ }
87+ }
88+
89+ /// Returns a reference to the current node in the traversal.
90+ fn node ( & self ) -> & Node < T > {
91+ match self . child {
92+ None => self . parent ,
93+ Some ( i) => & self . parent . children [ i] ,
94+ }
95+ }
96+
97+ /// Returns a mutable reference to the current node in the traversal.
98+ fn node_mut ( & mut self ) -> & mut Node < T > {
99+ match self . child {
100+ None => self . parent ,
101+ Some ( i) => & mut self . parent . children [ i] ,
102+ }
103+ }
104+
105+ /// Move the current node to its i'th child.
106+ fn set_child ( self , i : usize ) -> InsertState < ' node , T > {
107+ match self . child {
108+ None => InsertState {
109+ parent : self . parent ,
110+ child : Some ( i) ,
111+ } ,
112+ Some ( prev) => InsertState {
113+ parent : & mut self . parent . children [ prev] ,
114+ child : Some ( i) ,
115+ } ,
116+ }
117+ }
118+ }
119+
74120impl < T > Node < T > {
75121 // Insert a route into the tree.
76122 pub fn insert ( & mut self , route : String , val : T ) -> Result < ( ) , InsertError > {
@@ -88,21 +134,27 @@ impl<T> Node<T> {
88134 return Ok ( ( ) ) ;
89135 }
90136
91- let mut node = self ;
137+ let mut state = InsertState {
138+ parent : self ,
139+ child : None ,
140+ } ;
141+
92142 ' walk: loop {
93143 // Find the common prefix between the route and the current node.
94- let len = min ( remaining. len ( ) , node. prefix . len ( ) ) ;
144+ let len = min ( remaining. len ( ) , state . node ( ) . prefix . len ( ) ) ;
95145 let common_prefix = ( 0 ..len)
96146 . find ( |& i| {
97- remaining[ i] != node. prefix [ i]
147+ remaining[ i] != state . node ( ) . prefix [ i]
98148 // Make sure not confuse the start of a wildcard with an escaped `{`.
99- || remaining. is_escaped ( i) != node. prefix . is_escaped ( i)
149+ || remaining. is_escaped ( i) != state . node ( ) . prefix . is_escaped ( i)
100150 } )
101151 . unwrap_or ( len) ;
102152
103153 // If this node has a longer prefix than we need, we have to fork and extract the
104154 // common prefix into a shared parent.
105- if node. prefix . len ( ) > common_prefix {
155+ if state. node ( ) . prefix . len ( ) > common_prefix {
156+ let node = state. node_mut ( ) ;
157+
106158 // Move the non-matching suffix into a child node.
107159 let suffix = node. prefix . as_ref ( ) . slice_off ( common_prefix) . to_owned ( ) ;
108160 let child = Node {
@@ -125,6 +177,8 @@ impl<T> Node<T> {
125177 }
126178
127179 if remaining. len ( ) == common_prefix {
180+ let node = state. node_mut ( ) ;
181+
128182 // This node must not already contain a value.
129183 if node. value . is_some ( ) {
130184 return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
@@ -136,30 +190,50 @@ impl<T> Node<T> {
136190 return Ok ( ( ) ) ;
137191 }
138192
193+ let common_remaining = remaining;
194+
139195 // Otherwise, the route has a remaining non-matching suffix.
140196 //
141197 // We have to search deeper.
142198 remaining = remaining. slice_off ( common_prefix) ;
143199 let next = remaining[ 0 ] ;
144200
145- // For parameters with a suffix, we have to find the matching suffix or
146- // create a new child node.
147- if matches ! ( node. node_type, NodeType :: Param { .. } ) {
201+ // For parameters with a suffix, we have to find the matching suffix or create a new child node.
202+ if matches ! ( state. node( ) . node_type, NodeType :: Param { .. } ) {
148203 let terminator = remaining
149204 . iter ( )
150205 . position ( |& b| b == b'/' )
206+ // Include the '/' in the suffix.
151207 . map ( |b| b + 1 )
152208 . unwrap_or ( remaining. len ( ) ) ;
153209
154210 let suffix = remaining. slice_until ( terminator) ;
155211
156- for ( i, child) in node. children . iter ( ) . enumerate ( ) {
212+ let mut extra_trailing_slash = false ;
213+ for ( i, child) in state. node ( ) . children . iter ( ) . enumerate ( ) {
157214 // Find a matching suffix.
158215 if * child. prefix == * * suffix {
159- node = & mut node . children [ i ] ;
160- node . priority += 1 ;
216+ state . node_mut ( ) . priority += 1 ;
217+ state = state . set_child ( i ) ;
161218 continue ' walk;
162219 }
220+
221+ // The suffix matches except for an extra trailing slash.
222+ if let Some ( ( common, remaining) ) = suffix. split_at_checked ( child. prefix . len ( ) ) {
223+ if * common == * child. prefix && remaining == * b"/" {
224+ extra_trailing_slash = true ;
225+ }
226+ }
227+ }
228+
229+ // If we are inserting a conflicting suffix, and there is a static prefix that already leads to
230+ // this route parameter, we have a prefix-suffix conflict.
231+ if !extra_trailing_slash && !matches ! ( * suffix, b"" | b"/" ) {
232+ if let Some ( parent) = state. parent ( ) {
233+ if parent. prefix_wild_child_in_segment ( ) {
234+ return Err ( InsertError :: conflict ( & route, common_remaining, parent) ) ;
235+ }
236+ }
163237 }
164238
165239 // Multiple parameters within the same segment, e.g. `/{foo}{bar}`.
@@ -168,19 +242,20 @@ impl<T> Node<T> {
168242 }
169243
170244 // If there is no matching suffix, create a new suffix node.
171- let child = node . add_suffix_child ( Node {
245+ let child = state . node_mut ( ) . add_suffix_child ( Node {
172246 prefix : suffix. to_owned ( ) ,
173247 node_type : NodeType :: Static ,
174248 priority : 1 ,
175249 ..Node :: default ( )
176250 } ) ;
177- node. node_type = NodeType :: Param { suffix : true } ;
178- node = & mut node. children [ child] ;
251+ let has_suffix = !matches ! ( * suffix, b"" | b"/" ) ;
252+ state. node_mut ( ) . node_type = NodeType :: Param { suffix : has_suffix } ;
253+ state = state. set_child ( child) ;
179254
180255 // If this is the final route segment, insert the value.
181256 if terminator == remaining. len ( ) {
182- node . value = Some ( UnsafeCell :: new ( val) ) ;
183- node . remapping = remapping;
257+ state . node_mut ( ) . value = Some ( UnsafeCell :: new ( val) ) ;
258+ state . node_mut ( ) . remapping = remapping;
184259 return Ok ( ( ) ) ;
185260 }
186261
@@ -190,40 +265,66 @@ impl<T> Node<T> {
190265
191266 // Create a static node unless we are inserting a parameter.
192267 if remaining[ 0 ] != b'{' || remaining. is_escaped ( 0 ) {
193- let child = node . add_child ( Node {
268+ let child = state . node_mut ( ) . add_child ( Node {
194269 node_type : NodeType :: Static ,
195270 priority : 1 ,
196271 ..Node :: default ( )
197272 } ) ;
198- node . indices . push ( remaining[ 0 ] ) ;
199- node = & mut node . children [ child] ;
273+ state . node_mut ( ) . indices . push ( remaining[ 0 ] ) ;
274+ state = state . set_child ( child) ;
200275 }
201276
202277 // Insert the remaining route.
203- let last = node . insert_route ( remaining, val) ?;
278+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
204279 last. remapping = remapping;
205280 return Ok ( ( ) ) ;
206281 }
207282
208283 // Find a child node that matches the next character in the route.
209- for mut i in 0 ..node. indices . len ( ) {
210- if next == node. indices [ i] {
284+ for mut i in 0 ..state . node ( ) . indices . len ( ) {
285+ if next == state . node ( ) . indices [ i] {
211286 // Make sure not confuse the start of a wildcard with an escaped `{` or `}`.
212287 if matches ! ( next, b'{' | b'}' ) && !remaining. is_escaped ( 0 ) {
213288 continue ;
214289 }
215290
216291 // Continue searching in the child.
217- i = node . update_child_priority ( i) ;
218- node = & mut node . children [ i ] ;
292+ i = state . node_mut ( ) . update_child_priority ( i) ;
293+ state = state . set_child ( i ) ;
219294 continue ' walk;
220295 }
221296 }
222297
223298 // We couldn't find a matching child.
224299 //
225300 // If we're not inserting a wildcard we have to create a static child.
226- if ( next != b'{' || remaining. is_escaped ( 0 ) ) && node. node_type != NodeType :: CatchAll {
301+ if ( next != b'{' || remaining. is_escaped ( 0 ) )
302+ && state. node ( ) . node_type != NodeType :: CatchAll
303+ {
304+ let node = state. node_mut ( ) ;
305+
306+ let terminator = remaining
307+ . iter ( )
308+ . position ( |& b| b == b'/' )
309+ . unwrap_or ( remaining. len ( ) ) ;
310+
311+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) ) {
312+ // If we are inserting a parameter prefix and this node already has a parameter suffix, we
313+ // have a prefix-suffix conflict.
314+ if wildcard. start > 0 && node. suffix_wild_child_in_segment ( ) {
315+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
316+ }
317+
318+ // Similarly, we are inserting a parameter suffix and this node already has a parameter prefix, we
319+ // have a prefix-suffix conflict.
320+ let suffix = remaining. slice_off ( wildcard. end ) ;
321+ if !matches ! ( * suffix, b"" | b"/" ) {
322+ if node. prefix_wild_child_in_segment ( ) {
323+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
324+ }
325+ }
326+ }
327+
227328 node. indices . push ( next) ;
228329 let child = node. add_child ( Node :: default ( ) ) ;
229330 let child = node. update_child_priority ( child) ;
@@ -237,34 +338,118 @@ impl<T> Node<T> {
237338 // We're trying to insert a wildcard.
238339 //
239340 // If this node already has a wildcard child, we have to make sure it matches.
240- if node. wild_child {
341+ if state . node ( ) . wild_child {
241342 // Wildcards are always the last child.
242- node = node. children . last_mut ( ) . unwrap ( ) ;
243- node. priority += 1 ;
343+ let wild_child = state. node ( ) . children . len ( ) - 1 ;
344+ state = state. set_child ( wild_child) ;
345+ state. node_mut ( ) . priority += 1 ;
244346
245347 // Make sure the route parameter matches.
246- if let Some ( wildcard) = remaining. get ( ..node. prefix . len ( ) ) {
247- if * wildcard != * node. prefix {
248- return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
348+ if let Some ( wildcard) = remaining. get ( ..state . node ( ) . prefix . len ( ) ) {
349+ if * wildcard != * state . node ( ) . prefix {
350+ return Err ( InsertError :: conflict ( & route, remaining, state . node ( ) ) ) ;
249351 }
250352 }
251353
252354 // Catch-all routes cannot have children.
253- if node. node_type == NodeType :: CatchAll {
254- return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
355+ if state. node ( ) . node_type == NodeType :: CatchAll {
356+ return Err ( InsertError :: conflict ( & route, remaining, state. node ( ) ) ) ;
357+ }
358+
359+ if let Some ( parent) = state. parent ( ) {
360+ // If there is a route with both a prefix and a suffix, and we are inserting a route with a
361+ // matching prefix but _without_ a suffix, we have a prefix-suffix conflict.
362+ if !parent. prefix . ends_with ( b"/" )
363+ && !state. node ( ) . prefix . starts_with ( b"/" )
364+ && matches ! ( state. node( ) . node_type, NodeType :: Param { suffix: true } )
365+ {
366+ let terminator = remaining
367+ . iter ( )
368+ . position ( |& b| b == b'/' )
369+ // Include the '/' in the suffix.
370+ . map ( |b| b + 1 )
371+ . unwrap_or ( remaining. len ( ) ) ;
372+
373+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) )
374+ {
375+ let suffix = remaining. slice_off ( wildcard. end ) ;
376+ if matches ! ( * suffix, b"" | b"/" ) {
377+ return Err ( InsertError :: conflict ( & route, remaining, parent) ) ;
378+ }
379+ }
380+ }
255381 }
256382
257383 // Continue with the wildcard node.
258384 continue ' walk;
259385 }
260386
387+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining) {
388+ let node = state. node ( ) ;
389+ let suffix = remaining. slice_off ( wildcard. end ) ;
390+
391+ // If we are inserting a suffix and there is a static prefix that already leads to this
392+ // route parameter, we have a prefix-suffix conflict.
393+ if !matches ! ( * suffix, b"" | b"/" ) && node. prefix_wild_child_in_segment ( ) {
394+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
395+ }
396+
397+ // Similarly, if we are inserting a prefix, and there is a route that leads to this parameter that includes a
398+ // suffix, we have a prefix-suffix conflicts.
399+ if common_remaining[ common_prefix - 1 ] != b'/'
400+ && node. suffix_wild_child_in_segment ( )
401+ {
402+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
403+ }
404+ }
405+
261406 // Otherwise, create a new node for the wildcard and insert the route.
262- let last = node . insert_route ( remaining, val) ?;
407+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
263408 last. remapping = remapping;
264409 return Ok ( ( ) ) ;
265410 }
266411 }
267412
413+ /// Returns `true` if there is a wildcard node that contains a prefix within the current route segment,
414+ /// i.e. before the next trailing slash
415+ fn prefix_wild_child_in_segment ( & self ) -> bool {
416+ if self . prefix . ends_with ( b"/" ) {
417+ self . children . iter ( ) . any ( Node :: prefix_wild_child_in_segment)
418+ } else {
419+ self . children . iter ( ) . any ( Node :: wild_child_in_segment)
420+ }
421+ }
422+
423+ /// Returns `true` if there is a wildcard node within the current route segment, i.e. before the
424+ /// next trailing slash.
425+ fn wild_child_in_segment ( & self ) -> bool {
426+ if self . prefix . contains ( & b'/' ) {
427+ return false ;
428+ }
429+
430+ if matches ! ( self . node_type, NodeType :: Param { .. } ) {
431+ return true ;
432+ }
433+
434+ self . children . iter ( ) . any ( Node :: wild_child_in_segment)
435+ }
436+
437+ /// Returns `true` if there is a wildcard parameter node that contains a suffix within the current route
438+ /// segment, i.e. before a trailing slash.
439+ fn suffix_wild_child_in_segment ( & self ) -> bool {
440+ if matches ! ( self . node_type, NodeType :: Param { suffix: true } ) {
441+ return true ;
442+ }
443+
444+ self . children . iter ( ) . any ( |child| {
445+ if child. prefix . contains ( & b'/' ) {
446+ return false ;
447+ }
448+
449+ child. suffix_wild_child_in_segment ( )
450+ } )
451+ }
452+
268453 // Insert a route at this node.
269454 //
270455 // If the route starts with a wildcard, a child node will be created for the parameter
0 commit comments