@wiajs/request 3.0.33 → 3.0.36

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