@wiajs/request 3.0.35 → 3.0.37

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/dist/request.mjs CHANGED
@@ -1,176 +1,154 @@
1
1
  /*!
2
- * wia request v3.0.35
2
+ * wia request v3.0.37
3
3
  * (c) 2022-2025 Sibyl Yu and contributors
4
4
  * Released under the MIT License.
5
5
  */
6
- import stream, { Duplex } from 'node:stream';
7
6
  import { log as log$2, name } from '@wiajs/log';
7
+ import stream, { Duplex } from 'stream';
8
+ import assert from 'assert';
9
+ import http from 'http';
10
+ import https from 'https';
8
11
  import mime from 'mime-types';
9
- import assert from 'node:assert';
10
- import http from 'node:http';
11
- import https from 'node:https';
12
- import url from 'node:url';
13
- import zlib from 'node:zlib';
12
+ import url from 'url';
13
+ import zlib from 'zlib';
14
14
 
15
- class ZlibTransform extends stream.Transform {
16
- /**
17
- *
18
- * @param {*} chunk
19
- * @param {*} encoding
20
- * @param {*} callback
21
- */
22
- __transform(chunk, encoding, callback) {
23
- this.push(chunk);
24
- callback();
25
- }
26
-
27
- /**
28
- *
29
- * @param {*} chunk
30
- * @param {*} encoding
31
- * @param {*} callback
32
- */
33
- _transform(chunk, encoding, callback) {
34
- if (chunk.length !== 0) {
35
- this._transform = this.__transform;
36
-
37
- // Add Default Compression headers if no zlib headers are present
38
- if (chunk[0] !== 120) {
39
- // Hex: 78
40
- const header = Buffer.alloc(2);
41
- header[0] = 120; // Hex: 78
42
- header[1] = 156; // Hex: 9C
43
- this.push(header, encoding);
44
- }
45
- }
46
-
47
- this.__transform(chunk, encoding, callback);
48
- }
49
- }
15
+ let ZlibTransform = class ZlibTransform extends stream.Transform {
16
+ /**
17
+ *
18
+ * @param {*} chunk
19
+ * @param {*} encoding
20
+ * @param {*} callback
21
+ */ __transform(chunk, encoding, callback) {
22
+ this.push(chunk);
23
+ callback();
24
+ }
25
+ /**
26
+ *
27
+ * @param {*} chunk
28
+ * @param {*} encoding
29
+ * @param {*} callback
30
+ */ _transform(chunk, encoding, callback) {
31
+ if (chunk.length !== 0) {
32
+ this._transform = this.__transform;
33
+ // Add Default Compression headers if no zlib headers are present
34
+ if (chunk[0] !== 120) {
35
+ // Hex: 78
36
+ const header = Buffer.alloc(2);
37
+ header[0] = 120 // Hex: 78
38
+ ;
39
+ header[1] = 156 // Hex: 9C
40
+ ;
41
+ this.push(header, encoding);
42
+ }
43
+ }
44
+ this.__transform(chunk, encoding, callback);
45
+ }
46
+ };
50
47
 
51
- class Caseless {
52
- /**
53
- * @param {*} dict
54
- */
55
- constructor(dict) {
56
- this.dict = dict || {};
57
- }
58
-
59
- /**
48
+ let Caseless = class Caseless {
49
+ /**
60
50
  *
61
51
  * @param {*} name
62
52
  * @param {*} value
63
53
  * @param {*} clobber
64
54
  * @returns
65
- */
66
- set(name, value, clobber) {
67
- if (typeof name === 'object') {
68
- for (const n of name) {
69
- this.set(n, name[n], value);
70
- }
71
- } else {
72
- if (typeof clobber === 'undefined') clobber = true;
73
- const has = this.has(name);
74
-
75
- if (!clobber && has) this.dict[has] = this.dict[has] + ',' + value;
76
- else this.dict[has || name] = value;
77
- return has
78
- }
79
- }
80
-
81
- /**
55
+ */ set(name, value, clobber) {
56
+ if (typeof name === 'object') {
57
+ for (const n of name){
58
+ this.set(n, name[n], value);
59
+ }
60
+ } else {
61
+ if (typeof clobber === 'undefined') clobber = true;
62
+ const has = this.has(name);
63
+ if (!clobber && has) this.dict[has] = this.dict[has] + ',' + value;
64
+ else this.dict[has || name] = value;
65
+ return has;
66
+ }
67
+ }
68
+ /**
69
+ *
70
+ * @param {string} name
71
+ * @returns
72
+ */ has(name) {
73
+ const keys = Object.keys(this.dict);
74
+ name = name.toLowerCase();
75
+ for(let i = 0; i < keys.length; i++){
76
+ if (keys[i].toLowerCase() === name) return keys[i];
77
+ }
78
+ return false;
79
+ }
80
+ /**
82
81
  *
83
82
  * @param {string} name
84
83
  * @returns
85
- */
86
- has(name) {
87
- const keys = Object.keys(this.dict);
88
- name = name.toLowerCase();
89
- for (let i = 0; i < keys.length; i++) {
90
- if (keys[i].toLowerCase() === name) return keys[i]
91
- }
92
- return false
93
- }
94
-
95
- /**
84
+ */ get(name) {
85
+ name = name.toLowerCase();
86
+ let result;
87
+ let _key;
88
+ const headers = this.dict;
89
+ for (const key of Object.keys(headers)){
90
+ _key = key.toLowerCase();
91
+ if (name === _key) result = headers[key];
92
+ }
93
+ return result;
94
+ }
95
+ /**
96
96
  *
97
97
  * @param {string} name
98
98
  * @returns
99
- */
100
- get(name) {
101
- name = name.toLowerCase();
102
- let result;
103
- let _key;
104
- const headers = this.dict;
105
- for (const key of Object.keys(headers)) {
106
- _key = key.toLowerCase();
107
- if (name === _key) result = headers[key];
108
- }
109
- return result
110
- }
111
-
112
- /**
99
+ */ swap(name) {
100
+ const has = this.has(name);
101
+ if (has === name) return;
102
+ if (!has) throw new Error('There is no header than matches "' + name + '"');
103
+ this.dict[name] = this.dict[has];
104
+ delete this.dict[has];
105
+ }
106
+ /**
113
107
  *
114
108
  * @param {string} name
115
109
  * @returns
116
- */
117
- swap(name) {
118
- const has = this.has(name);
119
- if (has === name) return
120
- if (!has) throw new Error('There is no header than matches "' + name + '"')
121
- this.dict[name] = this.dict[has];
122
- delete this.dict[has];
123
- }
124
-
125
- /**
126
- *
127
- * @param {string} name
128
- * @returns
129
- */
130
- del(name) {
131
- name = String(name).toLowerCase();
132
- let deleted = false;
133
- let changed = 0;
134
- const dict = this.dict;
135
- for (const key of Object.keys(this.dict)) {
136
- if (name === String(key).toLowerCase()) {
137
- deleted = delete dict[key];
138
- changed += 1;
139
- }
140
- }
141
- return changed === 0 ? true : deleted
142
- }
143
- }
110
+ */ del(name) {
111
+ name = String(name).toLowerCase();
112
+ let deleted = false;
113
+ let changed = 0;
114
+ const dict = this.dict;
115
+ for (const key of Object.keys(this.dict)){
116
+ if (name === String(key).toLowerCase()) {
117
+ deleted = delete dict[key];
118
+ changed += 1;
119
+ }
120
+ }
121
+ return changed === 0 ? true : deleted;
122
+ }
123
+ /**
124
+ * @param {*} dict
125
+ */ constructor(dict){
126
+ this.dict = dict || {};
127
+ }
128
+ };
144
129
 
