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

needle

Package Overview
Dependencies
Maintainers
1
Versions
112
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

needle - npm Package Compare versions

Comparing version 0.11.0 to 1.0.0

license.txt

39

lib/cookies.js

@@ -10,15 +10,11 @@ //

// RegExps
const COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
const EXCLUDED_CHARS = /[\x00-\x1F\x7F\x3B\x3B\s\"\,\\"%]/g;
const TRAILING_SEMICOLON = /\x3B+$/;
const SEP_SEMICOLON = /\s*\x3B\s*/;
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
var EXCLUDED_CHARS = /[\x00-\x1F\x7F\x3B\x3B\s\"\,\\"%]/g;
var TRAILING_SEMICOLON = /\x3B+$/;
var SEP_SEMICOLON = /\s*\x3B\s*/;
// Constants
const KEY_INDEX = 1; // index of key from COOKIE_PAIR match
const VALUE_INDEX = 3; // index of value from COOKIE_PAIR match
var KEY_INDEX = 1; // index of key from COOKIE_PAIR match
var VALUE_INDEX = 3; // index of value from COOKIE_PAIR match
// Convenience functions
// Returns a copy str trimmed and without trainling semicolon.

@@ -34,4 +30,2 @@ function cleanCookieString(str) {

// Private functions
// Returns a encoded copy of str based on RFC6265 S4.1.1.

@@ -48,11 +42,12 @@ function encodeCookieComponent(str) {

var res = COOKIE_PAIR.exec(str);
if (!res || !res[VALUE_INDEX]) return null;
return {
name: decodeURIComponent(res[KEY_INDEX]),
value: decodeURIComponent(res[VALUE_INDEX])
name : decodeURIComponent(res[KEY_INDEX]),
value : decodeURIComponent(res[VALUE_INDEX])
};
}
// Parses a set-cookie-header and returns a key/value object. Each key
// represent a name of a cookie.
// Parses a set-cookie-header and returns a key/value object.
// Each key represents the name of a cookie.
function parseSetCookieHeader(header) {

@@ -63,3 +58,3 @@ header = (header instanceof Array) ? header : [header];

var cookie = parseSetCookieString(str);
res[cookie.name] = cookie.value;
if (cookie) res[cookie.name] = cookie.value;
return res;

@@ -72,11 +67,9 @@ }, {});

return Object.keys(obj).reduce(function(str, name) {
var encodedName = encodeCookieComponent(name);
var encodedName = encodeCookieComponent(name);
var encodedValue = encodeCookieComponent(obj[name]);
str += (str ? "; " : "") + encodedName + '=' + encodedValue;
str += (str ? '; ' : '') + encodedName + '=' + encodedValue;
return str;
}, "");
}, '');
}
// Module interface
// returns a key/val object from an array of cookie strings

@@ -86,2 +79,2 @@ exports.read = parseSetCookieHeader;

// writes a cookie string header
exports.write = writeCookieString;
exports.write = writeCookieString;

@@ -6,3 +6,3 @@ var readFile = require('fs').readFile,

if (typeof data != 'object')
if (typeof data != 'object' || typeof data.pipe == 'function')
return callback(new Error('Multipart builder expects data as key/val object.'));

@@ -9,0 +9,0 @@

@@ -29,4 +29,9 @@ //////////////////////////////////////////

var tls_options = 'agent pfx key passphrase cert ca ciphers rejectUnauthorized secureProtocol';
var tls_options = 'agent pfx key passphrase cert ca ciphers rejectUnauthorized secureProtocol checkServerIdentity';
// older versions of node (< 0.11.4) prevent the runtime from exiting
// because of connections in keep-alive state. so if this is the case
// we'll default new requests to set a Connection: close header.
var close_by_default = !http.Agent || http.Agent.defaultMaxSockets != Infinity;
//////////////////////////////////////////

@@ -59,3 +64,2 @@ // decompressors for gzip/deflate bodies

accept : '*/*',
connection : 'close',
user_agent : user_agent,

@@ -184,6 +188,9 @@

'Accept' : options.accept || defaults.accept,
'Connection' : options.connection || defaults.connection,
'User-Agent' : options.user_agent || defaults.user_agent
}
// set connection header if opts.connection was passed, or if node < 0.11.4 (close)
if (options.connection || close_by_default)
config.headers['Connection'] = options.connection || 'close';
if ((options.compressed || defaults.compressed) && typeof zlib != 'undefined')

