Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass request cookies in redirects if follow_set_cookies is true #307

Merged
merged 4 commits into from
Apr 8, 2020
Merged
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
21 changes: 14 additions & 7 deletions lib/needle.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,8 @@ Needle.prototype.send_request = function(count, method, uri, config, post_data,

// if we got cookies, parse them unless we were instructed not to. make sure to include any
// cookies that might have been set on previous redirects.
if (config.parse_cookies && (headers['set-cookie'] || config.stored_cookies)) {
resp.cookies = extend(config.stored_cookies || {}, cookies.read(headers['set-cookie']));
if (config.parse_cookies && (headers['set-cookie'] || config.previous_resp_cookies)) {
resp.cookies = extend(config.previous_resp_cookies || {}, cookies.read(headers['set-cookie']));
debug('Got cookies', resp.cookies);
}

Expand All @@ -511,10 +511,17 @@ Needle.prototype.send_request = function(count, method, uri, config, post_data,
delete config.headers['content-length']; // in case the original was a multipart POST request.
}

// if follow_set_cookies is true, make sure to put any cookies in the next request's headers.
if (config.follow_set_cookies && resp.cookies) {
config.stored_cookies = resp.cookies;
config.headers['cookie'] = cookies.write(resp.cookies);
// if follow_set_cookies is true, insert cookies in the next request's headers.
// we set both the original request cookies plus any response cookies we might have received.
if (config.follow_set_cookies) {
var request_cookies = cookies.read(config.headers['cookie']);
config.previous_resp_cookies = resp.cookies;
if (Object.keys(request_cookies).length || Object.keys(resp.cookies).length) {
config.headers['cookie'] = cookies.write(extend(request_cookies, resp.cookies));
}
} else if (config.headers['cookie']) {
debug('Clearing original request cookie', config.headers['cookie']);
delete config.headers['cookie'];
}

if (config.follow_set_referer)
Expand Down Expand Up @@ -779,7 +786,7 @@ module.exports.defaults = function(obj) {
}
defaults[target_key] = obj[key];
} else {
throw new Error('Invalid property for defaults:' + target_key);
throw new Error('Invalid property for defaults:' + target_key);
}
}

Expand Down
144 changes: 118 additions & 26 deletions test/cookies_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ describe('cookies', function() {
describe('and response is a redirect', function() {

var redirectServer, testPort = 22222;
var requestCookies = [];

var responseCookies = [
[ // first req
Expand All @@ -158,7 +159,10 @@ describe('cookies', function() {
var number = parseInt(req.url.replace('/', ''));
var nextUrl = 'http://' + TEST_HOST + ':' + testPort + '/' + (number + 1);

if (responseCookies[number]) { // got cookies
if (number == 0) requestCookies = []; // reset
requestCookies.push(req.headers['cookie']);

if (responseCookies[number]) { // we should send cookies for this request
res.statusCode = 302;
res.setHeader('Set-Cookie', responseCookies[number]);
res.setHeader('Location', nextUrl);
Expand All @@ -177,38 +181,126 @@ describe('cookies', function() {

describe('and follow_set_cookies is false', function() {

var opts = {
follow_set_cookies: false,
follow_max: 4
};
describe('with original request cookie', function() {

it('no cookie header set on redirection request', function(done) {
var spy = sinon.spy(cookies, 'write');
var opts = {
follow_set_cookies: false,
follow_max: 4,
cookies: { 'xxx': 123 }
};

needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
spy.callCount.should.eql(0);
done();
it('request cookie is not passed to redirects', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
requestCookies.should.eql(["xxx=123", undefined, undefined, undefined, undefined])
done();
});
});
});

it('response cookies are not passed either', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
should.not.exist(resp.cookies);
done();
});
});

})

describe('without original request cookie', function() {

var opts = {
follow_set_cookies: false,
follow_max: 4,
};

it('no request cookies are sent', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
requestCookies.should.eql([undefined, undefined, undefined, undefined, undefined])
done();
});
});

it('response cookies are not passed either', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
should.not.exist(resp.cookies);
done();
});
});

})

});

describe('and follow_set_cookies is true', function() {
var opts = {
follow_set_cookies: true,
follow_max: 4
};

it('should have all the cookies', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
resp.cookies.should.have.property(BASE64_COOKIE_NAME);
resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
resp.cookies.should.have.property('FOO');
resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
done();

describe('with original request cookie', function() {

var opts = {
follow_set_cookies: true,
follow_max: 4,
cookies: { 'xxx': 123 }
};

it('request cookie is passed passed to redirects, and response cookies are added too', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
requestCookies.should.eql([
"xxx=123",
"xxx=123; wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
])
done();
});
});
});

it('response cookies are passed as well', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
resp.cookies.should.have.property(BASE64_COOKIE_NAME);
resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
resp.cookies.should.have.property('FOO');
resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
done();
});
});

})

describe('without original request cookie', function() {

var opts = {
follow_set_cookies: true,
follow_max: 4,
};

it('response cookies are passed to redirects', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
requestCookies.should.eql([
undefined,
"wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
])
done();
});
});

it('response cookies are passed as well', function(done) {
needle.get(TEST_HOST + ':' + testPort + '/0', opts, function(err, resp) {
resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
resp.cookies.should.have.property(BASE64_COOKIE_NAME);
resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
resp.cookies.should.have.property('FOO');
resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
done();
});
});

})

});
});

Expand Down