@wiajs/request 3.0.5 → 3.0.7
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 +101 -96
- package/dist/request.mjs +95 -91
- package/lib/index.js +4 -0
- package/lib/request.js +38 -41
- package/package.json +1 -1
package/dist/request.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
2
|
+
* wia request v3.0.7
|
|
3
3
|
* (c) 2022-2024 Sibyl Yu and contributors
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -14,6 +14,7 @@ const stream = require('node:stream');
|
|
|
14
14
|
const zlib = require('node:zlib');
|
|
15
15
|
const mime = require('mime-types');
|
|
16
16
|
|
|
17
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
18
|
class ZlibTransform extends stream.Transform {
|
|
18
19
|
__transform(chunk, encoding, callback) {
|
|
19
20
|
this.push(chunk);
|
|
@@ -42,12 +43,12 @@ class ZlibTransform extends stream.Transform {
|
|
|
42
43
|
* utils for request
|
|
43
44
|
*/
|
|
44
45
|
|
|
45
|
-
const {URL} = url;
|
|
46
|
+
const {URL: URL$1} = url;
|
|
46
47
|
|
|
47
48
|
// Whether to use the native URL object or the legacy url module
|
|
48
49
|
let useNativeURL = false;
|
|
49
50
|
try {
|
|
50
|
-
assert(new URL(''));
|
|
51
|
+
assert(new URL$1(''));
|
|
51
52
|
} catch (error) {
|
|
52
53
|
useNativeURL = error.code === 'ERR_INVALID_URL';
|
|
53
54
|
}
|
|
@@ -193,7 +194,7 @@ const noop = () => {};
|
|
|
193
194
|
* @returns
|
|
194
195
|
*/
|
|
195
196
|
function isURL(value) {
|
|
196
|
-
return URL && value instanceof URL
|
|
197
|
+
return URL$1 && value instanceof URL$1
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
function isReadStream(rs) {
|
|
@@ -235,7 +236,7 @@ function parseUrl(input) {
|
|
|
235
236
|
let parsed;
|
|
236
237
|
// istanbul ignore else
|
|
237
238
|
if (useNativeURL) {
|
|
238
|
-
parsed = new URL(input);
|
|
239
|
+
parsed = new URL$1(input);
|
|
239
240
|
} else {
|
|
240
241
|
// Ensure the URL is valid and absolute
|
|
241
242
|
parsed = validateUrl(url.parse(input));
|
|
@@ -269,7 +270,7 @@ function validateUrl(input) {
|
|
|
269
270
|
*/
|
|
270
271
|
function resolveUrl(relative, base) {
|
|
271
272
|
// istanbul ignore next
|
|
272
|
-
return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative))
|
|
273
|
+
return useNativeURL ? new URL$1(relative, base) : parseUrl(url.resolve(base, relative))
|
|
273
274
|
}
|
|
274
275
|
|
|
275
276
|
/**
|
|
@@ -405,7 +406,7 @@ class Caseless {
|
|
|
405
406
|
* https://github.com/follow-redirects/follow-redirects
|
|
406
407
|
*/
|
|
407
408
|
|
|
408
|
-
const log$1 = log$2.log({env: `wia:req:${log$2.name(__filename)}`});
|
|
409
|
+
const log$1 = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}); // __filename
|
|
409
410
|
|
|
410
411
|
const httpModules = {'http:': http, 'https:': https};
|
|
411
412
|
|
|
@@ -444,7 +445,7 @@ const writeEventEmit = Object.create(null);
|
|
|
444
445
|
for (const ev of writeEvents)
|
|
445
446
|
writeEventEmit[ev] = function (...args) {
|
|
446
447
|
const m = this; // 事件回调,this === clientRequest 实例
|
|
447
|
-
log$1
|
|
448
|
+
log$1('req event', {ev});
|
|
448
449
|
m.redirectReq.emit(ev, ...args); // req 事情映射到 redirectReq 上触发
|
|
449
450
|
};
|
|
450
451
|
|
|
@@ -455,7 +456,7 @@ const readEventEmit = Object.create(null);
|
|
|
455
456
|
for (const ev of readEvents)
|
|
456
457
|
readEventEmit[ev] = function (...args) {
|
|
457
458
|
const m = this; // 事件回调,this === clientRequest 实例
|
|
458
|
-
log$1
|
|
459
|
+
log$1('res event', {ev});
|
|
459
460
|
m.redirectReq.emit(ev, ...args); // 向上触发事件
|
|
460
461
|
};
|
|
461
462
|
|
|
@@ -499,22 +500,25 @@ class Request extends stream.Duplex {
|
|
|
499
500
|
pipesrc = null // 被 pipe 时的 src stream
|
|
500
501
|
/** @type {stream.Writable[]} */
|
|
501
502
|
pipedests = [] // pipe dest
|
|
503
|
+
/** @type {*} */
|
|
504
|
+
startTimer = null
|
|
502
505
|
|
|
503
506
|
/**
|
|
504
507
|
* responseCallback 原消息处理回调
|
|
505
|
-
* @param {*}
|
|
508
|
+
* @param {*} opts
|
|
506
509
|
* @param {*} resCallback
|
|
507
510
|
*/
|
|
508
|
-
constructor(
|
|
511
|
+
constructor(opts, resCallback) {
|
|
509
512
|
super();
|
|
510
513
|
const m = this;
|
|
511
514
|
|
|
512
515
|
// log({options}, 'constructor');
|
|
513
516
|
|
|
514
517
|
// Initialize the request
|
|
515
|
-
m.
|
|
516
|
-
m.
|
|
517
|
-
m.headers =
|
|
518
|
+
m.sanitizeOptions(opts);
|
|
519
|
+
m.opt = opts;
|
|
520
|
+
m.headers = opts.headers;
|
|
521
|
+
// log({opts}, 'constructor')
|
|
518
522
|
m._ended = false;
|
|
519
523
|
m._ending = false;
|
|
520
524
|
m._redirectCount = 0;
|
|
@@ -528,35 +532,16 @@ class Request extends stream.Duplex {
|
|
|
528
532
|
m.resCallback = resCallback;
|
|
529
533
|
// React to responses of native requests
|
|
530
534
|
// 接管 response 事件,非重定向,触发 response 事件
|
|
531
|
-
m._onResponse =
|
|
535
|
+
m._onResponse = res => {
|
|
532
536
|
try {
|
|
533
|
-
m.processResponse(
|
|
537
|
+
m.processResponse(res);
|
|
534
538
|
} catch (cause) {
|
|
535
539
|
m.emit('error', cause instanceof RedirectionError ? cause : new RedirectionError({cause: cause}));
|
|
536
540
|
}
|
|
537
541
|
};
|
|
538
542
|
|
|
539
|
-
// Proxy all other public ClientRequest methods
|
|
540
|
-
for (const method of ['flushHeaders', 'setNoDelay', 'setSocketKeepAlive']) {
|
|
541
|
-
m[method] = (a, b) => {
|
|
542
|
-
log$1.debug(method, {a, b});
|
|
543
|
-
m._currentRequest[method](a, b);
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Proxy all public ClientRequest properties
|
|
548
|
-
for (const property of ['aborted', 'connection', 'socket']) {
|
|
549
|
-
Object.defineProperty(m, property, {
|
|
550
|
-
get() {
|
|
551
|
-
const val = m._currentRequest[property];
|
|
552
|
-
log$1.debug('get property', {property});
|
|
553
|
-
return val
|
|
554
|
-
},
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
|
|
558
543
|
// 流模式
|
|
559
|
-
if (
|
|
544
|
+
if (opts.stream) {
|
|
560
545
|
// 被 pipe 作为目标时触发,拷贝 src headers
|
|
561
546
|
m.on(
|
|
562
547
|
'pipe',
|
|
@@ -581,12 +566,11 @@ class Request extends stream.Duplex {
|
|
|
581
566
|
}
|
|
582
567
|
}
|
|
583
568
|
|
|
584
|
-
|
|
585
|
-
// m.method = src.method
|
|
586
|
-
// }
|
|
569
|
+
if (src.opt.method && !m.opt.method) m.opt.method = src.opt.method;
|
|
587
570
|
}
|
|
588
571
|
}
|
|
589
572
|
);
|
|
573
|
+
}
|
|
590
574
|
|
|
591
575
|
// Perform the first request
|
|
592
576
|
// m.request(); // 写入数据时执行,否则 pipe时无法写入header
|
|
@@ -598,10 +582,11 @@ class Request extends stream.Duplex {
|
|
|
598
582
|
*/
|
|
599
583
|
request() {
|
|
600
584
|
let R = null;
|
|
585
|
+
const m = this;
|
|
586
|
+
const {opt} = m;
|
|
601
587
|
|
|
602
588
|
try {
|
|
603
|
-
|
|
604
|
-
// read stream
|
|
589
|
+
// reset read stream
|
|
605
590
|
m.response = null;
|
|
606
591
|
m.responseStarted = false;
|
|
607
592
|
m.responseStream = null;
|
|
@@ -614,35 +599,53 @@ class Request extends stream.Duplex {
|
|
|
614
599
|
// m.httpModule = httpModules[protocol];
|
|
615
600
|
|
|
616
601
|
// Load the native protocol
|
|
617
|
-
let {protocol} =
|
|
618
|
-
const {agents} =
|
|
602
|
+
let {protocol} = opt;
|
|
603
|
+
const {agents} = opt;
|
|
619
604
|
|
|
620
605
|
// 代理以目的网址协议为准
|
|
621
606
|
// If specified, use the agent corresponding to the protocol
|
|
622
607
|
// (HTTP and HTTPS use different types of agents)
|
|
623
608
|
if (agents) {
|
|
624
609
|
const scheme = protocol.slice(0, -1);
|
|
625
|
-
|
|
626
|
-
}
|
|
610
|
+
opt.agent = agents[scheme];
|
|
627
611
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
612
|
+
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
613
|
+
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
614
|
+
if (protocol === 'http:' && agents.http) {
|
|
615
|
+
protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
|
|
616
|
+
}
|
|
632
617
|
}
|
|
633
618
|
|
|
634
619
|
const httpModule = httpModules[protocol];
|
|
635
620
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`)
|
|
636
621
|
|
|
637
|
-
log$1
|
|
638
|
-
|
|
639
|
-
debugger
|
|
640
|
-
|
|
622
|
+
log$1({opt, protocol}, 'request');
|
|
641
623
|
// Create the native request and set up its event handlers
|
|
642
|
-
const req = httpModule.request(
|
|
624
|
+
const req = httpModule.request(opt, m._onResponse);
|
|
643
625
|
m._currentRequest = req;
|
|
644
|
-
|
|
645
626
|
req.redirectReq = m;
|
|
627
|
+
|
|
628
|
+
// Proxy all other public ClientRequest methods
|
|
629
|
+
for (const method of ['flushHeaders', 'setNoDelay', 'setSocketKeepAlive']) {
|
|
630
|
+
m[method] = (a, b) => {
|
|
631
|
+
log$1.debug(method, {a, b});
|
|
632
|
+
m._currentRequest[method](a, b);
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Proxy all public ClientRequest properties
|
|
637
|
+
for (const property of ['aborted', 'connection', 'socket']) {
|
|
638
|
+
Object.defineProperty(m, property, {
|
|
639
|
+
get() {
|
|
640
|
+
const val = m._currentRequest[property];
|
|
641
|
+
log$1.debug('get property', {property});
|
|
642
|
+
return val
|
|
643
|
+
},
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
m._currentRequest.once('socket', m.startTimer);
|
|
648
|
+
|
|
646
649
|
// 接收req事件,转发 到 redirectReq 发射
|
|
647
650
|
for (const ev of writeEvents) req.on(ev, writeEventEmit[ev]);
|
|
648
651
|
|
|
@@ -650,7 +653,7 @@ class Request extends stream.Duplex {
|
|
|
650
653
|
// a client MUST send only the absolute path […] as the request-target.
|
|
651
654
|
// When making a request to a proxy, […]
|
|
652
655
|
// a client MUST send the target URI in absolute-form […].
|
|
653
|
-
m._currentUrl = /^\//.test(
|
|
656
|
+
m._currentUrl = /^\//.test(opt.path) ? url.format(opt) : opt.path;
|
|
654
657
|
|
|
655
658
|
// End a redirected request
|
|
656
659
|
// (The first request must be ended explicitly with RedirectableRequest#end)
|
|
@@ -745,7 +748,7 @@ class Request extends stream.Duplex {
|
|
|
745
748
|
}
|
|
746
749
|
|
|
747
750
|
// Only write when we don't exceed the maximum body length
|
|
748
|
-
if (m._requestBodyLength + chunk.length <= m.
|
|
751
|
+
if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
|
|
749
752
|
m._requestBodyLength += chunk.length;
|
|
750
753
|
m._requestBodyBuffers.push({data: chunk, encoding});
|
|
751
754
|
m._currentRequest.write(chunk, encoding, cb);
|
|
@@ -801,7 +804,7 @@ class Request extends stream.Duplex {
|
|
|
801
804
|
* @returns
|
|
802
805
|
*/
|
|
803
806
|
hasHeader(name) {
|
|
804
|
-
return this.
|
|
807
|
+
return this.opt.headers.includes(name)
|
|
805
808
|
}
|
|
806
809
|
|
|
807
810
|
/**
|
|
@@ -810,7 +813,7 @@ class Request extends stream.Duplex {
|
|
|
810
813
|
* @returns {string}
|
|
811
814
|
*/
|
|
812
815
|
getHeader(name) {
|
|
813
|
-
return this.
|
|
816
|
+
return this.opt.headers[name]
|
|
814
817
|
}
|
|
815
818
|
|
|
816
819
|
/**
|
|
@@ -818,7 +821,7 @@ class Request extends stream.Duplex {
|
|
|
818
821
|
* @param {string} name
|
|
819
822
|
*/
|
|
820
823
|
setHeader(name, value) {
|
|
821
|
-
this.
|
|
824
|
+
this.opt.headers[name] = value;
|
|
822
825
|
this._currentRequest?.setHeader(name, value);
|
|
823
826
|
}
|
|
824
827
|
|
|
@@ -827,7 +830,7 @@ class Request extends stream.Duplex {
|
|
|
827
830
|
* @param {string} name
|
|
828
831
|
*/
|
|
829
832
|
removeHeader(name) {
|
|
830
|
-
delete this.
|
|
833
|
+
delete this.opt.headers[name];
|
|
831
834
|
this._currentRequest?.removeHeader(name);
|
|
832
835
|
}
|
|
833
836
|
|
|
@@ -839,9 +842,8 @@ class Request extends stream.Duplex {
|
|
|
839
842
|
return this._currentRequest?.headersSent
|
|
840
843
|
}
|
|
841
844
|
|
|
842
|
-
// Global timeout for all underlying requests
|
|
843
845
|
/**
|
|
844
|
-
*
|
|
846
|
+
* Global timeout for all underlying requests
|
|
845
847
|
* @param {*} msecs
|
|
846
848
|
* @param {*} callback
|
|
847
849
|
* @returns
|
|
@@ -849,9 +851,8 @@ class Request extends stream.Duplex {
|
|
|
849
851
|
setTimeout(msecs, callback) {
|
|
850
852
|
const m = this;
|
|
851
853
|
|
|
852
|
-
// Destroys the socket on timeout
|
|
853
854
|
/**
|
|
854
|
-
*
|
|
855
|
+
* Destroys the socket on timeout
|
|
855
856
|
* @param {*} socket
|
|
856
857
|
*/
|
|
857
858
|
function destroyOnTimeout(socket) {
|
|
@@ -860,19 +861,18 @@ class Request extends stream.Duplex {
|
|
|
860
861
|
socket.addListener('timeout', socket.destroy);
|
|
861
862
|
}
|
|
862
863
|
|
|
863
|
-
// Sets up a timer to trigger a timeout event
|
|
864
864
|
/**
|
|
865
|
-
*
|
|
865
|
+
* Sets up a timer to trigger a timeout event
|
|
866
866
|
* @param {*} socket
|
|
867
867
|
*/
|
|
868
868
|
function startTimer(socket) {
|
|
869
|
-
if (m._timeout)
|
|
870
|
-
|
|
871
|
-
}
|
|
869
|
+
if (m._timeout) clearTimeout(m._timeout);
|
|
870
|
+
|
|
872
871
|
m._timeout = setTimeout(() => {
|
|
873
872
|
m.emit('timeout');
|
|
874
873
|
clearTimer();
|
|
875
874
|
}, msecs);
|
|
875
|
+
|
|
876
876
|
destroyOnTimeout(socket);
|
|
877
877
|
}
|
|
878
878
|
|
|
@@ -903,7 +903,7 @@ class Request extends stream.Duplex {
|
|
|
903
903
|
|
|
904
904
|
// Start the timer if or when the socket is opened
|
|
905
905
|
if (m.socket) startTimer(m.socket);
|
|
906
|
-
else m.
|
|
906
|
+
else m.startTimer = startTimer; // 未连接,先登记
|
|
907
907
|
|
|
908
908
|
// Clean up on events
|
|
909
909
|
m.on('socket', destroyOnTimeout);
|
|
@@ -914,7 +914,7 @@ class Request extends stream.Duplex {
|
|
|
914
914
|
return m
|
|
915
915
|
}
|
|
916
916
|
|
|
917
|
-
|
|
917
|
+
sanitizeOptions(options) {
|
|
918
918
|
// Ensure headers are always present
|
|
919
919
|
if (!options.headers) options.headers = {};
|
|
920
920
|
|
|
@@ -951,7 +951,7 @@ class Request extends stream.Duplex {
|
|
|
951
951
|
|
|
952
952
|
// Store the redirected response
|
|
953
953
|
const {statusCode} = response;
|
|
954
|
-
if (m.
|
|
954
|
+
if (m.opt.trackRedirects) {
|
|
955
955
|
m._redirects.push({
|
|
956
956
|
url: m._currentUrl,
|
|
957
957
|
headers: response.headers,
|
|
@@ -971,7 +971,7 @@ class Request extends stream.Duplex {
|
|
|
971
971
|
|
|
972
972
|
log$1('processResponse', {statusCode, headers: response.headers});
|
|
973
973
|
|
|
974
|
-
if (!location || m.
|
|
974
|
+
if (!location || m.opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
|
|
975
975
|
// 非重定向,返回给原始回调处理
|
|
976
976
|
response.responseUrl = m._currentUrl;
|
|
977
977
|
response.redirects = m._redirects;
|
|
@@ -1010,16 +1010,16 @@ class Request extends stream.Duplex {
|
|
|
1010
1010
|
|
|
1011
1011
|
// RFC7231§6.4: A client SHOULD detect and intervene
|
|
1012
1012
|
// in cyclical redirections (i.e., "infinite" redirection loops).
|
|
1013
|
-
if (++m._redirectCount > m.
|
|
1013
|
+
if (++m._redirectCount > m.opt.maxRedirects) throw new TooManyRedirectsError()
|
|
1014
1014
|
|
|
1015
1015
|
// Store the request headers if applicable
|
|
1016
1016
|
let requestHeaders;
|
|
1017
|
-
const {beforeRedirect} = m.
|
|
1017
|
+
const {beforeRedirect} = m.opt;
|
|
1018
1018
|
if (beforeRedirect) {
|
|
1019
1019
|
requestHeaders = {
|
|
1020
1020
|
// The Host header was set by nativeProtocol.request
|
|
1021
1021
|
Host: response.req.getHeader('host'),
|
|
1022
|
-
...m.
|
|
1022
|
+
...m.opt.headers,
|
|
1023
1023
|
};
|
|
1024
1024
|
}
|
|
1025
1025
|
|
|
@@ -1027,23 +1027,23 @@ class Request extends stream.Duplex {
|
|
|
1027
1027
|
// care for methods not known to be safe, […]
|
|
1028
1028
|
// RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
|
|
1029
1029
|
// the request method from POST to GET for the subsequent request.
|
|
1030
|
-
const {method} = m.
|
|
1030
|
+
const {method} = m.opt;
|
|
1031
1031
|
if (
|
|
1032
|
-
((statusCode === 301 || statusCode === 302) && m.
|
|
1032
|
+
((statusCode === 301 || statusCode === 302) && m.opt.method === 'POST') ||
|
|
1033
1033
|
// RFC7231§6.4.4: The 303 (See Other) status code indicates that
|
|
1034
1034
|
// the server is redirecting the user agent to a different resource […]
|
|
1035
1035
|
// A user agent can perform a retrieval request targeting that URI
|
|
1036
1036
|
// (a GET or HEAD request if using HTTP) […]
|
|
1037
|
-
(statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.
|
|
1037
|
+
(statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.opt.method))
|
|
1038
1038
|
) {
|
|
1039
|
-
m.
|
|
1039
|
+
m.opt.method = 'GET';
|
|
1040
1040
|
// Drop a possible entity and headers related to it
|
|
1041
1041
|
m._requestBodyBuffers = [];
|
|
1042
|
-
removeMatchingHeaders(/^content-/i, m.
|
|
1042
|
+
removeMatchingHeaders(/^content-/i, m.opt.headers);
|
|
1043
1043
|
}
|
|
1044
1044
|
|
|
1045
1045
|
// Drop the Host header, as the redirect might lead to a different host
|
|
1046
|
-
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.
|
|
1046
|
+
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.opt.headers);
|
|
1047
1047
|
|
|
1048
1048
|
// If the redirect is relative, carry over the host of the last request
|
|
1049
1049
|
const currentUrlParts = utils.parseUrl(m._currentUrl);
|
|
@@ -1057,7 +1057,7 @@ class Request extends stream.Duplex {
|
|
|
1057
1057
|
log$1({redirectUrl}, 'redirecting to');
|
|
1058
1058
|
m._isRedirect = true;
|
|
1059
1059
|
// 覆盖原 url 解析部分,包括 protocol、hostname、port等
|
|
1060
|
-
utils.spreadUrlObject(redirectUrl, m.
|
|
1060
|
+
utils.spreadUrlObject(redirectUrl, m.opt);
|
|
1061
1061
|
|
|
1062
1062
|
// Drop confidential headers when redirecting to a less secure protocol
|
|
1063
1063
|
// or to a different domain that is not a superdomain
|
|
@@ -1065,7 +1065,7 @@ class Request extends stream.Duplex {
|
|
|
1065
1065
|
(redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== 'https:') ||
|
|
1066
1066
|
(redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost))
|
|
1067
1067
|
) {
|
|
1068
|
-
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.
|
|
1068
|
+
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.opt.headers);
|
|
1069
1069
|
}
|
|
1070
1070
|
|
|
1071
1071
|
// Evaluate the beforeRedirect callback
|
|
@@ -1080,8 +1080,8 @@ class Request extends stream.Duplex {
|
|
|
1080
1080
|
headers: requestHeaders,
|
|
1081
1081
|
};
|
|
1082
1082
|
|
|
1083
|
-
beforeRedirect(m.
|
|
1084
|
-
m.
|
|
1083
|
+
beforeRedirect(m.opt, responseDetails, requestDetails);
|
|
1084
|
+
m.sanitizeOptions(m.opt);
|
|
1085
1085
|
}
|
|
1086
1086
|
|
|
1087
1087
|
// Perform the redirected request
|
|
@@ -1095,7 +1095,7 @@ class Request extends stream.Duplex {
|
|
|
1095
1095
|
*/
|
|
1096
1096
|
processStream(res) {
|
|
1097
1097
|
const m = this;
|
|
1098
|
-
const {
|
|
1098
|
+
const {opt: opts} = m;
|
|
1099
1099
|
|
|
1100
1100
|
const streams = [res];
|
|
1101
1101
|
|
|
@@ -1260,7 +1260,7 @@ class Request extends stream.Duplex {
|
|
|
1260
1260
|
*/
|
|
1261
1261
|
pipeDest(dest) {
|
|
1262
1262
|
const m = this;
|
|
1263
|
-
const {response
|
|
1263
|
+
const {response} = m;
|
|
1264
1264
|
|
|
1265
1265
|
// Called after the response is received
|
|
1266
1266
|
if (response?.headers && dest.headers && !dest.headersSent) {
|
|
@@ -1291,9 +1291,9 @@ class Request extends stream.Duplex {
|
|
|
1291
1291
|
dest.statusCode = response.statusCode;
|
|
1292
1292
|
}
|
|
1293
1293
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1294
|
+
if (m.pipefilter) {
|
|
1295
|
+
m.pipefilter(response, dest);
|
|
1296
|
+
}
|
|
1297
1297
|
}
|
|
1298
1298
|
|
|
1299
1299
|
/**
|
|
@@ -1362,16 +1362,16 @@ function isSubdomain(subdomain, domain) {
|
|
|
1362
1362
|
*/
|
|
1363
1363
|
|
|
1364
1364
|
|
|
1365
|
-
const log = log$2.log({env: `wia:req:${log$2.name(__filename)}`})
|
|
1365
|
+
const log = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}) // __filename
|
|
1366
1366
|
|
|
1367
1367
|
// Preventive platform detection
|
|
1368
|
-
// istanbul ignore
|
|
1368
|
+
// istanbul ignore
|
|
1369
1369
|
;(function detectUnsupportedEnvironment() {
|
|
1370
1370
|
const looksLikeNode = typeof process !== 'undefined';
|
|
1371
1371
|
const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
1372
1372
|
const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
|
|
1373
1373
|
if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
|
|
1374
|
-
|
|
1374
|
+
console.warn('The follow-redirects package should be excluded from browser builds.');
|
|
1375
1375
|
}
|
|
1376
1376
|
})();
|
|
1377
1377
|
|
|
@@ -1389,6 +1389,7 @@ const log = log$2.log({env: `wia:req:${log$2.name(__filename)}`})
|
|
|
1389
1389
|
* @returns
|
|
1390
1390
|
*/
|
|
1391
1391
|
function init(uri, options, callback) {
|
|
1392
|
+
let R;
|
|
1392
1393
|
try {
|
|
1393
1394
|
// Parse parameters, ensuring that input is an object
|
|
1394
1395
|
if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
|
|
@@ -1413,6 +1414,7 @@ function init(uri, options, callback) {
|
|
|
1413
1414
|
if (!utils.isString(options.host) && !utils.isString(options.hostname)) options.hostname = '::1';
|
|
1414
1415
|
|
|
1415
1416
|
R = {opts: options, cb: callback};
|
|
1417
|
+
// log({R}, 'init')
|
|
1416
1418
|
} catch (e) {
|
|
1417
1419
|
log.err(e, 'init');
|
|
1418
1420
|
}
|
|
@@ -1435,8 +1437,9 @@ function request(uri, options, callback) {
|
|
|
1435
1437
|
let R = null;
|
|
1436
1438
|
|
|
1437
1439
|
try {
|
|
1440
|
+
log({uri, options}, 'request');
|
|
1441
|
+
|
|
1438
1442
|
const {opts, cb} = init(uri, options, callback);
|
|
1439
|
-
// log.debug('request', {options})
|
|
1440
1443
|
R = new Request(opts, cb);
|
|
1441
1444
|
} catch (e) {
|
|
1442
1445
|
log.err(e, 'request');
|
|
@@ -1454,6 +1457,8 @@ function request(uri, options, callback) {
|
|
|
1454
1457
|
*/
|
|
1455
1458
|
function fn(verb) {
|
|
1456
1459
|
const method = verb.toUpperCase();
|
|
1460
|
+
|
|
1461
|
+
// @ts-ignore
|
|
1457
1462
|
return (uri, options, callback) => {
|
|
1458
1463
|
const {opts, cb} = init(uri, options, callback);
|
|
1459
1464
|
opts.method = method;
|
package/dist/request.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
2
|
+
* wia request v3.0.7
|
|
3
3
|
* (c) 2022-2024 Sibyl Yu and contributors
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -403,7 +403,7 @@ class Caseless {
|
|
|
403
403
|
* https://github.com/follow-redirects/follow-redirects
|
|
404
404
|
*/
|
|
405
405
|
|
|
406
|
-
const log$1 = log$2({env: `wia:req:${name(
|
|
406
|
+
const log$1 = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
|
|
407
407
|
|
|
408
408
|
const httpModules = {'http:': http, 'https:': https};
|
|
409
409
|
|
|
@@ -442,7 +442,7 @@ const writeEventEmit = Object.create(null);
|
|
|
442
442
|
for (const ev of writeEvents)
|
|
443
443
|
writeEventEmit[ev] = function (...args) {
|
|
444
444
|
const m = this; // 事件回调,this === clientRequest 实例
|
|
445
|
-
log$1
|
|
445
|
+
log$1('req event', {ev});
|
|
446
446
|
m.redirectReq.emit(ev, ...args); // req 事情映射到 redirectReq 上触发
|
|
447
447
|
};
|
|
448
448
|
|
|
@@ -453,7 +453,7 @@ const readEventEmit = Object.create(null);
|
|
|
453
453
|
for (const ev of readEvents)
|
|
454
454
|
readEventEmit[ev] = function (...args) {
|
|
455
455
|
const m = this; // 事件回调,this === clientRequest 实例
|
|
456
|
-
log$1
|
|
456
|
+
log$1('res event', {ev});
|
|
457
457
|
m.redirectReq.emit(ev, ...args); // 向上触发事件
|
|
458
458
|
};
|
|
459
459
|
|
|
@@ -497,22 +497,25 @@ class Request extends Duplex {
|
|
|
497
497
|
pipesrc = null // 被 pipe 时的 src stream
|
|
498
498
|
/** @type {stream.Writable[]} */
|
|
499
499
|
pipedests = [] // pipe dest
|
|
500
|
+
/** @type {*} */
|
|
501
|
+
startTimer = null
|
|
500
502
|
|
|
501
503
|
/**
|
|
502
504
|
* responseCallback 原消息处理回调
|
|
503
|
-
* @param {*}
|
|
505
|
+
* @param {*} opts
|
|
504
506
|
* @param {*} resCallback
|
|
505
507
|
*/
|
|
506
|
-
constructor(
|
|
508
|
+
constructor(opts, resCallback) {
|
|
507
509
|
super();
|
|
508
510
|
const m = this;
|
|
509
511
|
|
|
510
512
|
// log({options}, 'constructor');
|
|
511
513
|
|
|
512
514
|
// Initialize the request
|
|
513
|
-
m.
|
|
514
|
-
m.
|
|
515
|
-
m.headers =
|
|
515
|
+
m.sanitizeOptions(opts);
|
|
516
|
+
m.opt = opts;
|
|
517
|
+
m.headers = opts.headers;
|
|
518
|
+
// log({opts}, 'constructor')
|
|
516
519
|
m._ended = false;
|
|
517
520
|
m._ending = false;
|
|
518
521
|
m._redirectCount = 0;
|
|
@@ -526,35 +529,16 @@ class Request extends Duplex {
|
|
|
526
529
|
m.resCallback = resCallback;
|
|
527
530
|
// React to responses of native requests
|
|
528
531
|
// 接管 response 事件,非重定向,触发 response 事件
|
|
529
|
-
m._onResponse =
|
|
532
|
+
m._onResponse = res => {
|
|
530
533
|
try {
|
|
531
|
-
m.processResponse(
|
|
534
|
+
m.processResponse(res);
|
|
532
535
|
} catch (cause) {
|
|
533
536
|
m.emit('error', cause instanceof RedirectionError ? cause : new RedirectionError({cause: cause}));
|
|
534
537
|
}
|
|
535
538
|
};
|
|
536
539
|
|
|
537
|
-
// Proxy all other public ClientRequest methods
|
|
538
|
-
for (const method of ['flushHeaders', 'setNoDelay', 'setSocketKeepAlive']) {
|
|
539
|
-
m[method] = (a, b) => {
|
|
540
|
-
log$1.debug(method, {a, b});
|
|
541
|
-
m._currentRequest[method](a, b);
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
// Proxy all public ClientRequest properties
|
|
546
|
-
for (const property of ['aborted', 'connection', 'socket']) {
|
|
547
|
-
Object.defineProperty(m, property, {
|
|
548
|
-
get() {
|
|
549
|
-
const val = m._currentRequest[property];
|
|
550
|
-
log$1.debug('get property', {property});
|
|
551
|
-
return val
|
|
552
|
-
},
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
|
|
556
540
|
// 流模式
|
|
557
|
-
if (
|
|
541
|
+
if (opts.stream) {
|
|
558
542
|
// 被 pipe 作为目标时触发,拷贝 src headers
|
|
559
543
|
m.on(
|
|
560
544
|
'pipe',
|
|
@@ -579,12 +563,11 @@ class Request extends Duplex {
|
|
|
579
563
|
}
|
|
580
564
|
}
|
|
581
565
|
|
|
582
|
-
|
|
583
|
-
// m.method = src.method
|
|
584
|
-
// }
|
|
566
|
+
if (src.opt.method && !m.opt.method) m.opt.method = src.opt.method;
|
|
585
567
|
}
|
|
586
568
|
}
|
|
587
569
|
);
|
|
570
|
+
}
|
|
588
571
|
|
|
589
572
|
// Perform the first request
|
|
590
573
|
// m.request(); // 写入数据时执行,否则 pipe时无法写入header
|
|
@@ -596,10 +579,11 @@ class Request extends Duplex {
|
|
|
596
579
|
*/
|
|
597
580
|
request() {
|
|
598
581
|
let R = null;
|
|
582
|
+
const m = this;
|
|
583
|
+
const {opt} = m;
|
|
599
584
|
|
|
600
585
|
try {
|
|
601
|
-
|
|
602
|
-
// read stream
|
|
586
|
+
// reset read stream
|
|
603
587
|
m.response = null;
|
|
604
588
|
m.responseStarted = false;
|
|
605
589
|
m.responseStream = null;
|
|
@@ -612,35 +596,53 @@ class Request extends Duplex {
|
|
|
612
596
|
// m.httpModule = httpModules[protocol];
|
|
613
597
|
|
|
614
598
|
// Load the native protocol
|
|
615
|
-
let {protocol} =
|
|
616
|
-
const {agents} =
|
|
599
|
+
let {protocol} = opt;
|
|
600
|
+
const {agents} = opt;
|
|
617
601
|
|
|
618
602
|
// 代理以目的网址协议为准
|
|
619
603
|
// If specified, use the agent corresponding to the protocol
|
|
620
604
|
// (HTTP and HTTPS use different types of agents)
|
|
621
605
|
if (agents) {
|
|
622
606
|
const scheme = protocol.slice(0, -1);
|
|
623
|
-
|
|
624
|
-
}
|
|
607
|
+
opt.agent = agents[scheme];
|
|
625
608
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
609
|
+
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
610
|
+
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
611
|
+
if (protocol === 'http:' && agents.http) {
|
|
612
|
+
protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
|
|
613
|
+
}
|
|
630
614
|
}
|
|
631
615
|
|
|
632
616
|
const httpModule = httpModules[protocol];
|
|
633
617
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`)
|
|
634
618
|
|
|
635
|
-
log$1
|
|
636
|
-
|
|
637
|
-
debugger
|
|
638
|
-
|
|
619
|
+
log$1({opt, protocol}, 'request');
|
|
639
620
|
// Create the native request and set up its event handlers
|
|
640
|
-
const req = httpModule.request(
|
|
621
|
+
const req = httpModule.request(opt, m._onResponse);
|
|
641
622
|
m._currentRequest = req;
|
|
642
|
-
|
|
643
623
|
req.redirectReq = m;
|
|
624
|
+
|
|
625
|
+
// Proxy all other public ClientRequest methods
|
|
626
|
+
for (const method of ['flushHeaders', 'setNoDelay', 'setSocketKeepAlive']) {
|
|
627
|
+
m[method] = (a, b) => {
|
|
628
|
+
log$1.debug(method, {a, b});
|
|
629
|
+
m._currentRequest[method](a, b);
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Proxy all public ClientRequest properties
|
|
634
|
+
for (const property of ['aborted', 'connection', 'socket']) {
|
|
635
|
+
Object.defineProperty(m, property, {
|
|
636
|
+
get() {
|
|
637
|
+
const val = m._currentRequest[property];
|
|
638
|
+
log$1.debug('get property', {property});
|
|
639
|
+
return val
|
|
640
|
+
},
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
m._currentRequest.once('socket', m.startTimer);
|
|
645
|
+
|
|
644
646
|
// 接收req事件,转发 到 redirectReq 发射
|
|
645
647
|
for (const ev of writeEvents) req.on(ev, writeEventEmit[ev]);
|
|
646
648
|
|
|
@@ -648,7 +650,7 @@ class Request extends Duplex {
|
|
|
648
650
|
// a client MUST send only the absolute path […] as the request-target.
|
|
649
651
|
// When making a request to a proxy, […]
|
|
650
652
|
// a client MUST send the target URI in absolute-form […].
|
|
651
|
-
m._currentUrl = /^\//.test(
|
|
653
|
+
m._currentUrl = /^\//.test(opt.path) ? url.format(opt) : opt.path;
|
|
652
654
|
|
|
653
655
|
// End a redirected request
|
|
654
656
|
// (The first request must be ended explicitly with RedirectableRequest#end)
|
|
@@ -743,7 +745,7 @@ class Request extends Duplex {
|
|
|
743
745
|
}
|
|
744
746
|
|
|
745
747
|
// Only write when we don't exceed the maximum body length
|
|
746
|
-
if (m._requestBodyLength + chunk.length <= m.
|
|
748
|
+
if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
|
|
747
749
|
m._requestBodyLength += chunk.length;
|
|
748
750
|
m._requestBodyBuffers.push({data: chunk, encoding});
|
|
749
751
|
m._currentRequest.write(chunk, encoding, cb);
|
|
@@ -799,7 +801,7 @@ class Request extends Duplex {
|
|
|
799
801
|
* @returns
|
|
800
802
|
*/
|
|
801
803
|
hasHeader(name) {
|
|
802
|
-
return this.
|
|
804
|
+
return this.opt.headers.includes(name)
|
|
803
805
|
}
|
|
804
806
|
|
|
805
807
|
/**
|
|
@@ -808,7 +810,7 @@ class Request extends Duplex {
|
|
|
808
810
|
* @returns {string}
|
|
809
811
|
*/
|
|
810
812
|
getHeader(name) {
|
|
811
|
-
return this.
|
|
813
|
+
return this.opt.headers[name]
|
|
812
814
|
}
|
|
813
815
|
|
|
814
816
|
/**
|
|
@@ -816,7 +818,7 @@ class Request extends Duplex {
|
|
|
816
818
|
* @param {string} name
|
|
817
819
|
*/
|
|
818
820
|
setHeader(name, value) {
|
|
819
|
-
this.
|
|
821
|
+
this.opt.headers[name] = value;
|
|
820
822
|
this._currentRequest?.setHeader(name, value);
|
|
821
823
|
}
|
|
822
824
|
|
|
@@ -825,7 +827,7 @@ class Request extends Duplex {
|
|
|
825
827
|
* @param {string} name
|
|
826
828
|
*/
|
|
827
829
|
removeHeader(name) {
|
|
828
|
-
delete this.
|
|
830
|
+
delete this.opt.headers[name];
|
|
829
831
|
this._currentRequest?.removeHeader(name);
|
|
830
832
|
}
|
|
831
833
|
|
|
@@ -837,9 +839,8 @@ class Request extends Duplex {
|
|
|
837
839
|
return this._currentRequest?.headersSent
|
|
838
840
|
}
|
|
839
841
|
|
|
840
|
-
// Global timeout for all underlying requests
|
|
841
842
|
/**
|
|
842
|
-
*
|
|
843
|
+
* Global timeout for all underlying requests
|
|
843
844
|
* @param {*} msecs
|
|
844
845
|
* @param {*} callback
|
|
845
846
|
* @returns
|
|
@@ -847,9 +848,8 @@ class Request extends Duplex {
|
|
|
847
848
|
setTimeout(msecs, callback) {
|
|
848
849
|
const m = this;
|
|
849
850
|
|
|
850
|
-
// Destroys the socket on timeout
|
|
851
851
|
/**
|
|
852
|
-
*
|
|
852
|
+
* Destroys the socket on timeout
|
|
853
853
|
* @param {*} socket
|
|
854
854
|
*/
|
|
855
855
|
function destroyOnTimeout(socket) {
|
|
@@ -858,19 +858,18 @@ class Request extends Duplex {
|
|
|
858
858
|
socket.addListener('timeout', socket.destroy);
|
|
859
859
|
}
|
|
860
860
|
|
|
861
|
-
// Sets up a timer to trigger a timeout event
|
|
862
861
|
/**
|
|
863
|
-
*
|
|
862
|
+
* Sets up a timer to trigger a timeout event
|
|
864
863
|
* @param {*} socket
|
|
865
864
|
*/
|
|
866
865
|
function startTimer(socket) {
|
|
867
|
-
if (m._timeout)
|
|
868
|
-
|
|
869
|
-
}
|
|
866
|
+
if (m._timeout) clearTimeout(m._timeout);
|
|
867
|
+
|
|
870
868
|
m._timeout = setTimeout(() => {
|
|
871
869
|
m.emit('timeout');
|
|
872
870
|
clearTimer();
|
|
873
871
|
}, msecs);
|
|
872
|
+
|
|
874
873
|
destroyOnTimeout(socket);
|
|
875
874
|
}
|
|
876
875
|
|
|
@@ -901,7 +900,7 @@ class Request extends Duplex {
|
|
|
901
900
|
|
|
902
901
|
// Start the timer if or when the socket is opened
|
|
903
902
|
if (m.socket) startTimer(m.socket);
|
|
904
|
-
else m.
|
|
903
|
+
else m.startTimer = startTimer; // 未连接,先登记
|
|
905
904
|
|
|
906
905
|
// Clean up on events
|
|
907
906
|
m.on('socket', destroyOnTimeout);
|
|
@@ -912,7 +911,7 @@ class Request extends Duplex {
|
|
|
912
911
|
return m
|
|
913
912
|
}
|
|
914
913
|
|
|
915
|
-
|
|
914
|
+
sanitizeOptions(options) {
|
|
916
915
|
// Ensure headers are always present
|
|
917
916
|
if (!options.headers) options.headers = {};
|
|
918
917
|
|
|
@@ -949,7 +948,7 @@ class Request extends Duplex {
|
|
|
949
948
|
|
|
950
949
|
// Store the redirected response
|
|
951
950
|
const {statusCode} = response;
|
|
952
|
-
if (m.
|
|
951
|
+
if (m.opt.trackRedirects) {
|
|
953
952
|
m._redirects.push({
|
|
954
953
|
url: m._currentUrl,
|
|
955
954
|
headers: response.headers,
|
|
@@ -969,7 +968,7 @@ class Request extends Duplex {
|
|
|
969
968
|
|
|
970
969
|
log$1('processResponse', {statusCode, headers: response.headers});
|
|
971
970
|
|
|
972
|
-
if (!location || m.
|
|
971
|
+
if (!location || m.opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
|
|
973
972
|
// 非重定向,返回给原始回调处理
|
|
974
973
|
response.responseUrl = m._currentUrl;
|
|
975
974
|
response.redirects = m._redirects;
|
|
@@ -1008,16 +1007,16 @@ class Request extends Duplex {
|
|
|
1008
1007
|
|
|
1009
1008
|
// RFC7231§6.4: A client SHOULD detect and intervene
|
|
1010
1009
|
// in cyclical redirections (i.e., "infinite" redirection loops).
|
|
1011
|
-
if (++m._redirectCount > m.
|
|
1010
|
+
if (++m._redirectCount > m.opt.maxRedirects) throw new TooManyRedirectsError()
|
|
1012
1011
|
|
|
1013
1012
|
// Store the request headers if applicable
|
|
1014
1013
|
let requestHeaders;
|
|
1015
|
-
const {beforeRedirect} = m.
|
|
1014
|
+
const {beforeRedirect} = m.opt;
|
|
1016
1015
|
if (beforeRedirect) {
|
|
1017
1016
|
requestHeaders = {
|
|
1018
1017
|
// The Host header was set by nativeProtocol.request
|
|
1019
1018
|
Host: response.req.getHeader('host'),
|
|
1020
|
-
...m.
|
|
1019
|
+
...m.opt.headers,
|
|
1021
1020
|
};
|
|
1022
1021
|
}
|
|
1023
1022
|
|
|
@@ -1025,23 +1024,23 @@ class Request extends Duplex {
|
|
|
1025
1024
|
// care for methods not known to be safe, […]
|
|
1026
1025
|
// RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
|
|
1027
1026
|
// the request method from POST to GET for the subsequent request.
|
|
1028
|
-
const {method} = m.
|
|
1027
|
+
const {method} = m.opt;
|
|
1029
1028
|
if (
|
|
1030
|
-
((statusCode === 301 || statusCode === 302) && m.
|
|
1029
|
+
((statusCode === 301 || statusCode === 302) && m.opt.method === 'POST') ||
|
|
1031
1030
|
// RFC7231§6.4.4: The 303 (See Other) status code indicates that
|
|
1032
1031
|
// the server is redirecting the user agent to a different resource […]
|
|
1033
1032
|
// A user agent can perform a retrieval request targeting that URI
|
|
1034
1033
|
// (a GET or HEAD request if using HTTP) […]
|
|
1035
|
-
(statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.
|
|
1034
|
+
(statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.opt.method))
|
|
1036
1035
|
) {
|
|
1037
|
-
m.
|
|
1036
|
+
m.opt.method = 'GET';
|
|
1038
1037
|
// Drop a possible entity and headers related to it
|
|
1039
1038
|
m._requestBodyBuffers = [];
|
|
1040
|
-
removeMatchingHeaders(/^content-/i, m.
|
|
1039
|
+
removeMatchingHeaders(/^content-/i, m.opt.headers);
|
|
1041
1040
|
}
|
|
1042
1041
|
|
|
1043
1042
|
// Drop the Host header, as the redirect might lead to a different host
|
|
1044
|
-
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.
|
|
1043
|
+
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.opt.headers);
|
|
1045
1044
|
|
|
1046
1045
|
// If the redirect is relative, carry over the host of the last request
|
|
1047
1046
|
const currentUrlParts = utils.parseUrl(m._currentUrl);
|
|
@@ -1055,7 +1054,7 @@ class Request extends Duplex {
|
|
|
1055
1054
|
log$1({redirectUrl}, 'redirecting to');
|
|
1056
1055
|
m._isRedirect = true;
|
|
1057
1056
|
// 覆盖原 url 解析部分,包括 protocol、hostname、port等
|
|
1058
|
-
utils.spreadUrlObject(redirectUrl, m.
|
|
1057
|
+
utils.spreadUrlObject(redirectUrl, m.opt);
|
|
1059
1058
|
|
|
1060
1059
|
// Drop confidential headers when redirecting to a less secure protocol
|
|
1061
1060
|
// or to a different domain that is not a superdomain
|
|
@@ -1063,7 +1062,7 @@ class Request extends Duplex {
|
|
|
1063
1062
|
(redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== 'https:') ||
|
|
1064
1063
|
(redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost))
|
|
1065
1064
|
) {
|
|
1066
|
-
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.
|
|
1065
|
+
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.opt.headers);
|
|
1067
1066
|
}
|
|
1068
1067
|
|
|
1069
1068
|
// Evaluate the beforeRedirect callback
|
|
@@ -1078,8 +1077,8 @@ class Request extends Duplex {
|
|
|
1078
1077
|
headers: requestHeaders,
|
|
1079
1078
|
};
|
|
1080
1079
|
|
|
1081
|
-
beforeRedirect(m.
|
|
1082
|
-
m.
|
|
1080
|
+
beforeRedirect(m.opt, responseDetails, requestDetails);
|
|
1081
|
+
m.sanitizeOptions(m.opt);
|
|
1083
1082
|
}
|
|
1084
1083
|
|
|
1085
1084
|
// Perform the redirected request
|
|
@@ -1093,7 +1092,7 @@ class Request extends Duplex {
|
|
|
1093
1092
|
*/
|
|
1094
1093
|
processStream(res) {
|
|
1095
1094
|
const m = this;
|
|
1096
|
-
const {
|
|
1095
|
+
const {opt: opts} = m;
|
|
1097
1096
|
|
|
1098
1097
|
const streams = [res];
|
|
1099
1098
|
|
|
@@ -1258,7 +1257,7 @@ class Request extends Duplex {
|
|
|
1258
1257
|
*/
|
|
1259
1258
|
pipeDest(dest) {
|
|
1260
1259
|
const m = this;
|
|
1261
|
-
const {response
|
|
1260
|
+
const {response} = m;
|
|
1262
1261
|
|
|
1263
1262
|
// Called after the response is received
|
|
1264
1263
|
if (response?.headers && dest.headers && !dest.headersSent) {
|
|
@@ -1289,9 +1288,9 @@ class Request extends Duplex {
|
|
|
1289
1288
|
dest.statusCode = response.statusCode;
|
|
1290
1289
|
}
|
|
1291
1290
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1291
|
+
if (m.pipefilter) {
|
|
1292
|
+
m.pipefilter(response, dest);
|
|
1293
|
+
}
|
|
1295
1294
|
}
|
|
1296
1295
|
|
|
1297
1296
|
/**
|
|
@@ -1360,16 +1359,16 @@ function isSubdomain(subdomain, domain) {
|
|
|
1360
1359
|
*/
|
|
1361
1360
|
|
|
1362
1361
|
|
|
1363
|
-
const log = log$2({env: `wia:req:${name(
|
|
1362
|
+
const log = log$2({env: `wia:req:${name(import.meta.url)}`}) // __filename
|
|
1364
1363
|
|
|
1365
1364
|
// Preventive platform detection
|
|
1366
|
-
// istanbul ignore
|
|
1365
|
+
// istanbul ignore
|
|
1367
1366
|
;(function detectUnsupportedEnvironment() {
|
|
1368
1367
|
const looksLikeNode = typeof process !== 'undefined';
|
|
1369
1368
|
const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
1370
1369
|
const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
|
|
1371
1370
|
if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
|
|
1372
|
-
|
|
1371
|
+
console.warn('The follow-redirects package should be excluded from browser builds.');
|
|
1373
1372
|
}
|
|
1374
1373
|
})();
|
|
1375
1374
|
|
|
@@ -1387,6 +1386,7 @@ const log = log$2({env: `wia:req:${name(__filename)}`})
|
|
|
1387
1386
|
* @returns
|
|
1388
1387
|
*/
|
|
1389
1388
|
function init(uri, options, callback) {
|
|
1389
|
+
let R;
|
|
1390
1390
|
try {
|
|
1391
1391
|
// Parse parameters, ensuring that input is an object
|
|
1392
1392
|
if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
|
|
@@ -1411,6 +1411,7 @@ function init(uri, options, callback) {
|
|
|
1411
1411
|
if (!utils.isString(options.host) && !utils.isString(options.hostname)) options.hostname = '::1';
|
|
1412
1412
|
|
|
1413
1413
|
R = {opts: options, cb: callback};
|
|
1414
|
+
// log({R}, 'init')
|
|
1414
1415
|
} catch (e) {
|
|
1415
1416
|
log.err(e, 'init');
|
|
1416
1417
|
}
|
|
@@ -1433,8 +1434,9 @@ function request(uri, options, callback) {
|
|
|
1433
1434
|
let R = null;
|
|
1434
1435
|
|
|
1435
1436
|
try {
|
|
1437
|
+
log({uri, options}, 'request');
|
|
1438
|
+
|
|
1436
1439
|
const {opts, cb} = init(uri, options, callback);
|
|
1437
|
-
// log.debug('request', {options})
|
|
1438
1440
|
R = new Request(opts, cb);
|
|
1439
1441
|
} catch (e) {
|
|
1440
1442
|
log.err(e, 'request');
|
|
@@ -1452,6 +1454,8 @@ function request(uri, options, callback) {
|
|
|
1452
1454
|
*/
|
|
1453
1455
|
function fn(verb) {
|
|
1454
1456
|
const method = verb.toUpperCase();
|
|
1457
|
+
|
|
1458
|
+
// @ts-ignore
|
|
1455
1459
|
return (uri, options, callback) => {
|
|
1456
1460
|
const {opts, cb} = init(uri, options, callback);
|
|
1457
1461
|
opts.method = method;
|
package/lib/index.js
CHANGED
package/lib/request.js
CHANGED
|
@@ -94,7 +94,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
94
94
|
*/ constructor(opts, resCallback){
|
|
95
95
|
super(), this._timeout = 0, /** @type {*} */ this.socket = null, /** @type {http.ClientRequest} */ this._currentRequest = null, /** @type {stream.Readable} */ 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
|
|
96
96
|
, /** @type {stream.Writable[]} */ this.pipedests = [] // pipe dest
|
|
97
|
-
;
|
|
97
|
+
, /** @type {*} */ this.startTimer = null;
|
|
98
98
|
const m = this;
|
|
99
99
|
// log({options}, 'constructor');
|
|
100
100
|
// Initialize the request
|
|
@@ -121,36 +121,6 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
121
121
|
}));
|
|
122
122
|
}
|
|
123
123
|
};
|
|
124
|
-
// Proxy all other public ClientRequest methods
|
|
125
|
-
for (const method of [
|
|
126
|
-
'flushHeaders',
|
|
127
|
-
'setNoDelay',
|
|
128
|
-
'setSocketKeepAlive'
|
|
129
|
-
]){
|
|
130
|
-
m[method] = (a, b)=>{
|
|
131
|
-
log.debug(method, {
|
|
132
|
-
a,
|
|
133
|
-
b
|
|
134
|
-
});
|
|
135
|
-
m._currentRequest[method](a, b);
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
// Proxy all public ClientRequest properties
|
|
139
|
-
for (const property of [
|
|
140
|
-
'aborted',
|
|
141
|
-
'connection',
|
|
142
|
-
'socket'
|
|
143
|
-
]){
|
|
144
|
-
Object.defineProperty(m, property, {
|
|
145
|
-
get () {
|
|
146
|
-
const val = m._currentRequest[property];
|
|
147
|
-
log.debug('get property', {
|
|
148
|
-
property
|
|
149
|
-
});
|
|
150
|
-
return val;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
124
|
// 流模式
|
|
155
125
|
if (opts.stream) {
|
|
156
126
|
// 被 pipe 作为目标时触发,拷贝 src headers
|
|
@@ -222,6 +192,37 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
222
192
|
const req = httpModule.request(opt, m._onResponse);
|
|
223
193
|
m._currentRequest = req;
|
|
224
194
|
req.redirectReq = m;
|
|
195
|
+
// Proxy all other public ClientRequest methods
|
|
196
|
+
for (const method of [
|
|
197
|
+
'flushHeaders',
|
|
198
|
+
'setNoDelay',
|
|
199
|
+
'setSocketKeepAlive'
|
|
200
|
+
]){
|
|
201
|
+
m[method] = (a, b)=>{
|
|
202
|
+
log.debug(method, {
|
|
203
|
+
a,
|
|
204
|
+
b
|
|
205
|
+
});
|
|
206
|
+
m._currentRequest[method](a, b);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Proxy all public ClientRequest properties
|
|
210
|
+
for (const property of [
|
|
211
|
+
'aborted',
|
|
212
|
+
'connection',
|
|
213
|
+
'socket'
|
|
214
|
+
]){
|
|
215
|
+
Object.defineProperty(m, property, {
|
|
216
|
+
get () {
|
|
217
|
+
const val = m._currentRequest[property];
|
|
218
|
+
log.debug('get property', {
|
|
219
|
+
property
|
|
220
|
+
});
|
|
221
|
+
return val;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
m._currentRequest.once('socket', m.startTimer);
|
|
225
226
|
// 接收req事件,转发 到 redirectReq 发射
|
|
226
227
|
for (const ev of writeEvents)req.on(ev, writeEventEmit[ev]);
|
|
227
228
|
// RFC7230§5.3.1: When making a request directly to an origin server, […]
|
|
@@ -382,31 +383,26 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
382
383
|
*/ get headersSent() {
|
|
383
384
|
return this._currentRequest?.headersSent;
|
|
384
385
|
}
|
|
385
|
-
// Global timeout for all underlying requests
|
|
386
386
|
/**
|
|
387
|
-
*
|
|
387
|
+
* Global timeout for all underlying requests
|
|
388
388
|
* @param {*} msecs
|
|
389
389
|
* @param {*} callback
|
|
390
390
|
* @returns
|
|
391
391
|
*/ setTimeout(msecs, callback) {
|
|
392
392
|
const m = this;
|
|
393
|
-
// Destroys the socket on timeout
|
|
394
393
|
/**
|
|
395
|
-
*
|
|
394
|
+
* Destroys the socket on timeout
|
|
396
395
|
* @param {*} socket
|
|
397
396
|
*/ function destroyOnTimeout(socket) {
|
|
398
397
|
socket.setTimeout(msecs);
|
|
399
398
|
socket.removeListener('timeout', socket.destroy);
|
|
400
399
|
socket.addListener('timeout', socket.destroy);
|
|
401
400
|
}
|
|
402
|
-
// Sets up a timer to trigger a timeout event
|
|
403
401
|
/**
|
|
404
|
-
*
|
|
402
|
+
* Sets up a timer to trigger a timeout event
|
|
405
403
|
* @param {*} socket
|
|
406
404
|
*/ function startTimer(socket) {
|
|
407
|
-
if (m._timeout)
|
|
408
|
-
clearTimeout(m._timeout);
|
|
409
|
-
}
|
|
405
|
+
if (m._timeout) clearTimeout(m._timeout);
|
|
410
406
|
m._timeout = setTimeout(()=>{
|
|
411
407
|
m.emit('timeout');
|
|
412
408
|
clearTimer();
|
|
@@ -436,7 +432,8 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
436
432
|
if (callback) m.on('timeout', callback);
|
|
437
433
|
// Start the timer if or when the socket is opened
|
|
438
434
|
if (m.socket) startTimer(m.socket);
|
|
439
|
-
else m.
|
|
435
|
+
else m.startTimer = startTimer // 未连接,先登记
|
|
436
|
+
;
|
|
440
437
|
// Clean up on events
|
|
441
438
|
m.on('socket', destroyOnTimeout);
|
|
442
439
|
m.on('abort', clearTimer);
|