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,16 +1,43 @@
1
- var _BlobFromStream_stream, _BlobFromStream_type;
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 { Readable, isReadable } from 'stream';
6
- import { pipeline } from 'stream/promises';
6
+ import { createGunzip, createBrotliDecompress, gunzipSync, brotliDecompressSync, } from 'zlib';
7
7
  import { Blob } from 'buffer';
8
- import { createReadStream } from 'fs';
8
+ import { Readable, pipeline } from 'stream';
9
+ import stream from 'stream';
9
10
  import { basename } from 'path';
10
- import { fetch, Headers, FormData, } from 'undici';
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 { parseJSON } from './utils.js';
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 {
@@ -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.defaultArgs = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.defaultArgs;
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
- var _a, _b, _c, _d;
56
- const requestUrl = typeof url === 'string' ? new URL(url) : url;
57
- const args = {
58
- ...this.defaultArgs,
59
- ...options,
60
- emitter: this,
61
- };
62
- const requestStartTime = Date.now();
63
- // keep urllib createCallbackResponse style
64
- const resHeaders = {};
65
- const res = {
66
- status: -1,
67
- statusCode: -1,
68
- statusMessage: '',
69
- headers: resHeaders,
70
- size: 0,
71
- aborted: false,
72
- rt: 0,
73
- keepAliveSocket: true,
74
- requestUrls: [url.toString()],
75
- timing: {
76
- contentDownload: 0,
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
- let requestTimeout = 5000;
80
- if (args.timeout) {
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 requestTimeoutController = new AbortController();
89
- const requestTimerId = setTimeout(() => requestTimeoutController.abort(), requestTimeout);
90
- const method = ((_b = args.method) !== null && _b !== void 0 ? _b : 'GET').toUpperCase();
91
- try {
92
- const headers = new Headers((_c = args.headers) !== null && _c !== void 0 ? _c : {});
93
- if (!headers.has('user-agent')) {
94
- // need to set user-agent
95
- headers.set('user-agent', HEADER_USER_AGENT);
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
- if (args.dataType === 'json' && !headers.has('accept')) {
98
- headers.set('accept', 'application/json');
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
- const requestOptions = {
101
- method,
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
- const isGETOrHEAD = requestOptions.method === 'GET' || requestOptions.method === 'HEAD';
109
- // alias to args.content
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
- if (isGETOrHEAD) {
115
- requestOptions.method = 'POST';
225
+ else if (typeof args.files === 'object') {
226
+ for (const field in args.files) {
227
+ uploadFiles.push([field, args.files[field]]);
116
228
  }
117
- const formData = new FormData();
118
- const uploadFiles = [];
119
- if (Array.isArray(args.files)) {
120
- for (const [index, file] of args.files.entries()) {
121
- const field = index === 0 ? 'file' : `file${index}`;
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
- else if (args.files instanceof Readable || isReadable(args.files)) {
126
- uploadFiles.push(['file', args.files]);
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 (typeof args.files === 'string' || Buffer.isBuffer(args.files)) {
129
- uploadFiles.push(['file', args.files]);
245
+ else if (Buffer.isBuffer(file)) {
246
+ formData.append(field, new Blob([file]), `bufferfile${index}`);
130
247
  }
131
- else if (typeof args.files === 'object') {
132
- for (const field in args.files) {
133
- uploadFiles.push([field, args.files[field]]);
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
- // set normal fields first
137
- if (args.data) {
138
- for (const field in args.data) {
139
- formData.append(field, args.data[field]);
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
- for (const [index, [field, file]] of uploadFiles.entries()) {
143
- if (typeof file === 'string') {
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
- else if (args.content) {
162
- if (!isGETOrHEAD) {
163
- if (isReadable(args.content)) {
164
- // disable keepalive
165
- requestOptions.keepalive = false;
166
- }
167
- // handle content
168
- requestOptions.body = args.content;
169
- if (args.contentType) {
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 if (args.data) {
175
- const isStringOrBufferOrReadable = typeof args.data === 'string'
176
- || Buffer.isBuffer(args.data)
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 (isStringOrBufferOrReadable) {
187
- if (isReadable(args.data)) {
188
- // disable keepalive
189
- requestOptions.keepalive = false;
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
- if (args.contentType === 'json'
195
- || args.contentType === 'application/json'
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
- debug('%s %s, headers: %j, timeout: %s', requestOptions.method, url, headers, requestTimeout);
209
- requestOptions.headers = headers;
210
- const response = await fetch(requestUrl, requestOptions);
211
- for (const [name, value] of response.headers) {
212
- res.headers[name] = value;
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
- res.status = res.statusCode = response.status;
215
- res.statusMessage = response.statusText;
216
- if (response.redirected) {
217
- res.requestUrls.push(response.url);
353
+ else {
354
+ responseBodyStream = Object.assign(response.body, meta);
218
355
  }
219
- if (res.headers['content-length']) {
220
- res.size = parseInt(res.headers['content-length']);
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
- let data = null;
223
- let responseBodyStream;
224
- if (args.streaming || args.dataType === 'stream') {
225
- const meta = {
226
- status: res.status,
227
- statusCode: res.statusCode,
228
- statusMessage: res.statusMessage,
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
- else {
235
- responseBodyStream = Object.assign(response.body, meta);
375
+ catch (err) {
376
+ if (err.name === 'Error') {
377
+ err.name = 'UnzipError';
378
+ }
379
+ throw err;
236
380
  }
237
381
  }
238
- else if (args.writeStream) {
239
- await pipeline(response.body, args.writeStream);
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 (requestOptions.method === 'HEAD') {
246
- data = {};
386
+ if (data.length === 0) {
387
+ data = null;
247
388
  }
248
389
  else {
249
- data = await response.text();
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
- catch (e) {
274
- let err = e;
275
- if (requestTimeoutController.signal.aborted) {
276
- err = new HttpClientRequestTimeoutError(requestTimeout, { cause: e });
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
- finally {
285
- clearTimeout(requestTimerId);
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