got 5.5.0 → 5.7.1

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.
Files changed (3) hide show
  1. package/index.js +35 -20
  2. package/package.json +10 -9
  3. package/readme.md +62 -5
package/index.js CHANGED
@@ -18,7 +18,6 @@ var PinkiePromise = require('pinkie-promise');
18
18
  var unzipResponse = require('unzip-response');
19
19
  var createErrorClass = require('create-error-class');
20
20
  var nodeStatusCodes = require('node-status-codes');
21
- var isPlainObj = require('is-plain-obj');
22
21
  var parseJson = require('parse-json');
23
22
  var isRetryAllowed = require('is-retry-allowed');
24
23
  var pkg = require('./package.json');
@@ -27,8 +26,10 @@ function requestAsEventEmitter(opts) {
27
26
  opts = opts || {};
28
27
 
29
28
  var ee = new EventEmitter();
29
+ var requestUrl = opts.href || urlLib.resolve(urlLib.format(opts), opts.path);
30
30
  var redirectCount = 0;
31
31
  var retryCount = 0;
32
+ var redirectUrl;
32
33
 
33
34
  var get = function (opts) {
34
35
  var fn = opts.protocol === 'https:' ? https : http;
@@ -36,7 +37,7 @@ function requestAsEventEmitter(opts) {
36
37
  var req = fn.request(opts, function (res) {
37
38
  var statusCode = res.statusCode;
38
39
 
39
- if (isRedirect(statusCode) && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
40
+ if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
40
41
  res.resume();
41
42
 
42
43
  if (++redirectCount > 10) {
@@ -44,7 +45,7 @@ function requestAsEventEmitter(opts) {
44
45
  return;
45
46
  }
46
47
 
47
- var redirectUrl = urlLib.resolve(urlLib.format(opts), res.headers.location);
48
+ redirectUrl = urlLib.resolve(urlLib.format(opts), res.headers.location);
48
49
  var redirectOpts = objectAssign({}, opts, urlLib.parse(redirectUrl));
49
50
 
50
51
  ee.emit('redirect', res, redirectOpts);
@@ -55,7 +56,11 @@ function requestAsEventEmitter(opts) {
55
56
 
56
57
  // do not write ee.bind(...) instead of function - it will break gzip in Node.js 0.10
57
58
  setImmediate(function () {
58
- ee.emit('response', typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res);
59
+ var response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
60
+ response.url = redirectUrl || requestUrl;
61
+ response.requestUrl = requestUrl;
62
+
63
+ ee.emit('response', response);
59
64
  });
60
65
  });
61
66
 
@@ -94,28 +99,29 @@ function asCallback(opts, cb) {
94
99
  });
95
100
 
96
101
  ee.on('response', function (res) {
97
- readAllStream(res, opts.encoding, function (err, data) {
102
+ readAllStream(res, opts.encoding, function (error, data) {
98
103
  var statusCode = res.statusCode;
104
+ var limitStatusCode = opts.followRedirect ? 299 : 399;
99
105
 
100
- if (err) {
101
- cb(new got.ReadError(err, opts), null, res);
106
+ if (error) {
107
+ cb(new got.ReadError(error, opts), null, res);
102
108
  return;
103
109
  }
104
110
 
105
- if (statusCode < 200 || statusCode > 299) {
106
- err = new got.HTTPError(statusCode, opts);
111
+ if (statusCode < 200 || statusCode > limitStatusCode) {
112
+ error = new got.HTTPError(statusCode, opts);
107
113
  }
108
114
 
109
115
  if (opts.json && data) {
110
116
  try {
111
117
  data = parseJson(data);
112
- } catch (e) {
113
- e.fileName = urlLib.format(opts);
114
- err = new got.ParseError(e, statusCode, opts);
118
+ } catch (err) {
119
+ err.fileName = urlLib.format(opts);
120
+ error = new got.ParseError(err, statusCode, opts);
115
121
  }
116
122
  }
117
123
 
118
- cb(err, data, res);
124
+ cb(error, data, res);
119
125
  });
120
126
  });
121
127
 
@@ -183,10 +189,11 @@ function asStream(opts) {
183
189
 
184
190
  ee.on('response', function (res) {
185
191
  var statusCode = res.statusCode;
192
+ var limitStatusCode = opts.followRedirect ? 299 : 399;
186
193
 
187
194
  res.pipe(output);
188
195
 
189
- if (statusCode < 200 || statusCode > 299) {
196
+ if (statusCode < 200 || statusCode > limitStatusCode) {
190
197
  proxy.emit('error', new got.HTTPError(statusCode, opts), null, res);
191
198
  return;
192
199
  }
@@ -207,6 +214,7 @@ function normalizeArguments(url, opts) {
207
214
  }
208
215
 
209
216
  if (typeof url === 'string') {
217
+ url = url.replace(/^unix:/, 'http://$&');
210
218
  url = urlParseLax(url);
211
219
 
212
220
  if (url.auth) {
@@ -243,13 +251,16 @@ function normalizeArguments(url, opts) {
243
251
  var body = opts.body;
244
252
 
245
253
  if (body) {
246
- if (typeof body !== 'string' && !Buffer.isBuffer(body) && !isStream(body) && !isPlainObj(body)) {
254
+ if (typeof body !== 'string' && !(body !== null && typeof body === 'object')) {
247
255
  throw new Error('options.body must be a ReadableStream, string, Buffer or plain Object');
248
256
  }
249
257
 
250
258
  opts.method = opts.method || 'POST';
251
259
 
252
- if (isPlainObj(body)) {
260
+ if (isStream(body) && typeof body.getBoundary === 'function') {
261
+ // Special case for https://github.com/form-data/form-data
262
+ opts.headers['content-type'] = opts.headers['content-type'] || 'multipart/form-data; boundary=' + body.getBoundary();
263
+ } else if (body !== null && typeof body === 'object' && !Buffer.isBuffer(body) && !isStream(body)) {
253
264
  opts.headers['content-type'] = opts.headers['content-type'] || 'application/x-www-form-urlencoded';
254
265
  body = opts.body = querystring.stringify(body);
255
266
  }
@@ -265,7 +276,7 @@ function normalizeArguments(url, opts) {
265
276
  opts.method = opts.method.toUpperCase();
266
277
 
267
278
  if (opts.hostname === 'unix') {
268
- var matches = /(.+)\:(.+)/.exec(opts.path);
279
+ var matches = /(.+):(.+)/.exec(opts.path);
269
280
 
270
281
  if (matches) {
271
282
  opts.socketPath = matches[1];
@@ -282,10 +293,14 @@ function normalizeArguments(url, opts) {
282
293
  }
283
294
 
284
295
  var noise = Math.random() * 100;
285
- return (1 << iter) * 1000 + noise;
296
+ return ((1 << iter) * 1000) + noise;
286
297
  };
287
298
  }
288
299
 
300
+ if (opts.followRedirect === undefined) {
301
+ opts.followRedirect = true;
302
+ }
303
+
289
304
  return opts;
290
305
  }
291
306
 
@@ -302,8 +317,8 @@ function got(url, opts, cb) {
302
317
 
303
318
  try {
304
319
  return asPromise(normalizeArguments(url, opts));
305
- } catch (error) {
306
- return PinkiePromise.reject(error);
320
+ } catch (err) {
321
+ return PinkiePromise.reject(err);
307
322
  }
308
323
  }
309
324
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "5.5.0",
3
+ "version": "5.7.1",
4
4
  "description": "Simplified HTTP/HTTPS requests",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
@@ -17,7 +17,7 @@
17
17
  }
18
18
  ],
19
19
  "engines": {
20
- "node": ">=0.10.0"
20
+ "node": ">=0.10.0 <7"
21
21
  },
22
22
  "browser": {
23
23
  "unzip-response": false
@@ -45,9 +45,8 @@
45
45
  "fetch"
46
46
  ],
47
47
  "dependencies": {
48
- "create-error-class": "^2.0.0",
48
+ "create-error-class": "^3.0.1",
49
49
  "duplexer2": "^0.1.4",
50
- "is-plain-obj": "^1.0.0",
51
50
  "is-redirect": "^1.0.0",
52
51
  "is-retry-allowed": "^1.0.0",
53
52
  "is-stream": "^1.0.0",
@@ -58,20 +57,22 @@
58
57
  "pinkie-promise": "^2.0.0",
59
58
  "read-all-stream": "^3.0.0",
60
59
  "readable-stream": "^2.0.5",
61
- "timed-out": "^2.0.0",
62
- "unzip-response": "^1.0.0",
60
+ "timed-out": "^3.0.0",
61
+ "unzip-response": "^1.0.2",
63
62
  "url-parse-lax": "^1.0.0"
64
63
  },
65
64
  "devDependencies": {
66
- "ava": "^0.5.0",
65
+ "ava": "^0.16.0",
67
66
  "coveralls": "^2.11.4",
67
+ "form-data": "^2.1.1",
68
68
  "get-port": "^2.0.0",
69
+ "get-stream": "^2.3.0",
69
70
  "into-stream": "^2.0.0",
70
- "nyc": "^3.2.2",
71
+ "nyc": "^8.1.0",
71
72
  "pem": "^1.4.4",
72
73
  "pify": "^2.3.0",
73
74
  "tempfile": "^1.1.1",
74
- "xo": "*"
75
+ "xo": "0.16.x"
75
76
  },
76
77
  "xo": {
77
78
  "ignores": [
package/readme.md CHANGED
@@ -60,6 +60,10 @@ It's a `GET` request by default, but can be changed in `options`.
60
60
 
61
61
  #### got(url, [options], [callback])
62
62
 
63
+ Returns a Promise for a `response` object with a `body` property, a `url` property with the request URL or the final URL after redirects, and a `requestUrl` property with the original request URL.
64
+
65
+ Otherwise calls callback with `response` object (same as in previous case).
66
+
63
67
  ##### url
64
68
 
65
69
  Type: `string`, `object`
@@ -121,12 +125,19 @@ Milliseconds after which the request will be aborted and an error event with `ET
121
125
  Type: `number`, `function`
122
126
  Default: `5`
123
127
 
124
- Number of request retries when network errors happens. Delays between retries counts with function `Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 0).
125
-
126
- **Note:** `ENOTFOUND` and `ENETUNREACH` error will not be retried (see full list in [`is-retry-allowed`](https://github.com/floatdrop/is-retry-allowed/blob/master/index.js#L12) module).
128
+ Number of request retries when network errors happens. Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 0).
127
129
 
128
130
  Option accepts `function` with `retry` and `error` arguments. Function must return delay in milliseconds (`0` return value cancels retry).
129
131
 
132
+ **Note:** if `retries` is `number`, `ENOTFOUND` and `ENETUNREACH` error will not be retried (see full list in [`is-retry-allowed`](https://github.com/floatdrop/is-retry-allowed/blob/master/index.js#L12) module).
133
+
134
+ ###### followRedirect
135
+
136
+ Type: `boolean`<br>
137
+ Default: `true`
138
+
139
+ Defines if redirect responses should be followed automatically.
140
+
130
141
  ##### callback(error, data, response)
131
142
 
132
143
  Function to be called when error or data are received. If omitted, a promise will be returned.
@@ -135,8 +146,6 @@ Function to be called when error or data are received. If omitted, a promise wil
135
146
 
136
147
  `Error` object with HTTP status code as `statusCode` property.
137
148
 
138
- ###### data
139
-
140
149
  The data you requested.
141
150
 
142
151
  ###### response
@@ -239,6 +248,54 @@ got('google.com', {
239
248
  ```
240
249
 
241
250
 
251
+ ## Form data
252
+
253
+ You can use the [`form-data`](https://github.com/form-data/form-data) module to create POST request with form data:
254
+
255
+ ```js
256
+ const fs = require('fs');
257
+ const got = require('got');
258
+ const FormData = require('form-data');
259
+ const form = new FormData();
260
+
261
+ form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
262
+
263
+ got.post('google.com', {
264
+ body: form
265
+ });
266
+ ```
267
+
268
+
269
+ ## OAuth
270
+
271
+ You can use the [`oauth-1.0a`](https://github.com/ddo/oauth-1.0a) module to create a signed OAuth request:
272
+
273
+ ```js
274
+ const got = require('got');
275
+ const OAuth = require('oauth-1.0a');
276
+
277
+ const oauth = OAuth({
278
+ consumer: {
279
+ public: process.env.CONSUMER_KEY,
280
+ secret: process.env.CONSUMER_SECRET
281
+ },
282
+ signature_method: 'HMAC-SHA1'
283
+ });
284
+
285
+ const token = {
286
+ public: process.env.ACCESS_TOKEN,
287
+ secret: process.env.ACCESS_TOKEN_SECRET
288
+ };
289
+
290
+ const url = 'https://api.twitter.com/1.1/statuses/home_timeline.json';
291
+
292
+ got(url, {
293
+ headers: oauth.toHeader(oauth.authorize({url, method: 'GET'}, token)),
294
+ json: true
295
+ });
296
+ ```
297
+
298
+
242
299
  ## Unix Domain Sockets
243
300
 
244
301
  Requests can also be sent via [unix domain sockets](http://serverfault.com/questions/124517/whats-the-difference-between-unix-socket-and-tcp-ip-socket). Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH`.