🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
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

to
0.9.2

test/cookies_spec.js.orig

120

lib/cookies.js

@@ -1,77 +0,81 @@

var valid_keys = ['domain', 'path', 'expires', 'httponly', 'secure'];
//
// Simple cookie handling implementation based on the standard RFC 6265.
// This module just has two functionalities:
// - Parse a set-cookie-header as a key value object
// - Write a cookie-string from a key value object
// All cookie attributes are ignored.
//
// modified version of the parse function from the cookie lib by jshttp:
// https://github.com/jshttp/cookie/blob/master/index.js
// RegExps
function parse(str, opt) {
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*/;
var obj = {},
res = {},
pairs = str.split(/; */), // matches no whitespace too
dec = decodeURIComponent;
// Constants
pairs.forEach(function(pair) {
var index = pair.indexOf('=');
var KEY_INDEX = 1; // index of key from COOKIE_PAIR match
var VALUE_INDEX = 3; // index of value from COOKIE_PAIR match
// skip things that don't look like key=value
if (index < 0)
return;
// Convenience functions
var key = pair.substr(0, index).trim(),
val = pair.substr(++index, pair.length).trim();
// Returns a copy str trimmed and without trainling semicolon.
function cleanCookieString(str) {
return str.trim().replace(/\x3B+$/, '');
}
// quoted values
if ('"' == val[0]) {
val = val.slice(1, -1);
}
function getFirstPair(str) {
var index = str.indexOf('\x3B');
return index === -1 ? str : str.substr(0, index);
}
// only assign once
if (undefined == obj[key]) {
try {
obj[key] = dec(val);
} catch (e) {
obj[key] = val;
}
}
});
// Private functions
// if key is part of valid_keys, set it, otherwise set it as key=[key] and value=[val]
for (var key in obj) {
if (valid_keys.indexOf(key.toLowerCase()) != -1) {
res[key] = obj[key];
} else {
res.key = key;
res.value = obj[key];
}
}
// Returns a encoded copy of str based on RFC6265 S4.1.1.
function encodeCookieComponent(str) {
return str.toString().replace(EXCLUDED_CHARS, encodeURIComponent);
}
return res;
};
// Parses a set-cookie-string based on the standard definded in RFC6265 S4.1.1.
function parseSetCookieString(str) {
str = cleanCookieString(str);
str = getFirstPair(str);
function to_hash(arr, url) {
var res = {};
var res = COOKIE_PAIR.exec(str);
arr.forEach(function(obj) {
// if (!obj.path || (url.indexOf(obj.path) !== -1)) {
res[obj.key] = obj.value;
// }
})
return {
name: decodeURIComponent(res[KEY_INDEX]),
value: decodeURIComponent(res[VALUE_INDEX])
};
}
return res;
// Parses a set-cookie-header and returns a key/value object. Each key
// represent a name of a cookie.
function parseSetCookieHeader(header) {
header = (header instanceof Array) ? header : [header];
return header.reduce(function(res, str) {
var cookie = parseSetCookieString(str);
res[cookie.name] = cookie.value;
return res;
}, {});
}
// returns a key/val object from an array of
exports.read = function(header) {
var arr = (header instanceof Array) ? header : [header];
return to_hash(arr.map(function(c) { return parse(c); }));
// Writes a set-cookie-string based on the standard definded in RFC6265 S4.1.1.
function writeCookieString(obj) {
return Object.keys(obj).reduce(function(str, name) {
var encodedName = encodeCookieComponent(name);
var encodedValue = encodeCookieComponent(obj[name]);
str += (str ? "; " : "") + encodedName + '=' + encodedValue;
return str;
}, "");
}
exports.write = function(obj) {
var res, enc = encodeURIComponent;
// Module interface
res = Object.keys(obj).map(function(key) {
return enc(key) + '=' + enc(obj[key]);
})
// returns a key/val object from an array of cookie strings
exports.read = parseSetCookieHeader;
return res.join('; ');
};
// writes a cookie string header
exports.write = writeCookieString;

@@ -398,3 +398,3 @@ //////////////////////////////////////////

if (config.follow_set_cookies)
if (config.follow_set_cookies && resp.cookies)
config.headers['Cookie'] = cookies.write(resp.cookies);

@@ -401,0 +401,0 @@

@@ -16,3 +16,3 @@ // based on the qs module, but handles null objects as expected

} else {
throw new TypeError('Invalid object received:' + obj);
throw new TypeError('Cannot build a querystring out of: ' + obj);
}

@@ -19,0 +19,0 @@ };

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

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

@@ -1,75 +0,204 @@

