search walks the tree and returns matching handlers + captured params.
(method, path string, captured []string)
| 151 | |
| 152 | // search walks the tree and returns matching handlers + captured params. |
| 153 | func (n *node) search(method, path string, captured []string) ([]Handler, map[string]string, bool) { |
| 154 | // End of path — check for a handler at this leaf. |
| 155 | if path == "" { |
| 156 | if h, ok := n.handlers[method]; ok { |
| 157 | return h, buildParams(n.paramNames, captured), true |
| 158 | } |
| 159 | return nil, nil, false |
| 160 | } |
| 161 | |
| 162 | seg, rest := nextSegment(path) |
| 163 | |
| 164 | if seg == "" { |
| 165 | // An empty segment means consecutive slashes in the request path. |
| 166 | // No registered route can match this, so return not-found. |
| 167 | return nil, nil, false |
| 168 | } |
| 169 | |
| 170 | firstByte := seg[0] |
| 171 | |
| 172 | // 1. Try static children first (highest priority). |
| 173 | if n.children != nil { |
| 174 | if child, ok := n.children[firstByte]; ok { |
| 175 | if strings.HasPrefix(seg, child.path) { |
| 176 | remainder := seg[len(child.path):] |
| 177 | if remainder == "" { |
| 178 | if h, pm, found := child.search(method, rest, captured); found { |
| 179 | return h, pm, true |
| 180 | } |
| 181 | } else { |
| 182 | // The segment is longer than child.path — try descending. |
| 183 | if h, pm, found := child.search(method, remainder+segSep(rest), captured); found { |
| 184 | return h, pm, true |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | // 2. Try parametric child. |
| 192 | if n.paramChild != nil && len(seg) > 0 { |
| 193 | if h, pm, found := n.paramChild.search(method, rest, append(captured, seg)); found { |
| 194 | return h, pm, true |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | // 3. Try wildcard (catch-all): capture everything remaining. |
| 199 | if n.wildcard != nil { |
| 200 | if h, ok := n.wildcard.handlers[method]; ok { |
| 201 | remaining := path |
| 202 | return h, buildParams(n.wildcard.paramNames, append(captured, remaining)), true |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | return nil, nil, false |
| 207 | } |
| 208 | |
| 209 | // searchAnyMethod matches any registered method for OPTIONS/CORS fallback. |
| 210 | func (n *node) searchAnyMethod(path string, captured []string) ([]Handler, map[string]string, bool) { |
no test coverage detected