Socket
Socket
Sign inDemoInstall

node-fetch

Package Overview
Dependencies
2
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.6 to 3.0.0-beta.7

src/errors/base.js

136

./@types/index.d.ts

@@ -5,8 +5,15 @@ /// <reference types="node" />

import {Agent} from 'http';
import {AbortSignal} from 'abort-controller';
import Blob from 'fetch-blob';
import { Agent } from 'http';
import { URL, URLSearchParams } from 'url'
import Blob = require('fetch-blob');
type HeadersInit = Headers | string[][] | Record<string, string>;
type AbortSignal = {
readonly aborted: boolean;
addEventListener(type: "abort", listener: (this: AbortSignal) => void): void;
removeEventListener(type: "abort", listener: (this: AbortSignal) => void): void;
};
type HeadersInit = Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<Iterable<string>>;
/**

@@ -19,34 +26,32 @@ * This Fetch API interface allows you to perform various actions on HTTP request and response headers.

* */
interface Headers {
append: (name: string, value: string) => void;
delete: (name: string) => void;
get: (name: string) => string | null;
has: (name: string) => boolean;
set: (name: string, value: string) => void;
forEach: (
declare class Headers {
constructor(init?: HeadersInit);
append(name: string, value: string): void;
delete(name: string): void;
get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
forEach(
callbackfn: (value: string, key: string, parent: Headers) => void,
thisArg?: any
) => void;
): void;
[Symbol.iterator]: () => IterableIterator<[string, string]>;
[Symbol.iterator](): IterableIterator<[string, string]>;
/**
* Returns an iterator allowing to go through all key/value pairs contained in this object.
*/
entries: () => IterableIterator<[string, string]>;
entries(): IterableIterator<[string, string]>;
/**
* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object.
*/
keys: () => IterableIterator<string>;
keys(): IterableIterator<string>;
/**
* Returns an iterator allowing to go through all values of the key/value pairs contained in this object.
*/
values: () => IterableIterator<string>;
values(): IterableIterator<string>;
/** Node-fetch extension */
raw: () => Record<string, string[]>;
raw(): Record<string, string[]>;
}
declare var Headers: {
prototype: Headers;
new (init?: HeadersInit): Headers;
};

@@ -99,19 +104,22 @@ interface RequestInit {

| string;
interface Body {
type BodyType = { [K in keyof Body]: Body[K] };
declare class Body {
constructor(body?: BodyInit, opts?: { size?: number });
readonly body: NodeJS.ReadableStream | null;
readonly bodyUsed: boolean;
readonly size: number;
buffer: () => Promise<Buffer>;
arrayBuffer: () => Promise<ArrayBuffer>;
blob: () => Promise<Blob>;
json: () => Promise<unknown>;
text: () => Promise<string>;
buffer(): Promise<Buffer>;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
json(): Promise<unknown>;
text(): Promise<string>;
}
declare var Body: {
prototype: Body;
new (body?: BodyInit, opts?: {size?: number}): Body;
};
type RequestRedirect = 'error' | 'follow' | 'manual';
interface Request extends Body {
type RequestInfo = string | Body;
declare class Request extends Body {
constructor(input: RequestInfo, init?: RequestInit);
/**

@@ -137,11 +145,8 @@ * Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header.

readonly url: string;
clone: () => Request;
clone(): Request;
}
type RequestInfo = string | Body;
declare var Request: {
prototype: Request;
new (input: RequestInfo, init?: RequestInit): Request;
};
interface Response extends Body {
declare class Response extends Body {
constructor(body?: BodyInit | null, init?: ResponseInit);
readonly headers: Headers;

@@ -153,17 +158,8 @@ readonly ok: boolean;

readonly url: string;
clone: () => Response;
clone(): Response;
}
declare var Response: {
prototype: Response;
new (body?: BodyInit | null, init?: ResponseInit): Response;
};
declare class FetchError extends Error {
constructor(message: string, type: string, systemError?: object);
declare function fetch(url: RequestInfo, init?: RequestInit): Promise<Response>;
declare namespace fetch {
function isRedirect(code: number): boolean;
}
interface FetchError extends Error {
name: 'FetchError';

@@ -175,8 +171,4 @@ [Symbol.toStringTag]: 'FetchError';

}
declare var FetchError: {
prototype: FetchError;
new (message: string, type: string, systemError?: object): FetchError;
};
export class AbortError extends Error {
declare class AbortError extends Error {
type: string;

@@ -187,3 +179,31 @@ name: 'AbortError';

export {Headers, Request, Response, FetchError};
export default fetch;
declare function fetch(url: RequestInfo, init?: RequestInit): Promise<Response>;
declare class fetch {
static default: typeof fetch;
}
declare namespace fetch {
export function isRedirect(code: number): boolean;
export {
HeadersInit,
Headers,
RequestInit,
RequestRedirect,
RequestInfo,
Request,
BodyInit,
ResponseInit,
Response,
FetchError,
AbortError
};
export interface Body extends BodyType { }
}
export = fetch;
{
"name": "node-fetch",
"version": "3.0.0-beta.6",
"description": "A light-weight module that brings window.fetch to node.js",
"main": "./dist/index.cjs",
"module": "./src/index.js",
"sideEffects": false,
"type": "module",
"exports": {
"import": "./src/index.js",
"require": "./dist/index.cjs"
},
"files": [
"src",
"dist",
"@types/index.d.ts"
],
"types": "./@types/index.d.ts",
"engines": {
"node": ">=10.16"
},
"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",
"coverage": "c8 report --reporter=text-lcov | coveralls",
"test-types": "tsd",
"lint": "xo"
},
"repository": {
"type": "git",
"url": "https://github.com/node-fetch/node-fetch.git"
},
"keywords": [
"fetch",
"http",
"promise"
],
"author": "David Frank",
"license": "MIT",
"bugs": {
"url": "https://github.com/node-fetch/node-fetch/issues"
},
"homepage": "https://github.com/node-fetch/node-fetch",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
},
"devDependencies": {
"abort-controller": "^3.0.0",
"abortcontroller-polyfill": "^1.4.0",
"c8": "^7.1.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-iterator": "^3.0.2",
"chai-string": "^1.5.0",
"coveralls": "^3.1.0",
"delay": "^4.3.0",
"form-data": "^3.0.0",
"mocha": "^7.1.2",
"p-timeout": "^3.2.0",
"parted": "^0.1.1",
"promise": "^8.1.0",
"resumer": "0.0.0",
"rollup": "^2.10.8",
"string-to-arraybuffer": "^1.0.2",
"tsc": "^1.20150623.0",
"tsd": "^0.11.0",
"xo": "^0.30.0"
},
"dependencies": {
"data-uri-to-buffer": "^3.0.0",
"fetch-blob": "^1.0.6"
},
"tsd": {
"cwd": "@types",
"compilerOptions": {
"target": "esnext",
"lib": [
"es2018"
],
"allowSyntheticDefaultImports": true
}
},
"xo": {
"envs": [
"node",
"browser"
],
"rules": {
"complexity": 0,
"import/extensions": 0,
"import/no-useless-path-segments": 0,
"unicorn/import-index": 0,
"capitalized-comments": 0
},
"ignores": [
"dist",
"@types"
],
"overrides": [
{
"files": "test/**/*.js",
"envs": [
"node",
"mocha"
],
"rules": {
"max-nested-callbacks": 0,
"no-unused-expressions": 0,
"new-cap": 0,
"guard-for-in": 0,
"unicorn/prevent-abbreviations": 0,
"promise/prefer-await-to-then": 0,
"ava/no-import-test-files": 0
}
},
{
"files": "example.js",
"rules": {
"import/no-extraneous-dependencies": 0
}
}
]
},
"runkitExampleFilename": "example.js"
"name": "node-fetch",
"version": "3.0.0-beta.7",
"description": "A light-weight module that brings window.fetch to node.js",
"main": "./dist/index.cjs",
"module": "./src/index.js",
"sideEffects": false,
"type": "module",
"exports": {
"import": "./src/index.js",
"require": "./dist/index.cjs"
},
"files": [
"src",
"dist",
"@types/index.d.ts"
],
"types": "./@types/index.d.ts",
"engines": {
"node": ">=10.17"
},
"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",
"coverage": "c8 report --reporter=text-lcov | coveralls",
"test-types": "tsd",
"lint": "xo",
"prepublishOnly": "node ./test/commonjs/test-artifact.js"
},
"repository": {
"type": "git",
"url": "https://github.com/node-fetch/node-fetch.git"
},
"keywords": [
"fetch",
"http",
"promise"
],
"author": "David Frank",
"license": "MIT",
"bugs": {
"url": "https://github.com/node-fetch/node-fetch/issues"
},
"homepage": "https://github.com/node-fetch/node-fetch",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
},
"devDependencies": {
"abort-controller": "^3.0.0",
"abortcontroller-polyfill": "^1.4.0",
"busboy": "^0.3.1",
"c8": "^7.1.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-iterator": "^3.0.2",
"chai-string": "^1.5.0",
"coveralls": "^3.1.0",
"delay": "^4.3.0",
"form-data": "^3.0.0",
"formdata-node": "^2.2.0",
"mocha": "^8.0.0",
"p-timeout": "^3.2.0",
"parted": "^0.1.1",
"rollup": "^2.15.0",
"string-to-arraybuffer": "^1.0.2",
"tsd": "^0.11.0",
"xo": "^0.32.0"
},
"dependencies": {
"data-uri-to-buffer": "^3.0.1",
"fetch-blob": "^2.0.0"
},
"esm": {
"sourceMap": true,
"cjs": false
},
"tsd": {
"cwd": "@types",
"compilerOptions": {
"target": "esnext",
"lib": [
"es2018"
],
"allowSyntheticDefaultImports": false,
"esModuleInterop": false
}
},
"xo": {
"envs": [
"node",
"browser"
],
"rules": {
"complexity": 0,
"import/extensions": 0,
"import/no-useless-path-segments": 0,
"import/no-anonymous-default-export": 0,
"unicorn/import-index": 0,
"unicorn/no-reduce": 0,
"capitalized-comments": 0,
"node/no-unsupported-features/node-builtins": [
"error",
{
"ignores": [
"stream.Readable.from"
]
}
]
},
"ignores": [
"dist",
"@types"
],
"overrides": [
{
"files": "test/**/*.js",
"envs": [
"node",
"mocha"
],
"rules": {
"max-nested-callbacks": 0,
"no-unused-expressions": 0,
"new-cap": 0,
"guard-for-in": 0,
"unicorn/prevent-abbreviations": 0,
"promise/prefer-await-to-then": 0,
"ava/no-import-test-files": 0
}
},
{
"files": "example.js",
"rules": {
"import/no-extraneous-dependencies": 0
}
}
]
},
"runkitExampleFilename": "example.js"
}

