Skip to content

Commit d628942

Browse files
authored
perf: fallback should optimistically pick a new hostname when it falls back (#1695)
* perf: fallback should optimistically pick a new hostname when it falls back Fixes #1694 * update to fix tests
1 parent 76492f0 commit d628942

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

src/adapter/resourceProvider/basicResourceProvider.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ import { IRequestOptionsProvider } from './requestOptionsProvider';
1616

1717
@injectable()
1818
export class BasicResourceProvider implements IResourceProvider {
19+
/**
20+
* Map of ports to fallback hosts that ended up working. Used to optimistically
21+
* fallback (see #1694)
22+
*/
23+
private autoLocalhostPortFallbacks: Record<number, string> = {};
24+
1925
constructor(
2026
@inject(FS) private readonly fs: FsPromises,
2127
@optional() @inject(IRequestOptionsProvider) private readonly options?: IRequestOptionsProvider,
@@ -83,19 +89,32 @@ export class BasicResourceProvider implements IResourceProvider {
8389
const parsed = new URL(url);
8490

8591
const isSecure = parsed.protocol !== 'http:';
92+
const port = Number(parsed.port) ?? (isSecure ? 443 : 80);
8693
const options: OptionsOfTextResponseBody = { headers, followRedirect: true };
8794
if (isSecure && (await isLoopback(url))) {
8895
options.rejectUnauthorized = false;
8996
}
9097

9198
this.options?.provideOptions(options, url);
9299

93-
const response = await this.requestHttp(url, options, cancellationToken);
100+
const isLocalhost = parsed.hostname === 'localhost';
101+
const fallback = isLocalhost && this.autoLocalhostPortFallbacks[port];
102+
if (fallback) {
103+
const response = await this.requestHttp(parsed.toString(), options, cancellationToken);
104+
if (response.statusCode !== 503) {
105+
return response;
106+
}
107+
108+
delete this.autoLocalhostPortFallbacks[port];
109+
return this.requestHttp(url, options, cancellationToken);
110+
}
111+
112+
let response = await this.requestHttp(url, options, cancellationToken);
94113

95114
// Try the other net family if localhost fails,
96115
// see https://github.com/microsoft/vscode/issues/140536#issuecomment-1011281962
97116
// and later https://github.com/microsoft/vscode/issues/167353
98-
if (response.statusCode === 503 && parsed.hostname === 'localhost') {
117+
if (response.statusCode === 503 && isLocalhost) {
99118
let resolved: LookupAddress;
100119
try {
101120
resolved = await dns.lookup(parsed.hostname);
@@ -104,7 +123,10 @@ export class BasicResourceProvider implements IResourceProvider {
104123
}
105124

106125
parsed.hostname = resolved.family === 6 ? '127.0.0.1' : '[::1]';
107-
return this.requestHttp(parsed.toString(), options, cancellationToken);
126+
response = await this.requestHttp(parsed.toString(), options, cancellationToken);
127+
if (response.statusCode !== 503) {
128+
this.autoLocalhostPortFallbacks[port] = parsed.hostname;
129+
}
108130
}
109131

110132
return response;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Evaluating#1: //# sourceMappingURL=data:application/json;charset=utf-8;base64,ZGV2cw==
22

3-
stderr> Could not read source map for http://localhost:8001/eval1.js: Unexpected token d in JSON at position 0
3+
stderr> Could not read source map for http://localhost:8001/eval1.js: Unexpected token d

src/test/sources/sourcesTest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ describe('sources', () => {
230230
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,ZGV2cw==\n',
231231
);
232232
await p.logger.logOutput(await output);
233-
p.assertLog();
233+
p.assertLog({ substring: true });
234234
});
235235

236236
itIntegrates('logs not found errors', async ({ r }) => {

0 commit comments

Comments
 (0)