Socket
Socket
Sign inDemoInstall

node-fetch

Package Overview
Dependencies
4
Maintainers
4
Versions
96
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.0-beta.9 to 3.0.0-beta.10

@types/index.d.ts

79

package.json
{
"name": "node-fetch",
"version": "3.0.0-beta.9",
"version": "3.0.0-beta.10",
"description": "A light-weight module that brings Fetch API to node.js",
"main": "./dist/index.cjs",
"module": "./src/index.js",
"main": "./src/index.js",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"import": "./src/index.js",
"require": "./dist/index.cjs"
},
"./package.json": "./package.json"
},
"files": [
"src",
"dist",
"@types/index.d.ts"

@@ -23,11 +14,9 @@ ],

"engines": {
"node": "^10.17 || >=12.3"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"build": "rollup -c",
"test": "node --experimental-modules node_modules/c8/bin/c8 --reporter=html --reporter=lcov --reporter=text --check-coverage node --experimental-modules node_modules/mocha/bin/mocha",
"test": "mocha",
"coverage": "c8 report --reporter=text-lcov | coveralls",
"test-types": "tsd",
"lint": "xo",
"prepublishOnly": "node ./test/commonjs/test-artifact.js"
"lint": "xo"
},

@@ -60,6 +49,6 @@ "repository": {

"abort-controller": "^3.0.0",
"abortcontroller-polyfill": "^1.5.0",
"abortcontroller-polyfill": "^1.7.1",
"busboy": "^0.3.1",
"c8": "^7.3.0",
"chai": "^4.2.0",
"c8": "^7.7.2",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",

@@ -69,28 +58,18 @@ "chai-iterator": "^3.0.2",

"coveralls": "^3.1.0",
"delay": "^4.4.0",
"form-data": "^3.0.0",
"formdata-node": "^2.4.0",
"mocha": "^8.1.3",
"p-timeout": "^3.2.0",
"rollup": "^2.26.10",
"tsd": "^0.13.1",
"xo": "^0.33.1"
"delay": "^5.0.0",
"form-data": "^4.0.0",
"formdata-node": "^3.5.4",
"mocha": "^8.3.2",
"p-timeout": "^5.0.0",
"tsd": "^0.14.0",
"xo": "^0.39.1"
},
"dependencies": {
"data-uri-to-buffer": "^3.0.1",
"fetch-blob": "^2.1.1"
"fetch-blob": "^3.1.2"
},
"esm": {
"sourceMap": true,
"cjs": false
},
"tsd": {
"cwd": "@types",
"compilerOptions": {
"target": "esnext",
"lib": [
"es2018"
],
"allowSyntheticDefaultImports": false,
"esModuleInterop": false
"esModuleInterop": true
}

@@ -103,2 +82,5 @@ },

],
"ignores": [
"example.js"
],
"rules": {

@@ -109,10 +91,11 @@ "complexity": 0,

"import/no-anonymous-default-export": 0,
"import/no-named-as-default": 0,
"unicorn/import-index": 0,
"unicorn/no-reduce": 0,
"capitalized-comments": 0
"unicorn/no-array-reduce": 0,
"unicorn/prefer-node-protocol": 0,
"unicorn/numeric-separators-style": 0,
"unicorn/explicit-length-check": 0,
"capitalized-comments": 0,
"@typescript-eslint/member-ordering": 0
},
"ignores": [
"dist",
"@types"
],
"overrides": [

@@ -128,4 +111,6 @@ {

"no-unused-expressions": 0,
"no-warning-comments": 0,
"new-cap": 0,
"guard-for-in": 0,
"unicorn/no-array-for-each": 0,
"unicorn/prevent-abbreviations": 0,

@@ -135,8 +120,2 @@ "promise/prefer-await-to-then": 0,

}
},
{
"files": "example.js",
"rules": {
"import/no-extraneous-dependencies": 0
}
}

@@ -143,0 +122,0 @@ ]

<div align="center">
<img src="docs/media/Banner.svg" alt="Node Fetch"/>
<br>
<p>A light-weight module that brings <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> to Node.js.</p>
<img src="docs/media/Banner.svg" alt="Node Fetch"/>
<br>
<p>A light-weight module that brings <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> to Node.js.</p>
<a href="https://github.com/node-fetch/node-fetch/actions"><img src="https://github.com/node-fetch/node-fetch/workflows/CI/badge.svg?branch=master" alt="Build status"></a>

