nolint:revive
(handler http.Handler, accessURL *url.URL, tunnel bool, appHostnameRegex *regexp.Regexp)
| 2475 | |
| 2476 | // nolint:revive |
| 2477 | func redirectToAccessURL(handler http.Handler, accessURL *url.URL, tunnel bool, appHostnameRegex *regexp.Regexp) http.Handler { |
| 2478 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 2479 | redirect := func() { |
| 2480 | http.Redirect(w, r, accessURL.String(), http.StatusTemporaryRedirect) |
| 2481 | } |
| 2482 | |
| 2483 | // Exception: /healthz |
| 2484 | // Kubernetes doesn't like it if you redirect your healthcheck or liveness check endpoint. |
| 2485 | if r.URL.Path == "/healthz" { |
| 2486 | handler.ServeHTTP(w, r) |
| 2487 | return |
| 2488 | } |
| 2489 | |
| 2490 | // Exception: DERP |
| 2491 | // We use this endpoint when creating a DERP-mesh in the enterprise version to directly |
| 2492 | // dial other Coderd derpers. Redirecting to the access URL breaks direct dial since the |
| 2493 | // access URL will be load-balanced in a multi-replica deployment. |
| 2494 | // |
| 2495 | // It's totally fine to access DERP over TLS, but we also don't need to redirect HTTP to |
| 2496 | // HTTPS as DERP is itself an encrypted protocol. |
| 2497 | if isDERPPath(r.URL.Path) { |
| 2498 | handler.ServeHTTP(w, r) |
| 2499 | return |
| 2500 | } |
| 2501 | |
| 2502 | // Exception: inter-replica relay. |
| 2503 | // Enterprise chat streaming relays message_part events |
| 2504 | // between replicas by dialing the worker replica's |
| 2505 | // DERP relay address directly. Redirecting these |
| 2506 | // requests to the access URL breaks the WebSocket |
| 2507 | // handshake because the redirect strips the Upgrade |
| 2508 | // headers, causing the load-balanced access URL to |
| 2509 | // return HTTP 200 (SPA catch-all) instead of 101. |
| 2510 | if isReplicaRelayRequest(r) { |
| 2511 | handler.ServeHTTP(w, r) |
| 2512 | return |
| 2513 | } |
| 2514 | |
| 2515 | // Only do this if we aren't tunneling. |
| 2516 | // If we are tunneling, we want to allow the request to go through |
| 2517 | // because the tunnel doesn't proxy with TLS. |
| 2518 | if !tunnel && accessURL.Scheme == "https" && r.TLS == nil { |
| 2519 | redirect() |
| 2520 | return |
| 2521 | } |
| 2522 | |
| 2523 | if r.Host == accessURL.Host { |
| 2524 | handler.ServeHTTP(w, r) |
| 2525 | return |
| 2526 | } |
| 2527 | |
| 2528 | if r.Header.Get("X-Forwarded-Host") == accessURL.Host { |
| 2529 | handler.ServeHTTP(w, r) |
| 2530 | return |
| 2531 | } |
| 2532 | |
| 2533 | if appHostnameRegex != nil && appHostnameRegex.MatchString(r.Host) { |
| 2534 | handler.ServeHTTP(w, r) |
no test coverage detected