superagent 4.0.0-alpha.1 → 4.1.0
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 +4 -1
- package/.zuul.yml +0 -2
- package/History.md +12 -2
- package/Makefile +10 -1
- package/Readme.md +12 -11
- package/docs/index.md +82 -49
- package/docs/test.html +6 -6
- package/dump.js +1 -0
- package/lib/client.js +1 -2
- package/lib/node/http2wrapper.js +188 -0
- package/lib/node/index.js +122 -14
- package/lib/node/response.js +1 -1
- package/lib/node/unzip.js +2 -2
- package/lib/request-base.js +8 -0
- package/package.json +13 -13
- package/superagent.js +11 -2
- package/yarn.lock +1643 -431
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const http2 = require('http2');
|
|
4
|
+
const Stream = require('stream');
|
|
5
|
+
const util = require('util');
|
|
6
|
+
const net = require('net');
|
|
7
|
+
const tls = require('tls');
|
|
8
|
+
const parse = require('url').parse;
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
HTTP2_HEADER_PATH,
|
|
12
|
+
HTTP2_HEADER_STATUS,
|
|
13
|
+
HTTP2_HEADER_METHOD,
|
|
14
|
+
HTTP2_HEADER_AUTHORITY,
|
|
15
|
+
HTTP2_HEADER_HOST,
|
|
16
|
+
HTTP2_HEADER_SET_COOKIE,
|
|
17
|
+
NGHTTP2_CANCEL,
|
|
18
|
+
} = http2.constants;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function setProtocol(protocol) {
|
|
22
|
+
return {
|
|
23
|
+
request: function (options) {
|
|
24
|
+
return new Request(protocol, options);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function Request(protocol, options) {
|
|
30
|
+
Stream.call(this);
|
|
31
|
+
const defaultPort = protocol === 'https:' ? 443 : 80;
|
|
32
|
+
const defaultHost = 'localhost'
|
|
33
|
+
const port = options.port || defaultPort;
|
|
34
|
+
const host = options.host || defaultHost;
|
|
35
|
+
|
|
36
|
+
delete options.port
|
|
37
|
+
delete options.host
|
|
38
|
+
|
|
39
|
+
this.method = options.method;
|
|
40
|
+
this.path = options.path;
|
|
41
|
+
this.protocol = protocol;
|
|
42
|
+
this.host = host;
|
|
43
|
+
|
|
44
|
+
delete options.method
|
|
45
|
+
delete options.path
|
|
46
|
+
|
|
47
|
+
const sessionOptions = Object.assign({}, options);
|
|
48
|
+
if (options.socketPath) {
|
|
49
|
+
sessionOptions.socketPath = options.socketPath;
|
|
50
|
+
sessionOptions.createConnection = this.createUnixConnection.bind(this);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this._headers = {};
|
|
54
|
+
|
|
55
|
+
const session = http2.connect(`${protocol}//${host}:${port}`, sessionOptions);
|
|
56
|
+
this.setHeader('host', `${host}:${port}`)
|
|
57
|
+
|
|
58
|
+
session.on('error', (err) => this.emit('error', err));
|
|
59
|
+
|
|
60
|
+
this.session = session;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Inherit from `Stream` (which inherits from `EventEmitter`).
|
|
65
|
+
*/
|
|
66
|
+
util.inherits(Request, Stream);
|
|
67
|
+
|
|
68
|
+
Request.prototype.createUnixConnection = function (authority, options) {
|
|
69
|
+
switch (this.protocol) {
|
|
70
|
+
case 'http:':
|
|
71
|
+
return net.connect(options.socketPath);
|
|
72
|
+
case 'https:':
|
|
73
|
+
options.ALPNProtocols = ['h2'];
|
|
74
|
+
options.servername = this.host;
|
|
75
|
+
options.allowHalfOpen = true;
|
|
76
|
+
return tls.connect(options.socketPath, options);
|
|
77
|
+
default:
|
|
78
|
+
throw new Error('Unsupported protocol', this.protocol);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Request.prototype.setNoDelay = function (bool) {
|
|
83
|
+
// We can not use setNoDelay with HTTP/2.
|
|
84
|
+
// Node 10 limits http2session.socket methods to ones safe to use with HTTP/2.
|
|
85
|
+
// See also https://nodejs.org/api/http2.html#http2_http2session_socket
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Request.prototype.getFrame = function () {
|
|
89
|
+
if (this.frame) {
|
|
90
|
+
return this.frame;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const method = {
|
|
94
|
+
[HTTP2_HEADER_PATH]: this.path,
|
|
95
|
+
[HTTP2_HEADER_METHOD]: this.method,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let headers = this.mapToHttp2Header(this._headers);
|
|
99
|
+
|
|
100
|
+
headers = Object.assign(headers, method);
|
|
101
|
+
|
|
102
|
+
const frame = this.session.request(headers);
|
|
103
|
+
frame.once('response', (headers, flags) => {
|
|
104
|
+
headers = this.mapToHttpHeader(headers);
|
|
105
|
+
frame.headers = headers;
|
|
106
|
+
frame.status = frame.statusCode = headers[HTTP2_HEADER_STATUS];
|
|
107
|
+
this.emit('response', frame);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
this._headerSent = true;
|
|
111
|
+
|
|
112
|
+
frame.once('drain', () => this.emit('drain'));
|
|
113
|
+
frame.on('error', (err) => this.emit('error', err));
|
|
114
|
+
frame.on('close', () => this.session.close());
|
|
115
|
+
|
|
116
|
+
this.frame = frame;
|
|
117
|
+
return frame;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Request.prototype.mapToHttpHeader = function (headers) {
|
|
121
|
+
const keys = Object.keys(headers);
|
|
122
|
+
const http2Headers = {};
|
|
123
|
+
for (var i = 0; i < keys.length; i++) {
|
|
124
|
+
let key = keys[i];
|
|
125
|
+
let value = headers[key];
|
|
126
|
+
key = key.toLowerCase();
|
|
127
|
+
switch (key) {
|
|
128
|
+
case HTTP2_HEADER_SET_COOKIE:
|
|
129
|
+
value = Array.isArray(value) ? value : [value];
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
http2Headers[key] = value;
|
|
135
|
+
}
|
|
136
|
+
return http2Headers;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Request.prototype.mapToHttp2Header = function (headers) {
|
|
140
|
+
const keys = Object.keys(headers);
|
|
141
|
+
const http2Headers = {};
|
|
142
|
+
for (var i = 0; i < keys.length; i++) {
|
|
143
|
+
let key = keys[i];
|
|
144
|
+
let value = headers[key];
|
|
145
|
+
key = key.toLowerCase();
|
|
146
|
+
switch (key) {
|
|
147
|
+
case HTTP2_HEADER_HOST:
|
|
148
|
+
key = HTTP2_HEADER_AUTHORITY;
|
|
149
|
+
value = /^http\:\/\/|^https\:\/\//.test(value) ? parse(value).host : value;
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
http2Headers[key] = value;
|
|
155
|
+
}
|
|
156
|
+
return http2Headers;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Request.prototype.setHeader = function (name, value) {
|
|
160
|
+
this._headers[name.toLowerCase()] = value;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
Request.prototype.getHeader = function (name) {
|
|
164
|
+
return this._headers[name.toLowerCase()];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
Request.prototype.write = function (data, encoding) {
|
|
168
|
+
const frame = this.getFrame();
|
|
169
|
+
return frame.write(data, encoding);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
Request.prototype.pipe = function (stream, options) {
|
|
173
|
+
const frame = this.getFrame();
|
|
174
|
+
return frame.pipe(stream, options);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
Request.prototype.end = function (data) {
|
|
178
|
+
const frame = this.getFrame();
|
|
179
|
+
frame.end(data);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
Request.prototype.abort = function (data) {
|
|
183
|
+
const frame = this.getFrame();
|
|
184
|
+
frame.close(NGHTTP2_CANCEL);
|
|
185
|
+
this.session.destroy();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
exports.setProtocol = setProtocol;
|
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');
|
|
@@ -27,6 +26,11 @@ const pkg = require('../../package.json');
|
|
|
27
26
|
const RequestBase = require('../request-base');
|
|
28
27
|
const CookieJar = require('cookiejar');
|
|
29
28
|
|
|
29
|
+
let http2;
|
|
30
|
+
try {
|
|
31
|
+
http2 = require('./http2wrapper');
|
|
32
|
+
} catch (_) {}
|
|
33
|
+
|
|
30
34
|
function request(method, url) {
|
|
31
35
|
// callback
|
|
32
36
|
if ('function' == typeof url) {
|
|
@@ -81,6 +85,7 @@ mime.define({
|
|
|
81
85
|
exports.protocols = {
|
|
82
86
|
'http:': http,
|
|
83
87
|
'https:': https,
|
|
88
|
+
'http2:': http2,
|
|
84
89
|
};
|
|
85
90
|
|
|
86
91
|
/**
|
|
@@ -144,6 +149,7 @@ function _initHeaders(req) {
|
|
|
144
149
|
function Request(method, url) {
|
|
145
150
|
Stream.call(this);
|
|
146
151
|
if ('string' != typeof url) url = format(url);
|
|
152
|
+
this._enableHttp2 = !!process.env.HTTP2_TEST; // internal only
|
|
147
153
|
this._agent = false;
|
|
148
154
|
this._formData = null;
|
|
149
155
|
this.method = method;
|
|
@@ -168,6 +174,43 @@ function Request(method, url) {
|
|
|
168
174
|
util.inherits(Request, Stream);
|
|
169
175
|
RequestBase(Request.prototype);
|
|
170
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Enable or Disable http2.
|
|
179
|
+
*
|
|
180
|
+
* Enable http2.
|
|
181
|
+
*
|
|
182
|
+
* ``` js
|
|
183
|
+
* request.get('http://localhost/')
|
|
184
|
+
* .http2()
|
|
185
|
+
* .end(callback);
|
|
186
|
+
*
|
|
187
|
+
* request.get('http://localhost/')
|
|
188
|
+
* .http2(true)
|
|
189
|
+
* .end(callback);
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* Disable http2.
|
|
193
|
+
*
|
|
194
|
+
* ``` js
|
|
195
|
+
* request = request.http2();
|
|
196
|
+
* request.get('http://localhost/')
|
|
197
|
+
* .http2(false)
|
|
198
|
+
* .end(callback);
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* @param {Boolean} enable
|
|
202
|
+
* @return {Request} for chaining
|
|
203
|
+
* @api public
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
Request.prototype.http2 = function(bool){
|
|
207
|
+
if (exports.protocols['http2:'] === undefined) {
|
|
208
|
+
throw new Error('superagent: this version of Node.js does not support http2');
|
|
209
|
+
}
|
|
210
|
+
this._enableHttp2 = bool === undefined ? true : bool;
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
|
|
171
214
|
/**
|
|
172
215
|
* Queue the given `file` as an attachment to the specified `field`,
|
|
173
216
|
* with optional `options` (or filename).
|
|
@@ -319,7 +362,7 @@ Request.prototype.query = function(val){
|
|
|
319
362
|
if ('string' == typeof val) {
|
|
320
363
|
this._query.push(val);
|
|
321
364
|
} else {
|
|
322
|
-
|
|
365
|
+
Object.assign(this.qs, val);
|
|
323
366
|
}
|
|
324
367
|
return this;
|
|
325
368
|
};
|
|
@@ -504,7 +547,7 @@ Request.prototype.auth = function(user, pass, options){
|
|
|
504
547
|
options = { type: 'basic' };
|
|
505
548
|
}
|
|
506
549
|
|
|
507
|
-
const encoder = string => new Buffer(string).toString('base64');
|
|
550
|
+
const encoder = string => new Buffer.from(string).toString('base64');
|
|
508
551
|
|
|
509
552
|
return this._auth(user, pass, options, encoder);
|
|
510
553
|
};
|
|
@@ -631,6 +674,24 @@ Request.prototype.request = function(){
|
|
|
631
674
|
url.path = unixParts[2];
|
|
632
675
|
}
|
|
633
676
|
|
|
677
|
+
// Override IP address of a hostname
|
|
678
|
+
if (this._connectOverride) {
|
|
679
|
+
const hostname = url.hostname;
|
|
680
|
+
const match = hostname in this._connectOverride ? this._connectOverride[hostname] : this._connectOverride['*'];
|
|
681
|
+
if (match) {
|
|
682
|
+
// backup the real host
|
|
683
|
+
if (!this._header['host']) {
|
|
684
|
+
this.set('host', url.host);
|
|
685
|
+
}
|
|
686
|
+
// wrap [ipv6]
|
|
687
|
+
url.host = /:/.test(match) ? `[${match}]` : match;
|
|
688
|
+
if (url.port) {
|
|
689
|
+
url.host += `:${url.port}`;
|
|
690
|
+
}
|
|
691
|
+
url.hostname = match;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
634
695
|
// options
|
|
635
696
|
options.method = this.method;
|
|
636
697
|
options.port = url.port;
|
|
@@ -648,8 +709,12 @@ Request.prototype.request = function(){
|
|
|
648
709
|
options.servername = this._header['host'].replace(/:[0-9]+$/,'');
|
|
649
710
|
}
|
|
650
711
|
|
|
712
|
+
if (this._trustLocalhost && /^(?:localhost|127\.0\.0\.\d+|(0*:)+:0*1)$/.test(url.hostname)) {
|
|
713
|
+
options.rejectUnauthorized = false;
|
|
714
|
+
}
|
|
715
|
+
|
|
651
716
|
// initiate request
|
|
652
|
-
const mod = exports.protocols[url.protocol];
|
|
717
|
+
const mod = this._enableHttp2 ? exports.protocols['http2:'].setProtocol(url.protocol) : exports.protocols[url.protocol];
|
|
653
718
|
|
|
654
719
|
// request
|
|
655
720
|
const req = (this.req = mod.request(options));
|
|
@@ -695,10 +760,10 @@ Request.prototype.request = function(){
|
|
|
695
760
|
|
|
696
761
|
// add cookies
|
|
697
762
|
if (this.cookies) {
|
|
698
|
-
if(this.
|
|
763
|
+
if(this._header.hasOwnProperty('cookie')) {
|
|
699
764
|
// merge
|
|
700
765
|
const tmpJar = new CookieJar.CookieJar();
|
|
701
|
-
tmpJar.setCookies(this.
|
|
766
|
+
tmpJar.setCookies(this._header.cookie.split(';'));
|
|
702
767
|
tmpJar.setCookies(this.cookies.split(';'));
|
|
703
768
|
req.setHeader('Cookie',tmpJar.getCookies(CookieJar.CookieAccessInfo.All).toValueString());
|
|
704
769
|
} else {
|
|
@@ -789,6 +854,11 @@ Request.prototype._emitResponse = function(body, files) {
|
|
|
789
854
|
response.body = body;
|
|
790
855
|
}
|
|
791
856
|
response.files = files;
|
|
857
|
+
if (this._endCalled) {
|
|
858
|
+
response.pipe = function() {
|
|
859
|
+
throw Error("end() has already been called, so it's too late to start piping");
|
|
860
|
+
}
|
|
861
|
+
}
|
|
792
862
|
this.emit('response', response);
|
|
793
863
|
return response;
|
|
794
864
|
};
|
|
@@ -798,8 +868,8 @@ Request.prototype.end = function(fn) {
|
|
|
798
868
|
debug('%s %s', this.method, this.url);
|
|
799
869
|
|
|
800
870
|
if (this._endCalled) {
|
|
801
|
-
|
|
802
|
-
'
|
|
871
|
+
throw Error(
|
|
872
|
+
'.end() was called twice. This is not supported in superagent'
|
|
803
873
|
);
|
|
804
874
|
}
|
|
805
875
|
this._endCalled = true;
|
|
@@ -807,7 +877,7 @@ Request.prototype.end = function(fn) {
|
|
|
807
877
|
// store callback
|
|
808
878
|
this._callback = fn || noop;
|
|
809
879
|
|
|
810
|
-
|
|
880
|
+
this._end();
|
|
811
881
|
};
|
|
812
882
|
|
|
813
883
|
Request.prototype._end = function() {
|
|
@@ -815,7 +885,6 @@ Request.prototype._end = function() {
|
|
|
815
885
|
|
|
816
886
|
let data = this._data;
|
|
817
887
|
const req = this.req;
|
|
818
|
-
let buffer = this._buffer;
|
|
819
888
|
const method = this.method;
|
|
820
889
|
|
|
821
890
|
this._setTimeouts();
|
|
@@ -827,7 +896,7 @@ Request.prototype._end = function() {
|
|
|
827
896
|
let contentType = req.getHeader('Content-Type');
|
|
828
897
|
// Parse out just the content type from the header (ignore the charset)
|
|
829
898
|
if (contentType) contentType = contentType.split(';')[0];
|
|
830
|
-
let serialize = exports.serialize[contentType];
|
|
899
|
+
let serialize = this._serializer || exports.serialize[contentType];
|
|
831
900
|
if (!serialize && isJSON(contentType)) {
|
|
832
901
|
serialize = exports.serialize['application/json'];
|
|
833
902
|
}
|
|
@@ -857,7 +926,6 @@ Request.prototype._end = function() {
|
|
|
857
926
|
const type = mime.split('/')[0];
|
|
858
927
|
const multipart = 'multipart' == type;
|
|
859
928
|
const redirect = isRedirect(res.statusCode);
|
|
860
|
-
let parser = this._parser;
|
|
861
929
|
const responseType = this._responseType;
|
|
862
930
|
|
|
863
931
|
this.res = res;
|
|
@@ -878,10 +946,19 @@ Request.prototype._end = function() {
|
|
|
878
946
|
unzip(req, res);
|
|
879
947
|
}
|
|
880
948
|
|
|
949
|
+
let buffer = this._buffer;
|
|
881
950
|
if (buffer === undefined && mime in exports.buffer){
|
|
882
951
|
buffer = !!exports.buffer[mime];
|
|
883
952
|
}
|
|
884
953
|
|
|
954
|
+
let parser = this._parser;
|
|
955
|
+
if (undefined === buffer) {
|
|
956
|
+
if (parser) {
|
|
957
|
+
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`");
|
|
958
|
+
buffer = true;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
885
962
|
if (!parser) {
|
|
886
963
|
if (responseType) {
|
|
887
964
|
parser = exports.parse.image; // It's actually a generic Buffer
|
|
@@ -905,6 +982,9 @@ Request.prototype._end = function() {
|
|
|
905
982
|
buffer = (buffer !== false);
|
|
906
983
|
} else if (buffer) {
|
|
907
984
|
parser = exports.parse.text;
|
|
985
|
+
} else if (undefined === buffer) {
|
|
986
|
+
parser = exports.parse.image; // It's actually a generic Buffer
|
|
987
|
+
buffer = true;
|
|
908
988
|
}
|
|
909
989
|
}
|
|
910
990
|
|
|
@@ -913,6 +993,7 @@ Request.prototype._end = function() {
|
|
|
913
993
|
buffer = true;
|
|
914
994
|
}
|
|
915
995
|
|
|
996
|
+
this._resBuffered = buffer;
|
|
916
997
|
let parserHandlesEnd = false;
|
|
917
998
|
if (buffer) {
|
|
918
999
|
// Protectiona against zip bombs and other nuisance
|
|
@@ -1059,8 +1140,6 @@ Request.prototype._end = function() {
|
|
|
1059
1140
|
} else {
|
|
1060
1141
|
req.end(data);
|
|
1061
1142
|
}
|
|
1062
|
-
|
|
1063
|
-
return this;
|
|
1064
1143
|
};
|
|
1065
1144
|
|
|
1066
1145
|
/**
|
|
@@ -1082,6 +1161,35 @@ Request.prototype._shouldUnzip = res => {
|
|
|
1082
1161
|
return /^\s*(?:deflate|gzip)\s*$/.test(res.headers['content-encoding']);
|
|
1083
1162
|
};
|
|
1084
1163
|
|
|
1164
|
+
/**
|
|
1165
|
+
* Overrides DNS for selected hostnames. Takes object mapping hostnames to IP addresses.
|
|
1166
|
+
*
|
|
1167
|
+
* When making a request to a URL with a hostname exactly matching a key in the object,
|
|
1168
|
+
* use the given IP address to connect, instead of using DNS to resolve the hostname.
|
|
1169
|
+
*
|
|
1170
|
+
* A special host `*` matches every hostname (keep redirects in mind!)
|
|
1171
|
+
*
|
|
1172
|
+
* request.connect({
|
|
1173
|
+
* 'test.example.com': '127.0.0.1',
|
|
1174
|
+
* 'ipv6.example.com': '::1',
|
|
1175
|
+
* })
|
|
1176
|
+
*/
|
|
1177
|
+
Request.prototype.connect = function(connectOverride) {
|
|
1178
|
+
if ('string' === typeof connectOverride) {
|
|
1179
|
+
this._connectOverride = {'*': connectOverride};
|
|
1180
|
+
} else if ('object' === typeof connectOverride) {
|
|
1181
|
+
this._connectOverride = connectOverride;
|
|
1182
|
+
} else {
|
|
1183
|
+
this._connectOverride = undefined;
|
|
1184
|
+
}
|
|
1185
|
+
return this;
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
Request.prototype.trustLocalhost = function(toggle) {
|
|
1189
|
+
this._trustLocalhost = toggle === undefined ? true : toggle;
|
|
1190
|
+
return this;
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1085
1193
|
// generate HTTP verb methods
|
|
1086
1194
|
if (methods.indexOf('del') == -1) {
|
|
1087
1195
|
// create a copy so we don't cause conflicts with
|
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);
|
package/lib/request-base.js
CHANGED
|
@@ -236,6 +236,14 @@ RequestBase.prototype.then = function then(resolve, reject) {
|
|
|
236
236
|
}
|
|
237
237
|
this._fullfilledPromise = new Promise((innerResolve, innerReject) => {
|
|
238
238
|
self.on('error', innerReject);
|
|
239
|
+
self.on('abort', () => {
|
|
240
|
+
const err = new Error('Aborted');
|
|
241
|
+
err.code = "ABORTED";
|
|
242
|
+
err.status = this.status;
|
|
243
|
+
err.method = this.method;
|
|
244
|
+
err.url = this.url;
|
|
245
|
+
innerReject(err);
|
|
246
|
+
});
|
|
239
247
|
self.end((err, res) => {
|
|
240
248
|
if (err) innerReject(err);
|
|
241
249
|
else innerResolve(res);
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superagent",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "elegant & feature rich browser / node HTTP with a fluent API",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepare": "make all",
|
|
7
|
-
"test": "make test"
|
|
7
|
+
"test": "make test",
|
|
8
|
+
"test-http2": "make test-node-http2"
|
|
8
9
|
},
|
|
9
10
|
"keywords": [
|
|
10
11
|
"http",
|
|
@@ -25,15 +26,14 @@
|
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"component-emitter": "^1.2.0",
|
|
28
|
-
"cookiejar": "^2.1.
|
|
29
|
-
"debug": "^
|
|
30
|
-
"
|
|
31
|
-
"form-data": "^2.3.2",
|
|
29
|
+
"cookiejar": "^2.1.2",
|
|
30
|
+
"debug": "^4.1.0",
|
|
31
|
+
"form-data": "^2.3.3",
|
|
32
32
|
"formidable": "^1.2.0",
|
|
33
33
|
"methods": "^1.1.1",
|
|
34
|
-
"mime": "^2.0
|
|
35
|
-
"qs": "^6.
|
|
36
|
-
"readable-stream": "^
|
|
34
|
+
"mime": "^2.4.0",
|
|
35
|
+
"qs": "^6.6.0",
|
|
36
|
+
"readable-stream": "^3.0.6"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"Base64": "^1.0.1",
|
|
@@ -42,16 +42,16 @@
|
|
|
42
42
|
"babelify": "^8.0.0",
|
|
43
43
|
"basic-auth-connect": "^1.0.0",
|
|
44
44
|
"body-parser": "^1.18.2",
|
|
45
|
-
"browserify": "^16.2.
|
|
45
|
+
"browserify": "^16.2.3",
|
|
46
46
|
"cookie-parser": "^1.4.3",
|
|
47
47
|
"express": "^4.16.3",
|
|
48
48
|
"express-session": "^1.15.6",
|
|
49
|
-
"marked": "^0.
|
|
49
|
+
"marked": "^0.5.2",
|
|
50
50
|
"mocha": "^3.5.3",
|
|
51
|
-
"multer": "^1.
|
|
51
|
+
"multer": "^1.4.1",
|
|
52
52
|
"should": "^13.2.0",
|
|
53
53
|
"should-http": "^0.1.1",
|
|
54
|
-
"zuul": "^3.
|
|
54
|
+
"zuul": "^3.12.0"
|
|
55
55
|
},
|
|
56
56
|
"browser": {
|
|
57
57
|
"./lib/node/index.js": "./lib/client.js",
|
package/superagent.js
CHANGED
|
@@ -274,6 +274,8 @@ RequestBase.prototype._retry = function () {
|
|
|
274
274
|
*/
|
|
275
275
|
|
|
276
276
|
RequestBase.prototype.then = function then(resolve, reject) {
|
|
277
|
+
var _this = this;
|
|
278
|
+
|
|
277
279
|
if (!this._fullfilledPromise) {
|
|
278
280
|
var self = this;
|
|
279
281
|
if (this._endCalled) {
|
|
@@ -281,6 +283,14 @@ RequestBase.prototype.then = function then(resolve, reject) {
|
|
|
281
283
|
}
|
|
282
284
|
this._fullfilledPromise = new Promise(function (innerResolve, innerReject) {
|
|
283
285
|
self.on('error', innerReject);
|
|
286
|
+
self.on('abort', function () {
|
|
287
|
+
var err = new Error('Aborted');
|
|
288
|
+
err.code = "ABORTED";
|
|
289
|
+
err.status = _this.status;
|
|
290
|
+
err.method = _this.method;
|
|
291
|
+
err.url = _this.url;
|
|
292
|
+
innerReject(err);
|
|
293
|
+
});
|
|
284
294
|
self.end(function (err, res) {
|
|
285
295
|
if (err) innerReject(err);else innerResolve(res);
|
|
286
296
|
});
|
|
@@ -1799,7 +1809,7 @@ Request.prototype.end = function (fn) {
|
|
|
1799
1809
|
// querystring
|
|
1800
1810
|
this._finalizeQueryString();
|
|
1801
1811
|
|
|
1802
|
-
|
|
1812
|
+
this._end();
|
|
1803
1813
|
};
|
|
1804
1814
|
|
|
1805
1815
|
Request.prototype._end = function () {
|
|
@@ -1901,7 +1911,6 @@ Request.prototype._end = function () {
|
|
|
1901
1911
|
// IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing)
|
|
1902
1912
|
// We need null here if data is undefined
|
|
1903
1913
|
xhr.send(typeof data !== 'undefined' ? data : null);
|
|
1904
|
-
return this;
|
|
1905
1914
|
};
|
|
1906
1915
|
|
|
1907
1916
|
request.agent = function () {
|