Socket
Socket
Sign inDemoInstall

node-fetch

Package Overview
Dependencies
Maintainers
1
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-fetch - npm Package Compare versions

Comparing version 1.5.2 to 1.5.3

test/dummy.txt

10

CHANGELOG.md

@@ -8,4 +8,12 @@

## v1.5.2 (master)
## v1.5.3 (master)
- Fix: handles 204 and 304 responses when body is empty but content-encoding is gzip/deflate
- Fix: allow resolving response and cloned response in any order
- Fix: avoid setting content-length when form-data body use streams
- Fix: send DELETE request with content-length when body is present
- Fix: allow any url when calling new Request, but still reject non-http(s) url in fetch
## v1.5.2
- Fix: allow node.js core to handle keep-alive connection pool when passing a custom agent

@@ -12,0 +20,0 @@

31

index.js

@@ -51,10 +51,12 @@

// build request object
var options;
try {
options = new Request(url, opts);
} catch (err) {
reject(err);
return;
var options = new Request(url, opts);
if (!options.protocol || !options.hostname) {
throw new Error('only absolute urls are supported');
}
if (options.protocol !== 'http:' && options.protocol !== 'https:') {
throw new Error('only http(s) protocols are supported');
}
var send;

@@ -91,8 +93,8 @@ if (options.protocol === 'https:') {

// bring node-fetch closer to browser behavior by setting content-length automatically for POST, PUT, PATCH requests when body is empty or string
if (!headers.has('content-length') && options.method.substr(0, 1).toUpperCase() === 'P') {
// bring node-fetch closer to browser behavior by setting content-length automatically
if (!headers.has('content-length') && /post|put|patch|delete/i.test(options.method)) {
if (typeof options.body === 'string') {
headers.set('content-length', Buffer.byteLength(options.body));
// detect form data input from form-data module, this hack avoid the need to add content-length header manually
} else if (options.body && typeof options.body.getLengthSync === 'function') {
} else if (options.body && typeof options.body.getLengthSync === 'function' && options.body._lengthRetrievers.length == 0) {
headers.set('content-length', options.body.getLengthSync().toString());

@@ -172,6 +174,9 @@ // this is only necessary for older nodejs releases (before iojs merge)

if (name == 'gzip' || name == 'x-gzip') {
body = body.pipe(zlib.createGunzip());
} else if (name == 'deflate' || name == 'x-deflate') {
body = body.pipe(zlib.createInflate());
// no need to pipe no content and not modified response body
if (res.statusCode !== 204 && res.statusCode !== 304) {
if (name == 'gzip' || name == 'x-gzip') {
body = body.pipe(zlib.createGunzip());
} else if (name == 'deflate' || name == 'x-deflate') {
body = body.pipe(zlib.createInflate());
}
}

@@ -178,0 +183,0 @@ }

@@ -208,3 +208,3 @@

Body.prototype._clone = function(instance) {
var pass;
var p1, p2;
var body = instance.body;

@@ -220,5 +220,10 @@

if (bodyStream(body) && typeof body.getBoundary !== 'function') {
pass = new PassThrough();
body.pipe(pass);
body = pass;
// tee instance body
p1 = new PassThrough();
p2 = new PassThrough();
body.pipe(p1);
body.pipe(p2);
// set instance body to teed body and return the other teed body
instance.body = p1;
body = p2;
}

@@ -225,0 +230,0 @@

@@ -34,10 +34,2 @@

if (!url_parsed.protocol || !url_parsed.hostname) {
throw new Error('only absolute urls are supported');
}
if (url_parsed.protocol !== 'http:' && url_parsed.protocol !== 'https:') {
throw new Error('only http(s) protocols are supported');
}
// normalize init

@@ -44,0 +36,0 @@ init = init || {};

{
"name": "node-fetch",
"version": "1.5.2",
"version": "1.5.3",
"description": "A light-weight module that brings window.fetch to node.js and io.js",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -267,3 +267,3 @@

if (p === '/empty') {
if (p === '/no-content') {
res.statusCode = 204;

@@ -273,2 +273,19 @@ res.end();

if (p === '/no-content/gzip') {
res.statusCode = 204;
res.setHeader('Content-Encoding', 'gzip');
res.end();
}
if (p === '/not-modified') {
res.statusCode = 304;
res.end();
}
if (p === '/not-modified/gzip') {
res.statusCode = 304;
res.setHeader('Content-Encoding', 'gzip');
res.end();
}
if (p === '/inspect') {

@@ -275,0 +292,0 @@ res.statusCode = 200;

@@ -14,2 +14,3 @@

var http = require('http');
var fs = require('fs');

@@ -420,4 +421,4 @@ var TestServer = require('./server');

it('should handle empty response', function() {
url = base + '/empty';
it('should handle no content response', function() {
url = base + '/no-content';
return fetch(url).then(function(res) {

@@ -434,2 +435,43 @@ expect(res.status).to.equal(204);

it('should handle no content response with gzip encoding', function() {
url = base + '/no-content/gzip';
return fetch(url).then(function(res) {
expect(res.status).to.equal(204);
expect(res.statusText).to.equal('No Content');
expect(res.headers.get('content-encoding')).to.equal('gzip');
expect(res.ok).to.be.true;
return res.text().then(function(result) {
expect(result).to.be.a('string');
expect(result).to.be.empty;
});
});
});
it('should handle not modified response', function() {
url = base + '/not-modified';
return fetch(url).then(function(res) {
expect(res.status).to.equal(304);
expect(res.statusText).to.equal('Not Modified');
expect(res.ok).to.be.false;
return res.text().then(function(result) {
expect(result).to.be.a('string');
expect(result).to.be.empty;
});
});
});
it('should handle not modified response with gzip encoding', function() {
url = base + '/not-modified/gzip';
return fetch(url).then(function(res) {
expect(res.status).to.equal(304);
expect(res.statusText).to.equal('Not Modified');
expect(res.headers.get('content-encoding')).to.equal('gzip');
expect(res.ok).to.be.false;
return res.text().then(function(result) {
expect(result).to.be.a('string');
expect(result).to.be.empty;
});
});
});
it('should decompress gzip response', function() {

@@ -572,6 +614,9 @@ url = base + '/gzip';

it('should allow POST request with readable stream as body', function() {
var body = resumer().queue('a=1').end();
body = body.pipe(new stream.PassThrough());
url = base + '/inspect';
opts = {
method: 'POST'
, body: resumer().queue('a=1').end()
, body: body
};

@@ -607,2 +652,22 @@ return fetch(url, opts).then(function(res) {

it('should allow POST request with form-data using stream as body', function() {
var form = new FormData();
form.append('my_field', fs.createReadStream('test/dummy.txt'));
url = base + '/multipart';
opts = {
method: 'POST'
, body: form
};
return fetch(url, opts).then(function(res) {
return res.json();
}).then(function(res) {
expect(res.method).to.equal('POST');
expect(res.headers['content-type']).to.contain('multipart/form-data');
expect(res.headers['content-length']).to.be.undefined;
expect(res.body).to.contain('my_field=');
});
});
it('should allow POST request with form-data as body and custom headers', function() {

@@ -658,2 +723,34 @@ var form = new FormData();

it('should allow POST request with string body', function() {
url = base + '/inspect';
opts = {
method: 'POST'
, body: 'a=1'
};
return fetch(url, opts).then(function(res) {
return res.json();
}).then(function(res) {
expect(res.method).to.equal('POST');
expect(res.body).to.equal('a=1');
expect(res.headers['transfer-encoding']).to.be.undefined;
expect(res.headers['content-length']).to.equal('3');
});
});
it('should allow DELETE request with string body', function() {
url = base + '/inspect';
opts = {
method: 'DELETE'
, body: 'a=1'
};
return fetch(url, opts).then(function(res) {
return res.json();
}).then(function(res) {
expect(res.method).to.equal('DELETE');
expect(res.body).to.equal('a=1');
expect(res.headers['transfer-encoding']).to.be.undefined;
expect(res.headers['content-length']).to.equal('3');
});
});
it('should allow PATCH request', function() {

@@ -907,2 +1004,15 @@ url = base + '/inspect';

it('should allow cloning a json response, first log as text response, then return json object', function() {
url = base + '/json';
return fetch(url).then(function(res) {
var r1 = res.clone();
return r1.text().then(function(result) {
expect(result).to.equal('{"name":"value"}');
return res.json().then(function(result) {
expect(result).to.deep.equal({name: 'value'});
});
});
});
});
it('should not allow cloning a response after its been used', function() {

@@ -1207,2 +1317,8 @@ url = base + '/hello';

it('should support arbitrary url in Request constructor', function() {
url = 'anything';
var req = new Request(url);
expect(req.url).to.equal('anything');
});
it('should support clone() method in Request constructor', function() {

@@ -1209,0 +1325,0 @@ url = base;

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