Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions lib/cookies.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var URL = require('url');
var libCookie = require('cookie');
var setCookie = require('set-cookie-parser');
var TLD = require('tld');
var Transform = require('stream').Transform;
Expand All @@ -21,6 +20,54 @@ function cookies(config) {

var REDIRECT_QUERY_PARAM = '__proxy_cookies_to';

// Serializes cookie without changing it
function serializeCookie(cookie) {
var str = cookie.name + '=' + cookie.value;

if (cookie.maxAge) {
str += '; Max-Age=' + cookie.maxAge;
}
if (cookie.domain) {
str += '; Domain=' + cookie.domain;
}
if (cookie.path) {
str += '; Path=' + cookie.path;
}
if (cookie.expires) {
str += '; Expires=' + cookie.expires.toUTCString();
}
if (cookie.httpOnly) {
str += '; HttpOnly';
}
if (cookie.secure) {
str += '; Secure';
}
return str;
}

// Parses the cookies without changing its value
function parseCookies(rawCookies) {
var obj = {};
var cookies;
if(typeof rawCookies !== 'string') return {};
if(rawCookies === '') return {};
cookies = rawCookies.split(';');
for (var i = 0, ii = cookies.length; i < ii; i++) {
// Removes first space if there is one
// V8 should always support trimLeft even though there is no standard for it.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimLeft
// https://www.npmjs.com/package/string could be a solution in case trimLeft() is dropped from V8.
cookies[i] = cookies[i].trimLeft();
// Puts the name and value in the object obj.
if(cookies[i].indexOf('=') !== -1) {
obj[cookies[i].substring(0, cookies[i].indexOf('='))] = cookies[i].substring(cookies[i].indexOf('=') + 1);
} else {
obj[cookies[i]] = '';
}
}
return obj;
}

// normally we do nothing here, but when the user is switching protocols or subdomains, the handleResponse function
// will rewrite the links to start with the old protocol & domain (so that we get sent the cookies), and then it
// will copy the old cookies to the new path
Expand All @@ -29,10 +76,11 @@ function cookies(config) {
if (uri.query[REDIRECT_QUERY_PARAM]) {
var nextUri = URL.parse(uri.query[REDIRECT_QUERY_PARAM]);
debug('copying cookies from %s to %s', data.url, uri.query[REDIRECT_QUERY_PARAM]);
var cookies = libCookie.parse(data.headers.cookie || '');
var cookies = parseCookies(data.headers.cookie || '');
var setCookieHeaders = Object.keys(cookies).map(function(name) {
var value = cookies[name];
return libCookie.serialize(name, value, {
return serializeCookie({
name: name,
value: cookies[name],
path: config.prefix + nextUri.protocol + '//' + nextUri.host + '/'
});
});
Expand Down Expand Up @@ -62,8 +110,7 @@ function cookies(config) {
cookie.path = config.prefix + targetUri.protocol + '//' + targetUri.host + (cookie.path || '/');
delete cookie.domain;
delete cookie.secure; // todo: maybe leave this if we knot the proxy is being accessed over https?
cookie.value = decodeURIComponent(cookie.value); // Used to avoid double percent-encoding
return libCookie.serialize(cookie.name, cookie.value, cookie);
return serializeCookie(cookie);
});
}

Expand All @@ -75,9 +122,11 @@ function cookies(config) {
debug('copying cookies from %s to %s', data.url, data.redirectUrl);

// get all of the old cookies (from the request) indexed by name, and create set-cookie headers for each one
var oldCookies = libCookie.parse(data.clientRequest.headers.cookie || '');
var oldCookies = parseCookies(data.clientRequest.headers.cookie || '');
var oldSetCookieHeaders = _.mapValues(oldCookies, function(value, name) {
return libCookie.serialize(name, value, {
return serializeCookie({
name: name,
value: value,
path: config.prefix + nextUri.protocol + '//' + nextUri.host + '/'
});
});
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"dependencies": {
"async": "^2.0.0",
"content-type": "^1.0.1",
"cookie": "^0.3.1",
"debug": "^2.2.0",
"iconv-lite": "^0.4.13",
"lodash": "^4.4.0",
Expand Down
16 changes: 16 additions & 0 deletions test/cookies_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ test('should rewrite the cookie that is percent-encoded correctly', function(t)
t.end();
});

test('should rewrite the cookie that is weird but correct correctly', function(t) {
var instance = cookies({
prefix: '/proxy/',
processContentTypes: []
});
var data = getData();
data.headers['set-cookie'] = ['myCookie=is=called&john=doe&for=a&reason=#WeDontParseCookieValues&only=its&parameters=!; Path=/myAwesomePath; HttpOnly'];
instance.handleResponse(data);
var expected = [
'myCookie=is=called&john=doe&for=a&reason=#WeDontParseCookieValues&only=its&parameters=!; Path=/proxy/http://example.com/myAwesomePath; HttpOnly'
];
var actual = data.headers['set-cookie'];
t.same(actual, expected);
t.end();
});

test("should copy any missing cookies to a 3xx redirect", function(t) {
t.plan(1);
var instance = cookies({
Expand Down