var needle = require('../'),
sinon = require('sinon'),
should = require('should'),
http = require('http'),
cookies = require('../lib/cookies');
var needle = require('../'),
sinon = require('sinon'),
http = require('http'),
should = require('should'),
assert = require('assert');
var WEIRD_COOKIE_NAME = 'wc',
BASE64_COOKIE_NAME = 'bc',
FORBIDDEN_COOKIE_NAME = 'fc',
NUMBER_COOKIE_NAME = 'nc',
WEIRD_COOKIE_VALUE = '!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[' +
']^_`abcdefghijklmnopqrstuvwxyz{|}~',
BASE64_COOKIE_VALUE = 'Y29va2llCg==',
FORBIDDEN_COOKIE_VALUE = ' ;"\\,',
NUMBER_COOKIE_VALUE = 12354342,
WEIRD_COOKIE = 'wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~',
BASE64_COOKIE = 'bc=Y29va2llCg==',
FORBIDDEN_COOKIE = 'fc=%20%3B%22%5C%2C',
NUMBER_COOKIE = 'nc=12354342',
COOKIE_HEADER = WEIRD_COOKIE + '; ' + BASE64_COOKIE + '; ' +
FORBIDDEN_COOKIE + '; ' + NUMBER_COOKIE,
TEST_HOST = 'localhost';
NO_COOKIES_TEST_PORT = 11112, ALL_COOKIES_TEST_PORT = 11113;
function decode(str) {
return decodeURIComponent(str);
}
function encode(str) {
str = str.toString().replace(/[\x00-\x1F\x7F]/g, encodeURIComponent);
return str.replace(/[\s\"\,;\\%]/g, encodeURIComponent);
}
describe('cookies', function() {
var last_req;
var headers, server, opts;
var server = http.createServer(function(req, res) {
last_req = req;
res.end('Thanks.');
})
before(function() {
setCookieHeader = [
WEIRD_COOKIE_NAME + '=' + encode(WEIRD_COOKIE_VALUE) + ';',
BASE64_COOKIE_NAME + '=' + encode(BASE64_COOKIE_VALUE) + ';',
FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE) + ';',
NUMBER_COOKIE_NAME + '=' + encode(NUMBER_COOKIE_VALUE) + ';'
];
});
before(function(done) {
server.listen(function() {
port = this.address().port;
done();
});
})
serverAllCookies = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.setHeader('Set-Cookie', setCookieHeader);
res.end('200');
}).listen(ALL_COOKIES_TEST_PORT, TEST_HOST, done);
});
after(function(done) {
server.close(done)
})
serverAllCookies.close(done);
});
describe('with default options', function() {
it('no cookie header is set on request', function(done) {
needle.get(
TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, function(err, response) {
assert(!response.req._headers.cookie);
done();
});
});
});
it('no cookie header is set on request', function() {
describe('if response does not contain cookies', function() {
before(function(done) {
serverNoCookies = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.end('200');
}).listen(NO_COOKIES_TEST_PORT, TEST_HOST, done);
});
})
it('response.cookies is undefined', function(done) {
needle.get(
TEST_HOST + ':' + NO_COOKIES_TEST_PORT, function(error, response) {
assert(!response.cookies);
done();
});
});
})
after(function(done) {
serverNoCookies.close(done);
});
});
describe('if response does not contain cookies', function() {
describe('if response contains cookies', function() {
it('puts them on resp.cookies', function(done) {
needle.get(
TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, function(error, response) {
response.should.have.property('cookies');
done();
});
});
it('resp.cookies is undefined', function() {
it('parses them as a object', function(done) {
needle.get(
TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, function(error, response) {
response.cookies.should.be.an.instanceOf(Object)
.and.have.property(WEIRD_COOKIE_NAME);
response.cookies.should.have.property(BASE64_COOKIE_NAME);
response.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
response.cookies.should.have.property(NUMBER_COOKIE_NAME);
done();
});
});
})
it('must decode it', function(done) {
needle.get(
TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, function(error, response) {
response.cookies.wc.should.be.eql(WEIRD_COOKIE_VALUE);
response.cookies.bc.should.be.eql(BASE64_COOKIE_VALUE);
response.cookies.fc.should.be.eql(FORBIDDEN_COOKIE_VALUE);
response.cookies.nc.should.be.eql(NUMBER_COOKIE_VALUE.toString());
done();
});
});
})
describe('and response is a redirect', function() {
describe('and follow_set_cookies is false', function() {
it('no cookie header set on redirection request', function() {});
});
describe('and follow_set_cookies is true', function() {});
});
});
describe('if response contains cookies', function() {
describe('if resquest contains cookie header', function() {
var opts = {
cookies: {}
};
it('parses them', function() {
before(function() {
opts.cookies[WEIRD_COOKIE_NAME] = WEIRD_COOKIE_VALUE;
opts.cookies[BASE64_COOKIE_NAME] = BASE64_COOKIE_VALUE;
opts.cookies[FORBIDDEN_COOKIE_NAME] = FORBIDDEN_COOKIE_VALUE;
opts.cookies[NUMBER_COOKIE_NAME] = NUMBER_COOKIE_VALUE;
});
})
it('must be a valid cookie string', function(done) {
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
it('puts them on resp.cookies', function() {
needle.get(TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
var cookieString = response.req._headers.cookie;
})
cookieString.should.be.type('string');
describe('and response is a redirect', function() {
cookieString.split(/\s*;\s*/).forEach(function(pair) {
COOKIE_PAIR.test(pair).should.be.exactly(true);
});
describe('and follow_set_cookies is false', function() {
cookieString.should.be.exactly(COOKIE_HEADER);
})
done();
});
});
describe('and follow_set_cookies is true', function() {
})
it('dont have to encode allowed characters', function(done) {
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
KEY_INDEX = 1,
VALUE_INEX = 3;
})
needle.get(TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
var cookieObj = {},
cookieString = response.req._headers.cookie;
})
cookieString.split(/\s*;\s*/).forEach(function(str) {
var pair = COOKIE_PAIR.exec(str);
cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
});
describe('when passing an object on options.cookies', function() {
cookieObj[WEIRD_COOKIE_NAME].should.be.exactly(WEIRD_COOKIE_VALUE);
cookieObj[BASE64_COOKIE_NAME].should.be.exactly(BASE64_COOKIE_VALUE);
done();
});
});
it('sets the cookies', function() {
it('must encode forbidden characters', function(done) {
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
KEY_INDEX = 1,
VALUE_INEX = 3;
})
needle.get(TEST_HOST + ':' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
var cookieObj = {},
cookieString = response.req._headers.cookie;
})
cookieString.split(/\s*;\s*/).forEach(function(str) {
var pair = COOKIE_PAIR.exec(str);
cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
});
});
cookieObj[FORBIDDEN_COOKIE_NAME].should.not.be.eql(
FORBIDDEN_COOKIE_VALUE);
cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
encode(FORBIDDEN_COOKIE_VALUE));
cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
encodeURIComponent(FORBIDDEN_COOKIE_VALUE));
done();
});
});
});
});

