urllib 3.0.0-alpha.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/History.md +844 -0
- package/README.md +63 -100
- package/package.json +13 -9
- package/src/HttpAgent.ts +72 -0
- package/src/HttpClient.ts +304 -85
- package/src/Request.ts +51 -54
- package/src/Response.ts +11 -10
- package/src/cjs/HttpAgent.d.ts +16 -0
- package/src/cjs/HttpAgent.js +62 -0
- package/src/cjs/HttpAgent.js.map +1 -0
- package/src/cjs/HttpClient.d.ts +29 -1
- package/src/cjs/HttpClient.js +373 -200
- package/src/cjs/HttpClient.js.map +1 -1
- package/src/cjs/Request.d.ts +47 -54
- package/src/cjs/Response.d.ts +9 -8
- package/src/cjs/index.d.ts +3 -1
- package/src/cjs/index.js +6 -1
- package/src/cjs/index.js.map +1 -1
- package/src/cjs/utils.d.ts +1 -0
- package/src/cjs/utils.js +7 -1
- package/src/cjs/utils.js.map +1 -1
- package/src/esm/HttpAgent.d.ts +16 -0
- package/src/esm/HttpAgent.js +58 -0
- package/src/esm/HttpAgent.js.map +1 -0
- package/src/esm/HttpClient.d.ts +29 -1
- package/src/esm/HttpClient.js +373 -200
- package/src/esm/HttpClient.js.map +1 -1
- package/src/esm/Request.d.ts +47 -54
- package/src/esm/Response.d.ts +9 -8
- package/src/esm/index.d.ts +3 -1
- package/src/esm/index.js +4 -2
- package/src/esm/index.js.map +1 -1
- package/src/esm/utils.d.ts +1 -0
- package/src/esm/utils.js +5 -0
- package/src/esm/utils.js.map +1 -1
- package/src/index.ts +4 -3
- package/src/utils.ts +6 -0
package/src/esm/HttpClient.js
CHANGED
@@ -1,16 +1,43 @@
|
|
1
|
-
var
|
1
|
+
var _a, _b, _c;
|
2
|
+
var _BlobFromStream_stream, _BlobFromStream_type, _HttpClient_instances, _HttpClient_defaultArgs, _HttpClient_dispatcher, _HttpClient_requestInternal;
|
2
3
|
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
3
4
|
import { EventEmitter } from 'events';
|
4
5
|
import { debuglog } from 'util';
|
5
|
-
import {
|
6
|
-
import { pipeline } from 'stream/promises';
|
6
|
+
import { createGunzip, createBrotliDecompress, gunzipSync, brotliDecompressSync, } from 'zlib';
|
7
7
|
import { Blob } from 'buffer';
|
8
|
-
import {
|
8
|
+
import { Readable, pipeline } from 'stream';
|
9
|
+
import stream from 'stream';
|
9
10
|
import { basename } from 'path';
|
10
|
-
import {
|
11
|
+
import { createReadStream } from 'fs';
|
12
|
+
import { performance } from 'perf_hooks';
|
13
|
+
import { FormData as FormDataNative, request as undiciRequest, } from 'undici';
|
14
|
+
import { FormData as FormDataNode } from 'formdata-node';
|
15
|
+
import { FormDataEncoder } from 'form-data-encoder';
|
11
16
|
import createUserAgent from 'default-user-agent';
|
12
17
|
import mime from 'mime-types';
|
13
|
-
import
|
18
|
+
import pump from 'pump';
|
19
|
+
import { HttpAgent } from './HttpAgent.js';
|
20
|
+
import { parseJSON, sleep } from './utils.js';
|
21
|
+
const FormData = FormDataNative !== null && FormDataNative !== void 0 ? FormDataNative : FormDataNode;
|
22
|
+
// impl isReadable on Node.js 14
|
23
|
+
const isReadable = (_a = stream.isReadable) !== null && _a !== void 0 ? _a : function isReadable(stream) {
|
24
|
+
return stream && typeof stream.read === 'function';
|
25
|
+
};
|
26
|
+
// impl promise pipeline on Node.js 14
|
27
|
+
const pipelinePromise = (_c = (_b = stream.promises) === null || _b === void 0 ? void 0 : _b.pipeline) !== null && _c !== void 0 ? _c : function pipeline(...args) {
|
28
|
+
return new Promise((resolve, reject) => {
|
29
|
+
pump(...args, (err) => {
|
30
|
+
if (err)
|
31
|
+
return reject(err);
|
32
|
+
resolve();
|
33
|
+
});
|
34
|
+
});
|
35
|
+
};
|
36
|
+
function noop() {
|
37
|
+
// noop
|
38
|
+
}
|
39
|
+
const MAX_REQURE_ID_VALUE = Math.pow(2, 31) - 10;
|
40
|
+
let globalRequestId = 0;
|
14
41
|
const debug = debuglog('urllib');
|
15
42
|
// https://github.com/octet-stream/form-data
|
16
43
|
class BlobFromStream {
|
@@ -38,7 +65,7 @@ class HttpClientRequestTimeoutError extends Error {
|
|
38
65
|
Error.captureStackTrace(this, this.constructor);
|
39
66
|
}
|
40
67
|
}
|
41
|
-
const HEADER_USER_AGENT = createUserAgent('node-urllib', '3.0.0');
|
68
|
+
export const HEADER_USER_AGENT = createUserAgent('node-urllib', '3.0.0');
|
42
69
|
function getFileName(stream) {
|
43
70
|
const filePath = stream.path;
|
44
71
|
if (filePath) {
|
@@ -46,244 +73,390 @@ function getFileName(stream) {
|
|
46
73
|
}
|
47
74
|
return '';
|
48
75
|
}
|
76
|
+
function defaultIsRetry(response) {
|
77
|
+
return response.status >= 500;
|
78
|
+
}
|
79
|
+
function performanceTime(startTime) {
|
80
|
+
return Math.floor((performance.now() - startTime) * 1000) / 1000;
|
81
|
+
}
|
49
82
|
export class HttpClient extends EventEmitter {
|
50
83
|
constructor(clientOptions) {
|
51
84
|
super();
|
52
|
-
this
|
85
|
+
_HttpClient_instances.add(this);
|
86
|
+
_HttpClient_defaultArgs.set(this, void 0);
|
87
|
+
_HttpClient_dispatcher.set(this, void 0);
|
88
|
+
__classPrivateFieldSet(this, _HttpClient_defaultArgs, clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.defaultArgs, "f");
|
89
|
+
if ((clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.lookup) || (clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.checkAddress) || (clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.connect)) {
|
90
|
+
__classPrivateFieldSet(this, _HttpClient_dispatcher, new HttpAgent({
|
91
|
+
lookup: clientOptions.lookup,
|
92
|
+
checkAddress: clientOptions.checkAddress,
|
93
|
+
connect: clientOptions.connect,
|
94
|
+
}), "f");
|
95
|
+
}
|
53
96
|
}
|
54
97
|
async request(url, options) {
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
98
|
+
return await __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_requestInternal).call(this, url, options);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
_HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(), _HttpClient_instances = new WeakSet(), _HttpClient_requestInternal = async function _HttpClient_requestInternal(url, options, requestContext) {
|
102
|
+
var _a, _b, _c, _d, _e, _f;
|
103
|
+
if (globalRequestId >= MAX_REQURE_ID_VALUE) {
|
104
|
+
globalRequestId = 0;
|
105
|
+
}
|
106
|
+
const requestId = ++globalRequestId;
|
107
|
+
const requestUrl = typeof url === 'string' ? new URL(url) : url;
|
108
|
+
const args = {
|
109
|
+
retry: 0,
|
110
|
+
...__classPrivateFieldGet(this, _HttpClient_defaultArgs, "f"),
|
111
|
+
...options,
|
112
|
+
};
|
113
|
+
requestContext = {
|
114
|
+
retries: 0,
|
115
|
+
...requestContext,
|
116
|
+
};
|
117
|
+
const requestStartTime = performance.now();
|
118
|
+
const reqMeta = {
|
119
|
+
requestId,
|
120
|
+
url: requestUrl.href,
|
121
|
+
args,
|
122
|
+
ctx: args.ctx,
|
123
|
+
};
|
124
|
+
// keep urllib createCallbackResponse style
|
125
|
+
const resHeaders = {};
|
126
|
+
const res = {
|
127
|
+
status: -1,
|
128
|
+
statusCode: -1,
|
129
|
+
headers: resHeaders,
|
130
|
+
size: 0,
|
131
|
+
aborted: false,
|
132
|
+
rt: 0,
|
133
|
+
keepAliveSocket: true,
|
134
|
+
requestUrls: [],
|
135
|
+
timing: {
|
136
|
+
waiting: 0,
|
137
|
+
contentDownload: 0,
|
138
|
+
},
|
139
|
+
};
|
140
|
+
let headersTimeout = 5000;
|
141
|
+
let bodyTimeout = 5000;
|
142
|
+
if (args.timeout) {
|
143
|
+
if (Array.isArray(args.timeout)) {
|
144
|
+
headersTimeout = (_a = args.timeout[0]) !== null && _a !== void 0 ? _a : headersTimeout;
|
145
|
+
bodyTimeout = (_b = args.timeout[1]) !== null && _b !== void 0 ? _b : bodyTimeout;
|
146
|
+
}
|
147
|
+
else {
|
148
|
+
headersTimeout = bodyTimeout = args.timeout;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
const method = ((_c = args.method) !== null && _c !== void 0 ? _c : 'GET').toUpperCase();
|
152
|
+
const headers = {};
|
153
|
+
if (args.headers) {
|
154
|
+
// convert headers to lower-case
|
155
|
+
for (const name in args.headers) {
|
156
|
+
headers[name.toLowerCase()] = args.headers[name];
|
157
|
+
}
|
158
|
+
}
|
159
|
+
// hidden user-agent
|
160
|
+
const hiddenUserAgent = 'user-agent' in headers && !headers['user-agent'];
|
161
|
+
if (hiddenUserAgent) {
|
162
|
+
delete headers['user-agent'];
|
163
|
+
}
|
164
|
+
else if (!headers['user-agent']) {
|
165
|
+
// need to set user-agent
|
166
|
+
headers['user-agent'] = HEADER_USER_AGENT;
|
167
|
+
}
|
168
|
+
// Alias to dataType = 'stream'
|
169
|
+
if (args.streaming || args.customResponse) {
|
170
|
+
args.dataType = 'stream';
|
171
|
+
}
|
172
|
+
if (args.dataType === 'json' && !headers.accept) {
|
173
|
+
headers.accept = 'application/json';
|
174
|
+
}
|
175
|
+
// gzip alias to compressed
|
176
|
+
if (args.gzip && args.compressed !== false) {
|
177
|
+
args.compressed = true;
|
178
|
+
}
|
179
|
+
if (args.compressed && !headers['accept-encoding']) {
|
180
|
+
headers['accept-encoding'] = 'gzip, br';
|
181
|
+
}
|
182
|
+
if (requestContext.retries > 0) {
|
183
|
+
headers['x-urllib-retry'] = `${requestContext.retries}/${args.retry}`;
|
184
|
+
}
|
185
|
+
if (args.auth && !headers.authorization) {
|
186
|
+
headers.authorization = `Basic ${Buffer.from(args.auth).toString('base64')}`;
|
187
|
+
}
|
188
|
+
let opaque = args.opaque;
|
189
|
+
try {
|
190
|
+
const requestOptions = {
|
191
|
+
method,
|
192
|
+
keepalive: true,
|
193
|
+
maxRedirections: (_d = args.maxRedirects) !== null && _d !== void 0 ? _d : 10,
|
194
|
+
headersTimeout,
|
195
|
+
bodyTimeout,
|
196
|
+
opaque,
|
197
|
+
dispatcher: __classPrivateFieldGet(this, _HttpClient_dispatcher, "f"),
|
78
198
|
};
|
79
|
-
|
80
|
-
|
81
|
-
if (Array.isArray(args.timeout)) {
|
82
|
-
requestTimeout = (_a = args.timeout[args.timeout.length - 1]) !== null && _a !== void 0 ? _a : requestTimeout;
|
83
|
-
}
|
84
|
-
else {
|
85
|
-
requestTimeout = args.timeout;
|
86
|
-
}
|
199
|
+
if (args.followRedirect === false) {
|
200
|
+
requestOptions.maxRedirections = 0;
|
87
201
|
}
|
88
|
-
const
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
202
|
+
const isGETOrHEAD = requestOptions.method === 'GET' || requestOptions.method === 'HEAD';
|
203
|
+
// alias to args.content
|
204
|
+
if (args.stream && !args.content) {
|
205
|
+
args.content = args.stream;
|
206
|
+
}
|
207
|
+
if (args.files) {
|
208
|
+
if (isGETOrHEAD) {
|
209
|
+
requestOptions.method = 'POST';
|
96
210
|
}
|
97
|
-
|
98
|
-
|
211
|
+
const formData = new FormData();
|
212
|
+
const uploadFiles = [];
|
213
|
+
if (Array.isArray(args.files)) {
|
214
|
+
for (const [index, file] of args.files.entries()) {
|
215
|
+
const field = index === 0 ? 'file' : `file${index}`;
|
216
|
+
uploadFiles.push([field, file]);
|
217
|
+
}
|
99
218
|
}
|
100
|
-
|
101
|
-
|
102
|
-
keepalive: true,
|
103
|
-
signal: requestTimeoutController.signal,
|
104
|
-
};
|
105
|
-
if (args.followRedirect === false) {
|
106
|
-
requestOptions.redirect = 'manual';
|
219
|
+
else if (args.files instanceof Readable || isReadable(args.files)) {
|
220
|
+
uploadFiles.push(['file', args.files]);
|
107
221
|
}
|
108
|
-
|
109
|
-
|
110
|
-
if (args.stream && !args.content) {
|
111
|
-
args.content = args.stream;
|
222
|
+
else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) {
|
223
|
+
uploadFiles.push(['file', args.files]);
|
112
224
|
}
|
113
|
-
if (args.files) {
|
114
|
-
|
115
|
-
|
225
|
+
else if (typeof args.files === 'object') {
|
226
|
+
for (const field in args.files) {
|
227
|
+
uploadFiles.push([field, args.files[field]]);
|
116
228
|
}
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
uploadFiles.push([field, file]);
|
123
|
-
}
|
229
|
+
}
|
230
|
+
// set normal fields first
|
231
|
+
if (args.data) {
|
232
|
+
for (const field in args.data) {
|
233
|
+
formData.append(field, args.data[field]);
|
124
234
|
}
|
125
|
-
|
126
|
-
|
235
|
+
}
|
236
|
+
for (const [index, [field, file]] of uploadFiles.entries()) {
|
237
|
+
if (typeof file === 'string') {
|
238
|
+
// FIXME: support non-ascii filename
|
239
|
+
// const fileName = encodeURIComponent(basename(file));
|
240
|
+
// formData.append(field, await fileFromPath(file, `utf-8''${fileName}`, { type: mime.lookup(fileName) || '' }));
|
241
|
+
const fileName = basename(file);
|
242
|
+
const fileReadable = createReadStream(file);
|
243
|
+
formData.append(field, new BlobFromStream(fileReadable, mime.lookup(fileName) || ''), fileName);
|
127
244
|
}
|
128
|
-
else if (
|
129
|
-
|
245
|
+
else if (Buffer.isBuffer(file)) {
|
246
|
+
formData.append(field, new Blob([file]), `bufferfile${index}`);
|
130
247
|
}
|
131
|
-
else if (
|
132
|
-
|
133
|
-
|
134
|
-
}
|
248
|
+
else if (file instanceof Readable || isReadable(file)) {
|
249
|
+
const fileName = getFileName(file) || `streamfile${index}`;
|
250
|
+
formData.append(field, new BlobFromStream(file, mime.lookup(fileName) || ''), fileName);
|
135
251
|
}
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
252
|
+
}
|
253
|
+
if (FormDataNative) {
|
254
|
+
requestOptions.body = formData;
|
255
|
+
}
|
256
|
+
else {
|
257
|
+
// Node.js 14 does not support spec-compliant FormData
|
258
|
+
// https://github.com/octet-stream/form-data#usage
|
259
|
+
const encoder = new FormDataEncoder(formData);
|
260
|
+
Object.assign(headers, encoder.headers);
|
261
|
+
// fix "Content-Length":"NaN"
|
262
|
+
delete headers['Content-Length'];
|
263
|
+
requestOptions.body = Readable.from(encoder);
|
264
|
+
}
|
265
|
+
}
|
266
|
+
else if (args.content) {
|
267
|
+
if (!isGETOrHEAD) {
|
268
|
+
// handle content
|
269
|
+
requestOptions.body = args.content;
|
270
|
+
if (args.contentType) {
|
271
|
+
headers['content-type'] = args.contentType;
|
141
272
|
}
|
142
|
-
|
143
|
-
|
144
|
-
// FIXME: support non-ascii filename
|
145
|
-
// const fileName = encodeURIComponent(basename(file));
|
146
|
-
// formData.append(field, await fileFromPath(file, `utf-8''${fileName}`, { type: mime.lookup(fileName) || '' }));
|
147
|
-
const fileName = basename(file);
|
148
|
-
const fileReader = createReadStream(file);
|
149
|
-
formData.append(field, new BlobFromStream(fileReader, mime.lookup(fileName) || ''), fileName);
|
150
|
-
}
|
151
|
-
else if (Buffer.isBuffer(file)) {
|
152
|
-
formData.append(field, new Blob([file]), `bufferfile${index}`);
|
153
|
-
}
|
154
|
-
else if (file instanceof Readable || isReadable(file)) {
|
155
|
-
const fileName = getFileName(file) || `streamfile${index}`;
|
156
|
-
formData.append(field, new BlobFromStream(file, mime.lookup(fileName) || ''), fileName);
|
157
|
-
}
|
273
|
+
if (typeof args.content === 'string' && !headers['content-type']) {
|
274
|
+
headers['content-type'] = 'text/plain;charset=UTF-8';
|
158
275
|
}
|
159
|
-
requestOptions.body = formData;
|
160
276
|
}
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
headers.set('content-type', args.contentType);
|
277
|
+
}
|
278
|
+
else if (args.data) {
|
279
|
+
const isStringOrBufferOrReadable = typeof args.data === 'string'
|
280
|
+
|| Buffer.isBuffer(args.data)
|
281
|
+
|| isReadable(args.data);
|
282
|
+
if (isGETOrHEAD) {
|
283
|
+
if (!isStringOrBufferOrReadable) {
|
284
|
+
for (const field in args.data) {
|
285
|
+
requestUrl.searchParams.append(field, args.data[field]);
|
171
286
|
}
|
172
287
|
}
|
173
288
|
}
|
174
|
-
else
|
175
|
-
|
176
|
-
|
177
|
-
|| isReadable(args.data);
|
178
|
-
if (isGETOrHEAD) {
|
179
|
-
if (!isStringOrBufferOrReadable) {
|
180
|
-
for (const field in args.data) {
|
181
|
-
requestUrl.searchParams.append(field, args.data[field]);
|
182
|
-
}
|
183
|
-
}
|
289
|
+
else {
|
290
|
+
if (isStringOrBufferOrReadable) {
|
291
|
+
requestOptions.body = args.data;
|
184
292
|
}
|
185
293
|
else {
|
186
|
-
if (
|
187
|
-
|
188
|
-
|
189
|
-
|
294
|
+
if (args.contentType === 'json'
|
295
|
+
|| args.contentType === 'application/json'
|
296
|
+
|| ((_e = headers['content-type']) === null || _e === void 0 ? void 0 : _e.startsWith('application/json'))) {
|
297
|
+
requestOptions.body = JSON.stringify(args.data);
|
298
|
+
if (!headers['content-type']) {
|
299
|
+
headers['content-type'] = 'application/json';
|
190
300
|
}
|
191
|
-
requestOptions.body = args.data;
|
192
301
|
}
|
193
302
|
else {
|
194
|
-
|
195
|
-
|
196
|
-
|| ((_d = headers.get('content-type')) === null || _d === void 0 ? void 0 : _d.startsWith('application/json'))) {
|
197
|
-
requestOptions.body = JSON.stringify(args.data);
|
198
|
-
if (!headers.has('content-type')) {
|
199
|
-
headers.set('content-type', 'application/json');
|
200
|
-
}
|
201
|
-
}
|
202
|
-
else {
|
203
|
-
requestOptions.body = new URLSearchParams(args.data);
|
204
|
-
}
|
303
|
+
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
304
|
+
requestOptions.body = new URLSearchParams(args.data).toString();
|
205
305
|
}
|
206
306
|
}
|
207
307
|
}
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
308
|
+
}
|
309
|
+
debug('Request#%d %s %s, headers: %j, headersTimeout: %s, bodyTimeout: %s', requestId, requestOptions.method, requestUrl.href, headers, headersTimeout, bodyTimeout);
|
310
|
+
requestOptions.headers = headers;
|
311
|
+
if (this.listenerCount('request') > 0) {
|
312
|
+
this.emit('request', reqMeta);
|
313
|
+
}
|
314
|
+
const response = await undiciRequest(requestUrl, requestOptions);
|
315
|
+
opaque = response.opaque;
|
316
|
+
if (args.timing) {
|
317
|
+
res.timing.waiting = performanceTime(requestStartTime);
|
318
|
+
}
|
319
|
+
const context = response.context;
|
320
|
+
let lastUrl = '';
|
321
|
+
if (context === null || context === void 0 ? void 0 : context.history) {
|
322
|
+
for (const urlObject of context === null || context === void 0 ? void 0 : context.history) {
|
323
|
+
res.requestUrls.push(urlObject.href);
|
324
|
+
lastUrl = urlObject.href;
|
325
|
+
}
|
326
|
+
}
|
327
|
+
else {
|
328
|
+
res.requestUrls.push(requestUrl.href);
|
329
|
+
lastUrl = requestUrl.href;
|
330
|
+
}
|
331
|
+
const contentEncoding = response.headers['content-encoding'];
|
332
|
+
const isCompressedContent = contentEncoding === 'gzip' || contentEncoding === 'br';
|
333
|
+
res.headers = response.headers;
|
334
|
+
res.status = res.statusCode = response.statusCode;
|
335
|
+
if (res.headers['content-length']) {
|
336
|
+
res.size = parseInt(res.headers['content-length']);
|
337
|
+
}
|
338
|
+
let data = null;
|
339
|
+
let responseBodyStream;
|
340
|
+
if (args.dataType === 'stream') {
|
341
|
+
// streaming mode will disable retry
|
342
|
+
args.retry = 0;
|
343
|
+
const meta = {
|
344
|
+
status: res.status,
|
345
|
+
statusCode: res.statusCode,
|
346
|
+
headers: res.headers,
|
347
|
+
};
|
348
|
+
if (isCompressedContent) {
|
349
|
+
// gzip or br
|
350
|
+
const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
|
351
|
+
responseBodyStream = Object.assign(pipeline(response.body, decoder, noop), meta);
|
213
352
|
}
|
214
|
-
|
215
|
-
|
216
|
-
if (response.redirected) {
|
217
|
-
res.requestUrls.push(response.url);
|
353
|
+
else {
|
354
|
+
responseBodyStream = Object.assign(response.body, meta);
|
218
355
|
}
|
219
|
-
|
220
|
-
|
356
|
+
}
|
357
|
+
else if (args.writeStream) {
|
358
|
+
// streaming mode will disable retry
|
359
|
+
args.retry = 0;
|
360
|
+
if (isCompressedContent) {
|
361
|
+
const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
|
362
|
+
await pipelinePromise(response.body, decoder, args.writeStream);
|
363
|
+
}
|
364
|
+
else {
|
365
|
+
await pipelinePromise(response.body, args.writeStream);
|
221
366
|
}
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
headers: res.headers,
|
230
|
-
};
|
231
|
-
if (typeof Readable.fromWeb === 'function') {
|
232
|
-
responseBodyStream = Object.assign(Readable.fromWeb(response.body), meta);
|
367
|
+
}
|
368
|
+
else {
|
369
|
+
// buffer
|
370
|
+
data = Buffer.from(await response.body.arrayBuffer());
|
371
|
+
if (isCompressedContent) {
|
372
|
+
try {
|
373
|
+
data = contentEncoding === 'gzip' ? gunzipSync(data) : brotliDecompressSync(data);
|
233
374
|
}
|
234
|
-
|
235
|
-
|
375
|
+
catch (err) {
|
376
|
+
if (err.name === 'Error') {
|
377
|
+
err.name = 'UnzipError';
|
378
|
+
}
|
379
|
+
throw err;
|
236
380
|
}
|
237
381
|
}
|
238
|
-
|
239
|
-
|
240
|
-
}
|
241
|
-
else if (args.dataType === 'text') {
|
242
|
-
data = await response.text();
|
382
|
+
if (args.dataType === 'text') {
|
383
|
+
data = data.toString();
|
243
384
|
}
|
244
385
|
else if (args.dataType === 'json') {
|
245
|
-
if (
|
246
|
-
data =
|
386
|
+
if (data.length === 0) {
|
387
|
+
data = null;
|
247
388
|
}
|
248
389
|
else {
|
249
|
-
data =
|
250
|
-
if (data.length === 0) {
|
251
|
-
data = null;
|
252
|
-
}
|
253
|
-
else {
|
254
|
-
data = parseJSON(data, args.fixJSONCtlChars);
|
255
|
-
}
|
390
|
+
data = parseJSON(data.toString(), args.fixJSONCtlChars);
|
256
391
|
}
|
257
392
|
}
|
258
|
-
else {
|
259
|
-
// buffer
|
260
|
-
data = Buffer.from(await response.arrayBuffer());
|
261
|
-
}
|
262
|
-
res.rt = res.timing.contentDownload = Date.now() - requestStartTime;
|
263
|
-
const clientResponse = {
|
264
|
-
status: res.status,
|
265
|
-
data,
|
266
|
-
headers: res.headers,
|
267
|
-
url: response.url,
|
268
|
-
redirected: response.redirected,
|
269
|
-
res: responseBodyStream !== null && responseBodyStream !== void 0 ? responseBodyStream : res,
|
270
|
-
};
|
271
|
-
return clientResponse;
|
272
393
|
}
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
394
|
+
res.rt = performanceTime(requestStartTime);
|
395
|
+
if (args.timing) {
|
396
|
+
res.timing.contentDownload = res.rt;
|
397
|
+
}
|
398
|
+
const clientResponse = {
|
399
|
+
opaque,
|
400
|
+
data,
|
401
|
+
status: res.status,
|
402
|
+
headers: res.headers,
|
403
|
+
url: lastUrl,
|
404
|
+
redirected: res.requestUrls.length > 1,
|
405
|
+
requestUrls: res.requestUrls,
|
406
|
+
res: responseBodyStream !== null && responseBodyStream !== void 0 ? responseBodyStream : res,
|
407
|
+
};
|
408
|
+
if (args.retry > 0 && requestContext.retries < args.retry) {
|
409
|
+
const isRetry = (_f = args.isRetry) !== null && _f !== void 0 ? _f : defaultIsRetry;
|
410
|
+
if (isRetry(clientResponse)) {
|
411
|
+
if (args.retryDelay) {
|
412
|
+
await sleep(args.retryDelay);
|
413
|
+
}
|
414
|
+
requestContext.retries++;
|
415
|
+
return await __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_requestInternal).call(this, url, options, requestContext);
|
277
416
|
}
|
278
|
-
err.res = res;
|
279
|
-
err.status = res.status;
|
280
|
-
err.headers = res.headers;
|
281
|
-
// console.error(err);
|
282
|
-
throw err;
|
283
417
|
}
|
284
|
-
|
285
|
-
|
418
|
+
if (this.listenerCount('response') > 0) {
|
419
|
+
this.emit('response', {
|
420
|
+
requestId,
|
421
|
+
error: null,
|
422
|
+
ctx: args.ctx,
|
423
|
+
req: reqMeta,
|
424
|
+
res,
|
425
|
+
});
|
286
426
|
}
|
427
|
+
return clientResponse;
|
287
428
|
}
|
288
|
-
|
429
|
+
catch (e) {
|
430
|
+
debug('Request#%d throw error: %s', requestId, e);
|
431
|
+
let err = e;
|
432
|
+
if (err.name === 'HeadersTimeoutError') {
|
433
|
+
err = new HttpClientRequestTimeoutError(headersTimeout, { cause: e });
|
434
|
+
}
|
435
|
+
else if (err.name === 'BodyTimeoutError') {
|
436
|
+
err = new HttpClientRequestTimeoutError(bodyTimeout, { cause: e });
|
437
|
+
}
|
438
|
+
err.opaque = opaque;
|
439
|
+
err.status = res.status;
|
440
|
+
err.headers = res.headers;
|
441
|
+
err.res = res;
|
442
|
+
// make sure requestUrls not empty
|
443
|
+
if (res.requestUrls.length === 0) {
|
444
|
+
res.requestUrls.push(requestUrl.href);
|
445
|
+
}
|
446
|
+
res.rt = performanceTime(requestStartTime);
|
447
|
+
if (args.timing) {
|
448
|
+
res.timing.contentDownload = res.rt;
|
449
|
+
}
|
450
|
+
if (this.listenerCount('response') > 0) {
|
451
|
+
this.emit('response', {
|
452
|
+
requestId,
|
453
|
+
error: err,
|
454
|
+
ctx: args.ctx,
|
455
|
+
req: reqMeta,
|
456
|
+
res,
|
457
|
+
});
|
458
|
+
}
|
459
|
+
throw err;
|
460
|
+
}
|
461
|
+
};
|
289
462
|
//# sourceMappingURL=HttpClient.js.map
|