@@ -88,5 +88,5 @@ <div align="center">

- Make conscious trade-off when following [WHATWG fetch spec][whatwg-fetch] and [stream spec](https://streams.spec.whatwg.org/) implementation details, document known differences.
- Use native promise, but allow substituting it with [insert your favorite promise library].
- Use native promise and async functions.
- Use native Node streams for body, on both request and response.
- Decode content encoding (gzip/deflate) properly, and convert string output (such as `res.text()` and `res.json()`) to UTF-8 automatically.
- Decode content encoding (gzip/deflate/brotli) properly, and convert string output (such as `res.text()` and `res.json()`) to UTF-8 automatically.
- Useful extensions such as redirect limit, response size limit, [explicit errors][error-handling.md] for troubleshooting.

@@ -120,11 +120,2 @@

If you are using a Promise library other than native, set it through `fetch.Promise`:
```js
const fetch = require('node-fetch');
const Bluebird = require('bluebird');
fetch.Promise = Bluebird;
```
If you want to patch the global object in node:

@@ -291,6 +282,6 @@

if (response.ok) {
return streamPipeline(res.body, fs.createWriteStream('./octocat.png'));
return streamPipeline(response.body, fs.createWriteStream('./octocat.png'));
}
throw new Error(`unexpected response ${res.statusText}`);
throw new Error(`unexpected response ${response.statusText}`);
})();

