@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 +1256 -1589
- package/dist/request.mjs +1256 -1589
- package/lib/ZlibTransform.js +9 -9
- package/lib/caseless.js +22 -21
- package/lib/index.js +11 -7
- package/lib/request.js +118 -108
- package/lib/utils.js +2 -2
- package/package.json +2 -3
package/dist/request.cjs
CHANGED
|
@@ -1,85 +1,158 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
3
|
-
* (c) 2022-
|
|
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
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @param {*}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
96
|
-
/**
|
|
167
|
+
*/ function createErrorType(code, message, baseClass) {
|
|
168
|
+
/**
|
|
97
169
|
* Create constructor
|
|
98
170
|
* @param {*} properties
|
|
99
|
-
*/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
168
|
-
|
|
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
|
|
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
|
-
|
|
220
|
-
|
|
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
|
-
|
|
229
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
//
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
]
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
m
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
);
|
|
567
|
-
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
);
|
|
573
|
-
|
|
574
|
-
const
|
|
575
|
-
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
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
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
}
|
|
866
|
-
|
|
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
|
-
|
|
882
|
-
|
|
883
|
-
|
|
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
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
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
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
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
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
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
|
-
|
|
1035
|
-
|
|
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
|
-
|
|
1044
|
-
|
|
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
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
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
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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
|
-
|
|
1071
|
-
|
|
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
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
786
|
+
*/ setTimeout(msecs, callback) {
|
|
787
|
+
const m = this;
|
|
788
|
+
/**
|
|
1084
789
|
* Destroys the socket on timeout
|
|
1085
790
|
* @param {*} socket
|
|
1086
|
-
*/
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
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
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
m.
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
m.
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
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
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
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
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
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
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
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
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
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
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
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
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
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
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
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
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
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
|
-
|
|
1667
|
-
|
|
1668
|
-
utils.
|
|
1669
|
-
|
|
1670
|
-
|
|
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
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
// log({R}, 'init')
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
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
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
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
|
-
|
|
1840
|
-
|
|
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
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
request.
|
|
1858
|
-
request.
|
|
1859
|
-
request.
|
|
1860
|
-
request.
|
|
1861
|
-
request.
|
|
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;
|