@@ -185,6 +185,8 @@ func (pset pathConfigSet) Swap(i, j int) {
185185}
186186
187187func (pset pathConfigSet ) find (path string ) (pc * pathConfig , subpath string ) {
188+ // Fast path with binary search to retrieve exact matches
189+ // e.g. given pset ["/", "/abc", "/xyz"], path "/def" won't match.
188190 i := sort .Search (len (pset ), func (i int ) bool {
189191 return pset [i ].path >= path
190192 })
@@ -194,5 +196,30 @@ func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) {
194196 if i > 0 && strings .HasPrefix (path , pset [i - 1 ].path + "/" ) {
195197 return & pset [i - 1 ], path [len (pset [i - 1 ].path )+ 1 :]
196198 }
197- return nil , ""
199+
200+ // Slow path, now looking for the longest prefix/shortest subpath i.e.
201+ // e.g. given pset ["/", "/abc/", "/abc/def/", "/xyz"/]
202+ // * query "/abc/foo" returns "/abc/" with a subpath of "foo"
203+ // * query "/x" returns "/" with a subpath of "x"
204+ lenShortestSubpath := len (path )
205+ var bestMatchConfig * pathConfig
206+
207+ // After binary search with the >= lexicographic comparison,
208+ // nothing greater than i will be a prefix of path.
209+ max := i
210+ for i := 0 ; i < max ; i ++ {
211+ ps := pset [i ]
212+ if len (ps .path ) >= len (path ) {
213+ // We previously didn't find the path by search, so any
214+ // route with equal or greater length is NOT a match.
215+ continue
216+ }
217+ sSubpath := strings .TrimPrefix (path , ps .path )
218+ if len (sSubpath ) < lenShortestSubpath {
219+ subpath = sSubpath
220+ lenShortestSubpath = len (sSubpath )
221+ bestMatchConfig = & pset [i ]
222+ }
223+ }
224+ return bestMatchConfig , subpath
198225}
0 commit comments