@@ -324,7 +315,7 @@ ```

console.log(res.ok);
console.log(res.status);
console.log(res.statusText);
console.log(res.headers.raw());
console.log(res.headers.get('content-type'));
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers.raw());
console.log(response.headers.get('content-type'));
})();

@@ -344,3 +335,3 @@ ```

// Returns an array of values, instead of a string of comma-separated values
console.log(res.headers.raw()['set-cookie']);
console.log(response.headers.raw()['set-cookie']);
})();

@@ -398,2 +389,16 @@ ```

node-fetch also supports spec-compliant FormData implementations such as [formdata-node](https://github.com/octet-stream/form-data):
```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

@@ -464,3 +469,4 @@

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.
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`.
}

@@ -556,2 +562,7 @@ ```

#### Insecure HTTP Parser
Passed through to the `insecureHTTPParser` option on http(s).request. See [`http.request`](https://nodejs.org/api/http.html#http_http_request_url_options_callback) for more information.
<a id="class-request"></a>

@@ -648,3 +659,3 @@

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

@@ -651,0 +662,0 @@ const meta = {

@@ -8,9 +8,12 @@

import Stream, {finished, PassThrough} from 'stream';
import Stream, {PassThrough} from 'stream';
import {types} from 'util';
import Blob from 'fetch-blob';
import FetchError from './errors/fetch-error.js';
import {isBlob, isURLSearchParameters, isAbortError} from './utils/is.js';
import {FetchError} from './errors/fetch-error.js';
import {FetchBaseError} from './errors/base.js';
import {formDataIterator, getBoundary, getFormDataLength} from './utils/form-data.js';
import {isBlob, isURLSearchParameters, isFormData} from './utils/is.js';
const INTERNALS = Symbol('Body internals');

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

} = {}) {
let boundary = null;
if (body === null) {

@@ -50,2 +55,6 @@ // Body is undefined or null

// Body is stream
} else if (isFormData(body)) {
// Body is an instance of formdata-node
boundary = `NodeFetchFormDataBoundary${getBoundary()}`;
body = Stream.Readable.from(formDataIterator(body, boundary));
} else {

@@ -59,2 +68,3 @@ // None of the above

body,
boundary,
disturbed: false,

@@ -67,3 +77,3 @@ error: null

body.on('error', err => {
const error = isAbortError(err) ?
const error = err instanceof FetchBaseError ?
err :

@@ -101,7 +111,6 @@ new FetchError(`Invalid response body while trying to fetch ${this.url}: ${err.message}`, 'system', err);

const ct = (this.headers && this.headers.get('content-type')) || (this[INTERNALS].body && this[INTERNALS].body.type) || '';
const buf = await consumeBody(this);
const buf = await this.buffer();
return new Blob([], {
type: ct.toLowerCase(),
buffer: buf
return new Blob([buf], {
type: ct
});

@@ -155,7 +164,7 @@ }

*
* @return Promise
* @return Promise
*/
const consumeBody = data => {
async function consumeBody(data) {
if (data[INTERNALS].disturbed) {
return Body.Promise.reject(new TypeError(`body used already for: ${data.url}`));
throw new TypeError(`body used already for: ${data.url}`);
}

@@ -166,3 +175,3 @@

if (data[INTERNALS].error) {
return Body.Promise.reject(data[INTERNALS].error);
throw data[INTERNALS].error;
}

@@ -174,3 +183,3 @@

if (body === null) {
return Body.Promise.resolve(Buffer.alloc(0));
return Buffer.alloc(0);
}

@@ -185,3 +194,3 @@

if (Buffer.isBuffer(body)) {
return Body.Promise.resolve(body);
return body;
}

@@ -191,3 +200,3 @@

if (!(body instanceof Stream)) {
return Body.Promise.resolve(Buffer.alloc(0));
return Buffer.alloc(0);
}

@@ -199,46 +208,38 @@

let accumBytes = 0;
let abort = false;
return new Body.Promise((resolve, reject) => {
body.on('data', chunk => {
if (abort || chunk === null) {
return;
try {
for await (const chunk of body) {
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;
}
if (data.size && accumBytes + chunk.length > data.size) {
abort = true;
reject(new FetchError(`content size at ${data.url} over limit: ${data.size}`, 'max-size'));
return;
}
accumBytes += chunk.length;
accum.push(chunk);
});
}
} 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);
}
}
finished(body, {writable: false}, err => {
if (err) {
if (isAbortError(err)) {
// If the request was aborted, reject with this Error
abort = true;
reject(err);
} else {
// Other errors, such as incorrect content-encoding
reject(new FetchError(`Invalid response body while trying to fetch ${data.url}: ${err.message}`, 'system', err));
}
} else {
if (abort) {
return;
}
try {
resolve(Buffer.concat(accum, accumBytes));
} catch (error) {
// Handle streams that have accumulated too much data (issue #414)
reject(new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, 'system', error));
}
if (body.readableEnded === true || body._readableState.ended === true) {
try {
if (accum.every(c => typeof c === 'string')) {
return Buffer.from(accum.join(''));
}
});
});
};
return Buffer.concat(accum, accumBytes);
} catch (error) {
throw new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, 'system', error);
}
} else {
throw new FetchError(`Premature close of server response while trying to fetch ${data.url}`);
}
}
/**

@@ -287,3 +288,3 @@ * Clone body given Res/Req instance

*/
export const extractContentType = body => {
export const extractContentType = (body, request) => {
// Body is null or undefined

@@ -319,2 +320,6 @@ if (body === null) {

if (isFormData(body)) {
return `multipart/form-data; boundary=${request[INTERNALS].boundary}`;
}
// Body is stream - can't really do much about this

@@ -338,3 +343,5 @@ if (body instanceof Stream) {

*/
export const getTotalBytes = ({body}) => {
export const getTotalBytes = request => {
const {body} = request;
// Body is null or undefined

@@ -360,2 +367,7 @@ if (body === null) {

// Body is a spec-compliant form-data
if (isFormData(body)) {
return getFormDataLength(request[INTERNALS].boundary);
}
// Body is stream

@@ -389,3 +401,1 @@ return null;

// Expose Promise
Body.Promise = global.Promise;

@@ -0,27 +1,10 @@

import {FetchBaseError} from './base.js';
/**
* Abort-error.js
*
* AbortError interface for cancelled requests
*/
/**
* Create AbortError instance
*
* @param String message Error message for human
* @param String type Error type for machine
* @param String systemError For Node.js system error
* @return AbortError
*/
export default class AbortError extends Error {
constructor(message) {
super(message);
this.type = 'aborted';
this.message = message;
this.name = 'AbortError';
this[Symbol.toStringTag] = 'AbortError';
// Hide custom error implementation details from end-users
Error.captureStackTrace(this, this.constructor);
export class AbortError extends FetchBaseError {
constructor(message, type = 'aborted') {
super(message, type);
}
}

@@ -0,24 +1,19 @@

import {FetchBaseError} from './base.js';
/**
* Fetch-error.js
*
* FetchError interface for operational errors
*/
* @typedef {{ address?: string, code: string, dest?: string, errno: number, info?: object, message: string, path?: string, port?: number, syscall: string}} SystemError
*/
/**
* Create FetchError instance
*
* @param String message Error message for human
* @param String type Error type for machine
* @param Object systemError For Node.js system error
* @return FetchError
* FetchError interface for operational errors
*/
export default class FetchError extends Error {
export class FetchError extends FetchBaseError {
/**
* @param {string} message - Error message for human
* @param {string} [type] - Error type for machine
* @param {SystemError} [systemError] - For Node.js system error
*/
constructor(message, type, systemError) {
super(message);
this.message = message;
this.type = type;
this.name = 'FetchError';
this[Symbol.toStringTag] = 'FetchError';
super(message, type);
// When err.type is `system`, err.erroredSysCall contains system error and err.code contains system error code

@@ -28,8 +23,5 @@ if (systemError) {

this.code = this.errno = systemError.code;
this.erroredSysCall = systemError;
this.erroredSysCall = systemError.syscall;
}
// Hide custom error implementation details from end-users
Error.captureStackTrace(this, this.constructor);
}
}

@@ -8,22 +8,26 @@ /**

import {types} from 'util';
import http from 'http';
const invalidTokenRegex = /[^`\-\w!#$%&'*+.|~]/;
const invalidHeaderCharRegex = /[^\t\u0020-\u007E\u0080-\u00FF]/;
const validateHeaderName = typeof http.validateHeaderName === 'function' ?
http.validateHeaderName :
name => {
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;
}
};
function validateName(name) {
name = String(name);
if (invalidTokenRegex.test(name) || name === '') {
throw new TypeError(`'${name}' is not a legal HTTP header name`);
}
}
const validateHeaderValue = typeof http.validateHeaderValue === 'function' ?
http.validateHeaderValue :
(name, value) => {
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;
}
};
function validateValue(value) {
value = String(value);
if (invalidHeaderCharRegex.test(value)) {
throw new TypeError(`'${value}' is not a legal HTTP header value`);
}
}
/**
* @typedef {Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<string>[]} HeadersInit
* @typedef {Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<Iterable<string>>} HeadersInit
*/

@@ -95,5 +99,5 @@

result.map(([name, value]) => {
validateName(name);
validateValue(value);
return [String(name).toLowerCase(), value];
validateHeaderName(name);
validateHeaderValue(name, String(value));
return [String(name).toLowerCase(), String(value)];
}) :

@@ -112,8 +116,8 @@ undefined;

return (name, value) => {
validateName(name);
validateValue(value);
validateHeaderName(name);
validateHeaderValue(name, String(value));
return URLSearchParams.prototype[p].call(
receiver,
String(name).toLowerCase(),
value
String(value)
);

@@ -126,3 +130,3 @@ };

return name => {
validateName(name);
validateHeaderName(name);
return URLSearchParams.prototype[p].call(

@@ -149,3 +153,3 @@ receiver,

get [Symbol.toStringTag]() {
return 'Headers';
return this.constructor.name;
}

@@ -255,5 +259,13 @@

}, [])
.filter(([name, value]) => !(invalidTokenRegex.test(name) || invalidHeaderCharRegex.test(value)))
.filter(([name, value]) => {
try {
validateHeaderName(name);
validateHeaderValue(name, String(value));
return true;
} catch {
return false;
}
})
);
}

@@ -13,10 +13,10 @@ /**

import Stream, {PassThrough, pipeline as pump} from 'stream';
import dataURIToBuffer from 'data-uri-to-buffer';
import dataUriToBuffer from 'data-uri-to-buffer';
import Body, {writeToStream, getTotalBytes} from './body.js';
import {writeToStream} from './body.js';
import Response from './response.js';
import Headers, {fromRawHeaders} from './headers.js';
import Request, {getNodeRequestOptions} from './request.js';
import FetchError from './errors/fetch-error.js';
import AbortError from './errors/abort-error.js';
import {FetchError} from './errors/fetch-error.js';
import {AbortError} from './errors/abort-error.js';
import {isRedirect} from './utils/is-redirect.js';

@@ -26,39 +26,28 @@

const supportedSchemas = new Set(['data:', 'http:', 'https:']);
/**
* Fetch function
*
* @param Mixed url Absolute url or Request instance
* @param Object opts Fetch options
* @return Promise
* @param {string | URL | import('./request').default} url - Absolute url or Request instance
* @param {*} [options_] - Fetch options
* @return {Promise<import('./response').default>}
*/
const fetch = (url, options_) => {
// Allow custom promise
if (!fetch.Promise) {
throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
}
// Regex for data uri
const dataUriRegex = /^\s*data:([a-z]+\/[a-z]+(;[a-z-]+=[a-z-]+)?)?(;base64)?,[\w!$&',()*+;=\-.~:@/?%\s]*\s*$/i;
// If valid data uri
if (dataUriRegex.test(url)) {
const data = dataURIToBuffer(url);
const response = new Response(data, {headers: {'Content-Type': data.type}});
return fetch.Promise.resolve(response);
}
// If invalid data uri
if (url.toString().startsWith('data:')) {
const request = new Request(url, options_);
return fetch.Promise.reject(new FetchError(`[${request.method}] ${request.url} invalid URL`, 'system'));
}
Body.Promise = fetch.Promise;
// Wrap http.request into fetch
return new fetch.Promise((resolve, reject) => {
export default async function fetch(url, options_) {
return new Promise((resolve, reject) => {
// Build request object
const request = new Request(url, options_);
const options = getNodeRequestOptions(request);
if (!supportedSchemas.has(options.protocol)) {
throw new TypeError(`node-fetch cannot load ${url}. URL scheme "${options.protocol.replace(/:$/, '')}" is not supported.`);
}
if (options.protocol === 'data:') {
const data = dataUriToBuffer(request.url);
const response = new Response(data, {headers: {'Content-Type': data.typeFull}});
resolve(response);
return;
}
// Wrap http.request into fetch
const send = (options.protocol === 'https:' ? https : http).request;

@@ -169,3 +158,3 @@ const {signal} = request;

// HTTP-redirect fetch step 9
if (response_.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
if (response_.statusCode !== 303 && request.body && options_.body instanceof Stream.Readable) {
reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect'));

@@ -204,2 +193,6 @@ finalize();

});
// see https://github.com/nodejs/node/pull/29376
if (process.version < 'v12.10') {
response_.on('aborted', abortAndFinalize);
}

@@ -295,7 +288,2 @@ const responseOptions = {

});
};
export default fetch;
// Expose Promise
fetch.Promise = global.Promise;
}

@@ -32,22 +32,2 @@

/**
* Wrapper around `new URL` to handle relative URLs (https://github.com/nodejs/node/issues/12682)
*
* @param {string} urlStr
* @return {void}
*/
const parseURL = urlString => {
/*
Check whether the URL is absolute or not
Scheme: https://tools.ietf.org/html/rfc3986#section-3.1
Absolute URL: https://tools.ietf.org/html/rfc3986#section-4.3
*/
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.exec(urlString)) {
return new URL(urlString);
}
throw new TypeError('Only absolute URLs are supported');
};
/**
* Request class

@@ -63,16 +43,7 @@ *

// Normalize input and force URL to be encoded as UTF-8 (https://github.com/bitinn/node-fetch/issues/245)
// Normalize input and force URL to be encoded as UTF-8 (https://github.com/node-fetch/node-fetch/issues/245)
if (isRequest(input)) {
parsedURL = parseURL(input.url);
parsedURL = new URL(input.url);
} else {
if (input && input.href) {
// In order to support Node.js' Url objects; though WHATWG's URL objects
// will fall into this branch also (since their `toString()` will return
// `href` property anyway)
parsedURL = parseURL(input.href);
} else {
// Coerce input to a string before attempting to parse
parsedURL = parseURL(`${input}`);
}
parsedURL = new URL(input);
input = {};

@@ -103,3 +74,3 @@ }

if (inputBody !== null && !headers.has('Content-Type')) {
const contentType = extractContentType(inputBody);
const contentType = extractContentType(inputBody, this);
if (contentType) {

@@ -135,2 +106,3 @@ headers.append('Content-Type', contentType);

this.highWaterMark = init.highWaterMark || input.highWaterMark || 16384;
this.insecureHTTPParser = init.insecureHTTPParser || input.insecureHTTPParser || false;
}

@@ -196,6 +168,2 @@

if (!/^https?:$/.test(parsedURL.protocol)) {
throw new TypeError('Only HTTP(S) protocols are supported');
}
// HTTP-network-or-cache fetch steps 2.4-2.7

@@ -209,3 +177,4 @@ let contentLengthValue = null;

const totalBytes = getTotalBytes(request);
if (typeof totalBytes === 'number') {
// Set Content-Length if totalBytes is a number (that is not NaN)
if (typeof totalBytes === 'number' && !Number.isNaN(totalBytes)) {
contentLengthValue = String(totalBytes);

@@ -256,2 +225,3 @@ }

headers: headers[Symbol.for('nodejs.util.inspect.custom')](),
insecureHTTPParser: request.insecureHTTPParser,
agent

@@ -258,0 +228,0 @@ };

@@ -31,3 +31,3 @@ /**

/**
* Check if `obj` is a W3C `Blob` object (which `File` inherits from)
* Check if `object` is a W3C `Blob` object (which `File` inherits from)
*

@@ -49,16 +49,25 @@ * @param {*} obj

/**
* Check if `obj` is an instance of AbortSignal.
* Check if `obj` is a spec-compliant `FormData` object
*
* @param {*} obj
* @param {*} object
* @return {boolean}
*/
export const isAbortSignal = object => {
export function isFormData(object) {
return (
typeof object === 'object' &&
object[NAME] === 'AbortSignal'
typeof object.append === 'function' &&
typeof object.set === 'function' &&
typeof object.get === 'function' &&
typeof object.getAll === 'function' &&
typeof object.delete === 'function' &&
typeof object.keys === 'function' &&
typeof object.values === 'function' &&
typeof object.entries === 'function' &&
typeof object.constructor === 'function' &&
object[NAME] === 'FormData'
);
};
}
/**
* Check if `obj` is an instance of AbortError.
* Check if `obj` is an instance of AbortSignal.
*

@@ -68,4 +77,8 @@ * @param {*} obj

*/
export const isAbortError = object => {
return object[NAME] === 'AbortError';
export const isAbortSignal = object => {
return (
typeof object === 'object' &&
object[NAME] === 'AbortSignal'
);
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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