|
1 | 1 | import * as http from "http"
|
2 | 2 | import { HttpCode, HttpError } from "../../common/http"
|
3 |
| -import { AuthType, HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http" |
| 3 | +import { HttpProvider, HttpProviderOptions, HttpProxyProvider, HttpResponse, Route } from "../http" |
4 | 4 |
|
5 | 5 | /**
|
6 | 6 | * Proxy HTTP provider.
|
7 | 7 | */
|
8 |
| -export class ProxyHttpProvider extends HttpProvider { |
9 |
| - public constructor(options: HttpProviderOptions, private readonly proxyDomains: string[]) { |
| 8 | +export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider { |
| 9 | + public readonly proxyDomains: string[] |
| 10 | + |
| 11 | + public constructor(options: HttpProviderOptions, proxyDomains: string[] = []) { |
10 | 12 | super(options)
|
| 13 | + this.proxyDomains = proxyDomains.map((d) => d.replace(/^\*\./, "")).filter((d, i, arr) => arr.indexOf(d) === i) |
11 | 14 | }
|
12 | 15 |
|
13 |
| - public async handleRequest(route: Route): Promise<HttpResponse> { |
14 |
| - if (this.options.auth !== AuthType.Password || route.requestPath !== "/index.html") { |
15 |
| - throw new HttpError("Not found", HttpCode.NotFound) |
| 16 | + public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> { |
| 17 | + if (!this.authenticated(request)) { |
| 18 | + if (route.requestPath === "/index.html") { |
| 19 | + return { redirect: "/login", query: { to: route.fullPath } } |
| 20 | + } |
| 21 | + throw new HttpError("Unauthorized", HttpCode.Unauthorized) |
16 | 22 | }
|
| 23 | + |
17 | 24 | const payload = this.proxy(route.base.replace(/^\//, ""))
|
18 |
| - if (!payload) { |
19 |
| - throw new HttpError("Not found", HttpCode.NotFound) |
| 25 | + if (payload) { |
| 26 | + return payload |
20 | 27 | }
|
21 |
| - return payload |
| 28 | + |
| 29 | + throw new HttpError("Not found", HttpCode.NotFound) |
22 | 30 | }
|
23 | 31 |
|
24 |
| - public async getRoot(route: Route, error?: Error): Promise<HttpResponse> { |
25 |
| - const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/login.html") |
26 |
| - response.content = response.content.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "") |
27 |
| - return this.replaceTemplates(route, response) |
| 32 | + public getProxyDomain(host?: string): string | undefined { |
| 33 | + if (!host || !this.proxyDomains) { |
| 34 | + return undefined |
| 35 | + } |
| 36 | + |
| 37 | + return this.proxyDomains.find((d) => host.endsWith(d)) |
28 | 38 | }
|
29 | 39 |
|
30 |
| - /** |
31 |
| - * Return a response if the request should be proxied. Anything that ends in a |
32 |
| - * proxy domain and has a subdomain should be proxied. The port is found in |
33 |
| - * the top-most subdomain. |
34 |
| - * |
35 |
| - * For example, if the proxy domain is `coder.com` then `8080.coder.com` and |
36 |
| - * `test.8080.coder.com` will both proxy to `8080` but `8080.test.coder.com` |
37 |
| - * will have an error because `test` isn't a port. If the proxy domain was |
38 |
| - * `test.coder.com` then it would work. |
39 |
| - */ |
40 | 40 | public maybeProxy(request: http.IncomingMessage): HttpResponse | undefined {
|
41 |
| - const host = request.headers.host |
42 |
| - if (!host || !this.proxyDomains) { |
| 41 | + // No proxy until we're authenticated. This will cause the login page to |
| 42 | + // show as well as let our assets keep loading normally. |
| 43 | + if (!this.authenticated(request)) { |
43 | 44 | return undefined
|
44 | 45 | }
|
45 | 46 |
|
46 |
| - const proxyDomain = this.proxyDomains.find((d) => host.endsWith(d)) |
47 |
| - if (!proxyDomain) { |
| 47 | + const host = request.headers.host |
| 48 | + const proxyDomain = this.getProxyDomain(host) |
| 49 | + if (!host || !proxyDomain) { |
48 | 50 | return undefined
|
49 | 51 | }
|
50 | 52 |
|
|
0 commit comments