@@ -59,2 +59,3 @@ <a href="https://coveralls.io/github/node-fetch/node-fetch"><img src="https://img.shields.io/coveralls/github/node-fetch/node-fetch" alt="Coverage status"></a>

- [response.redirected](#responseredirected)
- [response.type](#responsetype)
- [Class: Headers](#class-headers)

@@ -105,6 +106,6 @@ - [new Headers([init])](#new-headersinit)

Current stable release (`3.x`)
Current stable release (`3.x`) requires at least Node.js 12.20.0.
```sh
$ npm install node-fetch
npm install node-fetch
```

@@ -115,6 +116,2 @@

```js
// CommonJS
const fetch = require('node-fetch');
// ES Module
import fetch from 'node-fetch';

@@ -126,11 +123,9 @@ ```

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
if (!globalThis.fetch) {
globalThis.fetch = fetch;
globalThis.fetch = fetch;
}
```
For versions of Node earlier than 12, use this `globalThis` [polyfill](https://mathiasbynens.be/notes/globalthis).
## Upgrading

@@ -151,10 +146,8 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://github.com/');
const body = await response.text();
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
})();
console.log(body);
```

@@ -165,10 +158,8 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://api.github.com/users/github');
const json = await response.json();
const response = await fetch('https://api.github.com/users/github');
const data = await response.json();
console.log(json);
})();
console.log(data);
```

@@ -179,10 +170,8 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'});
const json = await response.json();
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'});
const data = await response.json();
console.log(json);
})();
console.log(data);
```

@@ -193,16 +182,14 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const body = {a: 1};
const body = {a: 1};
const response = await fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const json = await response.json();
const response = await fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const data = await response.json();
console.log(json);
})();
console.log(data);
```

@@ -217,3 +204,3 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';

@@ -223,8 +210,6 @@ const params = new URLSearchParams();

(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: params});
const json = await response.json();
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: params});
const data = await response.json();
console.log(json);
})();
console.log(data);
```

