Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

got

Package Overview
Dependencies
Maintainers
4
Versions
178
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

got - npm Package Compare versions

Comparing version 6.7.1 to 7.0.0

256

index.js

@@ -14,9 +14,14 @@ 'use strict';

const lowercaseKeys = require('lowercase-keys');
const isRedirect = require('is-redirect');
const unzipResponse = require('unzip-response');
const createErrorClass = require('create-error-class');
const decompressResponse = require('decompress-response');
const isRetryAllowed = require('is-retry-allowed');
const Buffer = require('safe-buffer').Buffer;
const isURL = require('isurl');
const isPlainObj = require('is-plain-obj');
const PCancelable = require('p-cancelable');
const pTimeout = require('p-timeout');
const pkg = require('./package');
const getMethodRedirectCodes = new Set([300, 301, 302, 303, 304, 305, 307, 308]);
const allMethodRedirectCodes = new Set([300, 303, 307, 308]);
function requestAsEventEmitter(opts) {

@@ -27,3 +32,3 @@ opts = opts || {};

const requestUrl = opts.href || urlLib.resolve(urlLib.format(opts), opts.path);
let redirectCount = 0;
const redirects = [];
let retryCount = 0;

@@ -33,12 +38,35 @@ let redirectUrl;

const get = opts => {
const fn = opts.protocol === 'https:' ? https : http;
if (opts.protocol !== 'http:' && opts.protocol !== 'https:') {
ee.emit('error', new got.UnsupportedProtocolError(opts));
return;
}
let fn = opts.protocol === 'https:' ? https : http;
if (opts.useElectronNet && process.versions.electron) {
const electron = require('electron');
fn = electron.net || electron.remote.net;
}
const req = fn.request(opts, res => {
const statusCode = res.statusCode;
if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
res.url = redirectUrl || requestUrl;
res.requestUrl = requestUrl;
const followRedirect = opts.followRedirect && 'location' in res.headers;
const redirectGet = followRedirect && getMethodRedirectCodes.has(statusCode);
const redirectAll = followRedirect && allMethodRedirectCodes.has(statusCode);
if (redirectAll || (redirectGet && (opts.method === 'GET' || opts.method === 'HEAD'))) {
res.resume();
if (++redirectCount > 10) {
ee.emit('error', new got.MaxRedirectsError(statusCode, opts), null, res);
if (statusCode === 303) {
// Server responded with "see other", indicating that the resource exists at another location,
// and the client should request it from that location via GET or HEAD.
opts.method = 'GET';
}
if (redirects.length >= 10) {
ee.emit('error', new got.MaxRedirectsError(statusCode, redirects, opts), null, res);
return;

@@ -50,2 +78,5 @@ }

redirectUrl = urlLib.resolve(urlLib.format(opts), bufferString);
redirects.push(redirectUrl);
const redirectOpts = Object.assign({}, opts, urlLib.parse(redirectUrl));

@@ -61,6 +92,7 @@

setImmediate(() => {
const response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
response.url = redirectUrl || requestUrl;
response.requestUrl = requestUrl;
const response = typeof decompressResponse === 'function' &&
req.method !== 'HEAD' ? decompressResponse(res) : res;
response.redirectUrls = redirects;
ee.emit('response', response);

@@ -90,3 +122,5 @@ });

get(opts);
setImmediate(() => {
get(opts);
});
return ee;

@@ -96,6 +130,23 @@ }

function asPromise(opts) {
return new Promise((resolve, reject) => {
const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :
requestPromise;
return timeoutFn(new PCancelable((onCancel, resolve, reject) => {
const ee = requestAsEventEmitter(opts);
let cancelOnRequest = false;
onCancel(() => {
cancelOnRequest = true;
});
ee.on('request', req => {
if (cancelOnRequest) {
req.abort();
}
onCancel(() => {
req.abort();
});
if (isStream(opts.body)) {

@@ -125,8 +176,10 @@ opts.body.pipe(req);

} catch (e) {
throw new got.ParseError(e, statusCode, opts, data);
if (statusCode >= 200 && statusCode < 300) {
throw new got.ParseError(e, statusCode, opts, data);
}
}
}
if (statusCode < 200 || statusCode > limitStatusCode) {
throw new got.HTTPError(statusCode, opts);
if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
throw new got.HTTPError(statusCode, res.headers, opts);
}

@@ -143,3 +196,3 @@

ee.on('error', reject);
});
}));
}

@@ -151,3 +204,10 @@

const proxy = duplexer3(input, output);
let timeout;
if (opts.gotTimeout && opts.gotTimeout.request) {
timeout = setTimeout(() => {
proxy.emit('error', new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts));
}, opts.gotTimeout.request);
}
if (opts.json) {

@@ -187,2 +247,4 @@ throw new Error('got can not be used as stream when options.json is used');

ee.on('response', res => {
clearTimeout(timeout);
const statusCode = res.statusCode;

@@ -192,4 +254,4 @@

if (statusCode < 200 || statusCode > 299) {
proxy.emit('error', new got.HTTPError(statusCode, opts), null, res);
if (statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
proxy.emit('error', new got.HTTPError(statusCode, res.headers, opts), null, res);
return;

@@ -209,3 +271,3 @@ }

if (typeof url !== 'string' && typeof url !== 'object') {
throw new Error(`Parameter \`url\` must be a string or object, not ${typeof url}`);
throw new TypeError(`Parameter \`url\` must be a string or object, not ${typeof url}`);
}

@@ -222,9 +284,20 @@

if (isURL.lenient(url)) {
url = urlParseLax(url.href);
if (url.auth) {
throw new Error('Basic authentication must be done with auth option');
}
}
opts = Object.assign(
{
protocol: 'http:',
path: '',
retries: 5
retries: 2,
useElectronNet: true
},
url,
{
protocol: url.protocol || 'http:' // Override both null/undefined with default protocol
},
opts

@@ -253,27 +326,34 @@ );

let body = opts.body;
const body = opts.body;
if (body !== null && body !== undefined) {
const headers = opts.headers;
if (!isStream(body) && typeof body !== 'string' && !Buffer.isBuffer(body) && !(opts.form || opts.json)) {
throw new TypeError('options.body must be a ReadableStream, string, Buffer or plain Object');
}
if (body) {
if (typeof body !== 'string' && !(body !== null && typeof body === 'object')) {
throw new Error('options.body must be a ReadableStream, string, Buffer or plain Object');
if ((opts.form || opts.json) && !isPlainObj(body)) {
throw new TypeError('options.body must be a plain Object when options.form or options.json is used');
}
opts.method = opts.method || 'POST';
if (isStream(body) && typeof body.getBoundary === 'function') {
// Special case for https://github.com/form-data/form-data
opts.headers['content-type'] = opts.headers['content-type'] || `multipart/form-data; boundary=${body.getBoundary()}`;
} else if (body !== null && typeof body === 'object' && !Buffer.isBuffer(body) && !isStream(body)) {
opts.headers['content-type'] = opts.headers['content-type'] || 'application/x-www-form-urlencoded';
body = opts.body = querystring.stringify(body);
headers['content-type'] = headers['content-type'] || `multipart/form-data; boundary=${body.getBoundary()}`;
} else if (opts.form && isPlainObj(body)) {
headers['content-type'] = headers['content-type'] || 'application/x-www-form-urlencoded';
opts.body = querystring.stringify(body);
} else if (opts.json && isPlainObj(body)) {
headers['content-type'] = headers['content-type'] || 'application/json';
opts.body = JSON.stringify(body);
}
if (opts.headers['content-length'] === undefined && opts.headers['transfer-encoding'] === undefined && !isStream(body)) {
const length = typeof body === 'string' ? Buffer.byteLength(body) : body.length;
opts.headers['content-length'] = length;
if (headers['content-length'] === undefined && headers['transfer-encoding'] === undefined && !isStream(body)) {
const length = typeof opts.body === 'string' ? Buffer.byteLength(opts.body) : opts.body.length;
headers['content-length'] = length;
}
opts.method = (opts.method || 'POST').toUpperCase();
} else {
opts.method = (opts.method || 'GET').toUpperCase();
}
opts.method = (opts.method || 'GET').toUpperCase();
if (opts.hostname === 'unix') {

@@ -308,3 +388,7 @@ const matches = /(.+):(.+)/.exec(opts.path);

if (opts.timeout) {
opts.gotTimeout = opts.timeout;
if (typeof opts.timeout === 'number') {
opts.gotTimeout = {request: opts.timeout};
} else {
opts.gotTimeout = opts.timeout;
}
delete opts.timeout;

@@ -343,39 +427,73 @@ }

function stdError(error, opts) {
if (error.code !== undefined) {
this.code = error.code;
class StdError extends Error {
constructor(message, error, opts) {
super(message);
this.name = 'StdError';
if (error.code !== undefined) {
this.code = error.code;
}
Object.assign(this, {
host: opts.host,
hostname: opts.hostname,
method: opts.method,
path: opts.path,
protocol: opts.protocol,
url: opts.href
});
}
Object.assign(this, {
message: error.message,
host: opts.host,
hostname: opts.hostname,
method: opts.method,
path: opts.path
});
}
got.RequestError = createErrorClass('RequestError', stdError);
got.ReadError = createErrorClass('ReadError', stdError);
got.ParseError = createErrorClass('ParseError', function (e, statusCode, opts, data) {
stdError.call(this, e, opts);
this.statusCode = statusCode;
this.statusMessage = http.STATUS_CODES[this.statusCode];
this.message = `${e.message} in "${urlLib.format(opts)}": \n${data.slice(0, 77)}...`;
});
got.RequestError = class extends StdError {
constructor(error, opts) {
super(error.message, error, opts);
this.name = 'RequestError';
}
};
got.HTTPError = createErrorClass('HTTPError', function (statusCode, opts) {
stdError.call(this, {}, opts);
this.statusCode = statusCode;
this.statusMessage = http.STATUS_CODES[this.statusCode];
this.message = `Response code ${this.statusCode} (${this.statusMessage})`;
});
got.ReadError = class extends StdError {
constructor(error, opts) {
super(error.message, error, opts);
this.name = 'ReadError';
}
};
got.MaxRedirectsError = createErrorClass('MaxRedirectsError', function (statusCode, opts) {
stdError.call(this, {}, opts);
this.statusCode = statusCode;
this.statusMessage = http.STATUS_CODES[this.statusCode];
this.message = 'Redirected 10 times. Aborting.';
});
got.ParseError = class extends StdError {
constructor(error, statusCode, opts, data) {
super(`${error.message} in "${urlLib.format(opts)}": \n${data.slice(0, 77)}...`, error, opts);
this.name = 'ParseError';
this.statusCode = statusCode;
this.statusMessage = http.STATUS_CODES[this.statusCode];
}
};
got.HTTPError = class extends StdError {
constructor(statusCode, headers, opts) {
const statusMessage = http.STATUS_CODES[statusCode];
super(`Response code ${statusCode} (${statusMessage})`, {}, opts);
this.name = 'HTTPError';
this.statusCode = statusCode;
this.statusMessage = statusMessage;
this.headers = headers;
}
};
got.MaxRedirectsError = class extends StdError {
constructor(statusCode, redirectUrls, opts) {
super('Redirected 10 times. Aborting.', {}, opts);
this.name = 'MaxRedirectsError';
this.statusCode = statusCode;
this.statusMessage = http.STATUS_CODES[this.statusCode];
this.redirectUrls = redirectUrls;
}
};
got.UnsupportedProtocolError = class extends StdError {
constructor(opts) {
super(`Unsupported protocol "${opts.protocol}"`, {}, opts);
this.name = 'UnsupportedProtocolError';
}
};
module.exports = got;
{
"name": "got",
"version": "6.7.1",
"version": "7.0.0",
"description": "Simplified HTTP requests",

@@ -17,2 +17,7 @@ "license": "MIT",

"url": "github.com/floatdrop"
},
{
"name": "Alexander Tesfamichael",
"email": "alex.tesfamichael@gmail.com",
"url": "alextes.me"
}

@@ -23,5 +28,2 @@ ],

},
"browser": {
"unzip-response": false
},
"scripts": {

@@ -47,22 +49,27 @@ "test": "xo && nyc ava",

"wget",
"fetch"
"fetch",
"net",
"network",
"electron"
],
"dependencies": {
"create-error-class": "^3.0.0",
"decompress-response": "^3.2.0",
"duplexer3": "^0.1.4",
"get-stream": "^3.0.0",
"is-redirect": "^1.0.0",
"is-plain-obj": "^1.1.0",
"is-retry-allowed": "^1.0.0",
"is-stream": "^1.0.0",
"isurl": "^1.0.0-alpha5",
"lowercase-keys": "^1.0.0",
"p-cancelable": "^0.2.0",
"p-timeout": "^1.1.1",
"safe-buffer": "^5.0.1",
"timed-out": "^4.0.0",
"unzip-response": "^2.0.1",
"url-parse-lax": "^1.0.0"
},
"devDependencies": {
"ava": "^0.17.0",
"ava": "^0.19.1",
"coveralls": "^2.11.4",
"form-data": "^2.1.1",
"get-port": "^2.0.0",
"get-port": "^3.0.0",
"into-stream": "^3.0.0",

@@ -73,10 +80,12 @@ "nyc": "^10.0.0",

"tempfile": "^1.1.1",
"xo": "*"
"tempy": "^0.1.0",
"universal-url": "^1.0.0-alpha",
"xo": "^0.18.0"
},
"xo": {
"esnext": true
},
"ava": {
"concurrency": 4
},
"browser": {
"decompress-response": false
}
}

@@ -15,7 +15,9 @@ <h1 align="center">

It supports following redirects, promises, streams, retries, automagically handling gzip/deflate and some convenience options.
It supports following redirects, promises, streams, retries, automagically handling gzip/deflate, canceling of requests, and some convenience options.
Created because [`request`](https://github.com/request/request) is bloated *(several megabytes!)*.
When used with Electron, it takes advantage of [`electron.net`](https://electron.atom.io/docs/api/net/).
## Install

@@ -66,3 +68,3 @@

The URL to request or a [`http.request` options](https://nodejs.org/api/http.html#http_http_request_options_callback) object.
The URL to request as simple string, a [`http.request` options](https://nodejs.org/api/http.html#http_http_request_options_callback), or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).

@@ -79,3 +81,3 @@ Properties from `options` will override properties in the parsed `url`.

Type: `string`, `buffer`, `readableStream`, `object`
Type: `string`, `buffer`, `readableStream`

@@ -90,4 +92,2 @@ *This is mutually exclusive with stream mode.*

If `body` is a plain object, it will be stringified with [`querystring.stringify`](https://nodejs.org/api/querystring.html#querystring_querystring_stringify_obj_sep_eq_options) and sent as `application/x-www-form-urlencoded`.
###### encoding

@@ -100,2 +100,13 @@

###### form
Type: `boolean`<br>
Default: `false`
*This is mutually exclusive with stream mode.*
If set to `true` and `Content-Type` header is not set, it will be set to `application/x-www-form-urlencoded`.
`body` must be a plain object and will be stringified.
###### json

@@ -108,4 +119,8 @@

Parse response body with `JSON.parse` and set `accept` header to `application/json`.
If set to `true` and `Content-Type` header is not set, it will be set to `application/json`.
Parse response body with `JSON.parse` and set `accept` header to `application/json`. If used in conjunction with the `form` option, the `body` will the stringified as querystring and the response parsed as JSON.
`body` must be a plain object and will be stringified.
###### query

@@ -121,5 +136,5 @@

Milliseconds to wait for a server to send response headers before aborting request with `ETIMEDOUT` error.
Milliseconds to wait for the server to end the response before aborting request with `ETIMEDOUT` error.
Option accepts `object` with separate `connect` and `socket` fields for connection and socket inactivity timeouts.
This also accepts an object with separate `connect`, `socket`, and `request` fields for connection, socket, and entire request timeouts.

@@ -129,3 +144,3 @@ ###### retries

Type: `number`, `function`<br>
Default: `5`
Default: `2`

@@ -145,3 +160,13 @@ 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).

Note that if a `303` is sent by the server in response to any request type (`POST`, `DELETE`, etc.), got will automatically
request the resource pointed to in the location header via `GET`. This is in accordance with [the spec](https://tools.ietf.org/html/rfc7231#section-6.4.4).
###### useElectronNet
Type: `boolean`<br>
Default: `true`
When used in Electron, Got will automatically use [`electron.net`](https://electron.atom.io/docs/api/net/) instead of the Node.js `http` module. It should be fully compatible, but you can turn it off here if you encounter a problem. Please open an issue if you do!
#### Streams

@@ -188,3 +213,3 @@

Each error contains (if available) `statusCode`, `statusMessage`, `host`, `hostname`, `method` and `path` properties to make debugging easier.
Each error contains (if available) `statusCode`, `statusMessage`, `host`, `hostname`, `method`, `path`, `protocol` and `url` properties to make debugging easier.

@@ -203,13 +228,22 @@ In Promise mode, the `response` is attached to the error.

When `json` option is enabled and `JSON.parse` fails.
When `json` option is enabled, server response code is 2xx, and `JSON.parse` fails.
#### got.HTTPError
When server response code is not 2xx. Contains `statusCode` and `statusMessage`.
When server response code is not 2xx. Includes `statusCode`, `statusMessage`, and `redirectUrls` properties.
#### got.MaxRedirectsError
When server redirects you more than 10 times.
When server redirects you more than 10 times. Includes a `redirectUrls` property, which is an array of the URLs Got was redirected to before giving up.
#### got.UnsupportedProtocolError
When given an unsupported protocol.
## Aborting the request
The promise returned by Got has a `.cancel()` function which, when called, aborts the request.
## Proxies

@@ -314,5 +348,46 @@

## AWS
## Tip
Requests to AWS services need to have their headers signed. This can be accomplished by using the [`aws4`](https://www.npmjs.com/package/aws4) package. This is an example for querying an ["Elasticsearch Service"](https://aws.amazon.com/elasticsearch-service/) host with a signed request.
```js
const url = require('url');
const AWS = require('aws-sdk');
const aws4 = require('aws4');
const got = require('got');
const config = require('./config');
// Reads keys from the environment or `~/.aws/credentials`. Could be a plain object.
const awsConfig = new AWS.Config({ region: config.region });
function request(uri, options) {
const awsOpts = {
region: awsConfig.region,
headers: {
accept: 'application/json',
'content-type': 'application/json'
},
method: 'GET',
json: true
};
// We need to parse the URL before passing it to `got` so `aws4` can sign the request
const opts = Object.assign(url.parse(uri), awsOpts, options);
aws4.sign(opts, awsConfig.credentials);
return got(opts);
}
request(`https://${config.host}/production/users/1`);
request(`https://${config.host}/production/`, {
// All usual `got` options
});
```
## Tips
### User Agent
It's a good idea to set the `'user-agent'` header so the provider can more easily see how their resource is used. By default, it's the URL to this repo.

@@ -331,3 +406,7 @@

### 304 Responses
Bear in mind, if you send an `if-modified-since` header and receive a `304 Not Modified` response, the body will be empty. It's your responsibility to cache and retrieve the body contents.
## Related

@@ -341,5 +420,5 @@

[![Sindre Sorhus](https://avatars.githubusercontent.com/u/170270?v=3&s=100)](https://sindresorhus.com) | [![Vsevolod Strukchinsky](https://avatars.githubusercontent.com/u/365089?v=3&s=100)](https://github.com/floatdrop)
---|---
[Sindre Sorhus](https://sindresorhus.com) | [Vsevolod Strukchinsky](https://github.com/floatdrop)
[![Sindre Sorhus](https://avatars.githubusercontent.com/u/170270?v=3&s=100)](https://sindresorhus.com) | [![Vsevolod Strukchinsky](https://avatars.githubusercontent.com/u/365089?v=3&s=100)](https://github.com/floatdrop) | [![Alexander Tesfamichael](https://avatars.githubusercontent.com/u/2011351?v=3&s=100)](https://alextes.me)
---|---|---
[Sindre Sorhus](https://sindresorhus.com) | [Vsevolod Strukchinsky](https://github.com/floatdrop) | [Alexander Tesfamichael](https://alextes.me)

@@ -349,2 +428,2 @@

MIT © [Sindre Sorhus](https://sindresorhus.com)
MIT
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc