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