123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- var helpers = require('./helpers'),
- should = require('should'),
- sinon = require('sinon'),
- needle = require('./../');
- var ports = {
- http : 8888,
- https : 9999
- }
- var protocols = {
- http : require('http'),
- https : require('https')
- }
- var code = 301;
- var location; // var to set the response location
- function response_code() {
- return code;
- }
- function response_headers() {
- return { 'Content-Type': 'text/plain', 'Location': location }
- }
- describe('redirects', function() {
- var spies = {},
- servers = {};
- var current_protocol;
- var hostname = require('os').hostname();
- // open two servers, one that responds to a redirect
- before(function(done) {
- var conf = {
- port : ports.http,
- code : response_code,
- headers : response_headers
- }
- servers.http = helpers.server(conf, function() {
- conf.port = ports.https;
- conf.protocol = 'https';
- servers.https = helpers.server(conf, done);
- });
- })
- after(function(done) {
- servers.http.close(function() {
- servers.https.close(done);
- });
- })
- var prots = {'http': 'https'};
- Object.keys(prots).forEach(function(protocol) {
- current_protocol = protocol;
- var other_protocol = protocol == 'http' ? 'https' : 'http';
- var opts, // each test will modify this
- host = '127.0.0.1',
- url = protocol + '://' + host + ':' + ports[protocol] + '/hello';
- function send_request(opts, cb) {
- if (protocol == 'https') opts.rejectUnauthorized = false;
- // console.log(' -- sending request ' + url + ' -- redirect to ' + location);
- needle.post(url, { foo: 'bar' }, opts, cb);
- }
- function not_followed(done) {
- send_request(opts, function(err, resp) {
- resp.statusCode.should.eql(301);
- if (current_protocol == 'http') {
- spies.http.callCount.should.eql(1); // only original request
- spies.https.callCount.should.eql(0);
- } else {
- spies.http.callCount.should.eql(0);
- spies.https.callCount.should.eql(1); // only original request
- }
- done();
- })
- }
- function followed_same_protocol(done) {
- send_request(opts, function(err, resp) {
- // the original request plus the redirect one
- spies[current_protocol].callCount.should.eql(2);
- done();
- })
- }
- function followed_other_protocol(done) {
- send_request(opts, function(err, resp) {
- // on new-ish node versions, https.request calls http.request internally,
- // so we need to amount for that additional call.
- // update: this doesn't happen on node > 10.x
- var node_major_ver = process.version.split('.')[0].replace('v', '');
- var http_calls = protocols.http.Agent.defaultMaxSockets == Infinity && parseInt(node_major_ver) < 10 ? 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)
- done();
- })
- }
- // set a spy on [protocol].request
- // so we can see how many times a request was made
- before(function() {
- spies.http = sinon.spy(protocols.http, 'request');
- spies.https = sinon.spy(protocols.https, 'request');
- })
- // and make sure it is restored after each test
- afterEach(function() {
- spies.http.reset();
- spies.https.reset();
- })
- after(function() {
- spies.http.restore();
- spies.https.restore();
- })
- describe('when overriding defaults', function() {
- before(function() {
- needle.defaults({ follow_max: 10 });
- opts = {};
- })
- after(function() {
- // reset values to previous
- needle.defaults({ follow_max: 0 });
- })
- describe('and redirected to the same path on same host and protocol', function() {
- before(function() {
- location = url;
- })
- it('does not follow redirect', not_followed);
- })
- describe('and redirected to the same path on same host and different protocol', function() {
- before(function() {
- location = url.replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
- })
- it('follows redirect', followed_other_protocol);
- })
- describe('and redirected to a different path on same host, same protocol', function() {
- before(function() {
- location = url.replace('/hello', '/goodbye');
- })
- it('follows redirect', followed_same_protocol);
- })
- describe('and redirected to a different path on same host, different protocol', function() {
- before(function() {
- location = url.replace('/hello', '/goodbye').replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
- })
- it('follows redirect', followed_other_protocol);
- })
- describe('and redirected to same path on another host, same protocol', function() {
- before(function() {
- location = url.replace(host, hostname);
- })
- it('follows redirect', followed_same_protocol);
- })
- describe('and redirected to same path on another host, different protocol', function() {
- before(function() {
- location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
- })
- it('follows redirect', followed_other_protocol);
- })
- })
- // false and null have the same result
- var values = [false, null];
- values.forEach(function(value) {
- describe('when follow is ' + value, function() {
- before(function() {
- opts = { follow: value };
- })
- describe('and redirected to the same path on same host and protocol', function() {
- before(function() {
- location = url;
- })
- it('throws an error', function() {
- (function() {
- send_request(opts, function() { });
- }).should.throw;
- })
- })
- })
- })
- describe('when follow is true', function() {
- before(function() {
- opts = { follow: true };
- })
- describe('and redirected to the same path on same host and protocol', function() {
- before(function() { location = url })
- it('throws an error', function() {
- (function() {
- send_request(opts, function() { });
- }).should.throw;
- })
- })
- })
- describe('when follow is > 0', function() {
- before(function() {
- needle.defaults({ follow: 10 });
- })
- after(function() {
- needle.defaults({ follow: 0 });
- })
- describe('when keep_method is false', function() {
- before(function() {
- opts = { follow_keep_method: false };
- })
- // defaults to follow host and protocol
- describe('and redirected to the same path on same host and different protocol', function() {
- before(function() {
- location = url.replace(protocol, other_protocol);
- })
- it('follows redirect', followed_other_protocol);
- it('sends a GET request with no data', function(done) {
- send_request(opts, function(err, resp) {
- // spy.args[0][3].should.eql(null);
- spies.http.args[0][0].method.should.eql('GET');
- done();
- })
- })
- it('does not resend cookies if follow_set_cookies is false', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = false;
- send_request(opts, function(err, resp) {
- should.not.exist(spies.http.args[0][0].headers['cookie']);
- done();
- })
- })
- it('resends cookies if follow_set_cookies is true', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = true;
- send_request(opts, function(err, resp) {
- spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
- done();
- })
- })
- })
- })
- describe('and set_referer is true', function() {
- before(function() {
- opts = { follow_set_referer: true };
- })
- // defaults to follow host and protocol
- describe('and redirected to the same path on same host and different protocol', function() {
- before(function() {
- location = url.replace(protocol, other_protocol);
- })
- it('follows redirect', followed_other_protocol);
- it('sets Referer header when following redirect', function(done) {
- send_request(opts, function(err, resp) {
- // spies.http.args[0][3].should.eql({ foo: 'bar'});
- spies.http.args[0][0].headers['referer'].should.eql("http://" + host + ":8888/hello");
- done();
- })
- })
- it('does not resend cookies if follow_set_cookies is false', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = false;
- send_request(opts, function(err, resp) {
- should.not.exist(spies.http.args[0][0].headers['cookie']);
- done();
- })
- })
- it('resends cookies if follow_set_cookies is true', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = true;
- send_request(opts, function(err, resp) {
- spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
- done();
- })
- })
- })
- })
- describe('and keep_method is true', function() {
- before(function() {
- opts = { follow_keep_method: true };
- })
- // defaults to follow host and protocol
- describe('and redirected to the same path on same host and different protocol', function() {
- before(function() {
- location = url.replace(protocol, other_protocol);
- })
- it('follows redirect', followed_other_protocol);
- it('sends a POST request with the original data', function(done) {
- send_request(opts, function(err, resp) {
- spies.http.args[0][0].method.should.eql('post');
- // spies.http.args[0][3].should.eql({ foo: 'bar'});
- done();
- })
- })
- it('does not resend cookies if follow_set_cookies is false', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = false;
- send_request(opts, function(err, resp) {
- should.not.exist(spies.http.args[0][0].headers['cookie']);
- done();
- })
- })
- it('resends cookies if follow_set_cookies is true', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = true;
- send_request(opts, function(err, resp) {
- spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
- done();
- })
- })
- })
- })
- describe('and if_same_host is false', function() {
- before(function() {
- opts = { follow_if_same_host: false };
- })
- // by default it will follow other protocols
- describe('and redirected to same path on another domain, same protocol', function() {
- before(function() {
- location = url.replace(host, hostname);
- })
- it('follows redirect', followed_same_protocol);
- it('does not resend cookies even if follow_set_cookies is true', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = true;
- send_request(opts, function(err, resp) {
- should.not.exist(spies.http.args[0][0].headers['cookie']);
- done();
- })
- })
- })
- })
- describe('and if_same_host is true', function() {
- before(function() {
- opts = { follow_if_same_host: true };
- })
- // by default it will follow other protocols
- describe('and redirected to same path on another domain, same protocol', function() {
- before(function() {
- location = url.replace(host, hostname);
- })
- it('does not follow redirect', not_followed);
- })
- })
- describe('and if_same_protocol is false', function() {
- before(function() {
- opts = { follow_if_same_protocol: false };
- })
- // by default it will follow other hosts
- describe('and redirected to same path on another domain, different protocol', function() {
- before(function() {
- location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
- })
- it('follows redirect', followed_other_protocol);
- it('does not resend cookies even if follow_set_cookies is true', function(done) {
- opts.cookies = {foo: 'bar'};
- opts.follow_set_cookies = true;
- send_request(opts, function(err, resp) {
- should.not.exist(spies.http.args[0][0].headers['cookie']);
- done();
- })
- })
- })
- })
- describe('and if_same_protocol is true', function() {
- before(function() {
- opts = { follow_if_same_protocol: true };
- })
- // by default it will follow other hosts
- describe('and redirected to same path on another domain, different protocol', function() {
- before(function() {
- location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
- })
- it('does not follow redirect', not_followed);
- })
- })
- })
- })
- });
|