@@ -16,6 +16,12 @@ import { IRequestOptionsProvider } from './requestOptionsProvider';
16
16
17
17
@injectable ( )
18
18
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
+
19
25
constructor (
20
26
@inject ( FS ) private readonly fs : FsPromises ,
21
27
@optional ( ) @inject ( IRequestOptionsProvider ) private readonly options ?: IRequestOptionsProvider ,
@@ -83,19 +89,32 @@ export class BasicResourceProvider implements IResourceProvider {
83
89
const parsed = new URL ( url ) ;
84
90
85
91
const isSecure = parsed . protocol !== 'http:' ;
92
+ const port = Number ( parsed . port ) ?? ( isSecure ? 443 : 80 ) ;
86
93
const options : OptionsOfTextResponseBody = { headers, followRedirect : true } ;
87
94
if ( isSecure && ( await isLoopback ( url ) ) ) {
88
95
options . rejectUnauthorized = false ;
89
96
}
90
97
91
98
this . options ?. provideOptions ( options , url ) ;
92
99
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 ) ;
94
113
95
114
// Try the other net family if localhost fails,
96
115
// see https://github.com/microsoft/vscode/issues/140536#issuecomment-1011281962
97
116
// and later https://github.com/microsoft/vscode/issues/167353
98
- if ( response . statusCode === 503 && parsed . hostname === 'localhost' ) {
117
+ if ( response . statusCode === 503 && isLocalhost ) {
99
118
let resolved : LookupAddress ;
100
119
try {
101
120
resolved = await dns . lookup ( parsed . hostname ) ;
@@ -104,7 +123,10 @@ export class BasicResourceProvider implements IResourceProvider {
104
123
}
105
124
106
125
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
+ }
108
130
}
109
131
110
132
return response ;
0 commit comments