ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path.
(w http.ResponseWriter, r *http.Request)
| 405 | |
| 406 | // ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path. |
| 407 | func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
| 408 | ctx := r.Context() |
| 409 | |
| 410 | path := r.URL.Path |
| 411 | if !strings.HasPrefix(path, "/") { |
| 412 | _, outboundMarshaler := MarshalerForRequest(s, r) |
| 413 | s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusBadRequest) |
| 414 | return |
| 415 | } |
| 416 | |
| 417 | // TODO(v3): remove UnescapingModeLegacy |
| 418 | if s.unescapingMode != UnescapingModeLegacy && r.URL.RawPath != "" { |
| 419 | path = r.URL.RawPath |
| 420 | } |
| 421 | |
| 422 | if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && !s.disableHTTPMethodOverride && s.isPathLengthFallback(r) { |
| 423 | if err := r.ParseForm(); err != nil { |
| 424 | _, outboundMarshaler := MarshalerForRequest(s, r) |
| 425 | sterr := status.Error(codes.InvalidArgument, err.Error()) |
| 426 | s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) |
| 427 | return |
| 428 | } |
| 429 | r.Method = strings.ToUpper(override) |
| 430 | } |
| 431 | |
| 432 | var pathComponents []string |
| 433 | // since in UnescapeModeLegacy, the URL will already have been fully unescaped, if we also split on "%2F" |
| 434 | // in this escaping mode we would be double unescaping but in UnescapingModeAllCharacters, we still do as the |
| 435 | // path is the RawPath (i.e. unescaped). That does mean that the behavior of this function will change its default |
| 436 | // behavior when the UnescapingModeDefault gets changed from UnescapingModeLegacy to UnescapingModeAllExceptReserved |
| 437 | if s.unescapingMode == UnescapingModeAllCharacters { |
| 438 | pathComponents = encodedPathSplitter.Split(path[1:], -1) |
| 439 | } else { |
| 440 | pathComponents = strings.Split(path[1:], "/") |
| 441 | } |
| 442 | |
| 443 | lastPathComponent := pathComponents[len(pathComponents)-1] |
| 444 | |
| 445 | for _, h := range s.handlers[r.Method] { |
| 446 | // If the pattern has a verb, explicitly look for a suffix in the last |
| 447 | // component that matches a colon plus the verb. This allows us to |
| 448 | // handle some cases that otherwise can't be correctly handled by the |
| 449 | // former LastIndex case, such as when the verb literal itself contains |
| 450 | // a colon. This should work for all cases that have run through the |
| 451 | // parser because we know what verb we're looking for, however, there |
| 452 | // are still some cases that the parser itself cannot disambiguate. See |
| 453 | // the comment there if interested. |
| 454 | |
| 455 | var verb string |
| 456 | patVerb := h.pat.Verb() |
| 457 | |
| 458 | idx := -1 |
| 459 | if patVerb != "" && strings.HasSuffix(lastPathComponent, ":"+patVerb) { |
| 460 | idx = len(lastPathComponent) - len(patVerb) - 1 |
| 461 | } |
| 462 | if idx == 0 { |
| 463 | _, outboundMarshaler := MarshalerForRequest(s, r) |
| 464 | s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) |