[6a3a178] | 1 | var needle = require('../'),
|
---|
| 2 | cookies = require('../lib/cookies'),
|
---|
| 3 | sinon = require('sinon'),
|
---|
| 4 | http = require('http'),
|
---|
| 5 | should = require('should');
|
---|
| 6 |
|
---|
| 7 | var WEIRD_COOKIE_NAME = 'wc',
|
---|
| 8 | BASE64_COOKIE_NAME = 'bc',
|
---|
| 9 | FORBIDDEN_COOKIE_NAME = 'fc',
|
---|
| 10 | NUMBER_COOKIE_NAME = 'nc';
|
---|
| 11 |
|
---|
| 12 | var WEIRD_COOKIE_VALUE = '!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~',
|
---|
| 13 | BASE64_COOKIE_VALUE = 'Y29va2llCg==',
|
---|
| 14 | FORBIDDEN_COOKIE_VALUE = ' ;"\\,',
|
---|
| 15 | NUMBER_COOKIE_VALUE = 12354342;
|
---|
| 16 |
|
---|
| 17 | var NO_COOKIES_TEST_PORT = 11112,
|
---|
| 18 | ALL_COOKIES_TEST_PORT = 11113;
|
---|
| 19 |
|
---|
| 20 | describe('cookies', function() {
|
---|
| 21 |
|
---|
| 22 | var setCookieHeader, headers, server, opts;
|
---|
| 23 |
|
---|
| 24 | function decode(str) {
|
---|
| 25 | return decodeURIComponent(str);
|
---|
| 26 | }
|
---|
| 27 |
|
---|
| 28 | function encode(str) {
|
---|
| 29 | str = str.toString().replace(/[\x00-\x1F\x7F]/g, encodeURIComponent);
|
---|
| 30 | return str.replace(/[\s\"\,;\\%]/g, encodeURIComponent);
|
---|
| 31 | }
|
---|
| 32 |
|
---|
| 33 | before(function() {
|
---|
| 34 | setCookieHeader = [
|
---|
| 35 | WEIRD_COOKIE_NAME + '=' + encode(WEIRD_COOKIE_VALUE) + ';',
|
---|
| 36 | BASE64_COOKIE_NAME + '=' + encode(BASE64_COOKIE_VALUE) + ';',
|
---|
| 37 | FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE) + ';',
|
---|
| 38 | NUMBER_COOKIE_NAME + '=' + encode(NUMBER_COOKIE_VALUE) + ';'
|
---|
| 39 | ];
|
---|
| 40 | });
|
---|
| 41 |
|
---|
| 42 | before(function(done) {
|
---|
| 43 | serverAllCookies = http.createServer(function(req, res) {
|
---|
| 44 | res.setHeader('Content-Type', 'text/html');
|
---|
| 45 | res.setHeader('Set-Cookie', setCookieHeader);
|
---|
| 46 | res.end('200');
|
---|
| 47 | }).listen(ALL_COOKIES_TEST_PORT, done);
|
---|
| 48 | });
|
---|
| 49 |
|
---|
| 50 | after(function(done) {
|
---|
| 51 | serverAllCookies.close(done);
|
---|
| 52 | });
|
---|
| 53 |
|
---|
| 54 | describe('with default options', function() {
|
---|
| 55 | it('no cookie header is set on request', function(done) {
|
---|
| 56 | needle.get(
|
---|
| 57 | 'localhost:' + ALL_COOKIES_TEST_PORT, function(err, response) {
|
---|
| 58 | should.not.exist(response.req._headers.cookie);
|
---|
| 59 | done();
|
---|
| 60 | });
|
---|
| 61 | });
|
---|
| 62 | });
|
---|
| 63 |
|
---|
| 64 | describe('if response does not contain cookies', function() {
|
---|
| 65 | before(function(done) {
|
---|
| 66 | serverNoCookies = http.createServer(function(req, res) {
|
---|
| 67 | res.setHeader('Content-Type', 'text/html');
|
---|
| 68 | res.end('200');
|
---|
| 69 | }).listen(NO_COOKIES_TEST_PORT, done);
|
---|
| 70 | });
|
---|
| 71 |
|
---|
| 72 | it('response.cookies is undefined', function(done) {
|
---|
| 73 | needle.get(
|
---|
| 74 | 'localhost:' + NO_COOKIES_TEST_PORT, function(error, response) {
|
---|
| 75 | should.not.exist(response.cookies);
|
---|
| 76 | done();
|
---|
| 77 | });
|
---|
| 78 | });
|
---|
| 79 |
|
---|
| 80 | after(function(done) {
|
---|
| 81 | serverNoCookies.close(done);
|
---|
| 82 | });
|
---|
| 83 | });
|
---|
| 84 |
|
---|
| 85 | describe('if response contains cookies', function() {
|
---|
| 86 |
|
---|
| 87 | it('puts them on resp.cookies', function(done) {
|
---|
| 88 | needle.get(
|
---|
| 89 | 'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
---|
| 90 | response.should.have.property('cookies');
|
---|
| 91 | done();
|
---|
| 92 | });
|
---|
| 93 | });
|
---|
| 94 |
|
---|
| 95 | it('parses them as a object', function(done) {
|
---|
| 96 | needle.get(
|
---|
| 97 | 'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
---|
| 98 | response.cookies.should.be.an.instanceOf(Object)
|
---|
| 99 | .and.have.property(WEIRD_COOKIE_NAME);
|
---|
| 100 | response.cookies.should.have.property(BASE64_COOKIE_NAME);
|
---|
| 101 | response.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
---|
| 102 | response.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
---|
| 103 | done();
|
---|
| 104 | });
|
---|
| 105 | });
|
---|
| 106 |
|
---|
| 107 | it('must decode it', function(done) {
|
---|
| 108 | needle.get(
|
---|
| 109 | 'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
---|
| 110 | response.cookies.wc.should.be.eql(WEIRD_COOKIE_VALUE);
|
---|
| 111 | response.cookies.bc.should.be.eql(BASE64_COOKIE_VALUE);
|
---|
| 112 | response.cookies.fc.should.be.eql(FORBIDDEN_COOKIE_VALUE);
|
---|
| 113 | response.cookies.nc.should.be.eql(NUMBER_COOKIE_VALUE.toString());
|
---|
| 114 | done();
|
---|
| 115 | });
|
---|
| 116 | });
|
---|
| 117 |
|
---|
| 118 | describe('when a cookie value is invalid', function() {
|
---|
| 119 |
|
---|
| 120 | before(function() {
|
---|
| 121 | setCookieHeader = [
|
---|
| 122 | 'geo_city=%D1%E0%ED%EA%F2-%CF%E5%F2%E5%F0%E1%F3%F0%E3'
|
---|
| 123 | ];
|
---|
| 124 | })
|
---|
| 125 |
|
---|
| 126 | it('doesnt blow up', function(done) {
|
---|
| 127 | needle.get('localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
---|
| 128 | should.not.exist(error)
|
---|
| 129 | var whatever = 'efbfbdefbfbdefbfbdefbfbdefbfbd2defbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd';
|
---|
| 130 | Buffer.from(response.cookies.geo_city).toString('hex').should.eql(whatever)
|
---|
| 131 | done();
|
---|
| 132 | });
|
---|
| 133 | })
|
---|
| 134 |
|
---|
| 135 | })
|
---|
| 136 |
|
---|
| 137 | describe('and response is a redirect', function() {
|
---|
| 138 |
|
---|
| 139 | var redirectServer, testPort = 22222;
|
---|
| 140 | var requestCookies = [];
|
---|
| 141 |
|
---|
| 142 | var responseCookies = [
|
---|
| 143 | [ // first req
|
---|
| 144 | WEIRD_COOKIE_NAME + '=' + encode(WEIRD_COOKIE_VALUE) + ';',
|
---|
| 145 | BASE64_COOKIE_NAME + '=' + encode(BASE64_COOKIE_VALUE) + ';',
|
---|
| 146 | 'FOO=123;'
|
---|
| 147 | ], [ // second req
|
---|
| 148 | FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE) + ';',
|
---|
| 149 | NUMBER_COOKIE_NAME + '=' + encode(NUMBER_COOKIE_VALUE) + ';'
|
---|
| 150 | ], [ // third red
|
---|
| 151 | 'FOO=BAR;'
|
---|
| 152 | ]
|
---|
| 153 | ]
|
---|
| 154 |
|
---|
| 155 | before(function(done) {
|
---|
| 156 | redirectServer = http.createServer(function(req, res) {
|
---|
| 157 | var number = parseInt(req.url.replace('/', ''));
|
---|
| 158 | var nextUrl = 'http://' + 'localhost:' + testPort + '/' + (number + 1);
|
---|
| 159 |
|
---|
| 160 | if (number == 0) requestCookies = []; // reset
|
---|
| 161 | requestCookies.push(req.headers['cookie']);
|
---|
| 162 |
|
---|
| 163 | if (responseCookies[number]) { // we should send cookies for this request
|
---|
| 164 | res.statusCode = 302;
|
---|
| 165 | res.setHeader('Set-Cookie', responseCookies[number]);
|
---|
| 166 | res.setHeader('Location', nextUrl);
|
---|
| 167 | } else if (number == 3) {
|
---|
| 168 | res.statusCode = 302; // redirect but without cookies
|
---|
| 169 | res.setHeader('Location', nextUrl);
|
---|
| 170 | }
|
---|
| 171 |
|
---|
| 172 | res.end('OK');
|
---|
| 173 | }).listen(22222, done);
|
---|
| 174 | });
|
---|
| 175 |
|
---|
| 176 | after(function(done) {
|
---|
| 177 | redirectServer.close(done);
|
---|
| 178 | })
|
---|
| 179 |
|
---|
| 180 | describe('and follow_set_cookies is false', function() {
|
---|
| 181 |
|
---|
| 182 | describe('with original request cookie', function() {
|
---|
| 183 |
|
---|
| 184 | var opts = {
|
---|
| 185 | follow_set_cookies: false,
|
---|
| 186 | follow_max: 4,
|
---|
| 187 | cookies: { 'xxx': 123 }
|
---|
| 188 | };
|
---|
| 189 |
|
---|
| 190 | it('request cookie is not passed to redirects', function(done) {
|
---|
| 191 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 192 | requestCookies.should.eql(["xxx=123", undefined, undefined, undefined, undefined])
|
---|
| 193 | done();
|
---|
| 194 | });
|
---|
| 195 | });
|
---|
| 196 |
|
---|
| 197 | it('response cookies are not passed either', function(done) {
|
---|
| 198 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 199 | should.not.exist(resp.cookies);
|
---|
| 200 | done();
|
---|
| 201 | });
|
---|
| 202 | });
|
---|
| 203 |
|
---|
| 204 | })
|
---|
| 205 |
|
---|
| 206 | describe('without original request cookie', function() {
|
---|
| 207 |
|
---|
| 208 | var opts = {
|
---|
| 209 | follow_set_cookies: false,
|
---|
| 210 | follow_max: 4,
|
---|
| 211 | };
|
---|
| 212 |
|
---|
| 213 | it('no request cookies are sent', function(done) {
|
---|
| 214 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 215 | requestCookies.should.eql([undefined, undefined, undefined, undefined, undefined])
|
---|
| 216 | done();
|
---|
| 217 | });
|
---|
| 218 | });
|
---|
| 219 |
|
---|
| 220 | it('response cookies are not passed either', function(done) {
|
---|
| 221 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 222 | should.not.exist(resp.cookies);
|
---|
| 223 | done();
|
---|
| 224 | });
|
---|
| 225 | });
|
---|
| 226 |
|
---|
| 227 | })
|
---|
| 228 |
|
---|
| 229 | });
|
---|
| 230 |
|
---|
| 231 | describe('and follow_set_cookies is true', function() {
|
---|
| 232 |
|
---|
| 233 | describe('with original request cookie', function() {
|
---|
| 234 |
|
---|
| 235 | var opts = {
|
---|
| 236 | follow_set_cookies: true,
|
---|
| 237 | follow_max: 4,
|
---|
| 238 | cookies: { 'xxx': 123 }
|
---|
| 239 | };
|
---|
| 240 |
|
---|
| 241 | it('request cookie is passed passed to redirects, and response cookies are added too', function(done) {
|
---|
| 242 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 243 | requestCookies.should.eql([
|
---|
| 244 | "xxx=123",
|
---|
| 245 | "xxx=123; wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
|
---|
| 246 | "xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
|
---|
| 247 | "xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
|
---|
| 248 | "xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
|
---|
| 249 | ])
|
---|
| 250 | done();
|
---|
| 251 | });
|
---|
| 252 | });
|
---|
| 253 |
|
---|
| 254 | it('response cookies are passed as well', function(done) {
|
---|
| 255 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 256 | resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
|
---|
| 257 | resp.cookies.should.have.property(BASE64_COOKIE_NAME);
|
---|
| 258 | resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
---|
| 259 | resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
---|
| 260 | resp.cookies.should.have.property('FOO');
|
---|
| 261 | resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
|
---|
| 262 | done();
|
---|
| 263 | });
|
---|
| 264 | });
|
---|
| 265 |
|
---|
| 266 | })
|
---|
| 267 |
|
---|
| 268 | describe('without original request cookie', function() {
|
---|
| 269 |
|
---|
| 270 | var opts = {
|
---|
| 271 | follow_set_cookies: true,
|
---|
| 272 | follow_max: 4,
|
---|
| 273 | };
|
---|
| 274 |
|
---|
| 275 | it('response cookies are passed to redirects', function(done) {
|
---|
| 276 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 277 | requestCookies.should.eql([
|
---|
| 278 | undefined,
|
---|
| 279 | "wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
|
---|
| 280 | "wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
|
---|
| 281 | "wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
|
---|
| 282 | "wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
|
---|
| 283 | ])
|
---|
| 284 | done();
|
---|
| 285 | });
|
---|
| 286 | });
|
---|
| 287 |
|
---|
| 288 | it('response cookies are passed as well', function(done) {
|
---|
| 289 | needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
---|
| 290 | // resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
|
---|
| 291 | // resp.cookies.should.have.property(BASE64_COOKIE_NAME);
|
---|
| 292 | // resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
---|
| 293 | // resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
---|
| 294 | // resp.cookies.should.have.property('FOO');
|
---|
| 295 | // resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
|
---|
| 296 | done();
|
---|
| 297 | });
|
---|
| 298 | });
|
---|
| 299 |
|
---|
| 300 | })
|
---|
| 301 |
|
---|
| 302 | });
|
---|
| 303 | });
|
---|
| 304 |
|
---|
| 305 | describe('with parse_cookies = false', function() {
|
---|
| 306 | it('does not parse them', function(done) {
|
---|
| 307 | needle.get(
|
---|
| 308 | 'localhost:' + ALL_COOKIES_TEST_PORT, { parse_cookies: false }, function(error, response) {
|
---|
| 309 | should.not.exist(response.cookies);
|
---|
| 310 | done();
|
---|
| 311 | });
|
---|
| 312 | });
|
---|
| 313 | });
|
---|
| 314 | });
|
---|
| 315 |
|
---|
| 316 | describe('if request contains cookie header', function() {
|
---|
| 317 | var opts = {
|
---|
| 318 | cookies: {}
|
---|
| 319 | };
|
---|
| 320 |
|
---|
| 321 | before(function() {
|
---|
| 322 | opts.cookies[WEIRD_COOKIE_NAME] = WEIRD_COOKIE_VALUE;
|
---|
| 323 | opts.cookies[BASE64_COOKIE_NAME] = BASE64_COOKIE_VALUE;
|
---|
| 324 | opts.cookies[FORBIDDEN_COOKIE_NAME] = FORBIDDEN_COOKIE_VALUE;
|
---|
| 325 | opts.cookies[NUMBER_COOKIE_NAME] = NUMBER_COOKIE_VALUE;
|
---|
| 326 | });
|
---|
| 327 |
|
---|
| 328 | it('must be a valid cookie string', function(done) {
|
---|
| 329 | var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
|
---|
| 330 |
|
---|
| 331 | var full_header = [
|
---|
| 332 | WEIRD_COOKIE_NAME + '=' + WEIRD_COOKIE_VALUE,
|
---|
| 333 | BASE64_COOKIE_NAME + '=' + BASE64_COOKIE_VALUE,
|
---|
| 334 | FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE),
|
---|
| 335 | NUMBER_COOKIE_NAME + '=' + NUMBER_COOKIE_VALUE
|
---|
| 336 | ].join('; ')
|
---|
| 337 |
|
---|
| 338 | needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
---|
| 339 | var cookieString = response.req._headers.cookie;
|
---|
| 340 | cookieString.should.be.type('string');
|
---|
| 341 |
|
---|
| 342 | cookieString.split(/\s*;\s*/).forEach(function(pair) {
|
---|
| 343 | COOKIE_PAIR.test(pair).should.be.exactly(true);
|
---|
| 344 | });
|
---|
| 345 |
|
---|
| 346 | cookieString.should.be.exactly(full_header);
|
---|
| 347 | done();
|
---|
| 348 | });
|
---|
| 349 | });
|
---|
| 350 |
|
---|
| 351 | it('dont have to encode allowed characters', function(done) {
|
---|
| 352 | var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
|
---|
| 353 | KEY_INDEX = 1,
|
---|
| 354 | VALUE_INEX = 3;
|
---|
| 355 |
|
---|
| 356 | needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
---|
| 357 | var cookieObj = {},
|
---|
| 358 | cookieString = response.req._headers.cookie;
|
---|
| 359 |
|
---|
| 360 | cookieString.split(/\s*;\s*/).forEach(function(str) {
|
---|
| 361 | var pair = COOKIE_PAIR.exec(str);
|
---|
| 362 | cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
|
---|
| 363 | });
|
---|
| 364 |
|
---|
| 365 | cookieObj[WEIRD_COOKIE_NAME].should.be.exactly(WEIRD_COOKIE_VALUE);
|
---|
| 366 | cookieObj[BASE64_COOKIE_NAME].should.be.exactly(BASE64_COOKIE_VALUE);
|
---|
| 367 | done();
|
---|
| 368 | });
|
---|
| 369 | });
|
---|
| 370 |
|
---|
| 371 | it('must encode forbidden characters', function(done) {
|
---|
| 372 | var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
|
---|
| 373 | KEY_INDEX = 1,
|
---|
| 374 | VALUE_INEX = 3;
|
---|
| 375 |
|
---|
| 376 | needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
---|
| 377 | var cookieObj = {},
|
---|
| 378 | cookieString = response.req._headers.cookie;
|
---|
| 379 |
|
---|
| 380 | cookieString.split(/\s*;\s*/).forEach(function(str) {
|
---|
| 381 | var pair = COOKIE_PAIR.exec(str);
|
---|
| 382 | cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
|
---|
| 383 | });
|
---|
| 384 |
|
---|
| 385 | cookieObj[FORBIDDEN_COOKIE_NAME].should.not.be.eql(
|
---|
| 386 | FORBIDDEN_COOKIE_VALUE);
|
---|
| 387 | cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
|
---|
| 388 | encode(FORBIDDEN_COOKIE_VALUE));
|
---|
| 389 | cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
|
---|
| 390 | encodeURIComponent(FORBIDDEN_COOKIE_VALUE));
|
---|
| 391 | done();
|
---|
| 392 | });
|
---|
| 393 | });
|
---|
| 394 | });
|
---|
| 395 |
|
---|
| 396 | });
|
---|