Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/parts/request/common/requestImpl.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { bufferToStream, VSBuffer } from '../../../common/buffer.js';
7
import { CancellationToken } from '../../../common/cancellation.js';
8
import { canceled } from '../../../common/errors.js';
9
import { IHeaders, IRequestContext, IRequestOptions, OfflineError } from './request.js';
10
11
export async function request(options: IRequestOptions, token: CancellationToken, isOnline?: () => boolean): Promise<IRequestContext> {
12
if (token.isCancellationRequested) {
13
throw canceled();
14
}
15
16
const cancellation = new AbortController();
17
const disposable = token.onCancellationRequested(() => cancellation.abort());
18
const signal = options.timeout ? AbortSignal.any([
19
cancellation.signal,
20
AbortSignal.timeout(options.timeout),
21
]) : cancellation.signal;
22
23
try {
24
const fetchInit: RequestInit = {
25
method: options.type || 'GET',
26
headers: getRequestHeaders(options),
27
body: options.data,
28
signal
29
};
30
if (options.disableCache) {
31
fetchInit.cache = 'no-store';
32
}
33
const res = await fetch(options.url || '', fetchInit);
34
return {
35
res: {
36
statusCode: res.status,
37
headers: getResponseHeaders(res),
38
},
39
stream: bufferToStream(VSBuffer.wrap(new Uint8Array(await res.arrayBuffer()))),
40
};
41
} catch (err) {
42
if (isOnline && !isOnline()) {
43
throw new OfflineError();
44
}
45
if (err?.name === 'AbortError') {
46
throw canceled();
47
}
48
if (err?.name === 'TimeoutError') {
49
throw new Error(`Fetch timeout: ${options.timeout}ms`);
50
}
51
throw err;
52
} finally {
53
disposable.dispose();
54
}
55
}
56
57
function getRequestHeaders(options: IRequestOptions) {
58
if (options.headers || options.user || options.password || options.proxyAuthorization) {
59
const headers = new Headers();
60
outer: for (const k in options.headers) {
61
switch (k.toLowerCase()) {
62
case 'user-agent':
63
case 'accept-encoding':
64
case 'content-length':
65
// unsafe headers
66
continue outer;
67
}
68
const header = options.headers[k];
69
if (typeof header === 'string') {
70
headers.set(k, header);
71
} else if (Array.isArray(header)) {
72
for (const h of header) {
73
headers.append(k, h);
74
}
75
}
76
}
77
if (options.user || options.password) {
78
headers.set('Authorization', 'Basic ' + btoa(`${options.user || ''}:${options.password || ''}`));
79
}
80
if (options.proxyAuthorization) {
81
headers.set('Proxy-Authorization', options.proxyAuthorization);
82
}
83
return headers;
84
}
85
return undefined;
86
}
87
88
function getResponseHeaders(res: Response): IHeaders {
89
const headers: IHeaders = Object.create(null);
90
res.headers.forEach((value, key) => {
91
if (headers[key]) {
92
if (Array.isArray(headers[key])) {
93
headers[key].push(value);
94
} else {
95
headers[key] = [headers[key], value];
96
}
97
} else {
98
headers[key] = value;
99
}
100
});
101
return headers;
102
}
103
104