@@ -239,6 +224,6 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
try {
fetch('https://domain.invalid/');
await fetch('https://domain.invalid/');
} catch (error) {

@@ -254,19 +239,30 @@ console.log(error);

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
const checkStatus = res => {
if (res.ok) {
// res.status >= 200 && res.status < 300
return res;
class HTTPResponseError extends Error {
constructor(response, ...args) {
this.response = response;
super(`HTTP Error Response: ${response.status} ${response.statusText}`, ...args);
}
}
const checkStatus = response => {
if (response.ok) {
// response.status >= 200 && response.status < 300
return response;
} else {
throw MyCustomError(res.statusText);
throw new HTTPResponseError(response);
}
}
(async () => {
const response = await fetch('https://httpbin.org/status/400');
const data = checkStatus(response);
const response = await fetch('https://httpbin.org/status/400');
console.log(data); //=> MyCustomError
})();
try {
checkStatus(response);
} catch (error) {
console.error(error);
const errorBody = await error.response.text();
console.error(`Error body: ${errorBody}`);
}
```

@@ -285,15 +281,63 @@

```js
const util = require('util');
const fs = require('fs');
const streamPipeline = util.promisify(require('stream').pipeline);
import {createWriteStream} from 'fs';
import {pipeline} from 'stream';
import {promisify} from 'util'
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png');
if (response.ok) {
return streamPipeline(response.body, fs.createWriteStream('./octocat.png'));
const streamPipeline = promisify(pipeline);
const response = await fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png');
if (!response.ok) throw new Error(`unexpected response ${response.statusText}`);
await streamPipeline(response.body, createWriteStream('./octocat.png'));
```
In Node.js 14 you can also use async iterators to read `body`; however, be careful to catch
errors -- the longer a response runs, the more likely it is to encounter an error.
```js
import fetch from 'node-fetch';
const response = await fetch('https://httpbin.org/stream/3');
try {
for await (const chunk of response.body) {
console.dir(JSON.parse(chunk.toString()));
}
} catch (err) {
console.error(err.stack);
}
```
throw new Error(`unexpected response ${response.statusText}`);
})();
In Node.js 12 you can also use async iterators to read `body`; however, async iterators with streams
did not mature until Node.js 14, so you need to do some extra work to ensure you handle errors
directly from the stream and wait on it response to fully close.
```js
import fetch from 'node-fetch';
const read = async body => {
let error;
body.on('error', err => {
error = err;
});
for await (const chunk of body) {
console.dir(JSON.parse(chunk.toString()));
}
return new Promise((resolve, reject) => {
body.on('close', () => {
error ? reject(error) : resolve();
});
});
};
try {
const response = await fetch('https://httpbin.org/stream/3');
await read(response.body);
} catch (err) {
console.error(err.stack);
}
```

@@ -306,12 +350,10 @@

```js
const fetch = require('node-fetch');
const fileType = require('file-type');
import fetch from 'node-fetch';
import fileType from 'file-type';
(async () => {
const response = await fetch('https://octodex.github.com/images/Fintechtocat.png');
const buffer = await response.buffer();
const type = fileType.fromBuffer(buffer)
console.log(type);
})();
const response = await fetch('https://octodex.github.com/images/Fintechtocat.png');
const buffer = await response.buffer();
const type = await fileType.fromBuffer(buffer)
console.log(type);
```

@@ -322,13 +364,11 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://github.com/');
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers.raw());
console.log(response.headers.get('content-type'));
})();
const response = await fetch('https://github.com/');
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers.raw());
console.log(response.headers.get('content-type'));
```

@@ -341,10 +381,8 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://example.com');
// Returns an array of values, instead of a string of comma-separated values
console.log(response.headers.raw()['set-cookie']);
})();
const response = await fetch('https://example.com');
// Returns an array of values, instead of a string of comma-separated values
console.log(response.headers.raw()['set-cookie']);
```

@@ -355,62 +393,32 @@

```js
const {createReadStream} = require('fs');
const fetch = require('node-fetch');
import {createReadStream} from 'fs';
import fetch from 'node-fetch';
const stream = createReadStream('input.txt');
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: stream});
const json = await response.json();
console.log(json)
})();
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: stream});
const data = await response.json();
console.log(data)
```
### Post with form-data (detect multipart)
node-fetch also supports spec-compliant FormData implementations such as [formdata-polyfill](https://www.npmjs.com/package/formdata-polyfill) and [formdata-node](https://github.com/octet-stream/form-data):
```js
const fetch = require('node-fetch');
const FormData = require('form-data');
import fetch from 'node-fetch';
import {FormData} from 'formdata-polyfill/esm-min.js';
// Alternative package:
import {FormData} from 'formdata-node';
const form = new FormData();
form.append('a', 1);
form.set('greeting', 'Hello, world!');
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: form});
const json = await response.json();
console.log(json)
})();
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: form});
const data = await response.json();
// OR, using custom headers
// NOTE: getHeaders() is non-standard API
const options = {
method: 'POST',
body: form,
headers: form.getHeaders()
};
(async () => {
const response = await fetch('https://httpbin.org/post', options);
const json = await response.json();
console.log(json)
})();
console.log(data);
```
node-fetch also supports spec-compliant FormData implementations such as [formdata-node](https://github.com/octet-stream/form-data):
node-fetch also support form-data but it's now discouraged due to not being spec-compliant and needs workarounds to function - which we hope to remove one day
```js
const fetch = require('node-fetch');
const FormData = require('formdata-node');
const form = new FormData();
form.set('greeting', 'Hello, world!');
fetch('https://httpbin.org/post', {method: 'POST', body: form})
.then(res => res.json())
.then(json => console.log(json));
```
### Request cancellation with AbortSignal

@@ -423,4 +431,4 @@

```js
const fetch = require('node-fetch');
const AbortController = require('abort-controller');
import fetch from 'node-fetch';
import AbortController from 'abort-controller';

@@ -432,16 +440,12 @@ const controller = new AbortController();

(async () => {
try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
useData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('request was aborted');
}
} finally {
clearTimeout(timeout);
try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
} catch (error) {
if (error instanceof fetch.AbortError) {
console.log('request was aborted');
}
})();
} finally {
clearTimeout(timeout);
}
```

@@ -471,16 +475,16 @@

{
// These properties are part of the Fetch Standard
method: 'GET',
headers: {}, // Request headers. format is the identical to that accepted by the Headers constructor (see below)
body: null, // Request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream
redirect: 'follow', // Set to `manual` to extract redirect headers, `error` to reject redirect
signal: null, // Pass an instance of AbortSignal to optionally abort requests
// These properties are part of the Fetch Standard
method: 'GET',
headers: {}, // Request headers. format is the identical to that accepted by the Headers constructor (see below)
body: null, // Request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream
redirect: 'follow', // Set to `manual` to extract redirect headers, `error` to reject redirect
signal: null, // Pass an instance of AbortSignal to optionally abort requests
// The following properties are node-fetch extensions
follow: 20, // maximum redirect count. 0 to not follow redirect
compress: true, // support gzip/deflate content encoding. false to disable
size: 0, // maximum response body size in bytes. 0 to disable
agent: null, // http(s).Agent instance or function that returns an instance (see below)
highWaterMark: 16384, // the maximum number of bytes to store in the internal buffer before ceasing to read from the underlying resource.
insecureHTTPParser: false // Use an insecure HTTP parser that accepts invalid HTTP headers when `true`.
// The following properties are node-fetch extensions
follow: 20, // maximum redirect count. 0 to not follow redirect
compress: true, // support gzip/deflate content encoding. false to disable
size: 0, // maximum response body size in bytes. 0 to disable
agent: null, // http(s).Agent instance or function that returns an instance (see below)
highWaterMark: 16384, // the maximum number of bytes to store in the internal buffer before ceasing to read from the underlying resource.
insecureHTTPParser: false // Use an insecure HTTP parser that accepts invalid HTTP headers when `true`.
}

@@ -518,4 +522,4 @@ ```

```js
const http = require('http');
const https = require('https');
import http from 'http';
import https from 'https';

@@ -549,13 +553,11 @@ const httpAgent = new http.Agent({

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://example.com');
const r1 = await response.clone();
return Promise.all([res.json(), r1.text()]).then(results => {
console.log(results[0]);
console.log(results[1]);
});
})();
const response = await fetch('https://example.com');
const r1 = await response.clone();
const results = await Promise.all([response.json(), r1.text()]);
console.log(results[0]);
console.log(results[1]);
```

@@ -566,12 +568,11 @@

```js
const fetch = require('node-fetch');
import fetch from 'node-fetch';
(async () => {
const response = await fetch('https://example.com', {
// About 1MB
highWaterMark: 1024 * 1024
});
return res.clone().buffer();
})();
const response = await fetch('https://example.com', {
// About 1MB
highWaterMark: 1024 * 1024
});
const result = await res.clone().buffer();
console.dir(result);
```

@@ -631,5 +632,2 @@

- `Response.error()`
- `Response.redirect()`
- `type`
- `trailer`

@@ -660,2 +658,8 @@

#### response.type
<small>_(deviation from spec)_</small>
Convenience property representing the response's type. node-fetch only supports `'default'` and `'error'` and does not make use of [filtered responses](https://fetch.spec.whatwg.org/#concept-filtered-response).
<a id="class-headers"></a>

@@ -677,3 +681,3 @@

// Example adapted from https://fetch.spec.whatwg.org/#example-headers-class
const { Headers } = require('node-fetch');
import {Headers} from 'node-fetch';

@@ -769,3 +773,3 @@ const meta = {

```sh
$ npm install --save-dev @types/node-fetch
npm install --save-dev @types/node-fetch
```

@@ -781,3 +785,3 @@

| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| [David Frank](https://bitinn.net/) | [Jimmy Wärting](https://jimmy.warting.se/) | [Antoni Kepinski](https://kepinski.me) | [Richie Bendall](https://www.richie-bendall.ml/) | [Gregor Martynus](https://twitter.com/gr2m) |
| [David Frank](https://bitinn.net/) | [Jimmy Wärting](https://jimmy.warting.se/) | [Antoni Kepinski](https://kepinski.ch) | [Richie Bendall](https://www.richie-bendall.ml/) | [Gregor Martynus](https://twitter.com/gr2m) |

@@ -784,0 +788,0 @@ ###### Former

@@ -72,6 +72,6 @@

if (body instanceof Stream) {
body.on('error', err => {
const error = err instanceof FetchBaseError ?
err :
new FetchError(`Invalid response body while trying to fetch ${this.url}: ${err.message}`, 'system', err);
body.on('error', error_ => {
const error = error_ instanceof FetchBaseError ?
error_ :
new FetchError(`Invalid response body while trying to fetch ${this.url}: ${error_.message}`, 'system', error_);
this[INTERNALS].error = error;

@@ -181,3 +181,3 @@ });

if (isBlob(body)) {
body = body.stream();
body = Stream.Readable.from(body.stream());
}

@@ -203,5 +203,5 @@

if (data.size > 0 && accumBytes + chunk.length > data.size) {
const err = new FetchError(`content size at ${data.url} over limit: ${data.size}`, 'max-size');
body.destroy(err);
throw err;
const error = new FetchError(`content size at ${data.url} over limit: ${data.size}`, 'max-size');
body.destroy(error);
throw error;
}

@@ -213,8 +213,4 @@

} catch (error) {
if (error instanceof FetchBaseError) {
throw error;
} else {
// Other errors, such as incorrect content-encoding
throw new FetchError(`Invalid response body while trying to fetch ${data.url}: ${error.message}`, 'system', error);
}
const error_ = error instanceof FetchBaseError ? error : new FetchError(`Invalid response body while trying to fetch ${data.url}: ${error.message}`, 'system', error);
throw error_;
}

@@ -378,3 +374,3 @@

// Body is Blob
body.stream().pipe(dest);
Stream.Readable.from(body.stream()).pipe(dest);
} else if (Buffer.isBuffer(body)) {

@@ -389,2 +385,1 @@ // Body is buffer

};

@@ -1,3 +0,1 @@

'use strict';
export class FetchBaseError extends Error {

@@ -20,2 +18,1 @@ constructor(message, type) {

}

@@ -14,5 +14,5 @@ /**

if (!/^[\^`\-\w!#$%&'*+.|~]+$/.test(name)) {
const err = new TypeError(`Header name must be a valid HTTP token [${name}]`);
Object.defineProperty(err, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'});
throw err;
const error = new TypeError(`Header name must be a valid HTTP token [${name}]`);
Object.defineProperty(error, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'});
throw error;
}

@@ -25,5 +25,5 @@ };

if (/[^\t\u0020-\u007E\u0080-\u00FF]/.test(value)) {
const err = new TypeError(`Invalid character in header content ["${name}"]`);
Object.defineProperty(err, 'code', {value: 'ERR_INVALID_CHAR'});
throw err;
const error = new TypeError(`Invalid character in header content ["${name}"]`);
Object.defineProperty(error, 'code', {value: 'ERR_INVALID_CHAR'});
throw error;
}

@@ -119,3 +119,3 @@ };

return URLSearchParams.prototype[p].call(
receiver,
target,
String(name).toLowerCase(),

@@ -132,3 +132,3 @@ String(value)

return URLSearchParams.prototype[p].call(
receiver,
target,
String(name).toLowerCase()

@@ -174,5 +174,5 @@ );

forEach(callback) {
forEach(callback, thisArg = undefined) {
for (const name of this.keys()) {
callback(this.get(name), name);
Reflect.apply(callback, thisArg, [this.get(name), name, this]);
}

@@ -179,0 +179,0 @@ }

@@ -93,7 +93,31 @@ /**

request_.on('error', err => {
reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
request_.on('error', error => {
reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, 'system', error));
finalize();
});
fixResponseChunkedTransferBadEnding(request_, error => {
response.body.destroy(error);
});
/* c8 ignore next 18 */
if (process.version < 'v14') {
// Before Node.js 14, pipeline() does not fully support async iterators and does not always
// properly handle when the socket close/end events are out of order.
request_.on('socket', s => {
let endedWithEventsCount;
s.prependListener('end', () => {
endedWithEventsCount = s._eventsCount;
});
s.prependListener('close', hadError => {
// if end happened before close but the socket didn't emit an error, do it now
if (response && endedWithEventsCount < s._eventsCount && !hadError) {
const error = new Error('Premature close');
error.code = 'ERR_STREAM_PREMATURE_CLOSE';
response.body.emit('error', error);
}
});
});
}
request_.on('response', response_ => {

@@ -120,9 +144,3 @@ request_.setTimeout(0);

if (locationURL !== null) {
// Handle corrupted header
try {
headers.set('Location', locationURL);
/* c8 ignore next 3 */
} catch (error) {
reject(error);
}
headers.set('Location', locationURL);
}

@@ -179,3 +197,3 @@

default:
// Do nothing
return reject(new TypeError(`Redirect option '${request.redirect}' is not a valid value of RequestRedirect`));
}

@@ -185,11 +203,9 @@ }

// Prepare response
response_.once('end', () => {
if (signal) {
if (signal) {
response_.once('end', () => {
signal.removeEventListener('abort', abortAndFinalize);
}
});
});
}
let body = pump(response_, new PassThrough(), error => {
reject(error);
});
let body = pump(response_, new PassThrough(), reject);
// see https://github.com/nodejs/node/pull/29376

@@ -239,5 +255,3 @@ if (process.version < 'v12.10') {

if (codings === 'gzip' || codings === 'x-gzip') {
body = pump(body, zlib.createGunzip(zlibOptions), error => {
reject(error);
});
body = pump(body, zlib.createGunzip(zlibOptions), reject);
response = new Response(body, responseOptions);

@@ -252,16 +266,6 @@ resolve(response);

// a hack for old IIS and Apache servers
const raw = pump(response_, new PassThrough(), error => {
reject(error);
});
const raw = pump(response_, new PassThrough(), reject);
raw.once('data', chunk => {
// See http://stackoverflow.com/questions/37519828
if ((chunk[0] & 0x0F) === 0x08) {
body = pump(body, zlib.createInflate(), error => {
reject(error);
});
} else {
body = pump(body, zlib.createInflateRaw(), error => {
reject(error);
});
}
body = (chunk[0] & 0x0F) === 0x08 ? pump(body, zlib.createInflate(), reject) : pump(body, zlib.createInflateRaw(), reject);

@@ -276,5 +280,3 @@ response = new Response(body, responseOptions);

if (codings === 'br') {
body = pump(body, zlib.createBrotliDecompress(), error => {
reject(error);
});
body = pump(body, zlib.createBrotliDecompress(), reject);
response = new Response(body, responseOptions);

@@ -293,1 +295,29 @@ resolve(response);

}
function fixResponseChunkedTransferBadEnding(request, errorCallback) {
const LAST_CHUNK = Buffer.from('0\r\n');
let socket;
request.on('socket', s => {
socket = s;
});
request.on('response', response => {
const {headers} = response;
if (headers['transfer-encoding'] === 'chunked' && !headers['content-length']) {
let properLastChunkReceived = false;
socket.on('data', buf => {
properLastChunkReceived = Buffer.compare(buf.slice(-3), LAST_CHUNK) === 0;
});
socket.prependListener('close', () => {
if (!properLastChunkReceived) {
const error = new Error('Premature close');
error.code = 'ERR_STREAM_PREMATURE_CLOSE';
errorCallback(error);
}
});
}
});
}

@@ -34,2 +34,4 @@

*
* Ref: https://fetch.spec.whatwg.org/#request-class
*
* @param Mixed input Url or Request instance

@@ -86,4 +88,5 @@ * @param Object init Custom options

if (signal !== null && !isAbortSignal(signal)) {
throw new TypeError('Expected signal to be an instanceof AbortSignal');
// eslint-disable-next-line no-eq-null, eqeqeq
if (signal != null && !isAbortSignal(signal)) {
throw new TypeError('Expected signal to be an instanceof AbortSignal or EventTarget');
}

@@ -90,0 +93,0 @@

@@ -16,2 +16,4 @@ /**

*
* Ref: https://fetch.spec.whatwg.org/#response-class
*
* @param Stream body Readable stream

@@ -25,3 +27,5 @@ * @param Object opts Response options

const status = options.status || 200;
// eslint-disable-next-line no-eq-null, eqeqeq, no-negated-condition
const status = options.status != null ? options.status : 200;
const headers = new Headers(options.headers);

@@ -37,2 +41,3 @@

this[INTERNALS] = {
type: 'default',
url: options.url,

@@ -47,2 +52,6 @@ status,

get type() {
return this[INTERNALS].type;
}
get url() {

@@ -86,2 +95,3 @@ return this[INTERNALS].url || '';

return new Response(clone(this, this.highWaterMark), {
type: this.type,
url: this.url,

@@ -115,2 +125,8 @@ status: this.status,

static error() {
const response = new Response(null, {status: 0, statusText: ''});
response[INTERNALS].type = 'error';
return response;
}
get [Symbol.toStringTag]() {

@@ -122,2 +138,3 @@ return 'Response';

Object.defineProperties(Response.prototype, {
type: {enumerable: true},
url: {enumerable: true},

@@ -131,2 +148,1 @@ status: {enumerable: true},

});

@@ -70,7 +70,3 @@ import {randomBytes} from 'crypto';

if (isBlob(value)) {
length += value.size;
} else {
length += Buffer.byteLength(String(value));
}
length += isBlob(value) ? value.size : Buffer.byteLength(String(value));

@@ -77,0 +73,0 @@ length += carriageLength;

@@ -77,6 +77,8 @@ /**

return (
typeof object === 'object' &&
object[NAME] === 'AbortSignal'
typeof object === 'object' && (
object[NAME] === 'AbortSignal' ||
object[NAME] === 'EventTarget'
)
);
};
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc