@@ -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,51 @@ 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 child. prefix . len ( ) <= suffix. len ( ) {
223+ let ( common, remaining) = suffix. split_at ( child. prefix . len ( ) ) ;
224+ if * common == * child. prefix && remaining == * b"/" {
225+ extra_trailing_slash = true ;
226+ }
227+ }
228+ }
229+
230+ // If we are inserting a conflicting suffix, and there is a static prefix that
231+ // already leads to this route parameter, we have a prefix-suffix conflict.
232+ if !extra_trailing_slash && !matches ! ( * suffix, b"" | b"/" ) {
233+ if let Some ( parent) = state. parent ( ) {
234+ if parent. prefix_wild_child_in_segment ( ) {
235+ return Err ( InsertError :: conflict ( & route, common_remaining, parent) ) ;
236+ }
237+ }
163238 }
164239
165240 // Multiple parameters within the same segment, e.g. `/{foo}{bar}`.
@@ -168,19 +243,20 @@ impl<T> Node<T> {
168243 }
169244
170245 // If there is no matching suffix, create a new suffix node.
171- let child = node . add_suffix_child ( Node {
246+ let child = state . node_mut ( ) . add_suffix_child ( Node {
172247 prefix : suffix. to_owned ( ) ,
173248 node_type : NodeType :: Static ,
174249 priority : 1 ,
175250 ..Node :: default ( )
176251 } ) ;
177- node. node_type = NodeType :: Param { suffix : true } ;
178- node = & mut node. children [ child] ;
252+ let has_suffix = !matches ! ( * suffix, b"" | b"/" ) ;
253+ state. node_mut ( ) . node_type = NodeType :: Param { suffix : has_suffix } ;
254+ state = state. set_child ( child) ;
179255
180256 // If this is the final route segment, insert the value.
181257 if terminator == remaining. len ( ) {
182- node . value = Some ( UnsafeCell :: new ( val) ) ;
183- node . remapping = remapping;
258+ state . node_mut ( ) . value = Some ( UnsafeCell :: new ( val) ) ;
259+ state . node_mut ( ) . remapping = remapping;
184260 return Ok ( ( ) ) ;
185261 }
186262
@@ -190,40 +266,64 @@ impl<T> Node<T> {
190266
191267 // Create a static node unless we are inserting a parameter.
192268 if remaining[ 0 ] != b'{' || remaining. is_escaped ( 0 ) {
193- let child = node . add_child ( Node {
269+ let child = state . node_mut ( ) . add_child ( Node {
194270 node_type : NodeType :: Static ,
195271 priority : 1 ,
196272 ..Node :: default ( )
197273 } ) ;
198- node . indices . push ( remaining[ 0 ] ) ;
199- node = & mut node . children [ child] ;
274+ state . node_mut ( ) . indices . push ( remaining[ 0 ] ) ;
275+ state = state . set_child ( child) ;
200276 }
201277
202278 // Insert the remaining route.
203- let last = node . insert_route ( remaining, val) ?;
279+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
204280 last. remapping = remapping;
205281 return Ok ( ( ) ) ;
206282 }
207283
208284 // 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] {
285+ for mut i in 0 ..state . node ( ) . indices . len ( ) {
286+ if next == state . node ( ) . indices [ i] {
211287 // Make sure not confuse the start of a wildcard with an escaped `{` or `}`.
212288 if matches ! ( next, b'{' | b'}' ) && !remaining. is_escaped ( 0 ) {
213289 continue ;
214290 }
215291
216292 // Continue searching in the child.
217- i = node . update_child_priority ( i) ;
218- node = & mut node . children [ i ] ;
293+ i = state . node_mut ( ) . update_child_priority ( i) ;
294+ state = state . set_child ( i ) ;
219295 continue ' walk;
220296 }
221297 }
222298
223299 // We couldn't find a matching child.
224300 //
225301 // 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 {
302+ if ( next != b'{' || remaining. is_escaped ( 0 ) )
303+ && state. node ( ) . node_type != NodeType :: CatchAll
304+ {
305+ let node = state. node_mut ( ) ;
306+
307+ let terminator = remaining
308+ . iter ( )
309+ . position ( |& b| b == b'/' )
310+ . unwrap_or ( remaining. len ( ) ) ;
311+
312+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) ) {
313+ // If we are inserting a parameter prefix and this node already has a parameter suffix,
314+ // we have a prefix-suffix conflict.
315+ if wildcard. start > 0 && node. suffix_wild_child_in_segment ( ) {
316+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
317+ }
318+
319+ // Similarly, we are inserting a parameter suffix and this node already has a parameter
320+ // prefix, we have a prefix-suffix conflict.
321+ let suffix = remaining. slice_off ( wildcard. end ) ;
322+ if !matches ! ( * suffix, b"" | b"/" ) && node. prefix_wild_child_in_segment ( ) {
323+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
324+ }
325+ }
326+
227327 node. indices . push ( next) ;
228328 let child = node. add_child ( Node :: default ( ) ) ;
229329 let child = node. update_child_priority ( child) ;
@@ -237,34 +337,118 @@ impl<T> Node<T> {
237337 // We're trying to insert a wildcard.
238338 //
239339 // If this node already has a wildcard child, we have to make sure it matches.
240- if node. wild_child {
340+ if state . node ( ) . wild_child {
241341 // Wildcards are always the last child.
242- node = node. children . last_mut ( ) . unwrap ( ) ;
243- node. priority += 1 ;
342+ let wild_child = state. node ( ) . children . len ( ) - 1 ;
343+ state = state. set_child ( wild_child) ;
344+ state. node_mut ( ) . priority += 1 ;
244345
245346 // 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) ) ;
347+ if let Some ( wildcard) = remaining. get ( ..state . node ( ) . prefix . len ( ) ) {
348+ if * wildcard != * state . node ( ) . prefix {
349+ return Err ( InsertError :: conflict ( & route, remaining, state . node ( ) ) ) ;
249350 }
250351 }
251352
252353 // Catch-all routes cannot have children.
253- if node. node_type == NodeType :: CatchAll {
254- return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
354+ if state. node ( ) . node_type == NodeType :: CatchAll {
355+ return Err ( InsertError :: conflict ( & route, remaining, state. node ( ) ) ) ;
356+ }
357+
358+ if let Some ( parent) = state. parent ( ) {
359+ // If there is a route with both a prefix and a suffix, and we are inserting a route with
360+ // a matching prefix but _without_ a suffix, we have a prefix-suffix conflict.
361+ if !parent. prefix . ends_with ( b"/" )
362+ && !state. node ( ) . prefix . starts_with ( b"/" )
363+ && matches ! ( state. node( ) . node_type, NodeType :: Param { suffix: true } )
364+ {
365+ let terminator = remaining
366+ . iter ( )
367+ . position ( |& b| b == b'/' )
368+ // Include the '/' in the suffix.
369+ . map ( |b| b + 1 )
370+ . unwrap_or ( remaining. len ( ) ) ;
371+
372+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining. slice_until ( terminator) )
373+ {
374+ let suffix = remaining. slice_off ( wildcard. end ) ;
375+ if matches ! ( * suffix, b"" | b"/" ) {
376+ return Err ( InsertError :: conflict ( & route, remaining, parent) ) ;
377+ }
378+ }
379+ }
255380 }
256381
257382 // Continue with the wildcard node.
258383 continue ' walk;
259384 }
260385
386+ if let Ok ( Some ( wildcard) ) = find_wildcard ( remaining) {
387+ let node = state. node ( ) ;
388+ let suffix = remaining. slice_off ( wildcard. end ) ;
389+
390+ // If we are inserting a suffix and there is a static prefix that already leads to this
391+ // route parameter, we have a prefix-suffix conflict.
392+ if !matches ! ( * suffix, b"" | b"/" ) && node. prefix_wild_child_in_segment ( ) {
393+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
394+ }
395+
396+ // Similarly, if we are inserting a prefix, and there is a route that leads to this parameter
397+ // that includes a suffix, we have a prefix-suffix conflicts.
398+ if common_remaining[ common_prefix - 1 ] != b'/'
399+ && node. suffix_wild_child_in_segment ( )
400+ {
401+ return Err ( InsertError :: conflict ( & route, remaining, node) ) ;
402+ }
403+ }
404+
261405 // Otherwise, create a new node for the wildcard and insert the route.
262- let last = node . insert_route ( remaining, val) ?;
406+ let last = state . node_mut ( ) . insert_route ( remaining, val) ?;
263407 last. remapping = remapping;
264408 return Ok ( ( ) ) ;
265409 }
266410 }
267411
412+ /// Returns `true` if there is a wildcard node that contains a prefix within the current route segment,
413+ /// i.e. before the next trailing slash
414+ fn prefix_wild_child_in_segment ( & self ) -> bool {
415+ if self . prefix . ends_with ( b"/" ) {
416+ self . children . iter ( ) . any ( Node :: prefix_wild_child_in_segment)
417+ } else {
418+ self . children . iter ( ) . any ( Node :: wild_child_in_segment)
419+ }
420+ }
421+
422+ /// Returns `true` if there is a wildcard node within the current route segment, i.e. before the
423+ /// next trailing slash.
424+ fn wild_child_in_segment ( & self ) -> bool {
425+ if self . prefix . contains ( & b'/' ) {
426+ return false ;
427+ }
428+
429+ if matches ! ( self . node_type, NodeType :: Param { .. } ) {
430+ return true ;
431+ }
432+
433+ self . children . iter ( ) . any ( Node :: wild_child_in_segment)
434+ }
435+
436+ /// Returns `true` if there is a wildcard parameter node that contains a suffix within the current route
437+ /// segment, i.e. before a trailing slash.
438+ fn suffix_wild_child_in_segment ( & self ) -> bool {
439+ if matches ! ( self . node_type, NodeType :: Param { suffix: true } ) {
440+ return true ;
441+ }
442+
443+ self . children . iter ( ) . any ( |child| {
444+ if child. prefix . contains ( & b'/' ) {
445+ return false ;
446+ }
447+
448+ child. suffix_wild_child_in_segment ( )
449+ } )
450+ }
451+
268452 // Insert a route at this node.
269453 //
270454 // If the route starts with a wildcard, a child node will be created for the parameter
0 commit comments