Skip to content

Commit a130c6d

Browse files
committed
Clean up WebClient.
1 parent f8c059e commit a130c6d

1 file changed

Lines changed: 79 additions & 85 deletions

File tree

libraries/rush-lib/src/utilities/WebClient.ts

Lines changed: 79 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export interface IWebClientResponseBase {
2525
}
2626

2727
/**
28-
* For use with {@link WebClient}.
28+
* A response from {@link WebClient.fetchAsync}.
2929
*/
3030
export interface IWebClientResponse extends IWebClientResponseBase {
3131
getTextAsync: () => Promise<string>;
@@ -117,7 +117,7 @@ function _makeRawRequestAsync<TResponse>(
117117
resolve: (result: TResponse | PromiseLike<TResponse>) => void,
118118
reject: (error: Error) => void
119119
) => void,
120-
selfFn: (url: string, options: IRequestOptions, isRedirect?: boolean) => Promise<TResponse>
120+
requestFnAsync: (url: string, options: IRequestOptions, isRedirect?: boolean) => Promise<TResponse>
121121
): Promise<TResponse> {
122122
const { body, redirect } = options;
123123

@@ -128,25 +128,25 @@ function _makeRawRequestAsync<TResponse>(
128128
parsedUrl.protocol === 'https:' ? httpsRequest : httpRequest;
129129

130130
const req: ClientRequest = requestFunction(url, options, (response: IncomingMessage) => {
131-
const statusCode: number | undefined = response.statusCode;
132-
131+
const {
132+
statusCode,
133+
headers: { location: redirectUrl }
134+
} = response;
133135
if (statusCode === 301 || statusCode === 302) {
134136
// Drain the redirect response before following
135137
response.resume();
136138
switch (redirect) {
137139
case 'follow': {
138-
const redirectUrl: string | string[] | undefined = response.headers.location;
139-
if (typeof redirectUrl === 'string') {
140-
resolve(selfFn(redirectUrl, options, true));
140+
if (redirectUrl) {
141+
requestFnAsync(redirectUrl, options, true).then(resolve).catch(reject);
141142
} else {
142-
reject(
143-
new Error(`Received status code ${response.statusCode} with no location header: ${url}`)
144-
);
143+
reject(new Error(`Received status code ${statusCode} with no location header: ${url}`));
145144
}
146145
return;
147146
}
147+
148148
case 'error':
149-
reject(new Error(`Received status code ${response.statusCode}: ${url}`));
149+
reject(new Error(`Received status code ${statusCode}: ${url}`));
150150
return;
151151
}
152152
}
@@ -188,10 +188,8 @@ const makeRequestAsync: FetchFn = async (
188188
responseBuffers.push(Buffer.from(chunk));
189189
});
190190
response.on('end', () => {
191+
const { statusCode: status = 0, statusMessage: statusText, headers } = response;
191192
const responseData: Buffer = Buffer.concat(responseBuffers);
192-
const status: number = response.statusCode || 0;
193-
const statusText: string | undefined = response.statusMessage;
194-
const headers: Record<string, string | string[] | undefined> = response.headers;
195193

196194
let bodyString: string | undefined;
197195
let bodyJson: unknown | undefined;
@@ -285,10 +283,7 @@ const makeStreamRequestAsync: StreamFetchFn = async (
285283
wasRedirected: boolean,
286284
resolve: (result: IWebClientStreamResponse | PromiseLike<IWebClientStreamResponse>) => void
287285
): void => {
288-
const status: number = response.statusCode || 0;
289-
const statusText: string | undefined = response.statusMessage;
290-
const headers: Record<string, string | string[] | undefined> = response.headers;
291-
286+
const { statusCode: status = 0, statusMessage: statusText, headers } = response;
292287
resolve({
293288
ok: status >= 200 && status < 300,
294289
status,
@@ -306,8 +301,8 @@ const makeStreamRequestAsync: StreamFetchFn = async (
306301
* A helper for issuing HTTP requests.
307302
*/
308303
export class WebClient {
309-
private static _requestFn: FetchFn = makeRequestAsync;
310-
private static _streamRequestFn: StreamFetchFn = makeStreamRequestAsync;
304+
private static _requestFnAsync: FetchFn = makeRequestAsync;
305+
private static _streamRequestFnAsync: StreamFetchFn = makeStreamRequestAsync;
311306

312307
public readonly standardHeaders: Record<string, string> = {};
313308

@@ -317,19 +312,19 @@ export class WebClient {
317312
public proxy: WebClientProxy = WebClientProxy.Detect;
318313

319314
public static mockRequestFn(fn: FetchFn): void {
320-
WebClient._requestFn = fn;
315+
WebClient._requestFnAsync = fn;
321316
}
322317

323318
public static resetMockRequestFn(): void {
324-
WebClient._requestFn = makeRequestAsync;
319+
WebClient._requestFnAsync = makeRequestAsync;
325320
}
326321

327322
public static mockStreamRequestFn(fn: StreamFetchFn): void {
328-
WebClient._streamRequestFn = fn;
323+
WebClient._streamRequestFnAsync = fn;
329324
}
330325

331326
public static resetMockStreamRequestFn(): void {
332-
WebClient._streamRequestFn = makeStreamRequestAsync;
327+
WebClient._streamRequestFnAsync = makeStreamRequestAsync;
333328
}
334329

335330
public static mergeHeaders(target: Record<string, string>, source: Record<string, string>): void {
@@ -347,8 +342,8 @@ export class WebClient {
347342
url: string,
348343
options?: IGetFetchOptions | IFetchOptionsWithBody
349344
): Promise<IWebClientResponse> {
350-
const requestInit: IRequestOptions = buildRequestOptions(this, options);
351-
return await WebClient._requestFn(url, requestInit);
345+
const requestInit: IRequestOptions = this._buildRequestOptions(options);
346+
return await WebClient._requestFnAsync(url, requestInit);
352347
}
353348

354349
/**
@@ -359,71 +354,70 @@ export class WebClient {
359354
url: string,
360355
options?: IGetFetchOptions | IFetchOptionsWithBody
361356
): Promise<IWebClientStreamResponse> {
362-
const requestInit: IRequestOptions = buildRequestOptions(this, options);
363-
return await WebClient._streamRequestFn(url, requestInit);
357+
const requestInit: IRequestOptions = this._buildRequestOptions(options);
358+
return await WebClient._streamRequestFnAsync(url, requestInit);
364359
}
365-
}
366360

367-
function buildRequestOptions(
368-
client: WebClient,
369-
options?: IGetFetchOptions | IFetchOptionsWithBody
370-
): IRequestOptions {
371-
const {
372-
headers: optionsHeaders,
373-
timeoutMs = 15 * 1000,
374-
verb,
375-
redirect,
376-
body,
377-
noDecode
378-
} = (options as IFetchOptionsWithBody | undefined) ?? {};
379-
380-
const headers: Record<string, string> = {};
381-
382-
WebClient.mergeHeaders(headers, client.standardHeaders);
383-
384-
if (optionsHeaders) {
385-
WebClient.mergeHeaders(headers, optionsHeaders);
386-
}
361+
private _buildRequestOptions(options?: IGetFetchOptions | IFetchOptionsWithBody): IRequestOptions {
362+
const {
363+
headers: optionsHeaders,
364+
timeoutMs = 15 * 1000,
365+
verb,
366+
redirect,
367+
body,
368+
noDecode
369+
} = (options as IFetchOptionsWithBody | undefined) ?? {};
387370

388-
if (client.userAgent) {
389-
headers[USER_AGENT_HEADER_NAME] = client.userAgent;
390-
}
371+
const headers: Record<string, string> = {};
391372

392-
if (client.accept) {
393-
headers[ACCEPT_HEADER_NAME] = client.accept;
394-
}
373+
const { standardHeaders, userAgent, accept, proxy } = this;
395374

396-
let proxyUrl: string = '';
375+
WebClient.mergeHeaders(headers, standardHeaders);
397376

398-
switch (client.proxy) {
399-
case WebClientProxy.Detect:
400-
if (process.env.HTTPS_PROXY) {
401-
proxyUrl = process.env.HTTPS_PROXY;
402-
} else if (process.env.HTTP_PROXY) {
403-
proxyUrl = process.env.HTTP_PROXY;
404-
}
405-
break;
406-
407-
case WebClientProxy.Fiddler:
408-
// For debugging, disable cert validation
409-
// eslint-disable-next-line
410-
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
411-
proxyUrl = 'http://localhost:8888/';
412-
break;
413-
}
377+
if (optionsHeaders) {
378+
WebClient.mergeHeaders(headers, optionsHeaders);
379+
}
414380

415-
let agent: HttpAgent | undefined = undefined;
416-
if (proxyUrl) {
417-
agent = createHttpsProxyAgent(proxyUrl);
418-
}
381+
if (userAgent) {
382+
headers[USER_AGENT_HEADER_NAME] = userAgent;
383+
}
384+
385+
if (accept) {
386+
headers[ACCEPT_HEADER_NAME] = accept;
387+
}
388+
389+
let proxyUrl: string = '';
419390

420-
return {
421-
method: verb,
422-
headers,
423-
agent,
424-
timeout: timeoutMs,
425-
redirect,
426-
body,
427-
noDecode
428-
};
391+
switch (proxy) {
392+
case WebClientProxy.Detect:
393+
if (process.env.HTTPS_PROXY) {
394+
proxyUrl = process.env.HTTPS_PROXY;
395+
} else if (process.env.HTTP_PROXY) {
396+
proxyUrl = process.env.HTTP_PROXY;
397+
}
398+
break;
399+
400+
case WebClientProxy.Fiddler:
401+
// For debugging, disable cert validation
402+
// eslint-disable-next-line
403+
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
404+
proxyUrl = 'http://localhost:8888/';
405+
break;
406+
}
407+
408+
let agent: HttpAgent | undefined = undefined;
409+
if (proxyUrl) {
410+
agent = createHttpsProxyAgent(proxyUrl);
411+
}
412+
413+
return {
414+
method: verb,
415+
headers,
416+
agent,
417+
timeout: timeoutMs,
418+
redirect,
419+
body,
420+
noDecode
421+
};
422+
}
429423
}

0 commit comments

Comments
 (0)