@@ -9,7 +9,6 @@ var should = require('should'),

var url;
this.timeout(5000);
describe('test A', function() {
this.timeout(5000);
before(function() {

@@ -44,3 +43,3 @@ url = 'http://www.huanqiukexue.com/html/newgc/2014/1215/25011.html';

})
})

@@ -47,0 +46,0 @@

@@ -110,27 +110,27 @@ var needle = require('../'),

it('emits end event once, with error', function(done) {
var called = 0,
var callcount = 0,
stream = needle.get(url);
stream.on('end', function(err) {
called++;
callcount++;
})
setTimeout(function() {
called.should.equal(1);
callcount.should.equal(1);
done();
}, 50)
}, 200)
})
it('error should be ENOTFOUND or EADDRINFO', function(done){
var error,
it('error should be ENOTFOUND or EADDRINFO', function(done) {
var errorific,
stream = needle.get(url);
stream.on('end', function(err) {
error = err;
errorific = err;
})
setTimeout(function() {
error.code.should.match(/ENOTFOUND|EADDRINFO/)
errorific.code.should.match(/ENOTFOUND|EADDRINFO/)
done();
}, 50)
}, 200)
})

@@ -137,0 +137,0 @@

@@ -64,3 +64,4 @@ var helpers = require('./helpers'),

var opts, // each test will modify this
url = protocol + '://localhost:' + ports[protocol] + '/hello';
host = '127.0.0.1',
url = protocol + '://' + host + ':' + ports[protocol] + '/hello';

@@ -165,3 +166,3 @@ function send_request(opts, cb) {

before(function() {
location = url.replace('localhost', hostname);
location = url.replace(host, hostname);
})

@@ -173,3 +174,3 @@ it('follows redirect', followed_same_protocol);

before(function() {
location = url.replace('localhost', hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
})

@@ -283,3 +284,3 @@ it('follows redirect', followed_other_protocol);

send_request(opts, function(err, resp) {
spies.http.args[0][0].headers['Referer'].should.eql("http://localhost:8888/hello");
spies.http.args[0][0].headers['Referer'].should.eql("http://" + host + ":8888/hello");
// spies.http.args[0][3].should.eql({ foo: 'bar'});

@@ -330,3 +331,3 @@ done();

before(function() {
location = url.replace('localhost', hostname);
location = url.replace(host, hostname);
})

@@ -347,3 +348,3 @@ it('follows redirect', followed_same_protocol);

before(function() {
location = url.replace('localhost', hostname);
location = url.replace(host, hostname);
})

@@ -365,3 +366,3 @@

before(function() {
location = url.replace('localhost', hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
})

@@ -382,3 +383,3 @@ it('follows redirect', followed_other_protocol);

before(function() {
location = url.replace('localhost', hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
})

@@ -385,0 +386,0 @@ it('does not follow redirect', not_followed);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet