func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
	nn := n
	search := path

	for t, nds := range nn.children {
		ntyp := nodeTyp(t)
		if len(nds) == 0 {
			continue
		}

		var xn *node
		xsearch := search

		var label byte
		if search != "" {
			label = search[0]
		}

		switch ntyp {
		case ntStatic:
			xn = nds.findEdge(label)
			if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) {
				continue
			}
			xsearch = xsearch[len(xn.prefix):]

		case ntParam, ntRegexp:
			// short-circuit and return no matching route for empty param values
			if xsearch == "" {
				continue
			}

			// serially loop through each node grouped by the tail delimiter
			for idx := 0; idx < len(nds); idx++ {
				xn = nds[idx]

				// label for param nodes is the delimiter byte
				p := strings.IndexByte(xsearch, xn.tail)

				if p < 0 {
					if xn.tail == '/' {
						p = len(xsearch)
					} else {
						continue
					}
				}

				if ntyp == ntRegexp && xn.rex != nil {
					if xn.rex.Match([]byte(xsearch[:p])) == false {
						continue
					}
				} else if strings.IndexByte(xsearch[:p], '/') != -1 {
					// avoid a match across path segments
					continue
				}

				rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p])
				xsearch = xsearch[p:]
				break
			}

		default:
			// catch-all nodes
			rctx.routeParams.Values = append(rctx.routeParams.Values, search)
			xn = nds[0]
			xsearch = ""
		}

		if xn == nil {
			continue
		}

		// did we find it yet?
		if len(xsearch) == 0 {
			if xn.isLeaf() {
				h, _ := xn.endpoints[method]
				if h != nil && h.handler != nil {
					rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
					return xn
				}

				// flag that the routing context found a route, but not a corresponding
				// supported method
				rctx.methodNotAllowed = true
			}
		}

		// recursively find the next node..
		fin := xn.findRoute(rctx, method, xsearch)
		if fin != nil {
			return fin
		}

		// Did not find final handler, let's remove the param here if it was set
		if xn.typ > ntStatic {
			if len(rctx.routeParams.Values) > 0 {
				rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1]
			}
		}

	}

	return nil
}
func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
	nn := n
	search := path

	for t, nds := range nn.children {
		ntyp := nodeTyp(t)
		if len(nds) == 0 {
			continue
		}

		var xn *node
		xsearch := search

		var label byte
		if search != "" {
			label = search[0]
		}

		switch ntyp {
		case ntStatic:
			xn = nds.findEdge(label)
			if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) {
				continue
			}
			xsearch = xsearch[len(xn.prefix):]

		case ntParam, ntRegexp:
			
			if xsearch == "" {
				continue
			}

			
			for idx := 0; idx < len(nds); idx++ {
				xn = nds[idx]

				
				p := strings.IndexByte(xsearch, xn.tail)

				if p < 0 {
					if xn.tail == '/' {
						p = len(xsearch)
					} else {
						continue
					}
				}

				if ntyp == ntRegexp && xn.rex != nil {
					if xn.rex.Match([]byte(xsearch[:p])) == false {
						continue
					}
				} else if strings.IndexByte(xsearch[:p], '/') != -1 {
					
					continue
				}

				rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p])
				xsearch = xsearch[p:]
				break
			}

		default:
			
			rctx.routeParams.Values = append(rctx.routeParams.Values, search)
			xn = nds[0]
			xsearch = ""
		}

		if xn == nil {
			continue
		}

		
		if len(xsearch) == 0 {
			if xn.isLeaf() {
				h, _ := xn.endpoints[method]
				if h != nil && h.handler != nil {
					rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
					return xn
				}

				
				
				rctx.methodNotAllowed = true
			}
		}

		
		fin := xn.findRoute(rctx, method, xsearch)
		if fin != nil {
			return fin
		}

		
		if xn.typ > ntStatic {
			if len(rctx.routeParams.Values) > 0 {
				rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1]
			}
		}

	}

	return nil
}
func ( n * node ) findRoute ( rctx * Context , method methodTyp , path string ) * node { nn := n search := path for t , nds := range nn . children { ntyp := nodeTyp ( t ) if len ( nds ) == 0 { continue } var xn * node xsearch := search var label byte if search != " " { label = search [ 0 ] } switch ntyp { case ntStatic : xn = nds . findEdge ( label ) if xn == nil || ! strings . HasPrefix ( xsearch , xn . prefix ) { continue } xsearch = xsearch [ len ( xn . prefix ) : ] case ntParam , ntRegexp : // short-circuit and return no matching route for empty param values if xsearch == " " { continue } // serially loop through each node grouped by the tail delimiter for idx := 0 ; idx < len ( nds ) ; idx ++ { xn = nds [ idx ] // label for param nodes is the delimiter byte p := strings . IndexByte ( xsearch , xn . tail ) if p < 0 { if xn . tail == '/' { p = len ( xsearch ) } else { continue } } if ntyp == ntRegexp && xn . rex != nil { if xn . rex . Match ( [ ] byte ( xsearch [ : p ] ) ) == false { continue } } else if strings . IndexByte ( xsearch [ : p ] , '/' ) != - 1 { // avoid a match across path segments continue } rctx . routeParams . Values = append ( rctx . routeParams . Values , xsearch [ : p ] ) xsearch = xsearch [ p : ] break } default : // catch-all nodes rctx . routeParams . Values = append ( rctx . routeParams . Values , search ) xn = nds [ 0 ] xsearch = " " } if xn == nil { continue } // did we find it yet? if len ( xsearch ) == 0 { if xn . isLeaf ( ) { h , _ := xn . endpoints [ method ] if h != nil && h . handler != nil { rctx . routeParams . Keys = append ( rctx . routeParams . Keys , h . paramKeys ... ) return xn } // flag that the routing context found a route, but not a corresponding // supported method rctx . methodNotAllowed = true } } // recursively find the next node.. fin := xn . findRoute ( rctx , method , xsearch ) if fin != nil { return fin } // Did not find final handler, let's remove the param here if it was set if xn . typ > ntStatic { if len ( rctx . routeParams . Values ) > 0 { rctx . routeParams . Values = rctx . routeParams . Values [ : len ( rctx . routeParams . Values ) - 1 ] } } } return nil }
// Recursive edge traversal by checking all nodeTyp groups along the way.
// It's like searching through a multi-dimensional radix trie.
Recursive edge traversal by checking all nodeTyp groups along the way . It s like searching through a multi - dimensional radix trie .