tough-cookie 2.3.0 → 2.3.4

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/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  [RFC6265](https://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js
2
2
 
3
- [![Build Status](https://travis-ci.org/SalesforceEng/tough-cookie.png?branch=master)](https://travis-ci.org/SalesforceEng/tough-cookie)
3
+ [![npm package](https://nodei.co/npm/tough-cookie.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/tough-cookie/)
4
4
 
5
- [![NPM Stats](https://nodei.co/npm/tough-cookie.png?downloads=true&stars=true)](https://npmjs.org/package/tough-cookie)
6
- ![NPM Downloads](https://nodei.co/npm-dl/tough-cookie.png?months=9)
5
+ [![Build Status](https://travis-ci.org/salesforce/tough-cookie.png?branch=master)](https://travis-ci.org/salesforce/tough-cookie)
7
6
 
8
7
  # Synopsis
9
8
 
@@ -30,6 +29,10 @@ It's _so_ easy!
30
29
 
31
30
  Why the name? NPM modules `cookie`, `cookies` and `cookiejar` were already taken.
32
31
 
32
+ ## Version Support
33
+
34
+ Support for versions of node.js will follow that of the [request](https://www.npmjs.com/package/request) module.
35
+
33
36
  # API
34
37
 
35
38
  ## tough
@@ -131,6 +134,9 @@ else
131
134
  cookies = [Cookie.parse(res.headers['set-cookie'])];
132
135
  ```
133
136
 
137
+ _Note:_ in version 2.3.3, tough-cookie limited the number of spaces before the `=` to 256 characters. This limitation has since been removed.
138
+ See [Issue 92](https://github.com/salesforce/tough-cookie/issues/92)
139
+
134
140
  ### Properties
135
141
 
136
142
  Cookie object properties:
package/lib/cookie.js CHANGED
@@ -44,33 +44,24 @@ try {
44
44
  console.warn("cookie: can't load punycode; won't use punycode for domain normalization");
45
45
  }
46
46
 
47
- var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
48
-
49
47
  // From RFC6265 S4.1.1
50
48
  // note that it excludes \x3B ";"
51
- var COOKIE_OCTET = /[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/;
52
- var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'+$');
49
+ var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/;
53
50
 
54
51
  var CONTROL_CHARS = /[\x00-\x1F]/;
55
52
 
56
- // Double quotes are part of the value (see: S4.1.1).
57
- // '\r', '\n' and '\0' should be treated as a terminator in the "relaxed" mode
58
- // (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60)
59
- // '=' and ';' are attribute/values separators
60
- // (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L64)
61
- var COOKIE_PAIR = /^(([^=;]+))\s*=\s*([^\n\r\0]*)/;
62
-
63
- // Used to parse non-RFC-compliant cookies like '=abc' when given the `loose`
64
- // option in Cookie.parse:
65
- var LOOSE_COOKIE_PAIR = /^((?:=)?([^=;]*)\s*=\s*)?([^\n\r\0]*)/;
53
+ // From Chromium // '\r', '\n' and '\0' should be treated as a terminator in
54
+ // the "relaxed" mode, see:
55
+ // https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60
56
+ var TERMINATORS = ['\n', '\r', '\0'];
66
57
 
67
58
  // RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
68
59
  // Note ';' is \x3B
69
60
  var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
70
61
 
71
- var DAY_OF_MONTH = /^(\d{1,2})[^\d]*$/;
72
- var TIME = /^(\d{1,2})[^\d]*:(\d{1,2})[^\d]*:(\d{1,2})[^\d]*$/;
73
- var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i;
62
+ // date-time parsing constants (RFC6265 S5.1.1)
63
+
64
+ var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
74
65
 
75
66
  var MONTH_TO_NUM = {
76
67
  jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
@@ -83,13 +74,80 @@ var NUM_TO_DAY = [
83
74
  'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
84
75
  ];
85
76
 
86
- var YEAR = /^(\d{2}|\d{4})$/; // 2 to 4 digits
87
-
88
77
  var MAX_TIME = 2147483647000; // 31-bit max
89
78
  var MIN_TIME = 0; // 31-bit min
90
79
 
80
+ /*
81
+ * Parses a Natural number (i.e., non-negative integer) with either the
82
+ * <min>*<max>DIGIT ( non-digit *OCTET )
83
+ * or
84
+ * <min>*<max>DIGIT
85
+ * grammar (RFC6265 S5.1.1).
86
+ *
87
+ * The "trailingOK" boolean controls if the grammar accepts a
88
+ * "( non-digit *OCTET )" trailer.
89
+ */
90
+ function parseDigits(token, minDigits, maxDigits, trailingOK) {
91
+ var count = 0;
92
+ while (count < token.length) {
93
+ var c = token.charCodeAt(count);
94
+ // "non-digit = %x00-2F / %x3A-FF"
95
+ if (c <= 0x2F || c >= 0x3A) {
96
+ break;
97
+ }
98
+ count++;
99
+ }
100
+
101
+ // constrain to a minimum and maximum number of digits.
102
+ if (count < minDigits || count > maxDigits) {
103
+ return null;
104
+ }
105
+
106
+ if (!trailingOK && count != token.length) {
107
+ return null;
108
+ }
109
+
110
+ return parseInt(token.substr(0,count), 10);
111
+ }
112
+
113
+ function parseTime(token) {
114
+ var parts = token.split(':');
115
+ var result = [0,0,0];
116
+
117
+ /* RF6256 S5.1.1:
118
+ * time = hms-time ( non-digit *OCTET )
119
+ * hms-time = time-field ":" time-field ":" time-field
120
+ * time-field = 1*2DIGIT
121
+ */
122
+
123
+ if (parts.length !== 3) {
124
+ return null;
125
+ }
91
126
 
92
- // RFC6265 S5.1.1 date parser:
127
+ for (var i = 0; i < 3; i++) {
128
+ // "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
129
+ // followed by "( non-digit *OCTET )" so therefore the last time-field can
130
+ // have a trailer
131
+ var trailingOK = (i == 2);
132
+ var num = parseDigits(parts[i], 1, 2, trailingOK);
133
+ if (num === null) {
134
+ return null;
135
+ }
136
+ result[i] = num;
137
+ }
138
+
139
+ return result;
140
+ }
141
+
142
+ function parseMonth(token) {
143
+ token = String(token).substr(0,3).toLowerCase();
144
+ var num = MONTH_TO_NUM[token];
145
+ return num >= 0 ? num : null;
146
+ }
147
+
148
+ /*
149
+ * RFC6265 S5.1.1 date parser (see RFC for full grammar)
150
+ */
93
151
  function parseDate(str) {
94
152
  if (!str) {
95
153
  return;
@@ -105,9 +163,9 @@ function parseDate(str) {
105
163
  }
106
164
 
107
165
  var hour = null;
108
- var minutes = null;
109
- var seconds = null;
110
- var day = null;
166
+ var minute = null;
167
+ var second = null;
168
+ var dayOfMonth = null;
111
169
  var month = null;
112
170
  var year = null;
113
171
 
@@ -125,22 +183,12 @@ function parseDate(str) {
125
183
  * the date-token, respectively. Skip the remaining sub-steps and continue
126
184
  * to the next date-token.
127
185
  */
128
- if (seconds === null) {
129
- result = TIME.exec(token);
186
+ if (second === null) {
187
+ result = parseTime(token);
130
188
  if (result) {
131
- hour = parseInt(result[1], 10);
132
- minutes = parseInt(result[2], 10);
133
- seconds = parseInt(result[3], 10);
134
- /* RFC6265 S5.1.1.5:
135
- * [fail if]
136
- * * the hour-value is greater than 23,
137
- * * the minute-value is greater than 59, or
138
- * * the second-value is greater than 59.
139
- */
140
- if(hour > 23 || minutes > 59 || seconds > 59) {
141
- return;
142
- }
143
-
189
+ hour = result[0];
190
+ minute = result[1];
191
+ second = result[2];
144
192
  continue;
145
193
  }
146
194
  }
@@ -150,16 +198,11 @@ function parseDate(str) {
150
198
  * the day-of-month-value to the number denoted by the date-token. Skip
151
199
  * the remaining sub-steps and continue to the next date-token.
152
200
  */
153
- if (day === null) {
154
- result = DAY_OF_MONTH.exec(token);
155
- if (result) {
156
- day = parseInt(result, 10);
157
- /* RFC6265 S5.1.1.5:
158
- * [fail if] the day-of-month-value is less than 1 or greater than 31
159
- */
160
- if(day < 1 || day > 31) {
161
- return;
162
- }
201
+ if (dayOfMonth === null) {
202
+ // "day-of-month = 1*2DIGIT ( non-digit *OCTET )"
203
+ result = parseDigits(token, 1, 2, true);
204
+ if (result !== null) {
205
+ dayOfMonth = result;
163
206
  continue;
164
207
  }
165
208
  }
@@ -170,47 +213,63 @@ function parseDate(str) {
170
213
  * continue to the next date-token.
171
214
  */
172
215
  if (month === null) {
173
- result = MONTH.exec(token);
174
- if (result) {
175
- month = MONTH_TO_NUM[result[1].toLowerCase()];
216
+ result = parseMonth(token);
217
+ if (result !== null) {
218
+ month = result;
176
219
  continue;
177
220
  }
178
221
  }
179
222
 
180
- /* 2.4. If the found-year flag is not set and the date-token matches the year
181
- * production, set the found-year flag and set the year-value to the number
182
- * denoted by the date-token. Skip the remaining sub-steps and continue to
183
- * the next date-token.
223
+ /* 2.4. If the found-year flag is not set and the date-token matches the
224
+ * year production, set the found-year flag and set the year-value to the
225
+ * number denoted by the date-token. Skip the remaining sub-steps and
226
+ * continue to the next date-token.
184
227
  */
185
228
  if (year === null) {
186
- result = YEAR.exec(token);
187
- if (result) {
188
- year = parseInt(result[0], 10);
229
+ // "year = 2*4DIGIT ( non-digit *OCTET )"
230
+ result = parseDigits(token, 2, 4, true);
231
+ if (result !== null) {
232
+ year = result;
189
233
  /* From S5.1.1:
190
234
  * 3. If the year-value is greater than or equal to 70 and less
191
235
  * than or equal to 99, increment the year-value by 1900.
192
236
  * 4. If the year-value is greater than or equal to 0 and less
193
237
  * than or equal to 69, increment the year-value by 2000.
194
238
  */
195
- if (70 <= year && year <= 99) {
239
+ if (year >= 70 && year <= 99) {
196
240
  year += 1900;
197
- } else if (0 <= year && year <= 69) {
241
+ } else if (year >= 0 && year <= 69) {
198
242
  year += 2000;
199
243
  }
200
-
201
- if (year < 1601) {
202
- return; // 5. ... the year-value is less than 1601
203
- }
204
244
  }
205
245
  }
206
246
  }
207
247
 
208
- if (seconds === null || day === null || month === null || year === null) {
209
- return; // 5. ... at least one of the found-day-of-month, found-month, found-
210
- // year, or found-time flags is not set,
248
+ /* RFC 6265 S5.1.1
249
+ * "5. Abort these steps and fail to parse the cookie-date if:
250
+ * * at least one of the found-day-of-month, found-month, found-
251
+ * year, or found-time flags is not set,
252
+ * * the day-of-month-value is less than 1 or greater than 31,
253
+ * * the year-value is less than 1601,
254
+ * * the hour-value is greater than 23,
255
+ * * the minute-value is greater than 59, or
256
+ * * the second-value is greater than 59.
257
+ * (Note that leap seconds cannot be represented in this syntax.)"
258
+ *
259
+ * So, in order as above:
260
+ */
261
+ if (
262
+ dayOfMonth === null || month === null || year === null || second === null ||
263
+ dayOfMonth < 1 || dayOfMonth > 31 ||
264
+ year < 1601 ||
265
+ hour > 23 ||
266
+ minute > 59 ||
267
+ second > 59
268
+ ) {
269
+ return;
211
270
  }
212
271
 
213
- return new Date(Date.UTC(year, month, day, hour, minutes, seconds));
272
+ return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));
214
273
  }
215
274
 
216
275
  function formatDate(date) {
@@ -317,32 +376,62 @@ function defaultPath(path) {
317
376
  return path.slice(0, rightSlash);
318
377
  }
319
378
 
379
+ function trimTerminator(str) {
380
+ for (var t = 0; t < TERMINATORS.length; t++) {
381
+ var terminatorIdx = str.indexOf(TERMINATORS[t]);
382
+ if (terminatorIdx !== -1) {
383
+ str = str.substr(0,terminatorIdx);
384
+ }
385
+ }
320
386
 
321
- function parse(str, options) {
322
- if (!options || typeof options !== 'object') {
323
- options = {};
387
+ return str;
388
+ }
389
+
390
+ function parseCookiePair(cookiePair, looseMode) {
391
+ cookiePair = trimTerminator(cookiePair);
392
+
393
+ var firstEq = cookiePair.indexOf('=');
394
+ if (looseMode) {
395
+ if (firstEq === 0) { // '=' is immediately at start
396
+ cookiePair = cookiePair.substr(1);
397
+ firstEq = cookiePair.indexOf('='); // might still need to split on '='
398
+ }
399
+ } else { // non-loose mode
400
+ if (firstEq <= 0) { // no '=' or is at start
401
+ return; // needs to have non-empty "cookie-name"
402
+ }
324
403
  }
325
- str = str.trim();
326
404
 
327
- // We use a regex to parse the "name-value-pair" part of S5.2
328
- var firstSemi = str.indexOf(';'); // S5.2 step 1
329
- var pairRe = options.loose ? LOOSE_COOKIE_PAIR : COOKIE_PAIR;
330
- var result = pairRe.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
405
+ var cookieName, cookieValue;
406
+ if (firstEq <= 0) {
407
+ cookieName = "";
408
+ cookieValue = cookiePair.trim();
409
+ } else {
410
+ cookieName = cookiePair.substr(0, firstEq).trim();
411
+ cookieValue = cookiePair.substr(firstEq+1).trim();
412
+ }
331
413
 
332
- // Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
333
- // constraints as well as trimming any whitespace.
334
- if (!result) {
414
+ if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {
335
415
  return;
336
416
  }
337
417
 
338
418
  var c = new Cookie();
339
- if (result[1]) {
340
- c.key = result[2].trim();
341
- } else {
342
- c.key = '';
419
+ c.key = cookieName;
420
+ c.value = cookieValue;
421
+ return c;
422
+ }
423
+
424
+ function parse(str, options) {
425
+ if (!options || typeof options !== 'object') {
426
+ options = {};
343
427
  }
344
- c.value = result[3].trim();
345
- if (CONTROL_CHARS.test(c.key) || CONTROL_CHARS.test(c.value)) {
428
+ str = str.trim();
429
+
430
+ // We use a regex to parse the "name-value-pair" part of S5.2
431
+ var firstSemi = str.indexOf(';'); // S5.2 step 1
432
+ var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);
433
+ var c = parseCookiePair(cookiePair, !!options.loose);
434
+ if (!c) {
346
435
  return;
347
436
  }
348
437
 
@@ -1206,6 +1295,7 @@ CookieJar.prototype._importCookies = function(serialized, cb) {
1206
1295
  if (!cookies || !Array.isArray(cookies)) {
1207
1296
  return cb(new Error('serialized jar has no cookies array'));
1208
1297
  }
1298
+ cookies = cookies.slice(); // do not modify the original
1209
1299
 
1210
1300
  function putNext(err) {
1211
1301
  if (err) {