superagent 3.8.1 → 4.0.0-beta.5
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/.travis.yml +5 -2
- package/.zuul.yml +5 -2
- package/History.md +35 -0
- package/Makefile +10 -1
- package/Readme.md +10 -6
- package/docs/index.md +133 -69
- package/docs/test.html +6 -6
- package/dump.js +1 -0
- package/lib/agent-base.js +5 -5
- package/lib/client.js +80 -79
- package/lib/node/http2wrapper.js +188 -0
- package/lib/node/index.js +189 -52
- package/lib/node/parsers/text.js +1 -1
- package/lib/node/parsers/urlencoded.js +1 -1
- package/lib/node/response.js +1 -1
- package/lib/node/unzip.js +2 -2
- package/lib/request-base.js +29 -28
- package/lib/response-base.js +8 -6
- package/lib/utils.js +16 -22
- package/package.json +18 -15
- package/superagent.js +231 -209
- package/test.js +7 -0
- package/yarn.lock +1774 -1080
package/lib/node/index.js
CHANGED
|
@@ -15,7 +15,6 @@ let methods = require('methods');
|
|
|
15
15
|
const Stream = require('stream');
|
|
16
16
|
const utils = require('../utils');
|
|
17
17
|
const unzip = require('./unzip').unzip;
|
|
18
|
-
const extend = require('extend');
|
|
19
18
|
const mime = require('mime');
|
|
20
19
|
const https = require('https');
|
|
21
20
|
const http = require('http');
|
|
@@ -25,6 +24,13 @@ const zlib = require('zlib');
|
|
|
25
24
|
const util = require('util');
|
|
26
25
|
const pkg = require('../../package.json');
|
|
27
26
|
const RequestBase = require('../request-base');
|
|
27
|
+
const CookieJar = require('cookiejar');
|
|
28
|
+
let http2;
|
|
29
|
+
try {
|
|
30
|
+
http2 = require('./http2wrapper');
|
|
31
|
+
console.warn('superagent: Enable experimental feature http2');
|
|
32
|
+
} catch (_) {
|
|
33
|
+
}
|
|
28
34
|
|
|
29
35
|
function request(method, url) {
|
|
30
36
|
// callback
|
|
@@ -80,6 +86,7 @@ mime.define({
|
|
|
80
86
|
exports.protocols = {
|
|
81
87
|
'http:': http,
|
|
82
88
|
'https:': https,
|
|
89
|
+
'http2:': http2,
|
|
83
90
|
};
|
|
84
91
|
|
|
85
92
|
/**
|
|
@@ -107,6 +114,15 @@ exports.serialize = {
|
|
|
107
114
|
|
|
108
115
|
exports.parse = require('./parsers');
|
|
109
116
|
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Default buffering map. Can be used to set certain
|
|
120
|
+
* response types to buffer/not buffer.
|
|
121
|
+
*
|
|
122
|
+
* superagent.buffer['application/xml'] = true;
|
|
123
|
+
*/
|
|
124
|
+
exports.buffer = {};
|
|
125
|
+
|
|
110
126
|
/**
|
|
111
127
|
* Initialize internal header tracking properties on a request instance.
|
|
112
128
|
*
|
|
@@ -134,6 +150,7 @@ function _initHeaders(req) {
|
|
|
134
150
|
function Request(method, url) {
|
|
135
151
|
Stream.call(this);
|
|
136
152
|
if ('string' != typeof url) url = format(url);
|
|
153
|
+
this._enableHttp2 = !!process.env.HTTP2_TEST; // internal only
|
|
137
154
|
this._agent = false;
|
|
138
155
|
this._formData = null;
|
|
139
156
|
this.method = method;
|
|
@@ -158,13 +175,50 @@ function Request(method, url) {
|
|
|
158
175
|
util.inherits(Request, Stream);
|
|
159
176
|
RequestBase(Request.prototype);
|
|
160
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Enable or Disable http2.
|
|
180
|
+
*
|
|
181
|
+
* Enable http2.
|
|
182
|
+
*
|
|
183
|
+
* ``` js
|
|
184
|
+
* request.get('http://localhost/')
|
|
185
|
+
* .http2()
|
|
186
|
+
* .end(callback);
|
|
187
|
+
*
|
|
188
|
+
* request.get('http://localhost/')
|
|
189
|
+
* .http2(true)
|
|
190
|
+
* .end(callback);
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* Disable http2.
|
|
194
|
+
*
|
|
195
|
+
* ``` js
|
|
196
|
+
* request = request.http2();
|
|
197
|
+
* request.get('http://localhost/')
|
|
198
|
+
* .http2(false)
|
|
199
|
+
* .end(callback);
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @param {Boolean} enable
|
|
203
|
+
* @return {Request} for chaining
|
|
204
|
+
* @api public
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
Request.prototype.http2 = function(bool){
|
|
208
|
+
if (exports.protocols['http2:'] === undefined){
|
|
209
|
+
throw new Error('superagent: does not support http2');
|
|
210
|
+
}
|
|
211
|
+
this._enableHttp2 = bool === undefined ? true : bool;
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
|
|
161
215
|
/**
|
|
162
216
|
* Queue the given `file` as an attachment to the specified `field`,
|
|
163
217
|
* with optional `options` (or filename).
|
|
164
218
|
*
|
|
165
219
|
* ``` js
|
|
166
220
|
* request.post('http://localhost/upload')
|
|
167
|
-
* .attach(
|
|
221
|
+
* .attach('field', Buffer.from('<b>Hello world</b>'), 'hello.html')
|
|
168
222
|
* .end(callback);
|
|
169
223
|
* ```
|
|
170
224
|
*
|
|
@@ -234,7 +288,7 @@ Request.prototype.agent = function(agent){
|
|
|
234
288
|
};
|
|
235
289
|
|
|
236
290
|
/**
|
|
237
|
-
* Set _Content-Type_ response header passed through `mime.
|
|
291
|
+
* Set _Content-Type_ response header passed through `mime.getType()`.
|
|
238
292
|
*
|
|
239
293
|
* Examples:
|
|
240
294
|
*
|
|
@@ -261,12 +315,12 @@ Request.prototype.agent = function(agent){
|
|
|
261
315
|
Request.prototype.type = function(type) {
|
|
262
316
|
return this.set(
|
|
263
317
|
'Content-Type',
|
|
264
|
-
~type.indexOf('/') ? type : mime.
|
|
318
|
+
~type.indexOf('/') ? type : mime.getType(type)
|
|
265
319
|
);
|
|
266
320
|
};
|
|
267
321
|
|
|
268
322
|
/**
|
|
269
|
-
* Set _Accept_ response header passed through `mime.
|
|
323
|
+
* Set _Accept_ response header passed through `mime.getType()`.
|
|
270
324
|
*
|
|
271
325
|
* Examples:
|
|
272
326
|
*
|
|
@@ -288,7 +342,7 @@ Request.prototype.type = function(type) {
|
|
|
288
342
|
Request.prototype.accept = function(type){
|
|
289
343
|
return this.set('Accept', ~type.indexOf('/')
|
|
290
344
|
? type
|
|
291
|
-
: mime.
|
|
345
|
+
: mime.getType(type));
|
|
292
346
|
};
|
|
293
347
|
|
|
294
348
|
/**
|
|
@@ -309,7 +363,7 @@ Request.prototype.query = function(val){
|
|
|
309
363
|
if ('string' == typeof val) {
|
|
310
364
|
this._query.push(val);
|
|
311
365
|
} else {
|
|
312
|
-
|
|
366
|
+
Object.assign(this.qs, val);
|
|
313
367
|
}
|
|
314
368
|
return this;
|
|
315
369
|
};
|
|
@@ -494,9 +548,7 @@ Request.prototype.auth = function(user, pass, options){
|
|
|
494
548
|
options = { type: 'basic' };
|
|
495
549
|
}
|
|
496
550
|
|
|
497
|
-
|
|
498
|
-
return new Buffer(string).toString('base64');
|
|
499
|
-
};
|
|
551
|
+
const encoder = string => new Buffer.from(string).toString('base64');
|
|
500
552
|
|
|
501
553
|
return this._auth(user, pass, options, encoder);
|
|
502
554
|
};
|
|
@@ -587,10 +639,31 @@ Request.prototype.request = function(){
|
|
|
587
639
|
let url = this.url;
|
|
588
640
|
const retries = this._retries;
|
|
589
641
|
|
|
642
|
+
// Capture backticks as-is from the final query string built above.
|
|
643
|
+
// Note: this'll only find backticks entered in req.query(String)
|
|
644
|
+
// calls, because qs.stringify unconditionally encodes backticks.
|
|
645
|
+
let queryStringBackticks;
|
|
646
|
+
if(url.indexOf('`') > -1) {
|
|
647
|
+
const queryStartIndex = url.indexOf("?");
|
|
648
|
+
|
|
649
|
+
if(queryStartIndex !== -1) {
|
|
650
|
+
const queryString = url.substr(queryStartIndex + 1);
|
|
651
|
+
queryStringBackticks = queryString.match(/`|\%60/g);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
590
655
|
// default to http://
|
|
591
656
|
if (0 != url.indexOf('http')) url = `http://${url}`;
|
|
592
657
|
url = parse(url);
|
|
593
658
|
|
|
659
|
+
// See https://github.com/visionmedia/superagent/issues/1367
|
|
660
|
+
if(queryStringBackticks) {
|
|
661
|
+
let i = 0;
|
|
662
|
+
url.query = url.query.replace(/\%60/g, () => queryStringBackticks[i++]);
|
|
663
|
+
url.search = `?${url.query}`;
|
|
664
|
+
url.path = url.pathname + url.search;
|
|
665
|
+
}
|
|
666
|
+
|
|
594
667
|
// support unix sockets
|
|
595
668
|
if (/^https?\+unix:/.test(url.protocol) === true) {
|
|
596
669
|
// get the protocol
|
|
@@ -614,8 +687,13 @@ Request.prototype.request = function(){
|
|
|
614
687
|
options.passphrase = this._passphrase;
|
|
615
688
|
options.agent = this._agent;
|
|
616
689
|
|
|
690
|
+
// Allows request.get('https://1.2.3.4/').set('Host', 'example.com')
|
|
691
|
+
if (this._header['host']) {
|
|
692
|
+
options.servername = this._header['host'].replace(/:[0-9]+$/,'');
|
|
693
|
+
}
|
|
694
|
+
|
|
617
695
|
// initiate request
|
|
618
|
-
const mod = exports.protocols[url.protocol];
|
|
696
|
+
const mod = this._enableHttp2 ? exports.protocols['http2:'].setProtocol(url.protocol) : exports.protocols[url.protocol];
|
|
619
697
|
|
|
620
698
|
// request
|
|
621
699
|
const req = (this.req = mod.request(options));
|
|
@@ -632,7 +710,7 @@ Request.prototype.request = function(){
|
|
|
632
710
|
// expose events
|
|
633
711
|
req.once('drain', () => { this.emit('drain'); });
|
|
634
712
|
|
|
635
|
-
req.
|
|
713
|
+
req.on('error', err => {
|
|
636
714
|
// flag abortion here for out timeouts
|
|
637
715
|
// because node will emit a faux-error "socket hang up"
|
|
638
716
|
// when request is aborted before a connection is made
|
|
@@ -654,15 +732,24 @@ Request.prototype.request = function(){
|
|
|
654
732
|
if (this.username && this.password) {
|
|
655
733
|
this.auth(this.username, this.password);
|
|
656
734
|
}
|
|
657
|
-
|
|
658
|
-
// add cookies
|
|
659
|
-
if (this.cookies) req.setHeader('Cookie', this.cookies);
|
|
660
|
-
|
|
661
735
|
for (const key in this.header) {
|
|
662
736
|
if (this.header.hasOwnProperty(key))
|
|
663
737
|
req.setHeader(key, this.header[key]);
|
|
664
738
|
}
|
|
665
739
|
|
|
740
|
+
// add cookies
|
|
741
|
+
if (this.cookies) {
|
|
742
|
+
if(this._header.hasOwnProperty('cookie')) {
|
|
743
|
+
// merge
|
|
744
|
+
const tmpJar = new CookieJar.CookieJar();
|
|
745
|
+
tmpJar.setCookies(this._header.cookie.split(';'));
|
|
746
|
+
tmpJar.setCookies(this.cookies.split(';'));
|
|
747
|
+
req.setHeader('Cookie',tmpJar.getCookies(CookieJar.CookieAccessInfo.All).toValueString());
|
|
748
|
+
} else {
|
|
749
|
+
req.setHeader('Cookie', this.cookies);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
666
753
|
return req;
|
|
667
754
|
};
|
|
668
755
|
|
|
@@ -688,20 +775,23 @@ Request.prototype.callback = function(err, res){
|
|
|
688
775
|
|
|
689
776
|
if (!err) {
|
|
690
777
|
try {
|
|
691
|
-
if (this._isResponseOK(res)) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
778
|
+
if (!this._isResponseOK(res)) {
|
|
779
|
+
let msg = 'Unsuccessful HTTP response';
|
|
780
|
+
if (res) {
|
|
781
|
+
msg = http.STATUS_CODES[res.status] || msg;
|
|
782
|
+
}
|
|
783
|
+
err = new Error(msg);
|
|
784
|
+
err.status = res ? res.status : undefined;
|
|
698
785
|
}
|
|
699
|
-
err = new Error(msg);
|
|
700
|
-
err.status = res ? res.status : undefined;
|
|
701
786
|
} catch (new_err) {
|
|
702
787
|
err = new_err;
|
|
703
788
|
}
|
|
704
789
|
}
|
|
790
|
+
// It's important that the callback is called outside try/catch
|
|
791
|
+
// to avoid double callback
|
|
792
|
+
if (!err) {
|
|
793
|
+
return fn(null, res);
|
|
794
|
+
}
|
|
705
795
|
|
|
706
796
|
err.response = res;
|
|
707
797
|
if (this._maxRetries) err.retries = this._retries - 1;
|
|
@@ -743,6 +833,11 @@ Request.prototype._emitResponse = function(body, files) {
|
|
|
743
833
|
response.body = body;
|
|
744
834
|
}
|
|
745
835
|
response.files = files;
|
|
836
|
+
if (this._endCalled) {
|
|
837
|
+
response.pipe = function() {
|
|
838
|
+
throw Error("end() has already been called, so it's too late to start piping");
|
|
839
|
+
}
|
|
840
|
+
}
|
|
746
841
|
this.emit('response', response);
|
|
747
842
|
return response;
|
|
748
843
|
};
|
|
@@ -752,8 +847,8 @@ Request.prototype.end = function(fn) {
|
|
|
752
847
|
debug('%s %s', this.method, this.url);
|
|
753
848
|
|
|
754
849
|
if (this._endCalled) {
|
|
755
|
-
|
|
756
|
-
'
|
|
850
|
+
throw Error(
|
|
851
|
+
'.end() was called twice. This is not supported in superagent'
|
|
757
852
|
);
|
|
758
853
|
}
|
|
759
854
|
this._endCalled = true;
|
|
@@ -761,13 +856,14 @@ Request.prototype.end = function(fn) {
|
|
|
761
856
|
// store callback
|
|
762
857
|
this._callback = fn || noop;
|
|
763
858
|
|
|
764
|
-
|
|
859
|
+
this._end();
|
|
765
860
|
};
|
|
766
861
|
|
|
767
862
|
Request.prototype._end = function() {
|
|
863
|
+
if (this._aborted) return this.callback(Error("The request has been aborted even before .end() was called"));
|
|
864
|
+
|
|
768
865
|
let data = this._data;
|
|
769
866
|
const req = this.req;
|
|
770
|
-
let buffer = this._buffer;
|
|
771
867
|
const method = this.method;
|
|
772
868
|
|
|
773
869
|
this._setTimeouts();
|
|
@@ -779,7 +875,7 @@ Request.prototype._end = function() {
|
|
|
779
875
|
let contentType = req.getHeader('Content-Type');
|
|
780
876
|
// Parse out just the content type from the header (ignore the charset)
|
|
781
877
|
if (contentType) contentType = contentType.split(';')[0];
|
|
782
|
-
let serialize = exports.serialize[contentType];
|
|
878
|
+
let serialize = this._serializer || exports.serialize[contentType];
|
|
783
879
|
if (!serialize && isJSON(contentType)) {
|
|
784
880
|
serialize = exports.serialize['application/json'];
|
|
785
881
|
}
|
|
@@ -809,7 +905,6 @@ Request.prototype._end = function() {
|
|
|
809
905
|
const type = mime.split('/')[0];
|
|
810
906
|
const multipart = 'multipart' == type;
|
|
811
907
|
const redirect = isRedirect(res.statusCode);
|
|
812
|
-
let parser = this._parser;
|
|
813
908
|
const responseType = this._responseType;
|
|
814
909
|
|
|
815
910
|
this.res = res;
|
|
@@ -830,6 +925,19 @@ Request.prototype._end = function() {
|
|
|
830
925
|
unzip(req, res);
|
|
831
926
|
}
|
|
832
927
|
|
|
928
|
+
let buffer = this._buffer;
|
|
929
|
+
if (buffer === undefined && mime in exports.buffer){
|
|
930
|
+
buffer = !!exports.buffer[mime];
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
let parser = this._parser;
|
|
934
|
+
if (undefined === buffer) {
|
|
935
|
+
if (parser) {
|
|
936
|
+
console.warn("A custom superagent parser has been set, but buffering strategy for the parser hasn't been configured. Call `req.buffer(true or false)` or set `superagent.buffer[mime] = true or false`");
|
|
937
|
+
buffer = true;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
833
941
|
if (!parser) {
|
|
834
942
|
if (responseType) {
|
|
835
943
|
parser = exports.parse.image; // It's actually a generic Buffer
|
|
@@ -853,6 +961,9 @@ Request.prototype._end = function() {
|
|
|
853
961
|
buffer = (buffer !== false);
|
|
854
962
|
} else if (buffer) {
|
|
855
963
|
parser = exports.parse.text;
|
|
964
|
+
} else if (undefined === buffer) {
|
|
965
|
+
parser = exports.parse.image; // It's actually a generic Buffer
|
|
966
|
+
buffer = true;
|
|
856
967
|
}
|
|
857
968
|
}
|
|
858
969
|
|
|
@@ -861,6 +972,7 @@ Request.prototype._end = function() {
|
|
|
861
972
|
buffer = true;
|
|
862
973
|
}
|
|
863
974
|
|
|
975
|
+
this._resBuffered = buffer;
|
|
864
976
|
let parserHandlesEnd = false;
|
|
865
977
|
if (buffer) {
|
|
866
978
|
// Protectiona against zip bombs and other nuisance
|
|
@@ -939,6 +1051,47 @@ Request.prototype._end = function() {
|
|
|
939
1051
|
|
|
940
1052
|
this.emit('request', this);
|
|
941
1053
|
|
|
1054
|
+
const getProgressMonitor = () => {
|
|
1055
|
+
const lengthComputable = true;
|
|
1056
|
+
const total = req.getHeader('Content-Length');
|
|
1057
|
+
let loaded = 0;
|
|
1058
|
+
|
|
1059
|
+
const progress = new Stream.Transform();
|
|
1060
|
+
progress._transform = (chunk, encoding, cb) => {
|
|
1061
|
+
loaded += chunk.length;
|
|
1062
|
+
this.emit('progress', {
|
|
1063
|
+
direction: 'upload',
|
|
1064
|
+
lengthComputable,
|
|
1065
|
+
loaded,
|
|
1066
|
+
total,
|
|
1067
|
+
});
|
|
1068
|
+
cb(null, chunk);
|
|
1069
|
+
};
|
|
1070
|
+
return progress;
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
const bufferToChunks = (buffer) => {
|
|
1074
|
+
const chunkSize = 16 * 1024; // default highWaterMark value
|
|
1075
|
+
const chunking = new Stream.Readable();
|
|
1076
|
+
const totalLength = buffer.length;
|
|
1077
|
+
const remainder = totalLength % chunkSize;
|
|
1078
|
+
const cutoff = totalLength - remainder;
|
|
1079
|
+
|
|
1080
|
+
for (let i = 0; i < cutoff; i += chunkSize) {
|
|
1081
|
+
const chunk = buffer.slice(i, i + chunkSize);
|
|
1082
|
+
chunking.push(chunk);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
if (remainder > 0) {
|
|
1086
|
+
const remainderBuffer = buffer.slice(-remainder);
|
|
1087
|
+
chunking.push(remainderBuffer);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
chunking.push(null); // no more data
|
|
1091
|
+
|
|
1092
|
+
return chunking;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
942
1095
|
// if a FormData instance got created, then we send that as the request body
|
|
943
1096
|
const formData = this._formData;
|
|
944
1097
|
if (formData) {
|
|
@@ -959,31 +1112,13 @@ Request.prototype._end = function() {
|
|
|
959
1112
|
req.setHeader('Content-Length', length);
|
|
960
1113
|
}
|
|
961
1114
|
|
|
962
|
-
const getProgressMonitor = () => {
|
|
963
|
-
const lengthComputable = true;
|
|
964
|
-
const total = req.getHeader('Content-Length');
|
|
965
|
-
let loaded = 0;
|
|
966
|
-
|
|
967
|
-
const progress = new Stream.Transform();
|
|
968
|
-
progress._transform = (chunk, encoding, cb) => {
|
|
969
|
-
loaded += chunk.length;
|
|
970
|
-
this.emit('progress', {
|
|
971
|
-
direction: 'upload',
|
|
972
|
-
lengthComputable,
|
|
973
|
-
loaded,
|
|
974
|
-
total,
|
|
975
|
-
});
|
|
976
|
-
cb(null, chunk);
|
|
977
|
-
};
|
|
978
|
-
return progress;
|
|
979
|
-
};
|
|
980
1115
|
formData.pipe(getProgressMonitor()).pipe(req);
|
|
981
1116
|
});
|
|
1117
|
+
} else if (Buffer.isBuffer(data)) {
|
|
1118
|
+
bufferToChunks(data).pipe(getProgressMonitor()).pipe(req);
|
|
982
1119
|
} else {
|
|
983
1120
|
req.end(data);
|
|
984
1121
|
}
|
|
985
|
-
|
|
986
|
-
return this;
|
|
987
1122
|
};
|
|
988
1123
|
|
|
989
1124
|
/**
|
|
@@ -1064,7 +1199,9 @@ function isImageOrVideo(mime) {
|
|
|
1064
1199
|
*/
|
|
1065
1200
|
|
|
1066
1201
|
function isJSON(mime) {
|
|
1067
|
-
|
|
1202
|
+
// should match /json or +json
|
|
1203
|
+
// but not /json-seq
|
|
1204
|
+
return /[\/+]json($|[^-\w])/.test(mime);
|
|
1068
1205
|
}
|
|
1069
1206
|
|
|
1070
1207
|
/**
|
package/lib/node/parsers/text.js
CHANGED
package/lib/node/response.js
CHANGED
|
@@ -36,7 +36,7 @@ function Response(req) {
|
|
|
36
36
|
this.text = res.text;
|
|
37
37
|
this.body = res.body !== undefined ? res.body : {};
|
|
38
38
|
this.files = res.files || {};
|
|
39
|
-
this.buffered =
|
|
39
|
+
this.buffered = req._resBuffered;
|
|
40
40
|
this.header = this.headers = res.headers;
|
|
41
41
|
this._setStatusProperties(res.statusCode);
|
|
42
42
|
this._setHeaderProperties(this.header);
|
package/lib/node/unzip.js
CHANGED
|
@@ -59,9 +59,9 @@ exports.unzip = (req, res) => {
|
|
|
59
59
|
const _on = res.on;
|
|
60
60
|
res.on = function(type, fn) {
|
|
61
61
|
if ('data' == type || 'end' == type) {
|
|
62
|
-
stream.on(type, fn);
|
|
62
|
+
stream.on(type, fn.bind(res));
|
|
63
63
|
} else if ('error' == type) {
|
|
64
|
-
stream.on(type, fn);
|
|
64
|
+
stream.on(type, fn.bind(res));
|
|
65
65
|
_on.call(res, type, fn);
|
|
66
66
|
} else {
|
|
67
67
|
_on.call(res, type, fn);
|