Returns a top-level HTTP handler for a Router. This adds behavior for URLs that don't match anything -- it handles the OPTIONS method as well as returning either a 404 or 405 for URLs that don't match a route.
(sc *ServerContext, privs handlerPrivs, serverType serverType, router *mux.Router)
| 424 | // match anything -- it handles the OPTIONS method as well as returning either a 404 or 405 |
| 425 | // for URLs that don't match a route. |
| 426 | func wrapRouter(sc *ServerContext, privs handlerPrivs, serverType serverType, router *mux.Router) http.Handler { |
| 427 | return http.HandlerFunc(func(response http.ResponseWriter, rq *http.Request) { |
| 428 | FixQuotedSlashes(rq) |
| 429 | var match mux.RouteMatch |
| 430 | if router.Match(rq, &match) { |
| 431 | router.ServeHTTP(response, rq) |
| 432 | } else { |
| 433 | // Log the request |
| 434 | h := newHandler(sc, privs, serverType, response, rq, handlerOptions{}) |
| 435 | h.logRequestLine() |
| 436 | |
| 437 | // Inject CORS if enabled and requested and not admin port |
| 438 | // What methods would have matched? |
| 439 | var options []string |
| 440 | var keyspace string |
| 441 | for _, method := range []string{"GET", "HEAD", "POST", "PUT", "DELETE"} { |
| 442 | found, matchedKeyspace := wouldMatch(router, rq, method) |
| 443 | if found { |
| 444 | options = append(options, method) |
| 445 | if keyspace == "" && matchedKeyspace != "" { |
| 446 | keyspace = matchedKeyspace |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | cors := sc.Config.API.CORS |
| 452 | dbName, _, _, _ := ParseKeyspace(keyspace) |
| 453 | if dbName != "" { |
| 454 | db, err := h.server.GetActiveDatabase(dbName) |
| 455 | if err == nil { |
| 456 | cors = db.CORS |
| 457 | } |
| 458 | } |
| 459 | if !cors.IsEmpty() && privs != adminPrivs && privs != metricsPrivs { |
| 460 | cors.AddResponseHeaders(rq, response) |
| 461 | } |
| 462 | if len(options) == 0 { |
| 463 | h.writeStatus(http.StatusNotFound, "unknown URL") |
| 464 | } else { |
| 465 | // Add CORS headers for OPTIONS request, since these are never registered by muxer. |
| 466 | response.Header().Add("Allow", strings.Join(options, ", ")) |
| 467 | if privs != adminPrivs && cors != nil && len(rq.Header["Origin"]) > 0 { |
| 468 | response.Header().Add("Access-Control-Max-Age", strconv.Itoa(cors.MaxAge)) |
| 469 | response.Header().Add("Access-Control-Allow-Methods", strings.Join(options, ", ")) |
| 470 | } |
| 471 | if rq.Method != "OPTIONS" { |
| 472 | h.writeStatus(http.StatusMethodNotAllowed, "") |
| 473 | } else { |
| 474 | h.writeStatus(http.StatusNoContent, "") |
| 475 | } |
| 476 | } |
| 477 | h.logDuration(true) |
| 478 | } |
| 479 | }) |
| 480 | } |
| 481 | |
| 482 | func FixQuotedSlashes(rq *http.Request) { |
| 483 | uri := rq.RequestURI |
no test coverage detected