node-fetch
Advanced tools
Comparing version 1.7.1 to 1.7.2
@@ -10,2 +10,6 @@ | ||
## v1.7.2 | ||
- Fix: when using node-fetch with test framework such as `jest`, `instanceof` check could fail in `Headers` class. This is causing some header values, such as `set-cookie`, to be dropped incorrectly. | ||
## v1.7.1 | ||
@@ -12,0 +16,0 @@ |
@@ -38,3 +38,3 @@ | ||
} else if (headers[prop] instanceof Array) { | ||
} else if (Array.isArray(headers[prop])) { | ||
headers[prop].forEach(function(item) { | ||
@@ -41,0 +41,0 @@ self.append(prop, item.toString()); |
171
lib/index.js
@@ -5,12 +5,2 @@ 'use strict'; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var url = require('url'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
var zlib = require('zlib'); | ||
var Stream = require('stream'); | ||
var Stream__default = _interopDefault(Stream); | ||
var encoding = require('encoding'); | ||
// Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js | ||
@@ -49,9 +39,9 @@ // (MIT licensed) | ||
} else if (ArrayBuffer.isView(element)) { | ||
buffer = new Buffer(new Uint8Array(element.buffer, element.byteOffset, element.byteLength)); | ||
buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength); | ||
} else if (element instanceof ArrayBuffer) { | ||
buffer = new Buffer(new Uint8Array(element)); | ||
buffer = Buffer.from(element); | ||
} else if (element instanceof Blob) { | ||
buffer = element[BUFFER]; | ||
} else { | ||
buffer = new Buffer(typeof element === 'string' ? element : String(element)); | ||
buffer = Buffer.from(typeof element === 'string' ? element : String(element)); | ||
} | ||
@@ -158,4 +148,16 @@ buffers.push(buffer); | ||
const Stream = require('stream'); | ||
var _require$1 = require('stream'); | ||
const PassThrough$1 = _require$1.PassThrough; | ||
const DISTURBED = Symbol('disturbed'); | ||
let convert; | ||
try { | ||
convert = require('encoding').convert; | ||
} catch (e) {} | ||
/** | ||
@@ -183,2 +185,4 @@ * Body class | ||
// body is string | ||
} else if (isURLSearchParams(body)) { | ||
// body is a URLSearchParams | ||
} else if (body instanceof Blob) { | ||
@@ -188,3 +192,3 @@ // body is blob | ||
// body is buffer | ||
} else if (body instanceof Stream__default) { | ||
} else if (body instanceof Stream) { | ||
// body is stream | ||
@@ -242,4 +246,10 @@ } else { | ||
json() { | ||
var _this = this; | ||
return consumeBody.call(this).then(function (buffer) { | ||
return JSON.parse(buffer.toString()); | ||
try { | ||
return JSON.parse(buffer.toString()); | ||
} catch (err) { | ||
return Body.Promise.reject(new FetchError(`invalid json response body at ${_this.url} reason: ${err.message}`, 'invalid-json')); | ||
} | ||
}); | ||
@@ -275,6 +285,6 @@ }, | ||
textConverted() { | ||
var _this = this; | ||
var _this2 = this; | ||
return consumeBody.call(this).then(function (buffer) { | ||
return convertBody(buffer, _this.headers); | ||
return convertBody(buffer, _this2.headers); | ||
}); | ||
@@ -301,3 +311,3 @@ } | ||
function consumeBody(body) { | ||
var _this2 = this; | ||
var _this3 = this; | ||
@@ -312,3 +322,3 @@ if (this[DISTURBED]) { | ||
if (this.body === null) { | ||
return Body.Promise.resolve(new Buffer(0)); | ||
return Body.Promise.resolve(Buffer.alloc(0)); | ||
} | ||
@@ -318,3 +328,3 @@ | ||
if (typeof this.body === 'string') { | ||
return Body.Promise.resolve(new Buffer(this.body)); | ||
return Body.Promise.resolve(Buffer.from(this.body)); | ||
} | ||
@@ -333,4 +343,4 @@ | ||
// istanbul ignore if: should never happen | ||
if (!(this.body instanceof Stream__default)) { | ||
return Body.Promise.resolve(new Buffer(0)); | ||
if (!(this.body instanceof Stream)) { | ||
return Body.Promise.resolve(Buffer.alloc(0)); | ||
} | ||
@@ -344,19 +354,19 @@ | ||
return new Body.Promise(function (resolve$$1, reject) { | ||
return new Body.Promise(function (resolve, reject) { | ||
let resTimeout; | ||
// allow timeout on slow response body | ||
if (_this2.timeout) { | ||
if (_this3.timeout) { | ||
resTimeout = setTimeout(function () { | ||
abort = true; | ||
reject(new FetchError(`Response timeout while trying to fetch ${_this2.url} (over ${_this2.timeout}ms)`, 'body-timeout')); | ||
}, _this2.timeout); | ||
reject(new FetchError(`Response timeout while trying to fetch ${_this3.url} (over ${_this3.timeout}ms)`, 'body-timeout')); | ||
}, _this3.timeout); | ||
} | ||
// handle stream error, such as incorrect content-encoding | ||
_this2.body.on('error', function (err) { | ||
reject(new FetchError(`Invalid response body while trying to fetch ${_this2.url}: ${err.message}`, 'system', err)); | ||
_this3.body.on('error', function (err) { | ||
reject(new FetchError(`Invalid response body while trying to fetch ${_this3.url}: ${err.message}`, 'system', err)); | ||
}); | ||
_this2.body.on('data', function (chunk) { | ||
_this3.body.on('data', function (chunk) { | ||
if (abort || chunk === null) { | ||
@@ -366,5 +376,5 @@ return; | ||
if (_this2.size && accumBytes + chunk.length > _this2.size) { | ||
if (_this3.size && accumBytes + chunk.length > _this3.size) { | ||
abort = true; | ||
reject(new FetchError(`content size at ${_this2.url} over limit: ${_this2.size}`, 'max-size')); | ||
reject(new FetchError(`content size at ${_this3.url} over limit: ${_this3.size}`, 'max-size')); | ||
return; | ||
@@ -377,3 +387,3 @@ } | ||
_this2.body.on('end', function () { | ||
_this3.body.on('end', function () { | ||
if (abort) { | ||
@@ -384,3 +394,3 @@ return; | ||
clearTimeout(resTimeout); | ||
resolve$$1(Buffer.concat(accum)); | ||
resolve(Buffer.concat(accum)); | ||
}); | ||
@@ -399,2 +409,6 @@ }); | ||
function convertBody(buffer, headers) { | ||
if (typeof convert !== 'function') { | ||
throw new Error('The package `encoding` must be installed to use the textConverted() function'); | ||
} | ||
const ct = headers.get('content-type'); | ||
@@ -443,6 +457,23 @@ let charset = 'utf-8'; | ||
// turn raw buffers into a single utf-8 buffer | ||
return encoding.convert(buffer, 'UTF-8', charset).toString(); | ||
return convert(buffer, 'UTF-8', charset).toString(); | ||
} | ||
/** | ||
* Detect a URLSearchParams object | ||
* ref: https://github.com/bitinn/node-fetch/issues/296#issuecomment-307598143 | ||
* | ||
* @param Object obj Object to detect by type or brand | ||
* @return String | ||
*/ | ||
function isURLSearchParams(obj) { | ||
// Duck-typing as a necessary condition. | ||
if (typeof obj !== 'object' || typeof obj.append !== 'function' || typeof obj.delete !== 'function' || typeof obj.get !== 'function' || typeof obj.getAll !== 'function' || typeof obj.has !== 'function' || typeof obj.set !== 'function') { | ||
return false; | ||
} | ||
// Brand-checking and more duck-typing as optional condition. | ||
return obj.constructor.name === 'URLSearchParams' || Object.prototype.toString.call(obj) === '[object URLSearchParams]' || typeof obj.sort === 'function'; | ||
} | ||
/** | ||
* Clone body given Res/Req instance | ||
@@ -464,6 +495,6 @@ * | ||
// note: we can't clone the form-data object without having it as a dependency | ||
if (body instanceof Stream__default && typeof body.getBoundary !== 'function') { | ||
if (body instanceof Stream && typeof body.getBoundary !== 'function') { | ||
// tee instance body | ||
p1 = new Stream.PassThrough(); | ||
p2 = new Stream.PassThrough(); | ||
p1 = new PassThrough$1(); | ||
p2 = new PassThrough$1(); | ||
body.pipe(p1); | ||
@@ -500,2 +531,5 @@ body.pipe(p2); | ||
return 'text/plain;charset=UTF-8'; | ||
} else if (isURLSearchParams(body)) { | ||
// body is a URLSearchParams | ||
return 'application/x-www-form-urlencoded;charset=UTF-8'; | ||
} else if (body instanceof Blob) { | ||
@@ -528,2 +562,5 @@ // body is blob | ||
return Buffer.byteLength(body); | ||
} else if (isURLSearchParams(body)) { | ||
// body is URLSearchParams | ||
return Buffer.byteLength(String(body)); | ||
} else if (body instanceof Blob) { | ||
@@ -561,2 +598,6 @@ // body is blob | ||
dest.end(); | ||
} else if (isURLSearchParams(body)) { | ||
// body is URLSearchParams | ||
dest.write(Buffer.from(String(body))); | ||
dest.end(); | ||
} else if (body instanceof Blob) { | ||
@@ -968,2 +1009,6 @@ // body is blob | ||
var _require$2 = require('http'); | ||
const STATUS_CODES = _require$2.STATUS_CODES; | ||
/** | ||
@@ -976,2 +1021,3 @@ * Response class | ||
*/ | ||
class Response { | ||
@@ -986,3 +1032,3 @@ constructor() { | ||
this.status = opts.status || 200; | ||
this.statusText = opts.statusText || http.STATUS_CODES[this.status]; | ||
this.statusText = opts.statusText || STATUS_CODES[this.status]; | ||
@@ -1038,2 +1084,8 @@ this.headers = new Headers(opts.headers); | ||
var _require$3 = require('url'); | ||
const format_url = _require$3.format; | ||
const parse_url = _require$3.parse; | ||
const PARSED_URL = Symbol('url'); | ||
@@ -1060,10 +1112,10 @@ | ||
// `href` property anyway) | ||
parsedURL = url.parse(input.href); | ||
parsedURL = parse_url(input.href); | ||
} else { | ||
// coerce input to a string before attempting to parse | ||
parsedURL = url.parse(`${input}`); | ||
parsedURL = parse_url(`${input}`); | ||
} | ||
input = {}; | ||
} else { | ||
parsedURL = url.parse(input.url); | ||
parsedURL = parse_url(input.url); | ||
} | ||
@@ -1112,3 +1164,3 @@ | ||
get url() { | ||
return url.format(this[PARSED_URL]); | ||
return format_url(this[PARSED_URL]); | ||
} | ||
@@ -1197,2 +1249,15 @@ | ||
const http = require('http'); | ||
const https = require('https'); | ||
var _require = require('stream'); | ||
const PassThrough = _require.PassThrough; | ||
var _require2 = require('url'); | ||
const resolve_url = _require2.resolve; | ||
const zlib = require('zlib'); | ||
/** | ||
@@ -1205,3 +1270,3 @@ * Fetch function | ||
*/ | ||
function fetch(url$$1, opts) { | ||
function fetch(url, opts) { | ||
@@ -1216,5 +1281,5 @@ // allow custom promise | ||
// wrap http.request into fetch | ||
return new fetch.Promise(function (resolve$$1, reject) { | ||
return new fetch.Promise(function (resolve, reject) { | ||
// build request object | ||
const request = new Request(url$$1, opts); | ||
const request = new Request(url, opts); | ||
const options = getNodeRequestOptions(request); | ||
@@ -1276,3 +1341,3 @@ | ||
resolve$$1(fetch(url.resolve(request.url, res.headers.location), request)); | ||
resolve(fetch(resolve_url(request.url, res.headers.location), request)); | ||
return; | ||
@@ -1293,7 +1358,7 @@ } | ||
if (request.redirect === 'manual' && headers.has('location')) { | ||
headers.set('location', url.resolve(request.url, headers.get('location'))); | ||
headers.set('location', resolve_url(request.url, headers.get('location'))); | ||
} | ||
// prepare response | ||
let body = res.pipe(new Stream.PassThrough()); | ||
let body = res.pipe(new PassThrough()); | ||
const response_options = { | ||
@@ -1320,3 +1385,3 @@ url: request.url, | ||
if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) { | ||
resolve$$1(new Response(body, response_options)); | ||
resolve(new Response(body, response_options)); | ||
return; | ||
@@ -1338,3 +1403,3 @@ } | ||
body = body.pipe(zlib.createGunzip(zlibOptions)); | ||
resolve$$1(new Response(body, response_options)); | ||
resolve(new Response(body, response_options)); | ||
return; | ||
@@ -1347,3 +1412,3 @@ } | ||
// a hack for old IIS and Apache servers | ||
const raw = res.pipe(new Stream.PassThrough()); | ||
const raw = res.pipe(new PassThrough()); | ||
raw.once('data', function (chunk) { | ||
@@ -1356,3 +1421,3 @@ // see http://stackoverflow.com/questions/37519828 | ||
} | ||
resolve$$1(new Response(body, response_options)); | ||
resolve(new Response(body, response_options)); | ||
}); | ||
@@ -1363,3 +1428,3 @@ return; | ||
// otherwise, use response as-is | ||
resolve$$1(new Response(body, response_options)); | ||
resolve(new Response(body, response_options)); | ||
}); | ||
@@ -1366,0 +1431,0 @@ |
{ | ||
"name": "node-fetch", | ||
"version": "1.7.1", | ||
"version": "1.7.2", | ||
"description": "A light-weight module that brings window.fetch to node.js and io.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
121810
3531
122