urllib 3.0.0-alpha.1 → 3.0.0

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