HandleSubdomain handles subdomain-based application proxy requests (aka. DevURLs in Coder V1). There are a lot of paths here: 1. If api.Hostname is not set then we pass on. 2. If we can't read the request hostname then we return a 400. 3. If the request hostname matches api.AccessURL then we pass o
(middlewares ...func(http.Handler) http.Handler)
| 425 | // purposes regarding re-authentication and application proxy session |
| 426 | // tokens. |
| 427 | func (s *Server) HandleSubdomain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler { |
| 428 | return func(next http.Handler) http.Handler { |
| 429 | return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { |
| 430 | ctx := r.Context() |
| 431 | |
| 432 | // Step 1: Pass on if subdomain-based application proxying is not |
| 433 | // configured. |
| 434 | if s.Hostname == "" || s.HostnameRegex == nil { |
| 435 | next.ServeHTTP(rw, r) |
| 436 | return |
| 437 | } |
| 438 | |
| 439 | // Step 2: Get the request Host. |
| 440 | host := httpmw.EffectiveHost(s.RealIPConfig, r) |
| 441 | if host == "" { |
| 442 | if r.URL.Path == "/derp" { |
| 443 | // The /derp endpoint is used by wireguard clients to tunnel |
| 444 | // through coderd. For some reason these requests don't set |
| 445 | // a Host header properly sometimes in tests (no idea how), |
| 446 | // which causes this path to get hit. |
| 447 | next.ServeHTTP(rw, r) |
| 448 | return |
| 449 | } |
| 450 | |
| 451 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 452 | Message: "Could not determine request Host.", |
| 453 | }) |
| 454 | return |
| 455 | } |
| 456 | |
| 457 | // Steps 3-6: Parse application from subdomain. |
| 458 | app, ok := s.parseHostname(rw, r, next, host) |
| 459 | if !ok { |
| 460 | return |
| 461 | } |
| 462 | |
| 463 | if !s.handleAPIKeySmuggling(rw, r, AccessMethodSubdomain) { |
| 464 | return |
| 465 | } |
| 466 | |
| 467 | // Generate a signed token for the request. |
| 468 | token, ok := ResolveRequest(rw, r, ResolveRequestOptions{ |
| 469 | Logger: s.Logger, |
| 470 | Cookies: s.cookies, |
| 471 | CookieCfg: s.CookiesConfig, |
| 472 | SignedTokenProvider: s.SignedTokenProvider, |
| 473 | DashboardURL: s.DashboardURL, |
| 474 | PathAppBaseURL: s.AccessURL, |
| 475 | AppHostname: s.Hostname, |
| 476 | AppRequest: Request{ |
| 477 | AccessMethod: AccessMethodSubdomain, |
| 478 | BasePath: "/", |
| 479 | Prefix: app.Prefix, |
| 480 | UsernameOrID: app.Username, |
| 481 | WorkspaceNameOrID: app.WorkspaceName, |
| 482 | AgentNameOrID: app.AgentName, |
| 483 | AppSlugOrPort: app.AppSlugOrPort, |
| 484 | }, |