tough-cookie 0.12.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +12 -0
- package/.npmignore +1 -0
- package/.travis.yml +2 -1
- package/LICENSE +22 -26
- package/README.md +48 -38
- package/generate-pubsuffix.js +114 -60
- package/lib/cookie.js +163 -182
- package/lib/memstore.js +45 -26
- package/lib/pathMatch.js +61 -0
- package/lib/permuteDomain.js +56 -0
- package/lib/pubsuffix.js +52 -23
- package/lib/store.js +30 -0
- package/package.json +8 -11
- package/public-suffix.txt +5511 -661
- package/test/api_test.js +372 -0
- package/test/cookie_jar_test.js +468 -0
- package/test/cookie_sorting_test.js +90 -0
- package/test/cookie_to_json_test.js +164 -0
- package/test/cookie_to_string_test.js +162 -0
- package/test/date_test.js +79 -0
- package/test/domain_and_path_test.js +201 -0
- package/test/ietf_data/dates/bsd-examples.json +168 -0
- package/test/ietf_data/dates/examples.json +48 -0
- package/test/ietf_data/parser.json +1959 -0
- package/test/ietf_test.js +106 -0
- package/test/lifetime_test.js +97 -0
- package/test/parsing_test.js +294 -0
- package/test/regression_test.js +143 -0
- package/test.js +0 -1625
package/lib/cookie.js
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015, Salesforce.com, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
|
7
|
+
*
|
|
8
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
|
9
|
+
* this list of conditions and the following disclaimer.
|
|
10
|
+
*
|
|
11
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
* and/or other materials provided with the distribution.
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
15
|
+
* 3. Neither the name of Salesforce.com nor the names of its contributors may
|
|
16
|
+
* be used to endorse or promote products derived from this software without
|
|
17
|
+
* specific prior written permission.
|
|
12
18
|
*
|
|
13
|
-
*
|
|
14
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
22
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
23
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
24
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
25
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
26
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
27
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
28
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
29
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
|
20
30
|
*/
|
|
21
|
-
|
|
22
31
|
'use strict';
|
|
23
32
|
var net = require('net');
|
|
24
33
|
var urlParse = require('url').parse;
|
|
25
34
|
var pubsuffix = require('./pubsuffix');
|
|
26
35
|
var Store = require('./store').Store;
|
|
36
|
+
var MemoryCookieStore = require('./memstore').MemoryCookieStore;
|
|
37
|
+
var pathMatch = require('./pathMatch').pathMatch;
|
|
27
38
|
|
|
28
39
|
var punycode;
|
|
29
40
|
try {
|
|
@@ -34,42 +45,29 @@ try {
|
|
|
34
45
|
|
|
35
46
|
var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
|
|
36
47
|
|
|
37
|
-
// From RFC2616 S2.2:
|
|
38
|
-
var TOKEN = /[\x21\x23-\x26\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
|
|
39
|
-
|
|
40
48
|
// From RFC6265 S4.1.1
|
|
41
49
|
// note that it excludes \x3B ";"
|
|
42
50
|
var COOKIE_OCTET = /[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/;
|
|
43
51
|
var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'$');
|
|
44
52
|
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
// Double quotes are part of the value (see: S4.1.1).
|
|
54
|
+
// '\r', '\n' and '\0' should be treated as a terminator in the "relaxed" mode
|
|
55
|
+
// (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60)
|
|
56
|
+
// '=' and ';' are attribute/values separators
|
|
57
|
+
// (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L64)
|
|
58
|
+
var COOKIE_PAIR = /^([^=;]+)\s*=\s*(("?)[^\n\r\0]*\3)/;
|
|
48
59
|
|
|
49
|
-
// RFC6265 S4.1.1 defines
|
|
60
|
+
// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
|
|
50
61
|
// Note ';' is \x3B
|
|
51
|
-
var
|
|
52
|
-
var EXTENSION_AV = NON_CTL_SEMICOLON;
|
|
53
|
-
var PATH_VALUE = NON_CTL_SEMICOLON;
|
|
62
|
+
var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
|
|
54
63
|
|
|
55
64
|
// Used for checking whether or not there is a trailing semi-colon
|
|
56
65
|
var TRAILING_SEMICOLON = /;+$/;
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
var DAY_OF_MONTH = /^(0?[1-9]|[12][0-9]|3[01])$/;
|
|
67
|
+
var DAY_OF_MONTH = /^(\d{1,2})[^\d]*$/;
|
|
68
|
+
var TIME = /^(\d{1,2})[^\d]*:(\d{1,2})[^\d]*:(\d{1,2})[^\d]*$/;
|
|
69
|
+
var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i;
|
|
62
70
|
|
|
63
|
-
/* RFC6265 S5.1.1.5:
|
|
64
|
-
* [fail if]
|
|
65
|
-
* * the hour-value is greater than 23,
|
|
66
|
-
* * the minute-value is greater than 59, or
|
|
67
|
-
* * the second-value is greater than 59.
|
|
68
|
-
*/
|
|
69
|
-
var TIME = /(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])/;
|
|
70
|
-
var STRICT_TIME = /^(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/;
|
|
71
|
-
|
|
72
|
-
var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$/i;
|
|
73
71
|
var MONTH_TO_NUM = {
|
|
74
72
|
jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
|
|
75
73
|
jul:6, aug:7, sep:8, oct:9, nov:10, dec:11
|
|
@@ -81,18 +79,19 @@ var NUM_TO_DAY = [
|
|
|
81
79
|
'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
|
|
82
80
|
];
|
|
83
81
|
|
|
84
|
-
var YEAR = /^(
|
|
82
|
+
var YEAR = /^(\d{2}|\d{4})$/; // 2 to 4 digits
|
|
85
83
|
|
|
86
84
|
var MAX_TIME = 2147483647000; // 31-bit max
|
|
87
85
|
var MIN_TIME = 0; // 31-bit min
|
|
88
86
|
|
|
87
|
+
var cookiesCreated = 0; // Number of cookies created in runtime
|
|
88
|
+
|
|
89
89
|
|
|
90
90
|
// RFC6265 S5.1.1 date parser:
|
|
91
|
-
function parseDate(str
|
|
91
|
+
function parseDate(str) {
|
|
92
92
|
if (!str) {
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
|
-
var found_time, found_dom, found_month, found_year;
|
|
96
95
|
|
|
97
96
|
/* RFC6265 S5.1.1:
|
|
98
97
|
* 2. Process each date-token sequentially in the order the date-tokens
|
|
@@ -103,8 +102,12 @@ function parseDate(str,strict) {
|
|
|
103
102
|
return;
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
var
|
|
107
|
-
|
|
105
|
+
var hour = null;
|
|
106
|
+
var minutes = null;
|
|
107
|
+
var seconds = null;
|
|
108
|
+
var day = null;
|
|
109
|
+
var month = null;
|
|
110
|
+
var year = null;
|
|
108
111
|
|
|
109
112
|
for (var i=0; i<tokens.length; i++) {
|
|
110
113
|
var token = tokens[i].trim();
|
|
@@ -120,13 +123,22 @@ function parseDate(str,strict) {
|
|
|
120
123
|
* the date-token, respectively. Skip the remaining sub-steps and continue
|
|
121
124
|
* to the next date-token.
|
|
122
125
|
*/
|
|
123
|
-
if (
|
|
124
|
-
result =
|
|
126
|
+
if (seconds === null) {
|
|
127
|
+
result = TIME.exec(token);
|
|
125
128
|
if (result) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
hour = parseInt(result[1], 10);
|
|
130
|
+
minutes = parseInt(result[2], 10);
|
|
131
|
+
seconds = parseInt(result[3], 10);
|
|
132
|
+
/* RFC6265 S5.1.1.5:
|
|
133
|
+
* [fail if]
|
|
134
|
+
* * the hour-value is greater than 23,
|
|
135
|
+
* * the minute-value is greater than 59, or
|
|
136
|
+
* * the second-value is greater than 59.
|
|
137
|
+
*/
|
|
138
|
+
if(hour > 23 || minutes > 59 || seconds > 59) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
130
142
|
continue;
|
|
131
143
|
}
|
|
132
144
|
}
|
|
@@ -136,11 +148,16 @@ function parseDate(str,strict) {
|
|
|
136
148
|
* the day-of-month-value to the number denoted by the date-token. Skip
|
|
137
149
|
* the remaining sub-steps and continue to the next date-token.
|
|
138
150
|
*/
|
|
139
|
-
if (
|
|
151
|
+
if (day === null) {
|
|
140
152
|
result = DAY_OF_MONTH.exec(token);
|
|
141
153
|
if (result) {
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
day = parseInt(result, 10);
|
|
155
|
+
/* RFC6265 S5.1.1.5:
|
|
156
|
+
* [fail if] the day-of-month-value is less than 1 or greater than 31
|
|
157
|
+
*/
|
|
158
|
+
if(day < 1 || day > 31) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
144
161
|
continue;
|
|
145
162
|
}
|
|
146
163
|
}
|
|
@@ -150,11 +167,10 @@ function parseDate(str,strict) {
|
|
|
150
167
|
* the month denoted by the date-token. Skip the remaining sub-steps and
|
|
151
168
|
* continue to the next date-token.
|
|
152
169
|
*/
|
|
153
|
-
if (
|
|
170
|
+
if (month === null) {
|
|
154
171
|
result = MONTH.exec(token);
|
|
155
172
|
if (result) {
|
|
156
|
-
|
|
157
|
-
date.setUTCMonth(MONTH_TO_NUM[result[1].toLowerCase()]);
|
|
173
|
+
month = MONTH_TO_NUM[result[1].toLowerCase()];
|
|
158
174
|
continue;
|
|
159
175
|
}
|
|
160
176
|
}
|
|
@@ -164,10 +180,10 @@ function parseDate(str,strict) {
|
|
|
164
180
|
* denoted by the date-token. Skip the remaining sub-steps and continue to
|
|
165
181
|
* the next date-token.
|
|
166
182
|
*/
|
|
167
|
-
if (
|
|
183
|
+
if (year === null) {
|
|
168
184
|
result = YEAR.exec(token);
|
|
169
185
|
if (result) {
|
|
170
|
-
|
|
186
|
+
year = parseInt(result[0], 10);
|
|
171
187
|
/* From S5.1.1:
|
|
172
188
|
* 3. If the year-value is greater than or equal to 70 and less
|
|
173
189
|
* than or equal to 99, increment the year-value by 1900.
|
|
@@ -183,20 +199,16 @@ function parseDate(str,strict) {
|
|
|
183
199
|
if (year < 1601) {
|
|
184
200
|
return; // 5. ... the year-value is less than 1601
|
|
185
201
|
}
|
|
186
|
-
|
|
187
|
-
found_year = true;
|
|
188
|
-
date.setUTCFullYear(year);
|
|
189
|
-
continue;
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
204
|
}
|
|
193
205
|
|
|
194
|
-
if (
|
|
206
|
+
if (seconds === null || day === null || month === null || year === null) {
|
|
195
207
|
return; // 5. ... at least one of the found-day-of-month, found-month, found-
|
|
196
208
|
// year, or found-time flags is not set,
|
|
197
209
|
}
|
|
198
210
|
|
|
199
|
-
return
|
|
211
|
+
return new Date(Date.UTC(year, month, day, hour, minutes, seconds));
|
|
200
212
|
}
|
|
201
213
|
|
|
202
214
|
function formatDate(date) {
|
|
@@ -303,52 +315,19 @@ function defaultPath(path) {
|
|
|
303
315
|
return path.slice(0, rightSlash);
|
|
304
316
|
}
|
|
305
317
|
|
|
306
|
-
/*
|
|
307
|
-
* "A request-path path-matches a given cookie-path if at least one of the
|
|
308
|
-
* following conditions holds:"
|
|
309
|
-
*/
|
|
310
|
-
function pathMatch(reqPath,cookiePath) {
|
|
311
|
-
// "o The cookie-path and the request-path are identical."
|
|
312
|
-
if (cookiePath === reqPath) {
|
|
313
|
-
return true;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
var idx = reqPath.indexOf(cookiePath);
|
|
317
|
-
if (idx === 0) {
|
|
318
|
-
// "o The cookie-path is a prefix of the request-path, and the last
|
|
319
|
-
// character of the cookie-path is %x2F ("/")."
|
|
320
|
-
if (cookiePath.substr(-1) === "/") {
|
|
321
|
-
return true;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// " o The cookie-path is a prefix of the request-path, and the first
|
|
325
|
-
// character of the request-path that is not included in the cookie- path
|
|
326
|
-
// is a %x2F ("/") character."
|
|
327
|
-
if (reqPath.substr(cookiePath.length,1) === "/") {
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
318
|
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function parse(str, strict) {
|
|
319
|
+
function parse(str) {
|
|
336
320
|
str = str.trim();
|
|
337
321
|
|
|
338
322
|
// S4.1.1 Trailing semi-colons are not part of the specification.
|
|
339
|
-
// If we are not in strict mode we remove the trailing semi-colons.
|
|
340
323
|
var semiColonCheck = TRAILING_SEMICOLON.exec(str);
|
|
341
324
|
if (semiColonCheck) {
|
|
342
|
-
if (strict) {
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
325
|
str = str.slice(0, semiColonCheck.index);
|
|
346
326
|
}
|
|
347
327
|
|
|
348
328
|
// We use a regex to parse the "name-value-pair" part of S5.2
|
|
349
329
|
var firstSemi = str.indexOf(';'); // S5.2 step 1
|
|
350
|
-
var
|
|
351
|
-
var result = pairRx.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
|
|
330
|
+
var result = COOKIE_PAIR.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
|
|
352
331
|
|
|
353
332
|
// Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
|
|
354
333
|
// constraints as well as trimming any whitespace.
|
|
@@ -357,8 +336,8 @@ function parse(str, strict) {
|
|
|
357
336
|
}
|
|
358
337
|
|
|
359
338
|
var c = new Cookie();
|
|
360
|
-
c.key = result[1]
|
|
361
|
-
c.value = result[
|
|
339
|
+
c.key = result[1].trim();
|
|
340
|
+
c.value = result[2].trim();
|
|
362
341
|
|
|
363
342
|
if (firstSemi === -1) {
|
|
364
343
|
return c;
|
|
@@ -386,13 +365,9 @@ function parse(str, strict) {
|
|
|
386
365
|
var cookie_avs = unparsed.split(/\s*;\s*/);
|
|
387
366
|
while (cookie_avs.length) {
|
|
388
367
|
var av = cookie_avs.shift();
|
|
389
|
-
|
|
390
|
-
if (strict && !EXTENSION_AV.test(av)) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
368
|
var av_sep = av.indexOf('=');
|
|
395
369
|
var av_key, av_value;
|
|
370
|
+
|
|
396
371
|
if (av_sep === -1) {
|
|
397
372
|
av_key = av;
|
|
398
373
|
av_value = null;
|
|
@@ -402,47 +377,51 @@ function parse(str, strict) {
|
|
|
402
377
|
}
|
|
403
378
|
|
|
404
379
|
av_key = av_key.trim().toLowerCase();
|
|
380
|
+
|
|
405
381
|
if (av_value) {
|
|
406
382
|
av_value = av_value.trim();
|
|
407
383
|
}
|
|
408
384
|
|
|
409
385
|
switch(av_key) {
|
|
410
386
|
case 'expires': // S5.2.1
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
387
|
+
if (av_value) {
|
|
388
|
+
var exp = parseDate(av_value);
|
|
389
|
+
// "If the attribute-value failed to parse as a cookie date, ignore the
|
|
390
|
+
// cookie-av."
|
|
391
|
+
if (exp) {
|
|
392
|
+
// over and underflow not realistically a concern: V8's getTime() seems to
|
|
393
|
+
// store something larger than a 32-bit time_t (even with 32-bit node)
|
|
394
|
+
c.expires = exp;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
419
397
|
break;
|
|
420
398
|
|
|
421
399
|
case 'max-age': // S5.2.2
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
400
|
+
if (av_value) {
|
|
401
|
+
// "If the first character of the attribute-value is not a DIGIT or a "-"
|
|
402
|
+
// character ...[or]... If the remainder of attribute-value contains a
|
|
403
|
+
// non-DIGIT character, ignore the cookie-av."
|
|
404
|
+
if (/^-?[0-9]+$/.test(av_value)) {
|
|
405
|
+
var delta = parseInt(av_value, 10);
|
|
406
|
+
// "If delta-seconds is less than or equal to zero (0), let expiry-time
|
|
407
|
+
// be the earliest representable date and time."
|
|
408
|
+
c.setMaxAge(delta);
|
|
409
|
+
}
|
|
430
410
|
}
|
|
431
|
-
// "If delta-seconds is less than or equal to zero (0), let expiry-time
|
|
432
|
-
// be the earliest representable date and time."
|
|
433
|
-
c.setMaxAge(delta);
|
|
434
411
|
break;
|
|
435
412
|
|
|
436
413
|
case 'domain': // S5.2.3
|
|
437
414
|
// "If the attribute-value is empty, the behavior is undefined. However,
|
|
438
415
|
// the user agent SHOULD ignore the cookie-av entirely."
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
416
|
+
if (av_value) {
|
|
417
|
+
// S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E
|
|
418
|
+
// (".") character."
|
|
419
|
+
var domain = av_value.trim().replace(/^\./, '');
|
|
420
|
+
if (domain) {
|
|
421
|
+
// "Convert the cookie-domain to lower case."
|
|
422
|
+
c.domain = domain.toLowerCase();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
446
425
|
break;
|
|
447
426
|
|
|
448
427
|
case 'path': // S5.2.4
|
|
@@ -456,10 +435,7 @@ function parse(str, strict) {
|
|
|
456
435
|
* We'll represent the default-path as null since it depends on the
|
|
457
436
|
* context of the parsing.
|
|
458
437
|
*/
|
|
459
|
-
|
|
460
|
-
if(strict){return;}else{break;}
|
|
461
|
-
}
|
|
462
|
-
c.path = av_value;
|
|
438
|
+
c.path = av_value && av_value[0] === "/" ? av_value : null;
|
|
463
439
|
break;
|
|
464
440
|
|
|
465
441
|
case 'secure': // S5.2.5
|
|
@@ -468,12 +444,10 @@ function parse(str, strict) {
|
|
|
468
444
|
* the user agent MUST append an attribute to the cookie-attribute-list
|
|
469
445
|
* with an attribute-name of Secure and an empty attribute-value."
|
|
470
446
|
*/
|
|
471
|
-
if (av_value != null) { if(strict){return;} }
|
|
472
447
|
c.secure = true;
|
|
473
448
|
break;
|
|
474
449
|
|
|
475
450
|
case 'httponly': // S5.2.6 -- effectively the same as 'secure'
|
|
476
|
-
if (av_value != null) { if(strict){return;} }
|
|
477
451
|
c.httpOnly = true;
|
|
478
452
|
break;
|
|
479
453
|
|
|
@@ -486,6 +460,10 @@ function parse(str, strict) {
|
|
|
486
460
|
|
|
487
461
|
// ensure a default date for sorting:
|
|
488
462
|
c.creation = new Date();
|
|
463
|
+
//NOTE: add runtime index for the cookieCompare() to resolve the situation when Date's precision is not enough .
|
|
464
|
+
//Store initial UTC time as well, so we will be able to determine if we need to fallback to the Date object.
|
|
465
|
+
c._creationRuntimeIdx = ++cookiesCreated;
|
|
466
|
+
c._initialCreationTime = c.creation.getTime();
|
|
489
467
|
return c;
|
|
490
468
|
}
|
|
491
469
|
|
|
@@ -539,31 +517,18 @@ function cookieCompare(a,b) {
|
|
|
539
517
|
if (deltaLen !== 0) {
|
|
540
518
|
return deltaLen;
|
|
541
519
|
}
|
|
542
|
-
// ascending for time: a CMP b
|
|
543
|
-
return (a.creation ? a.creation.getTime() : MAX_TIME) -
|
|
544
|
-
(b.creation ? b.creation.getTime() : MAX_TIME);
|
|
545
|
-
}
|
|
546
520
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
function permuteDomain(domain) {
|
|
550
|
-
var pubSuf = pubsuffix.getPublicSuffix(domain);
|
|
551
|
-
if (!pubSuf) {
|
|
552
|
-
return null;
|
|
553
|
-
}
|
|
554
|
-
if (pubSuf == domain) {
|
|
555
|
-
return [domain];
|
|
556
|
-
}
|
|
521
|
+
var aTime = a.creation ? a.creation.getTime() : MAX_TIME;
|
|
522
|
+
var bTime = b.creation ? b.creation.getTime() : MAX_TIME;
|
|
557
523
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
while (parts.length) {
|
|
563
|
-
cur = parts.shift()+'.'+cur;
|
|
564
|
-
permutations.push(cur);
|
|
524
|
+
// NOTE: if creation dates are equal and they were not modified from the outside,
|
|
525
|
+
// then use _creationRuntimeIdx for the comparison.
|
|
526
|
+
if(aTime === bTime && aTime === a._initialCreationTime && bTime === b._initialCreationTime) {
|
|
527
|
+
return a._creationRuntimeIdx - b._creationRuntimeIdx;
|
|
565
528
|
}
|
|
566
|
-
|
|
529
|
+
|
|
530
|
+
// ascending for time: a CMP b
|
|
531
|
+
return aTime - bTime;
|
|
567
532
|
}
|
|
568
533
|
|
|
569
534
|
// Gives the permutation of all possible pathMatch()es of a given path. The
|
|
@@ -588,6 +553,21 @@ function permutePath(path) {
|
|
|
588
553
|
return permutations;
|
|
589
554
|
}
|
|
590
555
|
|
|
556
|
+
function getCookieContext(url) {
|
|
557
|
+
if (url instanceof Object) {
|
|
558
|
+
return url;
|
|
559
|
+
}
|
|
560
|
+
// NOTE: decodeURI will throw on malformed URIs (see GH-32).
|
|
561
|
+
// Therefore, we will just skip decoding for such URIs.
|
|
562
|
+
try {
|
|
563
|
+
url = decodeURI(url);
|
|
564
|
+
}
|
|
565
|
+
catch(err) {
|
|
566
|
+
// Silently swallow error
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return urlParse(url);
|
|
570
|
+
}
|
|
591
571
|
|
|
592
572
|
function Cookie (opts) {
|
|
593
573
|
if (typeof opts !== "object") {
|
|
@@ -619,6 +599,8 @@ Cookie.prototype.extensions = null;
|
|
|
619
599
|
Cookie.prototype.hostOnly = null; // boolean when set
|
|
620
600
|
Cookie.prototype.pathIsDefault = null; // boolean when set
|
|
621
601
|
Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
|
|
602
|
+
Cookie.prototype._initialCreationTime = null; // Used to determine if cookie.creation was modified
|
|
603
|
+
Cookie.prototype._creationRuntimeIdx = null; // Runtime index of the created cookie, used in cookieCompare()
|
|
622
604
|
Cookie.prototype.lastAccessed = null; // Date when set
|
|
623
605
|
|
|
624
606
|
var cookieProperties = Object.freeze(Object.keys(Cookie.prototype).map(function(p) {
|
|
@@ -642,7 +624,7 @@ Cookie.prototype.validate = function validate() {
|
|
|
642
624
|
if (!COOKIE_OCTETS.test(this.value)) {
|
|
643
625
|
return false;
|
|
644
626
|
}
|
|
645
|
-
if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires
|
|
627
|
+
if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires)) {
|
|
646
628
|
return false;
|
|
647
629
|
}
|
|
648
630
|
if (this.maxAge != null && this.maxAge <= 0) {
|
|
@@ -801,15 +783,13 @@ Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() {
|
|
|
801
783
|
};
|
|
802
784
|
|
|
803
785
|
|
|
804
|
-
var memstore;
|
|
805
786
|
function CookieJar(store, rejectPublicSuffixes) {
|
|
806
787
|
if (rejectPublicSuffixes != null) {
|
|
807
788
|
this.rejectPublicSuffixes = rejectPublicSuffixes;
|
|
808
789
|
}
|
|
809
790
|
|
|
810
791
|
if (!store) {
|
|
811
|
-
|
|
812
|
-
store = new memstore.MemoryCookieStore();
|
|
792
|
+
store = new MemoryCookieStore();
|
|
813
793
|
}
|
|
814
794
|
this.store = store;
|
|
815
795
|
}
|
|
@@ -820,7 +800,7 @@ var CAN_BE_SYNC = [];
|
|
|
820
800
|
CAN_BE_SYNC.push('setCookie');
|
|
821
801
|
CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
822
802
|
var err;
|
|
823
|
-
var context = (url
|
|
803
|
+
var context = getCookieContext(url);
|
|
824
804
|
if (options instanceof Function) {
|
|
825
805
|
cb = options;
|
|
826
806
|
options = {};
|
|
@@ -830,7 +810,7 @@ CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
|
830
810
|
|
|
831
811
|
// S5.3 step 1
|
|
832
812
|
if (!(cookie instanceof Cookie)) {
|
|
833
|
-
cookie = Cookie.parse(cookie
|
|
813
|
+
cookie = Cookie.parse(cookie);
|
|
834
814
|
}
|
|
835
815
|
if (!cookie) {
|
|
836
816
|
err = new Error("Cookie failed to parse");
|
|
@@ -869,15 +849,12 @@ CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
|
869
849
|
cookie.domain = host;
|
|
870
850
|
}
|
|
871
851
|
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
|
|
852
|
+
//S5.2.4 If the attribute-value is empty or if the first character of the
|
|
853
|
+
//attribute-value is not %x2F ("/"):
|
|
854
|
+
//Let cookie-path be the default-path.
|
|
855
|
+
if (!cookie.path || cookie.path[0] !== '/') {
|
|
875
856
|
cookie.path = defaultPath(context.pathname);
|
|
876
857
|
cookie.pathIsDefault = true;
|
|
877
|
-
} else {
|
|
878
|
-
if (cookie.path.length > 1 && cookie.path.substr(-1) == '/') {
|
|
879
|
-
cookie.path = cookie.path.slice(0,-1);
|
|
880
|
-
}
|
|
881
858
|
}
|
|
882
859
|
|
|
883
860
|
// S5.3 step 8: NOOP; secure attribute
|
|
@@ -934,7 +911,7 @@ CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
|
934
911
|
// RFC6365 S5.4
|
|
935
912
|
CAN_BE_SYNC.push('getCookies');
|
|
936
913
|
CookieJar.prototype.getCookies = function(url, options, cb) {
|
|
937
|
-
var context = (url
|
|
914
|
+
var context = getCookieContext(url);
|
|
938
915
|
if (options instanceof Function) {
|
|
939
916
|
cb = options;
|
|
940
917
|
options = {};
|
|
@@ -1035,9 +1012,12 @@ CookieJar.prototype.getCookieString = function(/*..., cb*/) {
|
|
|
1035
1012
|
if (err) {
|
|
1036
1013
|
cb(err);
|
|
1037
1014
|
} else {
|
|
1038
|
-
cb(null, cookies
|
|
1039
|
-
|
|
1040
|
-
|
|
1015
|
+
cb(null, cookies
|
|
1016
|
+
.sort(cookieCompare)
|
|
1017
|
+
.map(function(c){
|
|
1018
|
+
return c.cookieString();
|
|
1019
|
+
})
|
|
1020
|
+
.join('; '));
|
|
1041
1021
|
}
|
|
1042
1022
|
};
|
|
1043
1023
|
args.push(next);
|
|
@@ -1092,6 +1072,7 @@ module.exports = {
|
|
|
1092
1072
|
CookieJar: CookieJar,
|
|
1093
1073
|
Cookie: Cookie,
|
|
1094
1074
|
Store: Store,
|
|
1075
|
+
MemoryCookieStore: MemoryCookieStore,
|
|
1095
1076
|
parseDate: parseDate,
|
|
1096
1077
|
formatDate: formatDate,
|
|
1097
1078
|
parse: parse,
|
|
@@ -1101,7 +1082,7 @@ module.exports = {
|
|
|
1101
1082
|
pathMatch: pathMatch,
|
|
1102
1083
|
getPublicSuffix: pubsuffix.getPublicSuffix,
|
|
1103
1084
|
cookieCompare: cookieCompare,
|
|
1104
|
-
permuteDomain: permuteDomain,
|
|
1085
|
+
permuteDomain: require('./permuteDomain').permuteDomain,
|
|
1105
1086
|
permutePath: permutePath,
|
|
1106
|
-
canonicalDomain: canonicalDomain
|
|
1087
|
+
canonicalDomain: canonicalDomain
|
|
1107
1088
|
};
|