145
- /**
146
- * utils for request
147
- */
148
-
149
- const {URL} = url;
150
-
151
- // Whether to use the native URL object or the legacy url module
152
- let useNativeURL = false;
153
- try {
154
- assert(new URL(''));
155
- } catch (error) {
156
- useNativeURL = error.code === 'ERR_INVALID_URL';
157
- }
158
-
159
- // URL fields to preserve in copy operations
160
- const preservedUrlFields = [
161
- 'auth',
162
- 'host',
163
- 'hostname',
164
- 'href',
165
- 'path',
166
- 'pathname',
167
- 'port',
168
- 'protocol',
169
- 'query',
170
- 'search',
171
- 'hash',
172
- ];
173
-
130
+ const { URL } = url;
131
+ // Whether to use the native URL object or the legacy url module
132
+ let useNativeURL = false;
133
+ try {
134
+ assert(new URL(''));
135
+ } catch (error) {
136
+ useNativeURL = error.code === 'ERR_INVALID_URL';
137
+ }
138
+ // URL fields to preserve in copy operations
139
+ const preservedUrlFields = [
140
+ 'auth',
141
+ 'host',
142
+ 'hostname',
143
+ 'href',
144
+ 'path',
145
+ 'pathname',
146
+ 'port',
147
+ 'protocol',
148
+ 'query',
149
+ 'search',
150
+ 'hash'
151
+ ];
174
152
  /**
175
153
  * Create a custom error type.
176
154
  * @param {string} code - The error code.
@@ -182,272 +160,221 @@ const preservedUrlFields = [
182
160
  * @property {string} code - The error code.
183
161
  * @property {string} message - The error message.
184
162
  * @property {Error | undefined} cause - The optional error cause.
185
- */
186
- function createErrorType(code, message, baseClass) {
187
- /**
163
+ */ function createErrorType(code, message, baseClass) {
164
+ /**
188
165
  * Create constructor
189
166
  * @param {*} properties
190
- */
191
- function CustomError(properties) {
192
- // istanbul ignore else
193
- if (isFunction(Error.captureStackTrace)) {
194
- Error.captureStackTrace(this, this.constructor);
195
- }
196
- Object.assign(this, properties || {});
197
- this.code = code;
198
- // @ts-ignore
199
- this.message = this.cause ? `${message}: ${this.cause.message}` : message;
200
- }
201
-
202
- // Attach constructor and set default properties
203
- CustomError.prototype = new (baseClass || Error)();
204
- Object.defineProperties(CustomError.prototype, {
205
- constructor: {
206
- value: CustomError,
207
- enumerable: false,
208
- },
209
- name: {
210
- value: `Error [${code}]`,
211
- enumerable: false,
212
- },
213
- });
214
-
215
- // @ts-ignore
216
- return CustomError
217
- }
218
-
219
- const InvalidUrlError = createErrorType('ERR_INVALID_URL', 'Invalid URL', TypeError);
220
-
221
- // @ts-ignore
222
- const typeOfTest = type => thing => typeof thing === type;
223
-
167
+ */ function CustomError(properties) {
168
+ // istanbul ignore else
169
+ if (isFunction(Error.captureStackTrace)) {
170
+ Error.captureStackTrace(this, this.constructor);
171
+ }
172
+ Object.assign(this, properties || {});
173
+ this.code = code;
174
+ // @ts-ignore
175
+ this.message = this.cause ? `${message}: ${this.cause.message}` : message;
176
+ }
177
+ // Attach constructor and set default properties
178
+ CustomError.prototype = new (baseClass || Error)();
179
+ Object.defineProperties(CustomError.prototype, {
180
+ constructor: {
181
+ value: CustomError,
182
+ enumerable: false
183
+ },
184
+ name: {
185
+ value: `Error [${code}]`,
186
+ enumerable: false
187
+ }
188
+ });
189
+ // @ts-ignore
190
+ return CustomError;
191
+ }
192
+ const InvalidUrlError = createErrorType('ERR_INVALID_URL', 'Invalid URL', TypeError);
193
+ // @ts-ignore
194
+ const typeOfTest = (type)=>(thing)=>typeof thing === type;
224
195
  /**
225
196
  * Determine if a value is a String
226
197
  *
227
198
  * @param {*} val The value to test
228
199
  *
229
200
  * @returns {boolean} True if value is a String, otherwise false
230
- */
231
- const isString = typeOfTest('string');
232
-
201
+ */ const isString = typeOfTest('string');
233
202
  /**
234
203
  * Determine if a value is an Array
235
204
  *
236
205
  * @param {Object} val The value to test
237
206
  *
238
207
  * @returns {boolean} True if value is an Array, otherwise false
239
- */
240
- const {isArray} = Array;
241
-
208
+ */ const { isArray } = Array;
242
209
  /**
243
210
  * Determine if a value is undefined
244
211
  *
245
212
  * @param {*} val The value to test
246
213
  *
247
214
  * @returns {boolean} True if the value is undefined, otherwise false
248
- */
249
- const isUndefined = typeOfTest('undefined');
250
-
215
+ */ const isUndefined = typeOfTest('undefined');
251
216
  /**
252
217
  * Determine if a value is a Buffer
253
218
  *
254
219
  * @param {*} val The value to test
255
220
  *
256
221
  * @returns {boolean} True if value is a Buffer, otherwise false
257
- */
258
- function isBuffer(val) {
259
- return (
260
- val !== null &&
261
- !isUndefined(val) &&
262
- val.constructor !== null &&
263
- !isUndefined(val.constructor) &&
264
- isFunction(val.constructor.isBuffer) &&
265
- val.constructor.isBuffer(val)
266
- )
267
- }
268
-
222
+ */ function isBuffer(val) {
223
+ return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);
224
+ }
269
225
  /**
270
226
  * Determine if a value is a Function
271
227
  *
272
228
  * @param {*} val The value to test
273
229
  * @returns {boolean} True if value is a Function, otherwise false
274
- */
275
- const isFunction = typeOfTest('function');
276
-
230
+ */ const isFunction = typeOfTest('function');
277
231
  /**
278
232
  * Determine if a value is a Number
279
233
  *
280
234
  * @param {*} val The value to test
281
235
  *
282
236
  * @returns {boolean} True if value is a Number, otherwise false
283
- */
284
- const isNumber = typeOfTest('number');
285
-
237
+ */ const isNumber = typeOfTest('number');
286
238
  /**
287
239
  * Determine if a value is an Object
288
240
  *
289
241
  * @param {*} thing The value to test
290
242
  *
291
243
  * @returns {boolean} True if value is an Object, otherwise false
292
- */
293
- const isObject = thing => thing !== null && typeof thing === 'object';
294
-
244
+ */ const isObject = (thing)=>thing !== null && typeof thing === 'object';
295
245
  /**
296
246
  * Determine if a value is a Boolean
297
247
  *
298
248
  * @param {*} thing The value to test
299
249
  * @returns {boolean} True if value is a Boolean, otherwise false
300
- */
301
- const isBoolean = thing => thing === true || thing === false;
302
-
303
- const noop = () => {};
304
-
250
+ */ const isBoolean = (thing)=>thing === true || thing === false;
251
+ const noop = ()=>{};
305
252
  /**
306
253
  *
307
254
  * @param {*} value
308
255
  * @returns
309
- */
310
- function isURL(value) {
311
- return URL && value instanceof URL
312
- }
313
-
256
+ */ function isURL(value) {
257
+ return URL && value instanceof URL;
258
+ }
314
259
  /**
315
260
  *
316
261
  * @param {*} rs
317
262
  * @returns
318
- */
319
- function isReadStream(rs) {
320
- return rs.readable && rs.path && rs.mode
321
- }
322
-
263
+ */ function isReadStream(rs) {
264
+ return rs.readable && rs.path && rs.mode;
265
+ }
323
266
  /**
324
267
  *
325
268
  * @param {*} urlObject
326
269
  * @param {*} target
327
270
  * @returns
328
- */
329
- function spreadUrlObject(urlObject, target) {
330
- const spread = target || {};
331
- for (const key of preservedUrlFields) {
332
- spread[key] = urlObject[key];
333
- }
334
-
335
- // Fix IPv6 hostname
336
- if (spread.hostname.startsWith('[')) {
337
- spread.hostname = spread.hostname.slice(1, -1);
338
- }
339
- // Ensure port is a number
340
- if (spread.port !== '') {
341
- spread.port = Number(spread.port);
342
- }
343
- // Concatenate path
344
- spread.path = spread.search ? spread.pathname + spread.search : spread.pathname;
345
-
346
- return spread
347
- }
348
-
271
+ */ function spreadUrlObject(urlObject, target) {
272
+ const spread = target || {};
273
+ for (const key of preservedUrlFields){
274
+ spread[key] = urlObject[key];
275
+ }
276
+ // Fix IPv6 hostname
277
+ if (spread.hostname.startsWith('[')) {
278
+ spread.hostname = spread.hostname.slice(1, -1);
279
+ }
280
+ // Ensure port is a number
281
+ if (spread.port !== '') {
282
+ spread.port = Number(spread.port);
283
+ }
284
+ // Concatenate path
285
+ spread.path = spread.search ? spread.pathname + spread.search : spread.pathname;
286
+ return spread;
287
+ }
349
288
  /**
350
289
  *
351
290
  * @param {*} input
352
291
  * @returns
353
- */
354
- function parseUrl(input) {
355
- let parsed;
356
- // istanbul ignore else
357
- if (useNativeURL) {
358
- parsed = new URL(input);
359
- } else {
360
- // Ensure the URL is valid and absolute
361
- parsed = validateUrl(url.parse(input));
362
- if (!isString(parsed.protocol)) {
363
- throw new InvalidUrlError({input})
364
- }
365
- }
366
- return parsed
367
- }
368
-
292
+ */ function parseUrl(input) {
293
+ let parsed;
294
+ // istanbul ignore else
295
+ if (useNativeURL) {
296
+ parsed = new URL(input);
297
+ } else {
298
+ // Ensure the URL is valid and absolute
299
+ parsed = validateUrl(url.parse(input));
300
+ if (!isString(parsed.protocol)) {
301
+ throw new InvalidUrlError({
302
+ input
303
+ });
304
+ }
305
+ }
306
+ return parsed;
307
+ }
369
308
  /**
370
309
  *
371
310
  * @param {*} input
372
311
  * @returns
373
- */
374
- function validateUrl(input) {
375
- if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
376
- throw new InvalidUrlError({input: input.href || input})
377
- }
378
- if (/^\[/.test(input.host) && !/^\[[:0-9a-f]+\](:\d+)?$/i.test(input.host)) {
379
- throw new InvalidUrlError({input: input.href || input})
380
- }
381
- return input
382
- }
383
-
312
+ */ function validateUrl(input) {
313
+ if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
314
+ throw new InvalidUrlError({
315
+ input: input.href || input
316
+ });
317
+ }
318
+ if (/^\[/.test(input.host) && !/^\[[:0-9a-f]+\](:\d+)?$/i.test(input.host)) {
319
+ throw new InvalidUrlError({
320
+ input: input.href || input
321
+ });
322
+ }
323
+ return input;
324
+ }
384
325
  /**
385
326
  *
386
327
  * @param {*} relative
387
328
  * @param {*} base
388
329
  * @returns
389
- */
390
- function resolveUrl(relative, base) {
391
- // istanbul ignore next
392
- return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative))
393
- }
394
-
330
+ */ function resolveUrl(relative, base) {
331
+ // istanbul ignore next
332
+ return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative));
333
+ }
395
334
  /**
396
335
  *
397
336
  * @param {string} method
398
337
  * @param {number} code
399
338
  * @returns
400
- */
401
- function noBody(method, code) {
402
- return (
403
- method === 'HEAD' ||
404
- // Informational
405
- (code >= 100 && code < 200) ||
406
- // No Content
407
- code === 204 ||
408
- // Not Modified
409
- code === 304
410
- )
411
- }
412
-
339
+ */ function noBody(method, code) {
340
+ return method === 'HEAD' || // Informational
341
+ code >= 100 && code < 200 || // No Content
342
+ code === 204 || // Not Modified
343
+ code === 304;
344
+ }
413
345
  /**
414
346
  * Determine if a value is a Stream
415
347
  *
416
348
  * @param {*} val The value to test
417
349
  *
418
350
  * @returns {boolean} True if value is a Stream, otherwise false
419
- */
420
- const isStream = val => isObject(val) && isFunction(val.pipe);
421
-
422
- const utils = {
423
- createErrorType,
424
- InvalidUrlError,
425
- isString,
426
- isArray,
427
- isBuffer,
428
- isUndefined,
429
- isNumber,
430
- isBoolean,
431
- isFunction,
432
- isObject,
433
- isURL,
434
- isReadStream,
435
- isStream,
436
- noop,
437
- parseUrl,
438
- spreadUrlObject,
439
- validateUrl,
440
- resolveUrl,
441
- noBody,
351
+ */ const isStream = (val)=>isObject(val) && isFunction(val.pipe);
352
+ const utils = {
353
+ createErrorType,
354
+ InvalidUrlError,
355
+ isString,
356
+ isArray,
357
+ isBuffer,
358
+ isUndefined,
359
+ isNumber,
360
+ isBoolean,
361
+ isFunction,
362
+ isObject,
363
+ isURL,
364
+ isReadStream,
365
+ isStream,
366
+ noop,
367
+ parseUrl,
368
+ spreadUrlObject,
369
+ validateUrl,
370
+ resolveUrl,
371
+ noBody
442
372
  };
443
373
 
444
- /**
445
- * fork from follow-redirects
446
- * https://github.com/follow-redirects/follow-redirects
447
- */
448
-
449
- const log$1 = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
450
-
374
+ const log$1 = log$2({
375
+ env: `wia:req:${name(import.meta.url)}`
376
+ }) // __filename
377
+ ;
451
378
  /**
452
379
  * @typedef {object} Opts
453
380
  * @prop {Object.<string,string>} headers
@@ -467,470 +394,267 @@ const log$1 = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
467
394
  * @prop {number} [maxBodyLength = -1]
468
395
  * @prop {*} [trackRedirects]
469
396
  * @prop {*} [data]
470
- */
471
-
472
- /** @typedef {object} ResponseExt
397
+ */ /** @typedef {object} ResponseExt
473
398
  * @prop {*[]} [redirects]
474
399
  * @prop {string} [responseUrl]
475
400
  * @prop {number} [responseStartTime]
476
- */
477
-
478
- /** @typedef { http.IncomingMessage & ResponseExt} Response */
479
-
480
- const httpModules = {'http:': http, 'https:': https};
481
-
482
- const zlibOptions = {
483
- flush: zlib.constants.Z_SYNC_FLUSH,
484
- finishFlush: zlib.constants.Z_SYNC_FLUSH,
485
- };
486
-
487
- const brotliOptions = {
488
- flush: zlib.constants.BROTLI_OPERATION_FLUSH,
489
- finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH,
490
- };
491
-
492
- const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
493
-
494
- // clientRequest 属性转发
495
- const writeProps = [
496
- 'protocol',
497
- 'method',
498
- 'path',
499
- 'host',
500
- 'reusedSocket',
501
- 'socket',
502
- 'closed',
503
- 'destroyed',
504
- 'writable',
505
- 'writableAborted',
506
- 'writableEnded',
507
- 'writableCorked',
508
- 'errored',
509
- 'writableFinished',
510
- 'writableHighWaterMark',
511
- 'writableLength',
512
- 'writableNeedDrain',
513
- 'writableObjectMode',
514
- ];
515
-
516
- // clientReq 方法转发
517
- const writeMethods = ['cork', 'flushHeaders', 'setNoDelay', 'setSocketKeepAlive'];
518
-
519
- // Create handlers that pass events from native requests
520
- // clientRequest 事件转发写事件
521
- const writeEvents = [
522
- // 'abort', // 弃用
523
- // 'aborted', // 弃用
524
- 'close',
525
- 'connect',
526
- 'continue',
527
- 'drain',
528
- // 'error', // 单独处理,未注册 'error' 事件处理程序,错误将冒泡到全局导致程序崩溃
529
- 'finish',
530
- 'information',
531
- 'pipe',
532
- // 'response', 由 processResponse 触发
533
- 'socket', // 建立连接时触发
534
- 'timeout',
535
- 'unpipe',
536
- 'upgrade',
537
- ];
538
-
539
- const writeEventEmit = Object.create(null);
540
-
541
- for (const ev of writeEvents)
542
- writeEventEmit[ev] = /** @param {...any} args */ function (...args) {
543
- const m = this; // 事件回调,this === clientRequest 实例
544
- // log('req event', {ev})
545
- m.redirectReq.emit(ev, ...args); // 内部请求req 事情转发到 Request
546
- };
547
-
548
- // stream.Readable,在响应流上转发读流取事件
549
- // data 单独处理
550
- const readEvents = ['close', 'end', 'error', 'pause', 'readable', 'resume'];
551
- const readEventEmit = Object.create(null);
552
- for (const ev of readEvents)
553
- readEventEmit[ev] = /** @param {...any} args */ function (...args) {
554
- const m = this; // 事件回调,this === clientRequest 实例
555
- // log('res event', {ev})
556
- m.redirectReq.emit(ev, ...args); // 向上触发事件
557
- };
558
-
559
- // Error types with codes
560
- const RedirectionError = utils.createErrorType(
561
- 'ERR_FR_REDIRECTION_FAILURE',
562
- 'Redirected request failed'
563
- );
564
-
565
- const TooManyRedirectsError = utils.createErrorType(
566
- 'ERR_FR_TOO_MANY_REDIRECTS',
567
- 'Maximum number of redirects exceeded',
568
- RedirectionError
569
- );
570
-
571
- const MaxBodyLengthExceededError = utils.createErrorType(
572
- 'ERR_FR_MAX_BODY_LENGTH_EXCEEDED',
573
- 'Request body larger than maxBodyLength limit'
574
- );
575
-
576
- const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
577
-
578
- // request err
579
- const HostNotfoundError = utils.createErrorType('ERR_HOSTNOTFOUND', 'DNS 解析失败,主机名可能无效');
580
- const ConnRefusedError = utils.createErrorType(
581
- 'ERR_CONNREFUSED',
582
- '连接被拒绝,目标服务器可能不可用'
583
- );
584
- const ConnTimedoutError = utils.createErrorType(
585
- 'ERR_CONNTIMEDOUT',
586
- '请求超时,请检查网络连接或服务器负载'
587
- );
588
- const ConnResetError = utils.createErrorType(
589
- 'ERR_CONNRESET',
590
- '连接被重置,可能是网络问题或服务器关闭了连接'
591
- );
592
-
593
- /**
594
- * An HTTP(S) request that can be redirected
595
- * wrap http.ClientRequest
596
- */
597
- class Request extends Duplex {
598
- /** @type {NodeJS.Timeout} */
599
- _timeout = null
600
- /** @type {*} */
601
- socket = null
602
- /** @type {http.ClientRequest} */
603
- _currentRequest = null
604
- /** @type {Response} */
605
- response = null
606
- /** @type {stream.Readable} */
607
- responseStream = null
608
- timing = false
609
- responseStarted = false
610
- responseStartTime = 0
611
- _destdata = false
612
- _paused = false
613
- _respended = false
614
- /** @type {stream.Readable} */
615
- pipesrc = null // 被 pipe 时的 src stream
616
- /** @type {stream.Writable[]} */
617
- pipedests = [] // pipe dest
618
- /** @type {*} */
619
- startTimer = null
620
- /** @type {Opts} */
621
- opt
622
- /** @type {*} */
623
- pipefilter
624
- /** @type {string} */
625
- _currentUrl
626
-
627
- /**
628
- * responseCallback 原消息处理回调
629
- * @param {Opts} opts
630
- * @param {*} resCallback
631
- */
632
- constructor(opts, resCallback) {
633
- super();
634
- const m = this;
635
-
636
- // log({opts}, 'new Request')
637
-
638
- // Initialize the request
639
- m.sanitizeOptions(opts);
640
- m.opt = opts;
641
- m.headers = opts.headers;
642
-
643
- // log({opts}, 'constructor')
644
-
645
- m._ended = false;
646
- m._ending = false;
647
- m._redirectCount = 0;
648
- /** @type {any[]} */
649
- m._redirects = [];
650
- m._requestBodyLength = 0;
651
- /** @type {any[]} */
652
- m._requestBodyBuffers = [];
653
-
654
- // save the callback if passed
655
- m.resCallback = resCallback;
656
-
401
+ */ /** @typedef { http.IncomingMessage & ResponseExt} Response */ const httpModules = {
402
+ 'http:': http,
403
+ 'https:': https
404
+ };
405
+ const zlibOptions = {
406
+ flush: zlib.constants.Z_SYNC_FLUSH,
407
+ finishFlush: zlib.constants.Z_SYNC_FLUSH
408
+ };
409
+ const brotliOptions = {
410
+ flush: zlib.constants.BROTLI_OPERATION_FLUSH,
411
+ finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
412
+ };
413
+ const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
414
+ // clientRequest 属性转发
415
+ const writeProps = [
416
+ 'protocol',
417
+ 'method',
418
+ 'path',
419
+ 'host',
420
+ 'reusedSocket',
421
+ 'socket',
422
+ 'closed',
423
+ 'destroyed',
424
+ 'writable',
425
+ 'writableAborted',
426
+ 'writableEnded',
427
+ 'writableCorked',
428
+ 'errored',
429
+ 'writableFinished',
430
+ 'writableHighWaterMark',
431
+ 'writableLength',
432
+ 'writableNeedDrain',
433
+ 'writableObjectMode'
434
+ ];
435
+ // clientReq 方法转发
436
+ const writeMethods = [
437
+ 'cork',
438
+ 'flushHeaders',
439
+ 'setNoDelay',
440
+ 'setSocketKeepAlive'
441
+ ];
442
+ // Create handlers that pass events from native requests
443
+ // 在 clientRequest 事件转发写事件
444
+ const writeEvents = [
445
+ // 'abort', // 弃用
446
+ // 'aborted', // 弃用
447
+ 'close',
448
+ 'connect',
449
+ 'continue',
450
+ 'drain',
451
+ // 'error', // 单独处理,未注册 'error' 事件处理程序,错误将冒泡到全局导致程序崩溃
452
+ 'finish',
453
+ 'information',
454
+ 'pipe',
455
+ // 'response', 由 processResponse 触发
456
+ 'socket',
457
+ 'timeout',
458
+ 'unpipe',
459
+ 'upgrade'
460
+ ];
461
+ const writeEventEmit = Object.create(null);
462
+ for (const ev of writeEvents)writeEventEmit[ev] = /** @param {...any} args */ function(...args) {
463
+ const m = this // 事件回调,this === clientRequest 实例
464
+ ;
465
+ // log('req event', {ev})
466
+ m.redirectReq.emit(ev, ...args) // 内部请求req 事情转发到 Request
467
+ ;
468
+ };
469
+ // stream.Readable,在响应流上转发读流取事件
470
+ // data 单独处理
471
+ const readEvents = [
472
+ 'close',
473
+ 'end',
474
+ 'error',
475
+ 'pause',
476
+ 'readable',
477
+ 'resume'
478
+ ];
479
+ const readEventEmit = Object.create(null);
480
+ for (const ev of readEvents)readEventEmit[ev] = /** @param {...any} args */ function(...args) {
481
+ const m = this // 事件回调,this === clientRequest 实例
482
+ ;
483
+ // log('res event', {ev})
484
+ m.redirectReq.emit(ev, ...args) // 向上触发事件
485
+ ;
486
+ };
487
+ // Error types with codes
488
+ const RedirectionError = utils.createErrorType('ERR_FR_REDIRECTION_FAILURE', 'Redirected request failed');
489
+ const TooManyRedirectsError = utils.createErrorType('ERR_FR_TOO_MANY_REDIRECTS', 'Maximum number of redirects exceeded', RedirectionError);
490
+ const MaxBodyLengthExceededError = utils.createErrorType('ERR_FR_MAX_BODY_LENGTH_EXCEEDED', 'Request body larger than maxBodyLength limit');
491
+ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
492
+ // request err
493
+ const HostNotfoundError = utils.createErrorType('ERR_HOSTNOTFOUND', 'DNS 解析失败,主机名可能无效');
494
+ const ConnRefusedError = utils.createErrorType('ERR_CONNREFUSED', '连接被拒绝,目标服务器可能不可用');
495
+ const ConnTimedoutError = utils.createErrorType('ERR_CONNTIMEDOUT', '请求超时,请检查网络连接或服务器负载');
496
+ const ConnResetError = utils.createErrorType('ERR_CONNRESET', '连接被重置,可能是网络问题或服务器关闭了连接');
497
+ let Request = class Request extends Duplex {
657
498
  /**
658
- * React to responses of native requests
659
- * 接管 response 事件,非重定向,触发 response 事件
660
- * @param {Response} res
661
- */
662
- m._onResponse = res => {
663
- try {
664
- m.processResponse(res);
665
- } catch (cause) {
666
- m.emit(
667
- 'error',
668
- cause instanceof RedirectionError ? cause : new RedirectionError({cause: cause})
669
- );
670
- }
671
- };
672
-
673
- // Proxy all other public ClientRequest methods 'getHeader'
674
- for (const method of writeMethods) {
675
- // @ts-ignore
676
- m[method] = (a, b) => {
677
- // log(method, {a, b})
678
- // @ts-ignore
679
- m._currentRequest?.[method](a, b);
680
- };
681
- }
682
-
683
- // Proxy all public ClientRequest properties
684
- // 'aborted', 'connection' 弃用
685
- for (const property of writeProps) {
686
- Object.defineProperty(m, property, {
687
- get() {
688
- // @ts-ignore
689
- const val = m._currentRequest?.[property];
690
- // log('get property', {property})
691
- return val
692
- },
693
- });
694
- }
695
-
696
- // 流模式
697
- if (opts.stream) {
698
- // 被 pipe 作为目标时触发,拷贝 src headers
699
- m.on(
700
- 'pipe',
701
- /** @param {stream.Readable & {headers?: Object.<string, string>}} src */ src => {
702
- // m.ntick &&
703
- if (m._currentRequest) {
704
- m.emit(
705
- 'error',
706
- new Error('You cannot pipe to this stream after the outbound request has started.')
707
- );
708
- }
709
-
710
- m.pipesrc = src;
711
-
712
- if (utils.isReadStream(src)) {
713
- // @ts-ignore
714
- if (!m.hasHeader('content-type')) m.setHeader('content-type', mime.lookup(src.path));
715
- } else {
716
- // 拷贝请求头
717
- if (src.headers) {
718
- for (const k of Object.keys(src.headers)) {
719
- if (!m.hasHeader(k)) {
720
- m.setHeader(k, src.headers[k]);
721
- }
722
- }
723
- }
724
-
725
- // @ts-ignore
726
- if (src.opt.method && !m.opt.method) m.opt.method = src.opt.method;
727
- }
728
- }
729
- );
730
- }
731
-
732
- // Perform the first request
733
- // m.request(); // 创建时不连接,写入数据时连接,否则 pipe 时无法写入header
734
- }
735
-
736
- /**
737
499
  * Executes the next native request (initial or redirect)
738
500
  * @returns http(s) 实例
739
- */
740
- request() {
741
- let R = null;
742
- const m = this;
743
- const {opt} = m;
744
-
745
- try {
746
- // reset read stream
747
- m.response = null;
748
- m.responseStarted = false;
749
- m.responseStream = null;
750
- m.timing = false;
751
- m.responseStartTime = 0;
752
- m._destdata = false;
753
- m._paused = false;
754
- m._respended = false;
755
-
756
- // m.httpModule = httpModules[protocol];
757
-
758
- // Load the native protocol
759
- let {protocol} = opt;
760
- const {agents} = opt;
761
-
762
- // 代理以目的网址协议为准
763
- // If specified, use the agent corresponding to the protocol
764
- // (HTTP and HTTPS use different types of agents)
765
- // agents 优于 agent
766
- if (agents) {
767
- const scheme = protocol.slice(0, -1);
768
- opt.agent = agents[scheme];
769
-
770
- // http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
771
- // 代理内部会根据代理协议选择 http(s) 发起请求创建连接
772
- if (protocol === 'http:' && agents.http) {
773
- protocol =
774
- agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
775
- }
776
-
777
- // log({scheme, agents, protocol}, 'request')
778
- }
779
-
780
- const httpModule = httpModules[protocol];
781
- if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`)
782
-
783
- // log({opt, protocol}, 'request')
784
- // Create the native request and set up its event handlers
785
- // @ts-ignore
786
-
787
- log$1({httpModule, opt}, 'request');
788
- const req = httpModule.request(opt, m._onResponse);
789
- m._currentRequest = req;
790
- // @ts-ignore
791
- req.redirectReq = m;
792
-
793
- // 启动 startTimer
794
- if (m.startTimer) m._currentRequest.once('socket', m.startTimer);
795
-
796
- // set tcp keep alive to prevent drop connection by peer
797
- req.on(
798
- 'socket',
799
- /** @param {*} socket */ socket => {
800
- // default interval of sending ack packet is 1 minute
801
- socket.setKeepAlive(true, 1000 * 60);
802
- }
803
- );
804
-
805
- // 请求error单独处理
806
- // 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
807
- req.on('error', err => {
808
- destroyRequest(req); // 释放资源
809
- // @ts-ignore
810
- log$1.error({errcode: err?.code}, 'request');
811
- // @ts-ignore
812
- switch (err?.code) {
813
- case 'ENOTFOUND':
814
- m.emit('error', new HostNotfoundError());
815
- break
816
- case 'ECONNREFUSED':
817
- m.emit('error', new ConnRefusedError());
818
- break
819
- case 'ETIMEDOUT':
820
- m.emit('error', new ConnTimedoutError());
821
- break
822
- case 'ECONNRESET':
823
- m.emit('error', new ConnResetError());
824
- break
825
- default:
826
- m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
827
- }
828
- });
829
-
830
- // 接收req事件,转发 request 上发射,网络关闭事件,触发 error
831
- for (const ev of writeEvents) req.on(ev, writeEventEmit[ev]);
832
-
833
- // RFC7230§5.3.1: When making a request directly to an origin server, […]
834
- // a client MUST send only the absolute path […] as the request-target.
835
- // When making a request to a proxy, […]
836
- // a client MUST send the target URI in absolute-form […].
837
- m._currentUrl = /^\//.test(opt.path) ? url.format(opt) : opt.path;
838
-
839
- // End a redirected request
840
- // (The first request must be ended explicitly with RedirectableRequest#end)
841
- if (m._isRedirect) {
842
- // Write the request entity and end
843
- let i = 0;
844
- const buffers = m._requestBodyBuffers;
845
-
846
- /**
501
+ */ request() {
502
+ let R = null;
503
+ const m = this;
504
+ const { opt } = m;
505
+ try {
506
+ // reset read stream
507
+ m.response = null;
508
+ m.responseStarted = false;
509
+ m.responseStream = null;
510
+ m.timing = false;
511
+ m.responseStartTime = 0;
512
+ m._destdata = false;
513
+ m._paused = false;
514
+ m._respended = false;
515
+ // m.httpModule = httpModules[protocol];
516
+ // Load the native protocol
517
+ let { protocol } = opt;
518
+ const { agents } = opt;
519
+ // 代理以目的网址协议为准
520
+ // If specified, use the agent corresponding to the protocol
521
+ // (HTTP and HTTPS use different types of agents)
522
+ // agents 优于 agent
523
+ if (agents) {
524
+ const scheme = protocol.slice(0, -1);
525
+ opt.agent = agents[scheme];
526
+ // http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
527
+ // 代理内部会根据代理协议选择 http(s) 发起请求创建连接
528
+ if (protocol === 'http:' && agents.http) {
529
+ protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
530
+ }
531
+ // log({scheme, agents, protocol}, 'request')
532
+ }
533
+ const httpModule = httpModules[protocol];
534
+ if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
535
+ // log({opt, protocol}, 'request')
536
+ // Create the native request and set up its event handlers
537
+ // @ts-ignore
538
+ log$1({
539
+ httpModule,
540
+ opt
541
+ }, 'request');
542
+ const req = httpModule.request(opt, m._onResponse);
543
+ m._currentRequest = req;
544
+ // @ts-ignore
545
+ req.redirectReq = m;
546
+ // 启动 startTimer
547
+ if (m.startTimer) m._currentRequest.once('socket', m.startTimer);
548
+ // set tcp keep alive to prevent drop connection by peer
549
+ req.on('socket', /** @param {*} socket */ (socket)=>{
550
+ // default interval of sending ack packet is 1 minute
551
+ socket.setKeepAlive(true, 1000 * 60);
552
+ });
553
+ // 请求error单独处理
554
+ // 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
555
+ req.on('error', (err)=>{
556
+ destroyRequest(req) // 释放资源
557
+ ;
558
+ // @ts-ignore
559
+ log$1.error({
560
+ errcode: err == null ? void 0 : err.code
561
+ }, 'request');
562
+ // @ts-ignore
563
+ switch(err == null ? void 0 : err.code){
564
+ case 'ENOTFOUND':
565
+ m.emit('error', new HostNotfoundError());
566
+ break;
567
+ case 'ECONNREFUSED':
568
+ m.emit('error', new ConnRefusedError());
569
+ break;
570
+ case 'ETIMEDOUT':
571
+ m.emit('error', new ConnTimedoutError());
572
+ break;
573
+ case 'ECONNRESET':
574
+ m.emit('error', new ConnResetError());
575
+ break;
576
+ default:
577
+ m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
578
+ }
579
+ });
580
+ // 接收req事件,转发 到 request 上发射,网络关闭事件,触发 error
581
+ for (const ev of writeEvents)req.on(ev, writeEventEmit[ev]);
582
+ // RFC7230§5.3.1: When making a request directly to an origin server, […]
583
+ // a client MUST send only the absolute path […] as the request-target.
584
+ // When making a request to a proxy, […]
585
+ // a client MUST send the target URI in absolute-form […].
586
+ m._currentUrl = /^\//.test(opt.path) ? url.format(opt) : opt.path;
587
+ // End a redirected request
588
+ // (The first request must be ended explicitly with RedirectableRequest#end)
589
+ if (m._isRedirect) {
590
+ // Write the request entity and end
591
+ let i = 0;
592
+ const buffers = m._requestBodyBuffers;
593
+ /**
847
594
  *
848
595
  * @param {*} error
849
- */
850
- function writeNext(error) {
851
- // Only write if this request has not been redirected yet
852
- /* istanbul ignore else */
853
- if (req === m._currentRequest) {
854
- // Report any write errors
855
- /* istanbul ignore if */
856
- if (error) m.emit('error', error);
857
- // Write the next buffer if there are still left
858
- else if (i < buffers.length) {
859
- const buf = buffers[i++];
860
- /* istanbul ignore else */
861
- if (!req.finished) req.write(buf.data, buf.encoding, writeNext);
862
- }
863
- // End the request if `end` has been called on us
864
- else if (m._ended) req.end();
865
- }
866
- }
867
- writeNext();
868
- }
869
-
870
- R = req;
871
- } catch (e) {
872
- log$1.err(e, 'request');
873
- throw e
874
- }
875
-
876
- return R
877
- }
878
-
879
- /**
596
+ */ function writeNext(error) {
597
+ // Only write if this request has not been redirected yet
598
+ /* istanbul ignore else */ if (req === m._currentRequest) {
599
+ // Report any write errors
600
+ /* istanbul ignore if */ if (error) m.emit('error', error);
601
+ else if (i < buffers.length) {
602
+ const buf = buffers[i++];
603
+ /* istanbul ignore else */ if (!req.finished) req.write(buf.data, buf.encoding, writeNext);
604
+ } else if (m._ended) req.end();
605
+ }
606
+ }
607
+ writeNext();
608
+ }
609
+ R = req;
610
+ } catch (e) {
611
+ log$1.err(e, 'request');
612
+ throw e;
613
+ }
614
+ return R;
615
+ }
616
+ /**
880
617
  * 写入错误,释放请求,触发 abort 终止事件
881
- */
882
- abort() {
883
- destroyRequest(this._currentRequest);
884
- this.emit('abort');
885
- }
886
-
887
- /**
618
+ */ abort() {
619
+ destroyRequest(this._currentRequest);
620
+ this.emit('abort');
621
+ }
622
+ /**
888
623
  * 析构
889
624
  * @param {*} error
890
625
  * @returns
891
- */
892
- destroy(error) {
893
- const m = this;
894
- if (!m._ended) m.end();
895
- if (m.response) m.response.destroy();
896
- if (m.responseStream) m.responseStream.destroy();
897
-
898
- // m.clearTimeout();
899
- destroyRequest(m._currentRequest, error);
900
- super.destroy(error);
901
- return this
902
- }
903
-
904
- /**
626
+ */ destroy(error) {
627
+ const m = this;
628
+ if (!m._ended) m.end();
629
+ if (m.response) m.response.destroy();
630
+ if (m.responseStream) m.responseStream.destroy();
631
+ // m.clearTimeout();
632
+ destroyRequest(m._currentRequest, error);
633
+ super.destroy(error);
634
+ return this;
635
+ }
636
+ /**
905
637
  * 发送数据
906
- */
907
- send() {
908
- const m = this;
909
- const {data} = m.opt;
910
- // 发送数据
911
- if (utils.isStream(data)) {
912
-
913
- data.on('end', () => {
914
- });
915
-
916
- data.once(
917
- 'error',
918
- /** @param {*} err */ err => {
919
- // req.destroy(err)
920
- }
921
- );
922
-
923
- data.on('close', () => {
924
- // if (!ended && !errored) {
925
- // throw new WritebBeenAbortedError()
926
- // }
927
- });
928
-
929
- data.pipe(m); // 写入数据流
930
- } else m.end(data);
931
- }
932
-
933
- /**
638
+ */ send() {
639
+ const m = this;
640
+ const { data } = m.opt;
641
+ // 发送数据
642
+ if (utils.isStream(data)) {
643
+ data.on('end', ()=>{
644
+ });
645
+ data.once('error', /** @param {*} err */ (err)=>{
646
+ // req.destroy(err)
647
+ });
648
+ data.on('close', ()=>{
649
+ // if (!ended && !errored) {
650
+ // throw new WritebBeenAbortedError()
651
+ // }
652
+ });
653
+ data.pipe(m) // 写入数据流
654
+ ;
655
+ } else m.end(data);
656
+ }
657
+ /**
934
658
  * Writes buffered data to the current native request
935
659
  * 如 request 不存在,则创建连接,pipe 时可写入 header
936
660
  * @override - 重写父类方法
@@ -938,514 +662,427 @@ class Request extends Duplex {
938
662
  * @param {BufferEncoding | ((error: Error | null) => void)} [encoding] - Encoding for string data, or the callback if no encoding is provided.
939
663
  * @param {(error: Error | null) => void} [cb] - Callback to signal the end of the write operation.
940
664
  * @returns {boolean} True if the write was successful, false otherwise.
941
- */
942
- write(chunk, encoding, cb) {
943
- const m = this;
944
- // log({data: chunk, encoding, cb}, 'write')
945
-
946
- // Writing is not allowed if end has been called
947
- if (m._ending) {
948
- // throw new WriteAfterEndError()
949
- m.emit('error', new WriteAfterEndError());
950
- return
951
- }
952
-
953
- // ! 数据写入时连接,pipe 时可设置 header
954
- if (!m._currentRequest) m.request();
955
-
956
- // Validate input and shift parameters if necessary
957
- if (!utils.isString(chunk) && !utils.isBuffer(chunk))
958
- throw new TypeError('data should be a string, Buffer or Uint8Array')
959
-
960
- if (utils.isFunction(encoding)) {
961
- // @ts-ignore
962
- cb = encoding;
963
- encoding = null;
964
- }
965
-
966
- // Ignore empty buffers, since writing them doesn't invoke the callback
967
- // https://github.com/nodejs/node/issues/22066
968
- if (chunk.length === 0) {
969
- if (cb) cb(null);
970
- return
971
- }
972
-
973
- // Only write when we don't exceed the maximum body length
974
- if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
975
- m._requestBodyLength += chunk.length;
976
- m._requestBodyBuffers.push({data: chunk, encoding});
977
- // @ts-ignore
978
- m._currentRequest.write(chunk, encoding, cb);
979
- }
980
- // Error when we exceed the maximum body length
981
- else {
982
- m.emit('error', new MaxBodyLengthExceededError());
983
- m.abort();
984
- }
985
- }
986
-
987
- /**
665
+ */ write(chunk, encoding, cb) {
666
+ const m = this;
667
+ // log({data: chunk, encoding, cb}, 'write')
668
+ // Writing is not allowed if end has been called
669
+ if (m._ending) {
670
+ // throw new WriteAfterEndError()
671
+ m.emit('error', new WriteAfterEndError());
672
+ return;
673
+ }
674
+ // ! 数据写入时连接,pipe 时可设置 header
675
+ if (!m._currentRequest) m.request();
676
+ // Validate input and shift parameters if necessary
677
+ if (!utils.isString(chunk) && !utils.isBuffer(chunk)) throw new TypeError('data should be a string, Buffer or Uint8Array');
678
+ if (utils.isFunction(encoding)) {
679
+ // @ts-ignore
680
+ cb = encoding;
681
+ encoding = null;
682
+ }
683
+ // Ignore empty buffers, since writing them doesn't invoke the callback
684
+ // https://github.com/nodejs/node/issues/22066
685
+ if (chunk.length === 0) {
686
+ if (cb) cb(null);
687
+ return;
688
+ }
689
+ // Only write when we don't exceed the maximum body length
690
+ if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
691
+ m._requestBodyLength += chunk.length;
692
+ m._requestBodyBuffers.push({
693
+ data: chunk,
694
+ encoding
695
+ });
696
+ // @ts-ignore
697
+ m._currentRequest.write(chunk, encoding, cb);
698
+ } else {
699
+ m.emit('error', new MaxBodyLengthExceededError());
700
+ m.abort();
701
+ }
702
+ }
703
+ /**
988
704
  * Ends the current native request
989
705
  * @override - 重写父类方法
990
706
  * @param {*} [chunk] - Optional data to write before ending the stream.
991
707
  * @param {BufferEncoding | (() => void)} [encoding] - Encoding for string data, or the callback if no encoding is provided.
992
708
  * @param {() => void} [cb] - Optional callback to signal completion.
993
709
  * @returns {this} The current stream instance, to allow chaining.
994
- */
995
- end(chunk, encoding, cb) {
996
- const m = this;
997
-
998
- // Shift parameters if necessary
999
- if (utils.isFunction(chunk)) {
1000
- cb = chunk;
1001
- chunk = null;
1002
- encoding = null;
1003
- } else if (utils.isFunction(encoding)) {
1004
- // @ts-ignore
1005
- cb = encoding;
1006
- encoding = null;
1007
- }
1008
-
1009
- // ! 创建实例时不连接,数据写入时发起连接,连接后无法设置 header,因此 pipe 时可设置 header
1010
- if (!m._currentRequest) m.request();
1011
-
1012
- // Write data if needed and end
1013
- if (!chunk) {
1014
- m._ended = true;
1015
- m._ending = true;
1016
- m._currentRequest.end(null, null, cb);
1017
- } else {
1018
- const currentRequest = m._currentRequest;
1019
- m.write(chunk, encoding, () => {
1020
- m._ended = true;
1021
- currentRequest.end(null, null, cb);
1022
- });
1023
-
1024
- m._ending = true;
1025
- }
1026
-
1027
- return m
1028
- }
1029
-
1030
- /**
710
+ */ end(chunk, encoding, cb) {
711
+ const m = this;
712
+ // Shift parameters if necessary
713
+ if (utils.isFunction(chunk)) {
714
+ cb = chunk;
715
+ chunk = null;
716
+ encoding = null;
717
+ } else if (utils.isFunction(encoding)) {
718
+ // @ts-ignore
719
+ cb = encoding;
720
+ encoding = null;
721
+ }
722
+ // ! 创建实例时不连接,数据写入时发起连接,连接后无法设置 header,因此 pipe 时可设置 header
723
+ if (!m._currentRequest) m.request();
724
+ // Write data if needed and end
725
+ if (!chunk) {
726
+ m._ended = true;
727
+ m._ending = true;
728
+ m._currentRequest.end(null, null, cb);
729
+ } else {
730
+ const currentRequest = m._currentRequest;
731
+ m.write(chunk, encoding, ()=>{
732
+ m._ended = true;
733
+ currentRequest.end(null, null, cb);
734
+ });
735
+ m._ending = true;
736
+ }
737
+ return m;
738
+ }
739
+ /**
1031
740
  *
1032
741
  * @param {string} name
1033
742
  * @returns
1034
- */
1035
- hasHeader(name) {
1036
- return Object.keys(this.opt.headers).includes(name)
1037
- }
1038
-
1039
- /**
743
+ */ hasHeader(name) {
744
+ return Object.keys(this.opt.headers).includes(name);
745
+ }
746
+ /**
1040
747
  *
1041
748
  * @param {string} name
1042
749
  * @returns {string}
1043
- */
1044
- getHeader(name) {
1045
- return this.opt.headers[name]
1046
- }
1047
-
1048
- /**
750
+ */ getHeader(name) {
751
+ return this.opt.headers[name];
752
+ }
753
+ /**
1049
754
  * Sets a header value on the current native request
1050
755
  * @param {string} name
1051
756
  * @param {string} value
1052
- */
1053
- setHeader(name, value) {
1054
- this.opt.headers[name] = value;
1055
- this._currentRequest?.setHeader(name, value);
1056
- }
1057
-
1058
- /**
757
+ */ setHeader(name, value) {
758
+ var _this__currentRequest;
759
+ this.opt.headers[name] = value;
760
+ (_this__currentRequest = this._currentRequest) == null ? void 0 : _this__currentRequest.setHeader(name, value);
761
+ }
762
+ /**
1059
763
  * Clears a header value on the current native request
1060
764
  * @param {string} name
1061
- */
1062
- removeHeader(name) {
1063
- delete this.opt.headers[name];
1064
- this._currentRequest?.removeHeader(name);
1065
- }
1066
-
1067
- /**
765
+ */ removeHeader(name) {
766
+ var _this__currentRequest;
767
+ delete this.opt.headers[name];
768
+ (_this__currentRequest = this._currentRequest) == null ? void 0 : _this__currentRequest.removeHeader(name);
769
+ }
770
+ /**
1068
771
  * 标头是否已发送
1069
772
  * @returns
1070
- */
1071
- get headersSent() {
1072
- return this._currentRequest?.headersSent
1073
- }
1074
-
1075
- /**
773
+ */ get headersSent() {
774
+ var _this__currentRequest;
775
+ return (_this__currentRequest = this._currentRequest) == null ? void 0 : _this__currentRequest.headersSent;
776
+ }
777
+ /**
1076
778
  * Global timeout for all underlying requests
1077
779
  * @param {*} msecs
1078
780
  * @param {*} callback
1079
781
  * @returns
1080
- */
1081
- setTimeout(msecs, callback) {
1082
- const m = this;
1083
-
1084
- /**
782
+ */ setTimeout(msecs, callback) {
783
+ const m = this;
784
+ /**
1085
785
  * Destroys the socket on timeout
1086
786
  * @param {*} socket
1087
- */
1088
- function destroyOnTimeout(socket) {
1089
- socket.setTimeout(msecs);
1090
- socket.removeListener('timeout', socket.destroy);
1091
- socket.addListener('timeout', socket.destroy);
1092
- }
1093
-
1094
- /**
787
+ */ function destroyOnTimeout(socket) {
788
+ socket.setTimeout(msecs);
789
+ socket.removeListener('timeout', socket.destroy);
790
+ socket.addListener('timeout', socket.destroy);
791
+ }
792
+ /**
1095
793
  * Sets up a timer to trigger a timeout event
1096
794
  * @param {*} socket
1097
- */
1098
- function startTimer(socket) {
1099
- if (m.startTimer) m.startTimer = null;
1100
-
1101
- if (m._timeout) clearTimeout(m._timeout);
1102
-
1103
- m._timeout = setTimeout(() => {
1104
- m.emit('timeout');
1105
- clearTimer();
1106
- }, msecs);
1107
-
1108
- destroyOnTimeout(socket);
1109
- }
1110
-
1111
- // Stops a timeout from triggering
1112
- function clearTimer() {
1113
- // Clear the timeout
1114
- if (m._timeout) {
1115
- clearTimeout(m._timeout);
1116
- m._timeout = null;
1117
- }
1118
-
1119
- // Clean up all attached listeners
1120
- m.removeListener('abort', clearTimer);
1121
- m.removeListener('error', clearTimer);
1122
- m.removeListener('response', clearTimer);
1123
- m.removeListener('close', clearTimer);
1124
-
1125
- if (callback) {
1126
- m.removeListener('timeout', callback);
1127
- }
1128
- if (!m.socket) {
1129
- m._currentRequest.removeListener('socket', startTimer);
1130
- }
1131
- }
1132
-
1133
- // Attach callback if passed
1134
- if (callback) m.on('timeout', callback);
1135
-
1136
- // Start the timer if or when the socket is opened
1137
- if (m.socket) startTimer(m.socket);
1138
- else m.startTimer = startTimer; // 未连接,先登记,连接后启动
1139
-
1140
- // Clean up on events
1141
- m.on('socket', destroyOnTimeout);
1142
- m.on('abort', clearTimer);
1143
- m.on('error', clearTimer);
1144
- m.on('response', clearTimer);
1145
- m.on('close', clearTimer);
1146
-
1147
- return m
1148
- }
1149
-
1150
- /**
795
+ */ function startTimer(socket) {
796
+ if (m.startTimer) m.startTimer = null;
797
+ if (m._timeout) clearTimeout(m._timeout);
798
+ m._timeout = setTimeout(()=>{
799
+ m.emit('timeout');
800
+ clearTimer();
801
+ }, msecs);
802
+ destroyOnTimeout(socket);
803
+ }
804
+ // Stops a timeout from triggering
805
+ function clearTimer() {
806
+ // Clear the timeout
807
+ if (m._timeout) {
808
+ clearTimeout(m._timeout);
809
+ m._timeout = null;
810
+ }
811
+ // Clean up all attached listeners
812
+ m.removeListener('abort', clearTimer);
813
+ m.removeListener('error', clearTimer);
814
+ m.removeListener('response', clearTimer);
815
+ m.removeListener('close', clearTimer);
816
+ if (callback) {
817
+ m.removeListener('timeout', callback);
818
+ }
819
+ if (!m.socket) {
820
+ m._currentRequest.removeListener('socket', startTimer);
821
+ }
822
+ }
823
+ // Attach callback if passed
824
+ if (callback) m.on('timeout', callback);
825
+ // Start the timer if or when the socket is opened
826
+ if (m.socket) startTimer(m.socket);
827
+ else m.startTimer = startTimer // 未连接,先登记,连接后启动
828
+ ;
829
+ // Clean up on events
830
+ m.on('socket', destroyOnTimeout);
831
+ m.on('abort', clearTimer);
832
+ m.on('error', clearTimer);
833
+ m.on('response', clearTimer);
834
+ m.on('close', clearTimer);
835
+ return m;
836
+ }
837
+ /**
1151
838
  *
1152
839
  * @param {*} options
1153
- */
1154
- sanitizeOptions(options) {
1155
- // Ensure headers are always present
1156
- if (!options.headers) options.headers = {};
1157
-
1158
- // Since http.request treats host as an alias of hostname,
1159
- // but the url module interprets host as hostname plus port,
1160
- // eliminate the host property to avoid confusion.
1161
- if (options.host) {
1162
- // Use hostname if set, because it has precedence
1163
- if (!options.hostname) {
1164
- options.hostname = options.host;
1165
- }
1166
- options.host = undefined;
1167
- }
1168
-
1169
- // Complete the URL object when necessary
1170
- if (!options.pathname && options.path) {
1171
- const searchPos = options.path.indexOf('?');
1172
- if (searchPos < 0) {
1173
- options.pathname = options.path;
1174
- } else {
1175
- options.pathname = options.path.substring(0, searchPos);
1176
- options.search = options.path.substring(searchPos);
1177
- }
1178
- }
1179
- }
1180
-
1181
- /**
840
+ */ sanitizeOptions(options) {
841
+ // Ensure headers are always present
842
+ if (!options.headers) options.headers = {};
843
+ // Since http.request treats host as an alias of hostname,
844
+ // but the url module interprets host as hostname plus port,
845
+ // eliminate the host property to avoid confusion.
846
+ if (options.host) {
847
+ // Use hostname if set, because it has precedence
848
+ if (!options.hostname) {
849
+ options.hostname = options.host;
850
+ }
851
+ options.host = undefined;
852
+ }
853
+ // Complete the URL object when necessary
854
+ if (!options.pathname && options.path) {
855
+ const searchPos = options.path.indexOf('?');
856
+ if (searchPos < 0) {
857
+ options.pathname = options.path;
858
+ } else {
859
+ options.pathname = options.path.substring(0, searchPos);
860
+ options.search = options.path.substring(searchPos);
861
+ }
862
+ }
863
+ }
864
+ /**
1182
865
  * Processes a response from the current native request
1183
866
  * @param {Response} response
1184
867
  * @returns
1185
- */
1186
- processResponse(response) {
1187
- const m = this;
1188
- const {opt} = m;
1189
-
1190
- // Store the redirected response
1191
- const {statusCode} = response;
1192
- if (opt.trackRedirects) {
1193
- m._redirects.push({
1194
- url: m._currentUrl,
1195
- headers: response.headers,
1196
- statusCode,
1197
- });
1198
- }
1199
-
1200
- // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
1201
- // that further action needs to be taken by the user agent in order to
1202
- // fulfill the request. If a Location header field is provided,
1203
- // the user agent MAY automatically redirect its request to the URI
1204
- // referenced by the Location field value,
1205
- // even if the specific status code is not understood.
1206
-
1207
- // If the response is not a redirect; return it as-is
1208
- const {location} = response.headers;
1209
-
1210
- // log({statusCode, headers: response.headers}, 'processResponse')
1211
-
1212
- if (!location || opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
1213
- // 非重定向,返回给原始回调处理
1214
- response.responseUrl = m._currentUrl;
1215
- response.redirects = m._redirects;
1216
-
1217
- if (opt.stream) m.response = response;
1218
-
1219
- // Be a good stream and emit end when the response is finished.
1220
- // Hack to emit end on close because of a core bug that never fires end
1221
- response.on('close', () => {
1222
- if (!m._respended) {
1223
- response.emit('end');
1224
- }
1225
- });
1226
-
1227
- response.once('end', () => {
1228
- m._respended = true;
1229
- });
1230
-
1231
- const responseStream = m.processStream(response);
1232
- // NOTE: responseStartTime is deprecated in favor of .timings
1233
- response.responseStartTime = m.responseStartTime;
1234
-
1235
- // 触发原回调函数
1236
- m.resCallback?.(response, responseStream);
1237
-
1238
- // 类似 ClientRequest,触发 response 事件
1239
- m.emit('response', response, responseStream);
1240
-
1241
- // Clean up
1242
- m._requestBodyBuffers = [];
1243
- return // 退出,不继续处理
1244
- }
1245
-
1246
- // The response is a redirect, so abort the current request
1247
- destroyRequest(m._currentRequest);
1248
- // Discard the remainder of the response to avoid waiting for data
1249
- response.destroy();
1250
-
1251
- // RFC7231§6.4: A client SHOULD detect and intervene
1252
- // in cyclical redirections (i.e., "infinite" redirection loops).
1253
- if (++m._redirectCount > opt.maxRedirects) throw new TooManyRedirectsError()
1254
-
1255
- // Store the request headers if applicable
1256
- let requestHeaders;
1257
- const {beforeRedirect} = opt;
1258
- if (beforeRedirect) {
1259
- requestHeaders = {
1260
- // The Host header was set by nativeProtocol.request
1261
- // @ts-ignore
1262
- Host: response.req.getHeader('host'),
1263
- ...opt.headers,
1264
- };
1265
- }
1266
-
1267
- // RFC7231§6.4: Automatic redirection needs to done with
1268
- // care for methods not known to be safe, […]
1269
- // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
1270
- // the request method from POST to GET for the subsequent request.
1271
- const {method} = opt;
1272
- if (
1273
- ((statusCode === 301 || statusCode === 302) && opt.method === 'POST') ||
1274
- // RFC7231§6.4.4: The 303 (See Other) status code indicates that
1275
- // the server is redirecting the user agent to a different resource […]
1276
- // A user agent can perform a retrieval request targeting that URI
1277
- // (a GET or HEAD request if using HTTP) […]
1278
- (statusCode === 303 && !/^(?:GET|HEAD)$/.test(opt.method))
1279
- ) {
1280
- m.opt.method = 'GET';
1281
- // Drop a possible entity and headers related to it
1282
- m._requestBodyBuffers = [];
1283
- removeMatchingHeaders(/^content-/i, opt.headers);
1284
- }
1285
-
1286
- // Drop the Host header, as the redirect might lead to a different host
1287
- const currentHostHeader = removeMatchingHeaders(/^host$/i, opt.headers);
1288
-
1289
- // If the redirect is relative, carry over the host of the last request
1290
- const currentUrlParts = utils.parseUrl(m._currentUrl);
1291
- const currentHost = currentHostHeader || currentUrlParts.host;
1292
- const currentUrl = /^\w+:/.test(location)
1293
- ? m._currentUrl
1294
- : url.format(Object.assign(currentUrlParts, {host: currentHost}));
1295
-
1296
- // Create the redirected request
1297
- const redirectUrl = utils.resolveUrl(location, currentUrl);
1298
-
1299
- log$1({redirectUrl}, 'redirecting to');
1300
-
1301
- m._isRedirect = true;
1302
- // 覆盖原 url 解析部分,包括 protocol、hostname、port等
1303
- utils.spreadUrlObject(redirectUrl, m.opt);
1304
-
1305
- // Drop confidential headers when redirecting to a less secure protocol
1306
- // or to a different domain that is not a superdomain
1307
- if (
1308
- (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== 'https:') ||
1309
- (redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost))
1310
- ) {
1311
- removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.opt.headers);
1312
- }
1313
-
1314
- // Evaluate the beforeRedirect callback
1315
- if (utils.isFunction(beforeRedirect)) {
1316
- const responseDetails = {
1317
- headers: response.headers,
1318
- statusCode,
1319
- };
1320
- const requestDetails = {
1321
- url: currentUrl,
1322
- method,
1323
- headers: requestHeaders,
1324
- };
1325
-
1326
- beforeRedirect(opt, responseDetails, requestDetails);
1327
- m.sanitizeOptions(opt);
1328
- }
1329
-
1330
- // Perform the redirected request
1331
- m.request(); // 重新执行请求
1332
- }
1333
-
1334
- /**
868
+ */ processResponse(response) {
869
+ const m = this;
870
+ const { opt } = m;
871
+ // Store the redirected response
872
+ const { statusCode } = response;
873
+ if (opt.trackRedirects) {
874
+ m._redirects.push({
875
+ url: m._currentUrl,
876
+ headers: response.headers,
877
+ statusCode
878
+ });
879
+ }
880
+ // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
881
+ // that further action needs to be taken by the user agent in order to
882
+ // fulfill the request. If a Location header field is provided,
883
+ // the user agent MAY automatically redirect its request to the URI
884
+ // referenced by the Location field value,
885
+ // even if the specific status code is not understood.
886
+ // If the response is not a redirect; return it as-is
887
+ const { location } = response.headers;
888
+ // log({statusCode, headers: response.headers}, 'processResponse')
889
+ if (!location || opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
890
+ // 非重定向,返回给原始回调处理
891
+ response.responseUrl = m._currentUrl;
892
+ response.redirects = m._redirects;
893
+ if (opt.stream) m.response = response;
894
+ // Be a good stream and emit end when the response is finished.
895
+ // Hack to emit end on close because of a core bug that never fires end
896
+ response.on('close', ()=>{
897
+ if (!m._respended) {
898
+ response.emit('end');
899
+ }
900
+ });
901
+ response.once('end', ()=>{
902
+ m._respended = true;
903
+ });
904
+ const responseStream = m.processStream(response);
905
+ // NOTE: responseStartTime is deprecated in favor of .timings
906
+ response.responseStartTime = m.responseStartTime;
907
+ // 触发原回调函数
908
+ m.resCallback == null ? void 0 : m.resCallback.call(m, response, responseStream);
909
+ // 类似 ClientRequest,触发 response 事件
910
+ m.emit('response', response, responseStream);
911
+ // Clean up
912
+ m._requestBodyBuffers = [];
913
+ return; // 退出,不继续处理
914
+ }
915
+ // The response is a redirect, so abort the current request
916
+ destroyRequest(m._currentRequest);
917
+ // Discard the remainder of the response to avoid waiting for data
918
+ response.destroy();
919
+ // RFC7231§6.4: A client SHOULD detect and intervene
920
+ // in cyclical redirections (i.e., "infinite" redirection loops).
921
+ if (++m._redirectCount > opt.maxRedirects) throw new TooManyRedirectsError();
922
+ // Store the request headers if applicable
923
+ let requestHeaders;
924
+ const { beforeRedirect } = opt;
925
+ if (beforeRedirect) {
926
+ requestHeaders = {
927
+ // The Host header was set by nativeProtocol.request
928
+ // @ts-ignore
929
+ Host: response.req.getHeader('host'),
930
+ ...opt.headers
931
+ };
932
+ }
933
+ // RFC7231§6.4: Automatic redirection needs to done with
934
+ // care for methods not known to be safe, […]
935
+ // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
936
+ // the request method from POST to GET for the subsequent request.
937
+ const { method } = opt;
938
+ if ((statusCode === 301 || statusCode === 302) && opt.method === 'POST' || // RFC7231§6.4.4: The 303 (See Other) status code indicates that
939
+ // the server is redirecting the user agent to a different resource […]
940
+ // A user agent can perform a retrieval request targeting that URI
941
+ // (a GET or HEAD request if using HTTP) […]
942
+ statusCode === 303 && !/^(?:GET|HEAD)$/.test(opt.method)) {
943
+ m.opt.method = 'GET';
944
+ // Drop a possible entity and headers related to it
945
+ m._requestBodyBuffers = [];
946
+ removeMatchingHeaders(/^content-/i, opt.headers);
947
+ }
948
+ // Drop the Host header, as the redirect might lead to a different host
949
+ const currentHostHeader = removeMatchingHeaders(/^host$/i, opt.headers);
950
+ // If the redirect is relative, carry over the host of the last request
951
+ const currentUrlParts = utils.parseUrl(m._currentUrl);
952
+ const currentHost = currentHostHeader || currentUrlParts.host;
953
+ const currentUrl = /^\w+:/.test(location) ? m._currentUrl : url.format(Object.assign(currentUrlParts, {
954
+ host: currentHost
955
+ }));
956
+ // Create the redirected request
957
+ const redirectUrl = utils.resolveUrl(location, currentUrl);
958
+ log$1({
959
+ redirectUrl
960
+ }, 'redirecting to');
961
+ m._isRedirect = true;
962
+ // 覆盖原 url 解析部分,包括 protocol、hostname、port等
963
+ utils.spreadUrlObject(redirectUrl, m.opt);
964
+ // Drop confidential headers when redirecting to a less secure protocol
965
+ // or to a different domain that is not a superdomain
966
+ if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== 'https:' || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) {
967
+ removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.opt.headers);
968
+ }
969
+ // Evaluate the beforeRedirect callback
970
+ if (utils.isFunction(beforeRedirect)) {
971
+ const responseDetails = {
972
+ headers: response.headers,
973
+ statusCode
974
+ };
975
+ const requestDetails = {
976
+ url: currentUrl,
977
+ method,
978
+ headers: requestHeaders
979
+ };
980
+ beforeRedirect(opt, responseDetails, requestDetails);
981
+ m.sanitizeOptions(opt);
982
+ }
983
+ // Perform the redirected request
984
+ m.request() // 重新执行请求
985
+ ;
986
+ }
987
+ /**
1335
988
  * 处理响应stream
1336
989
  * 自动解压,透传流,需设置 decompress = false,避免解压数据
1337
990
  * @param {Response} res
1338
991
  * @returns {Response | stream.Readable}
1339
- */
1340
- processStream(res) {
1341
- const m = this;
1342
- const {opt} = m;
1343
-
1344
- const streams = [res];
1345
- let responseStream = res;
1346
- // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
1347
- const responseLength = +res.headers['content-length'];
1348
-
1349
- // log('processStream', {
1350
- // statusCode: res.statusCode,
1351
- // responseLength,
1352
- // headers: res.headers,
1353
- // })
1354
-
1355
- if (opt.transformStream) {
1356
- opt.transformStream.responseLength = responseLength;
1357
- streams.push(opt.transformStream);
1358
- }
1359
-
1360
- const empty = utils.noBody(opt.method, res.statusCode);
1361
- // decompress the response body transparently if required
1362
- if (opt.decompress !== false && res.headers['content-encoding']) {
1363
- // if decompress disabled we should not decompress
1364
- // 压缩内容,加入 解压 stream,自动解压,axios v1.2 存在bug,不能自动解压
1365
- // if no content, but headers still say that it is encoded,
1366
- // remove the header not confuse downstream operations
1367
- // if ((!responseLength || res.statusCode === 204) && res.headers['content-encoding']) {
1368
- if (empty && res.headers['content-encoding']) res.headers['content-encoding'] = undefined;
1369
-
1370
- // 'content-encoding': 'gzip',
1371
- switch ((res.headers['content-encoding'] || '').toLowerCase()) {
1372
- /*eslint default-case:0*/
1373
- case 'gzip':
1374
- case 'x-gzip':
1375
- case 'compress':
1376
- case 'x-compress':
1377
- // add the unzipper to the body stream processing pipeline
1378
- // @ts-ignore
1379
- streams.push(zlib.createUnzip(zlibOptions));
1380
-
1381
- // remove the content-encoding in order to not confuse downstream operations
1382
- res.headers['content-encoding'] = undefined;
1383
- break
1384
-
1385
- case 'deflate':
1386
- // @ts-ignore
1387
- streams.push(new ZlibTransform());
1388
-
1389
- // add the unzipper to the body stream processing pipeline
1390
- // @ts-ignore
1391
- streams.push(zlib.createUnzip(zlibOptions));
1392
-
1393
- // remove the content-encoding in order to not confuse downstream operations
1394
- res.headers['content-encoding'] = undefined;
1395
- break
1396
-
1397
- case 'br':
1398
- if (isBrotliSupported) {
1399
- // @ts-ignore
1400
- streams.push(zlib.createBrotliDecompress(brotliOptions));
1401
- res.headers['content-encoding'] = undefined;
1402
- }
1403
- break
1404
- }
1405
- }
1406
-
1407
- // 响应流,用于读
1408
- // @ts-ignore
1409
- responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
1410
- // 将内部 responseStream 可读流 映射到 redirectReq
1411
-
1412
- // @ts-ignore
1413
- m.responseStream = responseStream;
1414
- // @ts-ignore
1415
- responseStream.redirectReq = m; // 事情触发时引用
1416
-
1417
- // stream 模式,事件透传到 请求类
1418
- if (opt.stream) {
1419
- if (m._paused) responseStream.pause();
1420
- // 写入目的流
1421
- for (const dest of m.pipedests) m.pipeDest(dest);
1422
-
1423
- // 接收responseStream事件,转发 redirectReq 发射
1424
- for (const ev of readEvents) responseStream.on(ev, readEventEmit[ev]);
1425
-
1426
- // @ts-ignore
1427
- responseStream.on('data', chunk => {
1428
- if (m.timing && !m.responseStarted) {
1429
- m.responseStartTime = new Date().getTime();
1430
- }
1431
- m._destdata = true;
1432
- m.emit('data', chunk); // 向上触发
1433
- });
1434
- }
1435
-
1436
- // 可读流结束,触发 finished,方便上层清理
1437
- // A cleanup function which removes all registered listeners.
1438
- const offListeners = stream.finished(responseStream, () => {
1439
- offListeners(); // cleanup
1440
- this.emit('finished');
1441
- });
1442
-
1443
- return responseStream
1444
- }
1445
-
1446
- // Read Stream API
1447
-
1448
- /**
992
+ */ processStream(res) {
993
+ const m = this;
994
+ const { opt } = m;
995
+ const streams = [
996
+ res
997
+ ];
998
+ let responseStream = res;
999
+ // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
1000
+ const responseLength = +res.headers['content-length'];
1001
+ // log('processStream', {
1002
+ // statusCode: res.statusCode,
1003
+ // responseLength,
1004
+ // headers: res.headers,
1005
+ // })
1006
+ if (opt.transformStream) {
1007
+ opt.transformStream.responseLength = responseLength;
1008
+ streams.push(opt.transformStream);
1009
+ }
1010
+ const empty = utils.noBody(opt.method, res.statusCode);
1011
+ // decompress the response body transparently if required
1012
+ if (opt.decompress !== false && res.headers['content-encoding']) {
1013
+ // if decompress disabled we should not decompress
1014
+ // 压缩内容,加入 解压 stream,自动解压,axios v1.2 存在bug,不能自动解压
1015
+ // if no content, but headers still say that it is encoded,
1016
+ // remove the header not confuse downstream operations
1017
+ // if ((!responseLength || res.statusCode === 204) && res.headers['content-encoding']) {
1018
+ if (empty && res.headers['content-encoding']) res.headers['content-encoding'] = undefined;
1019
+ // 'content-encoding': 'gzip',
1020
+ switch((res.headers['content-encoding'] || '').toLowerCase()){
1021
+ /*eslint default-case:0*/ case 'gzip':
1022
+ case 'x-gzip':
1023
+ case 'compress':
1024
+ case 'x-compress':
1025
+ // add the unzipper to the body stream processing pipeline
1026
+ // @ts-ignore
1027
+ streams.push(zlib.createUnzip(zlibOptions));
1028
+ // remove the content-encoding in order to not confuse downstream operations
1029
+ res.headers['content-encoding'] = undefined;
1030
+ break;
1031
+ case 'deflate':
1032
+ // @ts-ignore
1033
+ streams.push(new ZlibTransform());
1034
+ // add the unzipper to the body stream processing pipeline
1035
+ // @ts-ignore
1036
+ streams.push(zlib.createUnzip(zlibOptions));
1037
+ // remove the content-encoding in order to not confuse downstream operations
1038
+ res.headers['content-encoding'] = undefined;
1039
+ break;
1040
+ case 'br':
1041
+ if (isBrotliSupported) {
1042
+ // @ts-ignore
1043
+ streams.push(zlib.createBrotliDecompress(brotliOptions));
1044
+ res.headers['content-encoding'] = undefined;
1045
+ }
1046
+ break;
1047
+ }
1048
+ }
1049
+ // 响应流,用于读
1050
+ // @ts-ignore
1051
+ responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
1052
+ // 将内部 responseStream 可读流 映射到 redirectReq
1053
+ // @ts-ignore
1054
+ m.responseStream = responseStream;
1055
+ // @ts-ignore
1056
+ responseStream.redirectReq = m // 事情触发时引用
1057
+ ;
1058
+ // stream 模式,事件透传到 请求类
1059
+ if (opt.stream) {
1060
+ if (m._paused) responseStream.pause();
1061
+ // 写入目的流
1062
+ for (const dest of m.pipedests)m.pipeDest(dest);
1063
+ // 接收responseStream事件,转发 redirectReq 发射
1064
+ for (const ev of readEvents)responseStream.on(ev, readEventEmit[ev]);
1065
+ // @ts-ignore
1066
+ responseStream.on('data', (chunk)=>{
1067
+ if (m.timing && !m.responseStarted) {
1068
+ m.responseStartTime = new Date().getTime();
1069
+ }
1070
+ m._destdata = true;
1071
+ m.emit('data', chunk) // 向上触发
1072
+ ;
1073
+ });
1074
+ }
1075
+ // 可读流结束,触发 finished,方便上层清理
1076
+ // A cleanup function which removes all registered listeners.
1077
+ const offListeners = stream.finished(responseStream, ()=>{
1078
+ offListeners() // cleanup
1079
+ ;
1080
+ this.emit('finished');
1081
+ });
1082
+ return responseStream;
1083
+ }
1084
+ // Read Stream API
1085
+ /**
1449
1086
  * 建立读取流管道
1450
1087
  * read stream to write stream
1451
1088
  * pipe 只是建立连接管道,后续自动传输数据
@@ -1455,192 +1092,248 @@ class Request extends Duplex {
1455
1092
  * @param {Object} [opt] - Optional configuration object.
1456
1093
  * @param {boolean} [opt.end=true] - Whether to end the writable stream when the readable stream ends.
1457
1094
  * @returns {T} The destination stream.
1458
- */
1459
- pipe(dest, opts = {}) {
1460
- const m = this;
1461
- // m.pipe()
1462
- // 请求已响应
1463
- if (m.responseStream) {
1464
- // 已有数据,不可pipe
1465
- if (m._destdata)
1466
- m.emit('error', new Error('You cannot pipe after data has been emitted from the response.'));
1467
- else if (m._respended)
1468
- m.emit('error', new Error('You cannot pipe after the response has been ended.'));
1469
- else {
1470
- // stream.Stream.prototype.pipe.call(self, dest, opts);
1471
- super.pipe(dest, opts); // 建立连接管道,自动传输数据
1472
- m.pipeDest(dest);
1473
- return dest // 返回写入 stream
1474
- }
1475
- } else {
1476
- // 已请求还未响应
1477
- m.pipedests.push(dest);
1478
- // stream.Stream.prototype.pipe.call(self, dest, opts);
1479
- super.pipe(dest, opts); // 建立连接管道
1480
- return dest // 返回写入 stream
1481
- }
1482
- }
1483
-
1484
- /**
1095
+ */ pipe(dest, opts = {}) {
1096
+ const m = this;
1097
+ // m.pipe()
1098
+ // 请求已响应
1099
+ if (m.responseStream) {
1100
+ // 已有数据,不可pipe
1101
+ if (m._destdata) m.emit('error', new Error('You cannot pipe after data has been emitted from the response.'));
1102
+ else if (m._respended) m.emit('error', new Error('You cannot pipe after the response has been ended.'));
1103
+ else {
1104
+ // stream.Stream.prototype.pipe.call(self, dest, opts);
1105
+ super.pipe(dest, opts) // 建立连接管道,自动传输数据
1106
+ ;
1107
+ m.pipeDest(dest);
1108
+ return dest // 返回写入 stream
1109
+ ;
1110
+ }
1111
+ } else {
1112
+ // 已请求还未响应
1113
+ m.pipedests.push(dest);
1114
+ // stream.Stream.prototype.pipe.call(self, dest, opts);
1115
+ super.pipe(dest, opts) // 建立连接管道
1116
+ ;
1117
+ return dest // 返回写入 stream
1118
+ ;
1119
+ }
1120
+ }
1121
+ /**
1485
1122
  * 分离先前使用pipe()方法附加的Writable流。
1486
1123
  * @param {stream.Writable} dest
1487
1124
  * @returns
1488
- */
1489
- unpipe(dest) {
1490
- const m = this;
1491
-
1492
- // 请求已响应
1493
- if (m.responseStream) {
1494
- // 已有数据,不可 unpipe
1495
- if (m._destdata)
1496
- m.emit(
1497
- 'error',
1498
- new Error('You cannot unpipe after data has been emitted from the response.')
1499
- );
1500
- else if (m._respended)
1501
- m.emit('error', new Error('You cannot unpipe after the response has been ended.'));
1502
- else {
1503
- // stream.Stream.prototype.pipe.call(self, dest, opts);
1504
- super.unpipe(dest); // 建立连接管道,自动传输数据
1505
- m.pipedests = m.pipedests.filter(v => v !== dest);
1506
- return m
1507
- }
1508
- } else {
1509
- // 已请求还未响应
1510
- m.pipedests = m.pipedests.filter(v => v !== dest);
1511
- super.unpipe(dest); // 从连接管道中分离
1512
- return m
1513
- }
1514
- }
1515
-
1516
- /**
1125
+ */ unpipe(dest) {
1126
+ const m = this;
1127
+ // 请求已响应
1128
+ if (m.responseStream) {
1129
+ // 已有数据,不可 unpipe
1130
+ if (m._destdata) m.emit('error', new Error('You cannot unpipe after data has been emitted from the response.'));
1131
+ else if (m._respended) m.emit('error', new Error('You cannot unpipe after the response has been ended.'));
1132
+ else {
1133
+ // stream.Stream.prototype.pipe.call(self, dest, opts);
1134
+ super.unpipe(dest) // 建立连接管道,自动传输数据
1135
+ ;
1136
+ m.pipedests = m.pipedests.filter((v)=>v !== dest);
1137
+ return m;
1138
+ }
1139
+ } else {
1140
+ // 已请求还未响应
1141
+ m.pipedests = m.pipedests.filter((v)=>v !== dest);
1142
+ super.unpipe(dest) // 从连接管道中分离
1143
+ ;
1144
+ return m;
1145
+ }
1146
+ }
1147
+ /**
1517
1148
  * 收请求响应,传输数据到可写流之前,设置可写流 header
1518
1149
  * content-type 和 content-length,实现数据 透传,比如图片
1519
1150
  * 流模式透传,需设置 decompress = false,避免解压数据
1520
1151
  * (await req.stream('http://google.com/img.png')).pipe(await req.stream('http://mysite.com/img.png'))
1521
1152
  * pipe to dest
1522
1153
  * @param {*} dest
1523
- */
1524
- pipeDest(dest) {
1525
- const m = this;
1526
- const {response} = m;
1527
-
1528
- // Called after the response is received
1529
- if (response?.headers && dest.headers && !dest.headersSent) {
1530
- const caseless = new Caseless(response.headers);
1531
- if (caseless.has('content-type')) {
1532
- const ctname = /** @type {string} */ (caseless.has('content-type'));
1533
- if (dest.setHeader) {
1534
- dest.setHeader(ctname, response.headers[ctname]);
1535
- } else {
1536
- dest.headers[ctname] = response.headers[ctname];
1537
- }
1538
- }
1539
-
1540
- if (caseless.has('content-length')) {
1541
- const clname = /** @type {string} */ (caseless.has('content-length'));
1542
- if (dest.setHeader) {
1543
- dest.setHeader(clname, response.headers[clname]);
1544
- } else {
1545
- dest.headers[clname] = response.headers[clname];
1546
- }
1547
- }
1548
- }
1549
-
1550
- if (response?.headers && dest.setHeader && !dest.headersSent) {
1551
- for (const k of Object.keys(response.headers)) dest.setHeader(k, response.headers[k]);
1552
-
1553
- dest.statusCode = response.statusCode;
1554
- }
1555
-
1556
- if (m.pipefilter) m.pipefilter(response, dest);
1557
- }
1558
-
1559
- /**
1154
+ */ pipeDest(dest) {
1155
+ const m = this;
1156
+ const { response } = m;
1157
+ // Called after the response is received
1158
+ if ((response == null ? void 0 : response.headers) && dest.headers && !dest.headersSent) {
1159
+ const caseless = new Caseless(response.headers);
1160
+ if (caseless.has('content-type')) {
1161
+ const ctname = /** @type {string} */ caseless.has('content-type');
1162
+ if (dest.setHeader) {
1163
+ dest.setHeader(ctname, response.headers[ctname]);
1164
+ } else {
1165
+ dest.headers[ctname] = response.headers[ctname];
1166
+ }
1167
+ }
1168
+ if (caseless.has('content-length')) {
1169
+ const clname = /** @type {string} */ caseless.has('content-length');
1170
+ if (dest.setHeader) {
1171
+ dest.setHeader(clname, response.headers[clname]);
1172
+ } else {
1173
+ dest.headers[clname] = response.headers[clname];
1174
+ }
1175
+ }
1176
+ }
1177
+ if ((response == null ? void 0 : response.headers) && dest.setHeader && !dest.headersSent) {
1178
+ for (const k of Object.keys(response.headers))dest.setHeader(k, response.headers[k]);
1179
+ dest.statusCode = response.statusCode;
1180
+ }
1181
+ if (m.pipefilter) m.pipefilter(response, dest);
1182
+ }
1183
+ /**
1560
1184
  * 暂停read流
1561
- */
1562
- pause() {
1563
- const m = this;
1564
- // 没有流
1565
- if (!m.responseStream) m._paused = true;
1566
- else m.responseStream.pause();
1567
- return m
1568
- }
1569
-
1570
- /**
1185
+ */ pause() {
1186
+ const m = this;
1187
+ // 没有流
1188
+ if (!m.responseStream) m._paused = true;
1189
+ else m.responseStream.pause();
1190
+ return m;
1191
+ }
1192
+ /**
1571
1193
  * 继续read响应流
1572
- */
1573
- resume() {
1574
- const m = this;
1575
- if (!m.responseStream) m._paused = false;
1576
- else m.responseStream.resume();
1577
- return m
1578
- }
1579
-
1580
- isPaused() {
1581
- return this._paused
1582
- }
1583
- }
1584
-
1194
+ */ resume() {
1195
+ const m = this;
1196
+ if (!m.responseStream) m._paused = false;
1197
+ else m.responseStream.resume();
1198
+ return m;
1199
+ }
1200
+ isPaused() {
1201
+ return this._paused;
1202
+ }
1203
+ /**
1204
+ * responseCallback 原消息处理回调
1205
+ * @param {Opts} opts
1206
+ * @param {*} resCallback
1207
+ */ constructor(opts, resCallback){
1208
+ super(), /** @type {NodeJS.Timeout} */ this._timeout = null, /** @type {*} */ this.socket = null, /** @type {http.ClientRequest} */ this._currentRequest = null, /** @type {Response} */ this.response = null, /** @type {stream.Readable} */ this.responseStream = null, this.timing = false, this.responseStarted = false, this.responseStartTime = 0, this._destdata = false, this._paused = false, this._respended = false, /** @type {stream.Readable} */ this.pipesrc = null // 被 pipe 时的 src stream
1209
+ , /** @type {stream.Writable[]} */ this.pipedests = [] // pipe dest
1210
+ , /** @type {*} */ this.startTimer = null;
1211
+ const m = this;
1212
+ // log({opts}, 'new Request')
1213
+ // Initialize the request
1214
+ m.sanitizeOptions(opts);
1215
+ m.opt = opts;
1216
+ m.headers = opts.headers;
1217
+ // log({opts}, 'constructor')
1218
+ m._ended = false;
1219
+ m._ending = false;
1220
+ m._redirectCount = 0;
1221
+ /** @type {any[]} */ m._redirects = [];
1222
+ m._requestBodyLength = 0;
1223
+ /** @type {any[]} */ m._requestBodyBuffers = [];
1224
+ // save the callback if passed
1225
+ m.resCallback = resCallback;
1226
+ /**
1227
+ * React to responses of native requests
1228
+ * 接管 response 事件,非重定向,触发 response 事件
1229
+ * @param {Response} res
1230
+ */ m._onResponse = (res)=>{
1231
+ try {
1232
+ m.processResponse(res);
1233
+ } catch (cause) {
1234
+ m.emit('error', cause instanceof RedirectionError ? cause : new RedirectionError({
1235
+ cause: cause
1236
+ }));
1237
+ }
1238
+ };
1239
+ // Proxy all other public ClientRequest methods 'getHeader'
1240
+ for (const method of writeMethods){
1241
+ // @ts-ignore
1242
+ m[method] = (a, b)=>{
1243
+ var // log(method, {a, b})
1244
+ // @ts-ignore
1245
+ _m__currentRequest;
1246
+ (_m__currentRequest = m._currentRequest) == null ? void 0 : _m__currentRequest[method](a, b);
1247
+ };
1248
+ }
1249
+ // Proxy all public ClientRequest properties
1250
+ // 'aborted', 'connection' 弃用
1251
+ for (const property of writeProps){
1252
+ Object.defineProperty(m, property, {
1253
+ get () {
1254
+ var _m__currentRequest;
1255
+ // @ts-ignore
1256
+ const val = (_m__currentRequest = m._currentRequest) == null ? void 0 : _m__currentRequest[property];
1257
+ // log('get property', {property})
1258
+ return val;
1259
+ }
1260
+ });
1261
+ }
1262
+ // 流模式
1263
+ if (opts.stream) {
1264
+ // 被 pipe 作为目标时触发,拷贝 src headers
1265
+ m.on('pipe', /** @param {stream.Readable & {headers?: Object.<string, string>}} src */ (src)=>{
1266
+ // m.ntick &&
1267
+ if (m._currentRequest) {
1268
+ m.emit('error', new Error('You cannot pipe to this stream after the outbound request has started.'));
1269
+ }
1270
+ m.pipesrc = src;
1271
+ if (utils.isReadStream(src)) {
1272
+ // @ts-ignore
1273
+ if (!m.hasHeader('content-type')) m.setHeader('content-type', mime.lookup(src.path));
1274
+ } else {
1275
+ // 拷贝请求头
1276
+ if (src.headers) {
1277
+ for (const k of Object.keys(src.headers)){
1278
+ if (!m.hasHeader(k)) {
1279
+ m.setHeader(k, src.headers[k]);
1280
+ }
1281
+ }
1282
+ }
1283
+ // @ts-ignore
1284
+ if (src.opt.method && !m.opt.method) m.opt.method = src.opt.method;
1285
+ }
1286
+ });
1287
+ }
1288
+ // Perform the first request
1289
+ // m.request(); // 创建时不连接,写入数据时连接,否则 pipe 时无法写入header
1290
+ }
1291
+ };
1585
1292
  /**
1586
1293
  * 释放请求,触发error事件
1587
1294
  * 'error' event, and emit a 'close' event.
1588
1295
  * Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
1589
1296
  * @param {*} request
1590
1297
  * @param {*} error
1591
- */
1592
- function destroyRequest(request, error) {
1593
- for (const ev of writeEvents) {
1594
- request.removeListener(ev, writeEventEmit[ev]);
1595
- }
1596
- request.on('error', utils.noop);
1597
- request.destroy(error); // 触发 error 事件
1598
- }
1599
-
1298
+ */ function destroyRequest(request, error) {
1299
+ for (const ev of writeEvents){
1300
+ request.removeListener(ev, writeEventEmit[ev]);
1301
+ }
1302
+ request.on('error', utils.noop);
1303
+ request.destroy(error) // 触发 error 事件
1304
+ ;
1305
+ }
1600
1306
  /**
1601
1307
  *
1602
1308
  * @param {RegExp} regex
1603
1309
  * @param {Object.<string, string>} headers
1604
1310
  * @returns
1605
- */
1606
- function removeMatchingHeaders(regex, headers) {
1607
- let lastValue;
1608
- for (const k of Object.keys(headers)) {
1609
- if (regex.test(k)) {
1610
- lastValue = headers[k];
1611
- delete headers[k];
1612
- }
1613
- }
1614
-
1615
- return lastValue === null || typeof lastValue === 'undefined'
1616
- ? undefined
1617
- : String(lastValue).trim()
1618
- }
1619
-
1311
+ */ function removeMatchingHeaders(regex, headers) {
1312
+ let lastValue;
1313
+ for (const k of Object.keys(headers)){
1314
+ if (regex.test(k)) {
1315
+ lastValue = headers[k];
1316
+ delete headers[k];
1317
+ }
1318
+ }
1319
+ return lastValue === null || typeof lastValue === 'undefined' ? undefined : String(lastValue).trim();
1320
+ }
1620
1321
  /**
1621
1322
  *
1622
1323
  * @param {string} subdomain
1623
1324
  * @param {string} domain
1624
1325
  * @returns
1625
- */
1626
- function isSubdomain(subdomain, domain) {
1627
- assert(utils.isString(subdomain) && utils.isString(domain));
1628
- const dot = subdomain.length - domain.length - 1;
1629
- return dot > 0 && subdomain[dot] === '.' && subdomain.endsWith(domain)
1326
+ */ function isSubdomain(subdomain, domain) {
1327
+ assert(utils.isString(subdomain) && utils.isString(domain));
1328
+ const dot = subdomain.length - domain.length - 1;
1329
+ return dot > 0 && subdomain[dot] === '.' && subdomain.endsWith(domain);
1630
1330
  }
1631
1331
 
1632
- /**
1633
- * from 'https://github.com/follow-redirects/follow-redirects'
1634
- * used by axios
1635
- * 修改以支持http、https 代理服务器
1636
- * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
1637
- */
1638
-
1639
- const log = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
1640
-
1641
- /** @typedef { import('./request').Response} Response */
1642
-
1643
- /**
1332
+ const log = log$2({
1333
+ env: `wia:req:${name(import.meta.url)}`
1334
+ }) // __filename
1335
+ ;
1336
+ /** @typedef { import('./request').Response} Response */ /**
1644
1337
  * @typedef {object} Opts
1645
1338
  * @prop {Object.<string,string>} [headers]
1646
1339
  * @prop {string} [url]
@@ -1662,104 +1355,89 @@ const log = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
1662
1355
  * @prop {number} [maxRedirects=21] - 最大重定向次数
1663
1356
  * @prop {number} [maxBodyLength = 0] - body限制,缺省不限
1664
1357
  * @prop {*} [trackRedirects]
1665
- */
1666
-
1667
- /** @typedef {(res: Response, stream?: stream.Readable) => void} Cb*/
1668
-
1669
- utils.createErrorType(
1670
- 'ERR_STREAM_WRITE_BEEN_ABORTED',
1671
- 'Request stream has been aborted'
1672
- )
1673
-
1674
- // Preventive platform detection
1675
- // istanbul ignore
1676
- ;(function detectUnsupportedEnvironment() {
1677
- const looksLikeNode = typeof process !== 'undefined';
1678
- const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
1679
- const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
1680
- if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
1681
- log.warn('The follow-redirects package should be excluded from browser builds.');
1682
- }
1683
- })();
1684
-
1358
+ */ /** @typedef {(res: Response, stream?: stream.Readable) => void} Cb*/ utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABORTED', 'Request stream has been aborted');
1359
+ (function detectUnsupportedEnvironment() {
1360
+ const looksLikeNode = typeof process !== 'undefined';
1361
+ const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
1362
+ const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
1363
+ if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
1364
+ log.warn('The follow-redirects package should be excluded from browser builds.');
1365
+ }
1366
+ })();
1685
1367
  /**
1686
1368
  * 封装http(s),实现重定向
1687
1369
  * 重定向可能切换http、https
1688
1370
  * 支持隧道及非隧道、http(s)代理
1689
- */
1690
-
1691
- /**
1371
+ */ /**
1692
1372
  * 初始化参数
1693
1373
  * @param {string | Opts} uri/opts
1694
1374
  * @param {Opts | Cb} [opts] /cb
1695
1375
  * @param {Cb} [cb]
1696
1376
  * @returns {{opt: Opts, cb: Cb}}
1697
- */
1698
- function init(uri, opts, cb) {
1699
- let R;
1700
- try {
1701
- // Parse parameters, ensuring that input is an object
1702
- if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
1703
- else if (utils.isString(uri)) uri = utils.spreadUrlObject(utils.parseUrl(uri));
1704
- else {
1705
- // @ts-ignore
1706
- cb = opts;
1707
- // @ts-ignore
1708
- opts = uri;
1709
- // @ts-ignore
1710
- const {url} = opts;
1711
- // url,解析
1712
- if (url) {
1713
- // @ts-ignore
1714
- // biome-ignore lint/performance/noDelete: <explanation>
1715
- delete opts.url;
1716
- if (utils.isURL(url)) uri = utils.spreadUrlObject(url);
1717
- else if (utils.isString(url)) uri = utils.spreadUrlObject(utils.parseUrl(url));
1718
- } else {
1719
- // @ts-ignore
1720
- opts = uri; // 不判断 utils.validateUrl(uri)
1721
- uri = {};
1722
- }
1723
- }
1724
-
1725
- if (utils.isFunction(opts)) {
1726
- // @ts-ignore
1727
- cb = opts;
1728
- opts = {};
1729
- }
1730
-
1731
- // copy options
1732
- /** @type {Opts} */
1733
- const opt = {
1734
- // @ts-ignore
1735
- ...uri,
1736
- ...opts,
1737
- };
1738
-
1739
- if (!utils.isString(opt.host) && !utils.isString(opt.hostname)) opt.hostname = '::1';
1740
- opt.method = (opt.method ?? 'get').toUpperCase();
1741
-
1742
- // follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
1743
- opt.maxBodyLength = opt.maxBodyLength ?? Number.POSITIVE_INFINITY;
1744
- opt.maxRedirects = opt.maxRedirects ?? 21;
1745
- if (opt.maxRedirects === 0) opt.followRedirects = false;
1746
- opt.headers = opt.headers ?? {
1747
- Accept: 'application/json, text/plain, */*',
1748
- 'User-Agent':
1749
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35',
1750
- 'Accept-Encoding': 'gzip, compress, deflate, br',
1751
- };
1752
-
1753
- R = {opt, cb};
1754
- // log({R}, 'init')
1755
- } catch (e) {
1756
- log.err(e, 'init');
1757
- }
1758
-
1759
- // @ts-ignore
1760
- return R
1761
- }
1762
-
1377
+ */ function init(uri, opts, cb) {
1378
+ let R;
1379
+ try {
1380
+ // Parse parameters, ensuring that input is an object
1381
+ if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
1382
+ else if (utils.isString(uri)) uri = utils.spreadUrlObject(utils.parseUrl(uri));
1383
+ else {
1384
+ // @ts-ignore
1385
+ cb = opts;
1386
+ // @ts-ignore
1387
+ opts = uri;
1388
+ // @ts-ignore
1389
+ const { url } = opts;
1390
+ // url,解析
1391
+ if (url) {
1392
+ // @ts-ignore
1393
+ // biome-ignore lint/performance/noDelete: <explanation>
1394
+ delete opts.url;
1395
+ if (utils.isURL(url)) uri = utils.spreadUrlObject(url);
1396
+ else if (utils.isString(url)) uri = utils.spreadUrlObject(utils.parseUrl(url));
1397
+ } else {
1398
+ // @ts-ignore
1399
+ opts = uri // 不判断 utils.validateUrl(uri)
1400
+ ;
1401
+ uri = {};
1402
+ }
1403
+ }
1404
+ if (utils.isFunction(opts)) {
1405
+ // @ts-ignore
1406
+ cb = opts;
1407
+ opts = {};
1408
+ }
1409
+ // copy options
1410
+ /** @type {Opts} */ const opt = {
1411
+ // @ts-ignore
1412
+ ...uri,
1413
+ ...opts
1414
+ };
1415
+ if (!utils.isString(opt.host) && !utils.isString(opt.hostname)) opt.hostname = '::1';
1416
+ var _opt_method;
1417
+ opt.method = ((_opt_method = opt.method) != null ? _opt_method : 'get').toUpperCase();
1418
+ var _opt_maxBodyLength;
1419
+ // follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
1420
+ opt.maxBodyLength = (_opt_maxBodyLength = opt.maxBodyLength) != null ? _opt_maxBodyLength : Number.POSITIVE_INFINITY;
1421
+ var _opt_maxRedirects;
1422
+ opt.maxRedirects = (_opt_maxRedirects = opt.maxRedirects) != null ? _opt_maxRedirects : 21;
1423
+ if (opt.maxRedirects === 0) opt.followRedirects = false;
1424
+ var _opt_headers;
1425
+ opt.headers = (_opt_headers = opt.headers) != null ? _opt_headers : {
1426
+ Accept: 'application/json, text/plain, */*',
1427
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35',
1428
+ 'Accept-Encoding': 'gzip, compress, deflate, br'
1429
+ };
1430
+ R = {
1431
+ opt,
1432
+ cb
1433
+ };
1434
+ // log({R}, 'init')
1435
+ } catch (e) {
1436
+ log.err(e, 'init');
1437
+ }
1438
+ // @ts-ignore
1439
+ return R;
1440
+ }
1763
1441
  /**
1764
1442
  * Executes a request, following redirects
1765
1443
  * 替换原 http(s).request,参数类似
@@ -1771,64 +1449,51 @@ function init(uri, opts, cb) {
1771
1449
  * @param {Opts | Cb} [opts] /callback
1772
1450
  * @param {Cb} [callback] /null
1773
1451
  * @returns {Request}
1774
- */
1775
- function request(uri, opts, callback) {
1776
- let R = null;
1777
-
1778
- try {
1779
- // @ts-ignore
1780
- const {opt, cb} = init(uri, opts, callback);
1781
- // log({uri, opt, opts}, 'request')
1782
-
1783
- const {data, stream} = opt;
1784
- // data 在本函数完成处理,不传递到 request
1785
- opt.data = undefined;
1786
-
1787
- // @ts-ignore
1788
- const req = new Request(opt, cb);
1789
-
1790
- // 非流模式,自动发送请求,流模式通过流写入发送
1791
- if (!stream) {
1792
- // 发送数据
1793
- if (utils.isStream(data)) {
1794
- // Send the request
1795
- let ended = false;
1796
- let errored = false;
1797
-
1798
- data.on('end', () => {
1799
- ended = true;
1800
- });
1801
-
1802
- data.once(
1803
- 'error',
1804
- /** @param {*} err */ err => {
1805
- errored = true;
1806
- // req.destroy(err)
1807
- }
1808
- );
1809
-
1810
- data.on('close', () => {
1811
- if (!ended && !errored) {
1812
- // throw new WritebBeenAbortedError()
1813
- }
1814
- });
1815
-
1816
- // log.error({data}, 'request data.pipe')
1817
- data.pipe(req); // 写入数据流
1818
- } else {
1819
- // log.error({data}, 'request req.end')
1820
- req.end(data); // 写入数据
1821
- }
1822
- }
1823
-
1824
- R = req;
1825
- } catch (e) {
1826
- log.err(e, 'request');
1827
- }
1828
-
1829
- return R
1830
- }
1831
-
1452
+ */ function request(uri, opts, callback) {
1453
+ let R = null;
1454
+ try {
1455
+ // @ts-ignore
1456
+ const { opt, cb } = init(uri, opts, callback);
1457
+ // log({uri, opt, opts}, 'request')
1458
+ const { data, stream } = opt;
1459
+ // data 在本函数完成处理,不传递到 request
1460
+ opt.data = undefined;
1461
+ // @ts-ignore
1462
+ const req = new Request(opt, cb);
1463
+ // 非流模式,自动发送请求,流模式通过流写入发送
1464
+ if (!stream) {
1465
+ // 发送数据
1466
+ if (utils.isStream(data)) {
1467
+ // Send the request
1468
+ let ended = false;
1469
+ let errored = false;
1470
+ data.on('end', ()=>{
1471
+ ended = true;
1472
+ });
1473
+ data.once('error', /** @param {*} err */ (err)=>{
1474
+ errored = true;
1475
+ // req.destroy(err)
1476
+ });
1477
+ data.on('close', ()=>{
1478
+ if (!ended && !errored) {
1479
+ // throw new WritebBeenAbortedError()
1480
+ }
1481
+ });
1482
+ // log.error({data}, 'request data.pipe')
1483
+ data.pipe(req) // 写入数据流
1484
+ ;
1485
+ } else {
1486
+ // log.error({data}, 'request req.end')
1487
+ req.end(data) // 写入数据
1488
+ ;
1489
+ }
1490
+ }
1491
+ R = req;
1492
+ } catch (e) {
1493
+ log.err(e, 'request');
1494
+ }
1495
+ return R;
1496
+ }
1832
1497
  /**
1833
1498
  * 执行简单的数据(支持stream)请求
1834
1499
  * 非流模式,直接写入数据流,流模式,由管道触发,或手动调用 end() data.pipe 写入数据
@@ -1836,32 +1501,29 @@ function request(uri, opts, callback) {
1836
1501
  * organize params for patch, post, put, head, del
1837
1502
  * @param {string} verb
1838
1503
  * @returns {(url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void}}
1839
- */
1840
- function fn(verb) {
1841
- const method = verb.toUpperCase();
1842
- /**
1504
+ */ function fn(verb) {
1505
+ const method = verb.toUpperCase();
1506
+ /**
1843
1507
  *
1844
1508
  * @param {string | Opts} uri /options
1845
1509
  * @param {Opts | Cb} [opts] /callback
1846
1510
  * @param {Cb} [cb] /null
1847
1511
  * @returns
1848
- */
1849
- function fn(uri, opts, cb) {
1850
- // @ts-ignore
1851
- opts.method = method;
1852
- return request(uri, opts, cb)
1853
- }
1854
- return fn
1855
- }
1856
-
1857
- // define like this to please codeintel/intellisense IDEs
1858
- request.get = fn('get');
1859
- request.head = fn('head');
1860
- request.options = fn('options');
1861
- request.post = fn('post');
1862
- request.put = fn('put');
1863
- request.patch = fn('patch');
1864
- request.del = fn('delete');
1512
+ */ function fn(uri, opts, cb) {
1513
+ // @ts-ignore
1514
+ opts.method = method;
1515
+ return request(uri, opts, cb);
1516
+ }
1517
+ return fn;
1518
+ }
1519
+ // define like this to please codeintel/intellisense IDEs
1520
+ request.get = fn('get');
1521
+ request.head = fn('head');
1522
+ request.options = fn('options');
1523
+ request.post = fn('post');
1524
+ request.put = fn('put');
1525
+ request.patch = fn('patch');
1526
+ request.del = fn('delete');
1865
1527
  request.delete = fn('delete');
1866
1528
 
1867
1529
  export { request as default };