Skip to content

Commit 4158a3c

Browse files
committed
Add support for protocol behind reverse proxies
When we pass it in we check for cert or link but that means any self-hosted reverse proxies will not work. Pull the information from the headers instead so it works generically. In practice this may not be necessary since we patch connections from the client to use the current URL instead of referencing the remote authority anyway. I also replaced a — because a git hook was complaining about it and preventing me from committing.
1 parent 122c0fa commit 4158a3c

File tree

3 files changed

+18
-44
lines changed

3 files changed

+18
-44
lines changed

src/vs/server/@types/code-server-lib/index.d.ts

-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ declare global {
6565
'github-auth'?: string;
6666
'log'?: string;
6767
'logsPath'?: string;
68-
/** @coder Added to support Coder Link and certs. */
69-
protocol?: 'http:' | 'https:';
7068

7169
_: string[];
7270
}

src/vs/server/serverEnvironmentService.ts

-8
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ export const serverOptions: OptionDescriptions<ServerParsedArgs> = {
5454
'github-auth': { type: 'string' },
5555
'log': { type: 'string' },
5656
'logsPath': { type: 'string' },
57-
'protocol': { type: 'string' },
5857
_: OPTIONS['_']
5958
};
6059

@@ -113,8 +112,6 @@ export interface ServerParsedArgs {
113112
'github-auth'?: string;
114113
'log'?: string;
115114
'logsPath'?: string;
116-
/** @coder Added to support Coder Link and certs. */
117-
protocol?: 'http:' | 'https:';
118115
_: string[];
119116
}
120117

@@ -125,7 +122,6 @@ export interface IServerEnvironmentService extends INativeEnvironmentService {
125122
readonly serviceWorkerFileName: string;
126123
readonly serviceWorkerPath: string;
127124
readonly proxyUri: string;
128-
readonly protocol: 'http:' | 'https:';
129125
}
130126

131127
export class ServerEnvironmentService extends NativeEnvironmentService implements IServerEnvironmentService {
@@ -143,8 +139,4 @@ export class ServerEnvironmentService extends NativeEnvironmentService implement
143139
public get proxyUri(): string {
144140
return '/proxy/{port}';
145141
}
146-
147-
public get protocol(): 'http:' | 'https:' {
148-
return this.args.protocol || 'http:';
149-
}
150142
}

src/vs/server/webClientServer.ts

+18-34
Original file line numberDiff line numberDiff line change
@@ -164,49 +164,33 @@ export class WebClientServer {
164164
private createRequestUrl(req: http.IncomingMessage, parsedUrl: url.UrlWithParsedQuery, pathname: string): URL {
165165
const pathPrefix = getPathPrefix(parsedUrl.pathname!);
166166
const remoteAuthority = this.getRemoteAuthority(req);
167-
// TODO: there isn't a good way for to determine the protocol. Defaulting to `http` for now.
168167
return new URL(path.join('/', pathPrefix, pathname), remoteAuthority);
169168
}
170169

171170
private _iconSizes = [192, 512];
172171

173-
private getRemoteAuthorityHeader = (req: http.IncomingMessage): string => {
174-
let remoteAuthority: string | undefined;
175-
172+
private getRemoteAuthority(req: http.IncomingMessage): URL {
176173
if (req.headers.forwarded) {
177174
const [parsedHeader] = parseForwardHeader(req.headers.forwarded);
178-
179-
if (parsedHeader && parsedHeader.host) {
180-
return parsedHeader.host;
181-
}
175+
return new URL(`${parsedHeader.proto}://${parsedHeader.host}`);
182176
}
183177

184-
// Listed in order of priority
185-
const headerNames = [
186-
'X-Forwarded-Host',
187-
'host'
188-
];
189-
190-
for (const headerName of headerNames) {
191-
const header = req.headers[headerName]?.toString();
192-
if (!isFalsyOrWhitespace(header)) {
193-
return header!;
178+
/* Return first non-empty header. */
179+
const parseHeaders = (headerNames: string[]): string | undefined => {
180+
for (const headerName of headerNames) {
181+
const header = req.headers[headerName]?.toString();
182+
if (!isFalsyOrWhitespace(header)) {
183+
return header;
184+
}
194185
}
195-
}
196-
197-
if (isFalsyOrWhitespace(remoteAuthority)) {
198-
throw new Error('Remote authority not present in host headers');
199-
}
200-
201-
return null as never;
202-
};
186+
return undefined;
187+
};
203188

204-
private getRemoteAuthority = (req: http.IncomingMessage): URL => {
205-
const { protocol } = this._environmentService;
206-
const remoteAuthority = new URL(`${protocol}//${this.getRemoteAuthorityHeader(req)}`);
189+
const proto = parseHeaders(["X-Forwarded-Proto"]) || "http";
190+
const host = parseHeaders(["X-Forwarded-Host", "host"]) || "localhost";
207191

208-
return remoteAuthority;
209-
};
192+
return new URL(`${proto}://${host}`);
193+
}
210194

211195
/**
212196
* PWA manifest file. This informs the browser that the app may be installed.
@@ -325,7 +309,7 @@ export class WebClientServer {
325309
},
326310
folderUri: (workspacePath && isFolder) ? transformer.transformOutgoing(URI.file(workspacePath)) : undefined,
327311
workspaceUri: (workspacePath && !isFolder) ? transformer.transformOutgoing(URI.file(workspacePath)) : undefined,
328-
// Add port to prevent client-side mismatch for Coder Link
312+
// Add port to prevent client-side mismatch for reverse proxies.
329313
remoteAuthority: `${remoteAuthority.hostname}:${remoteAuthority.port || (remoteAuthority.protocol === 'https:' ? '443' : '80')}`,
330314
_wrapWebWorkerExtHostInIframe,
331315
developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined },
@@ -340,7 +324,7 @@ export class WebClientServer {
340324
'img-src \'self\' https: data: blob:;',
341325
'media-src \'none\';',
342326
// the sha is the same as in src/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html
343-
`script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=' https://cloud.coder.com;`,
327+
`script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=';`,
344328
'child-src \'self\';',
345329
`frame-src 'self' https://*.vscode-webview.net ${this._productService.webEndpointUrl || ''} data:;`,
346330
'worker-src \'self\' data:;',
@@ -508,7 +492,7 @@ export class WebClientServer {
508492
.replace(/{{ERROR_HEADER}}/g, () => `${applicationName}`)
509493
.replace(/{{ERROR_CODE}}/g, () => code.toString())
510494
.replace(/{{ERROR_MESSAGE}}/g, () => message)
511-
.replace(/{{ERROR_FOOTER}}/g, () => `${version} ${commit}`)
495+
.replace(/{{ERROR_FOOTER}}/g, () => `${version} - ${commit}`)
512496
.replace(/{{CLIENT_BACKGROUND_COLOR}}/g, () => clientTheme.backgroundColor)
513497
.replace(/{{CLIENT_FOREGROUND_COLOR}}/g, () => clientTheme.foregroundColor);
514498

0 commit comments

Comments
 (0)