@@ -236,4 +243,3 @@ config.headers['Accept-Encoding'] = 'gzip,deflate';

var self = this,
out = new stream.PassThrough({ objectMode: false }),
var out = new stream.PassThrough({ objectMode: false }),
uri = this.uri,

@@ -249,20 +255,16 @@ data = this.data,

var config = this.setup(uri, options);
var body, config = this.setup(uri, options);
if (data) {
if (method.toUpperCase() == 'GET') { // build query string and append to URI
uri = uri.replace(/\?.*|$/, '?' + stringify(data));
post_data = null;
if (options.multipart) { // boss says we do multipart. so we do it.
} else if (options.multipart) { // build multipart body for request
var self = this, boundary = options.boundary || defaults.boundary;
var boundary = options.boundary || defaults.boundary;
multipart.build(data, boundary, function(err, body) {
multipart.build(data, boundary, function(err, parts) {
if (err) throw(err);
config.headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary;
config.headers['Content-Length'] = body.length;
self.send_request(1, method, uri, config, body, out, callback);
config.headers['Content-Length'] = parts.length;
self.send_request(1, method, uri, config, parts, out, callback);
});

@@ -274,25 +276,41 @@

post_data = data;
if (is_stream(data) && method.toUpperCase() == 'GET')
throw new Error('Refusing to pipe() a stream via GET. Did you mean .post?');
body = data; // use the raw buffer or stream as request body.
} else if (method.toUpperCase() == 'GET' && !options.json) {
// append the data to the URI as a querystring.
uri = uri.replace(/\?.*|$/, '?' + stringify(data));
} else { // string or object data, no multipart.
// if no content-type was passed, determine if json or not.
if (!config.headers['Content-Type']) {
config.headers['Content-Type'] = options.json
? 'application/json; charset=utf-8'
: 'application/x-www-form-urlencoded'; // no charset says W3 spec.
}
// if string, leave it as it is, otherwise, stringify.
body = (typeof(data) === 'string') ? data
: options.json ? JSON.stringify(data) : stringify(data);
// format post_data and build a buffer out of it.
var post_data = options.json ? JSON.stringify(data) : stringify(data);
post_data = new Buffer(post_data, config.encoding);
config.headers['Content-Length'] = post_data.length;
// ensure we have a buffer so bytecount is correct.
body = new Buffer(body, config.encoding);
}
// unless a specific accept header was passed, assume json wants json back.
if (options.json && config.headers['Accept'] === defaults.accept)
config.headers['Accept'] = 'application/json';
}
if (body) {
// unless we have a stream or set a querystring, set the content length.
if (body.length) config.headers['Content-Length'] = body.length;
// if no content-type was passed, determine if json or not.
if (!config.headers['Content-Type']) {
config.headers['Content-Type'] = options.json
? 'application/json; charset=utf-8'
: 'application/x-www-form-urlencoded'; // no charset says W3 spec.
}
// unless a specific accept header was passed, assume json wants json back.
if (options.json && config.headers['Accept'] === defaults.accept)
config.headers['Accept'] = 'application/json';
}
return this.send_request(1, method, uri, config, post_data, out, callback);
return this.send_request(1, method, uri, config, body, out, callback);
}

@@ -357,11 +375,13 @@

function done(err, resp, body) {
if (returned++ > 0) return;
if (returned++ > 0)
return debug('Already finished, stopping here.');
if (timer) clearTimeout(timer);
request.removeListener('error', had_error);
request.socket.removeListener('end', on_socket_end);
if (callback)
callback(err, resp, body);
else
out.emit('end', err, resp, body);
return callback(err, resp, body);
out.emit('end', err, resp, body);
}

@@ -379,2 +399,12 @@

// handle errors on the underlying socket, that may be closed while writing
// for an example case, see test/long_string_spec.js. we make sure this
// scenario ocurred by verifying the socket's writable & destroyed states.
function on_socket_end() {
if (!this.writable && this.destroyed === false) {
this.destroy();
had_error(new Error('Remote end closed socket abruptly.'))
}
}
debug('Making request #' + count, request_opts);

@@ -412,3 +442,3 @@ var request = protocol.request(request_opts, function(resp) {

if (config.follow_set_referer)
config.headers['Referer'] = uri;
config.headers['Referer'] = uri; // the original, not the destination URL.

@@ -424,3 +454,3 @@ config.headers['Host'] = null; // clear previous Host header to avoid conflicts.

// if authentication is requested and credentials were not passed, resend request if we have user/pass
// if auth is requested and credentials were not passed, resend request, provided we have user/pass.
if (resp.statusCode == 401 && headers['www-authenticate'] && config.credentials) {

@@ -437,3 +467,3 @@ if (!config.headers['Authorization']) { // only if authentication hasn't been sent

// ok so we got a valid (non-redirect & authorized) response. notify the stream guys.
// ok, so we got a valid (non-redirect & authorized) response. let's notify the stream guys.
out.emit('header', resp.statusCode, headers);

@@ -508,3 +538,3 @@ out.emit('headers', headers);

// Count the amount of (raw) bytes passed using a PassThrough stream.
// Gather and count the amount of (raw) bytes using a PassThrough stream.
var clean_pipe = new stream.PassThrough();

@@ -535,3 +565,3 @@ resp.pipe(clean_pipe);

out.on('end', function() {
// we may want access to the raw data, so keep a reference.
// we want to be able to access to the raw data later, so keep a reference.
resp.raw = Buffer.concat(resp.raw);

@@ -566,6 +596,13 @@

// unless timeout was disabled, set a timeout to abort the request
// unless open_timeout was disabled, set a timeout to abort the request.
set_timeout(config.open_timeout);
// handle errors on the request object. things might get bumpy.
request.on('error', had_error);
// handle socket 'end' event to ensure we don't get delayed EPIPE errors.
request.once('socket', function(socket) {
socket.once('end', on_socket_end.bind(socket));
})
if (post_data) {

@@ -572,0 +609,0 @@ if (is_stream(post_data)) {

{
"name": "needle",
"version": "0.11.0",
"version": "1.0.0",
"description": "The leanest and most handsome HTTP client in the Nodelands.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -20,3 +20,2 @@ var needle = require('../'),

describe('when host does not exist', function(){

@@ -54,2 +53,16 @@

it('does not emit an error event', function(done) {
var emitted = false;
var req = needle.get(url, function(err, resp) { })
req.on('error', function() {
emitted = true;
})
setTimeout(function() {
emitted.should.eql(false);
done();
}, 100);
})
})

@@ -106,2 +119,16 @@

it('does not emit an error event', function(done) {
var emitted = false,
req = needle.get(url);
req.on('error', function() {
emitted = true;
})
setTimeout(function() {
emitted.should.eql(false);
done();
}, 100);
})
})

@@ -163,2 +190,19 @@

it('does not emit an error event', function(done) {
var emitted = false;
var req = send_request(function(err, resp) {
should.not.exist(resp);
})
req.on('error', function() {
emitted = true;
})
setTimeout(function() {
emitted.should.eql(false);
done();
}, 100);
})
})

@@ -223,2 +267,16 @@

it('does not emit an error event', function(done) {
var emitted = false;
var req = send_request();
req.on('error', function() {
emitted = true;
})
setTimeout(function() {
emitted.should.eql(false);
done();
}, 100);
})
})

@@ -225,0 +283,0 @@

@@ -44,3 +44,3 @@ var fs = require('fs');

var handler = function(req, res){
var handler = function(req, res) {

@@ -50,2 +50,6 @@ req.setEncoding('utf8'); // get as string

req.on('data', function(str) { req.body += str })
req.socket.on('error', function(e) {
// res.writeHead(500, {'Content-Type': 'text/plain'});
// res.end('Error: ' + e.message);
})

@@ -52,0 +56,0 @@ setTimeout(function(){

@@ -98,3 +98,8 @@ var helpers = require('./helpers'),

send_request(opts, function(err, resp) {
spies.http.callCount.should.eql(1); // the one from http.request
// on new node versions, https.request calls http.request internally,
// so we need to amount for that additional call.
var http_calls = protocols.http.Agent.defaultMaxSockets == Infinity ? 2 : 1;
spies.http.callCount.should.eql(http_calls); // the one(s) from http.request
spies.https.callCount.should.eql(1); // the one from https.request (redirect)

@@ -101,0 +106,0 @@ done();

@@ -29,3 +29,5 @@ var should = require('should'),

stream._readableState.flowing.should.be.false;
// newer node versions set this to null instead of false
var bool = !!stream._readableState.flowing;
should.equal(false, bool);

@@ -46,3 +48,3 @@ var readableCalled = false;

it('should should emit a single data item which is our JSON object', function(done) {
var stream = needle.get('localhost:' + port)
var stream = needle.get('localhost:' + port)

@@ -49,0 +51,0 @@ var chunks = [];

Sorry, the diff of this file is not supported yet

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