tough-cookie 2.3.3 → 2.5.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/LICENSE CHANGED
@@ -10,18 +10,3 @@ Redistribution and use in source and binary forms, with or without modification,
10
10
  3. Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
11
 
12
12
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13
-
14
- ===
15
-
16
- The following exceptions apply:
17
-
18
- ===
19
-
20
- `public_suffix_list.dat` was obtained from
21
- <https://publicsuffix.org/list/public_suffix_list.dat> via
22
- <http://publicsuffix.org>. The license for this file is MPL/2.0. The header of
23
- that file reads as follows:
24
-
25
- // This Source Code Form is subject to the terms of the Mozilla Public
26
- // License, v. 2.0. If a copy of the MPL was not distributed with this
27
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
package/README.md CHANGED
@@ -57,7 +57,7 @@ Transforms a domain-name into a canonical domain-name. The canonical domain-nam
57
57
 
58
58
  Answers "does this real domain match the domain in a cookie?". The `str` is the "current" domain-name and the `domStr` is the "cookie" domain-name. Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a "suffix match".
59
59
 
60
- The `canonicalize` parameter will run the other two paramters through `canonicalDomain` or not.
60
+ The `canonicalize` parameter will run the other two parameters through `canonicalDomain` or not.
61
61
 
62
62
  ### `defaultPath(path)`
63
63
 
@@ -85,7 +85,7 @@ Returns the public suffix of this hostname. The public suffix is the shortest d
85
85
 
86
86
  For example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.
87
87
 
88
- For further information, see http://publicsuffix.org/. This module derives its list from that site.
88
+ For further information, see http://publicsuffix.org/. This module derives its list from that site. This call is currently a wrapper around [`psl`](https://www.npmjs.com/package/psl)'s [get() method](https://www.npmjs.com/package/psl#pslgetdomain).
89
89
 
90
90
  ### `cookieCompare(a,b)`
91
91
 
@@ -134,7 +134,7 @@ else
134
134
  cookies = [Cookie.parse(res.headers['set-cookie'])];
135
135
  ```
136
136
 
137
- _Potentially non-standard behavior:_ currently, tough-cookie will limit the number of spaces before the `=` to 256 characters.
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
138
  See [Issue 92](https://github.com/salesforce/tough-cookie/issues/92)
139
139
 
140
140
  ### Properties
@@ -186,7 +186,7 @@ sets the maxAge in seconds. Coerces `-Infinity` to `"-Infinity"` and `Infinity`
186
186
 
187
187
  expiryTime() Computes the absolute unix-epoch milliseconds that this cookie expires. expiryDate() works similarly, except it returns a `Date` object. Note that in both cases the `now` parameter should be milliseconds.
188
188
 
189
- Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` paramter -- is used to offset the `.maxAge` attribute.
189
+ Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` parameter -- is used to offset the `.maxAge` attribute.
190
190
 
191
191
  If Expires (`.expires`) is set, that's returned.
192
192
 
@@ -198,7 +198,7 @@ compute the TTL relative to `now` (milliseconds). The same precedence rules as
198
198
 
199
199
  The "number" `Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired. Otherwise a time-to-live in milliseconds is returned.
200
200
 
201
- ### `.canonicalizedDoman()`
201
+ ### `.canonicalizedDomain()`
202
202
 
203
203
  ### `.cdomain()`
204
204
 
@@ -354,6 +354,16 @@ The `store` argument is optional, but must be a _synchronous_ `Store` instance i
354
354
 
355
355
  The _source_ and _destination_ must both be synchronous `Store`s. If one or both stores are asynchronous, use `.clone` instead. Recall that `MemoryCookieStore` supports both synchronous and asynchronous API calls.
356
356
 
357
+ ### `.removeAllCookies(cb(err))`
358
+
359
+ Removes all cookies from the jar.
360
+
361
+ This is a new backwards-compatible feature of `tough-cookie` version 2.5, so not all Stores will implement it efficiently. For Stores that do not implement `removeAllCookies`, the fallback is to call `removeCookie` after `getAllCookies`. If `getAllCookies` fails or isn't implemented in the Store, that error is returned. If one or more of the `removeCookie` calls fail, only the first error is returned.
362
+
363
+ ### `.removeAllCookiesSync()`
364
+
365
+ Sync version of `.removeAllCookies()`
366
+
357
367
  ## Store
358
368
 
359
369
  Base class for CookieJar stores. Available as `tough.Store`.
@@ -418,19 +428,29 @@ Removes matching cookies from the store. The `path` parameter is optional, and
418
428
 
419
429
  Pass an error ONLY if removing any existing cookies failed.
420
430
 
431
+ ### `store.removeAllCookies(cb(err))`
432
+
433
+ _Optional_. Removes all cookies from the store.
434
+
435
+ Pass an error if one or more cookies can't be removed.
436
+
437
+ **Note**: New method as of `tough-cookie` version 2.5, so not all Stores will implement this, plus some stores may choose not to implement this.
438
+
421
439
  ### `store.getAllCookies(cb(err, cookies))`
422
440
 
423
- Produces an `Array` of all cookies during `jar.serialize()`. The items in the array can be true `Cookie` objects or generic `Object`s with the [Serialization Format] data structure.
441
+ _Optional_. Produces an `Array` of all cookies during `jar.serialize()`. The items in the array can be true `Cookie` objects or generic `Object`s with the [Serialization Format] data structure.
424
442
 
425
443
  Cookies SHOULD be returned in creation order to preserve sorting via `compareCookies()`. For reference, `MemoryCookieStore` will sort by `.creationIndex` since it uses true `Cookie` objects internally. If you don't return the cookies in creation order, they'll still be sorted by creation time, but this only has a precision of 1ms. See `compareCookies` for more detail.
426
444
 
427
445
  Pass an error if retrieval fails.
428
446
 
447
+ **Note**: not all Stores can implement this due to technical limitations, so it is optional.
448
+
429
449
  ## MemoryCookieStore
430
450
 
431
451
  Inherits from `Store`.
432
452
 
433
- A just-in-memory CookieJar synchronous store implementation, used by default. Despite being a synchronous implementation, it's usable with both the synchronous and asynchronous forms of the `CookieJar` API.
453
+ A just-in-memory CookieJar synchronous store implementation, used by default. Despite being a synchronous implementation, it's usable with both the synchronous and asynchronous forms of the `CookieJar` API. Supports serialization, `getAllCookies`, and `removeAllCookies`.
434
454
 
435
455
  ## Community Cookie Stores
436
456
 
@@ -473,7 +493,7 @@ These are some Store implementations authored and maintained by the community. T
473
493
 
474
494
  # Copyright and License
475
495
 
476
- (tl;dr: BSD-3-Clause with some MPL/2.0)
496
+ BSD-3-Clause:
477
497
 
478
498
  ```text
479
499
  Copyright (c) 2015, Salesforce.com, Inc.
@@ -505,5 +525,3 @@ These are some Store implementations authored and maintained by the community. T
505
525
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
506
526
  POSSIBILITY OF SUCH DAMAGE.
507
527
  ```
508
-
509
- Portions may be licensed under different licenses (in particular `public_suffix_list.dat` is MPL/2.0); please read that file and the LICENSE file for full details.
package/lib/cookie.js CHANGED
@@ -31,50 +31,38 @@
31
31
  'use strict';
32
32
  var net = require('net');
33
33
  var urlParse = require('url').parse;
34
- var pubsuffix = require('./pubsuffix');
34
+ var util = require('util');
35
+ var pubsuffix = require('./pubsuffix-psl');
35
36
  var Store = require('./store').Store;
36
37
  var MemoryCookieStore = require('./memstore').MemoryCookieStore;
37
38
  var pathMatch = require('./pathMatch').pathMatch;
38
- var VERSION = require('../package.json').version;
39
+ var VERSION = require('./version');
39
40
 
40
41
  var punycode;
41
42
  try {
42
43
  punycode = require('punycode');
43
44
  } catch(e) {
44
- console.warn("cookie: can't load punycode; won't use punycode for domain normalization");
45
+ console.warn("tough-cookie: can't load punycode; won't use punycode for domain normalization");
45
46
  }
46
47
 
47
- var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
48
-
49
48
  // From RFC6265 S4.1.1
50
49
  // 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+'+$');
50
+ var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/;
53
51
 
54
52
  var CONTROL_CHARS = /[\x00-\x1F]/;
55
53
 
56
- // For COOKIE_PAIR and LOOSE_COOKIE_PAIR below, the number of spaces has been
57
- // restricted to 256 to side-step a ReDoS issue reported here:
58
- // https://github.com/salesforce/tough-cookie/issues/92
59
-
60
- // Double quotes are part of the value (see: S4.1.1).
61
- // '\r', '\n' and '\0' should be treated as a terminator in the "relaxed" mode
62
- // (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60)
63
- // '=' and ';' are attribute/values separators
64
- // (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L64)
65
- var COOKIE_PAIR = /^(([^=;]+))\s{0,256}=\s*([^\n\r\0]*)/;
66
-
67
- // Used to parse non-RFC-compliant cookies like '=abc' when given the `loose`
68
- // option in Cookie.parse:
69
- var LOOSE_COOKIE_PAIR = /^((?:=)?([^=;]*)\s{0,256}=\s*)?([^\n\r\0]*)/;
54
+ // From Chromium // '\r', '\n' and '\0' should be treated as a terminator in
55
+ // the "relaxed" mode, see:
56
+ // https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60
57
+ var TERMINATORS = ['\n', '\r', '\0'];
70
58
 
71
59
  // RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
72
60
  // Note ';' is \x3B
73
61
  var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
74
62
 
75
- var DAY_OF_MONTH = /^(\d{1,2})[^\d]*$/;
76
- var TIME = /^(\d{1,2})[^\d]*:(\d{1,2})[^\d]*:(\d{1,2})[^\d]*$/;
77
- var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i;
63
+ // date-time parsing constants (RFC6265 S5.1.1)
64
+
65
+ var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
78
66
 
79
67
  var MONTH_TO_NUM = {
80
68
  jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
@@ -87,13 +75,80 @@ var NUM_TO_DAY = [
87
75
  'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
88
76
  ];
89
77
 
90
- var YEAR = /^(\d{2}|\d{4})$/; // 2 to 4 digits
91
-
92
78
  var MAX_TIME = 2147483647000; // 31-bit max
93
79
  var MIN_TIME = 0; // 31-bit min
94
80
 
81
+ /*
82
+ * Parses a Natural number (i.e., non-negative integer) with either the
83
+ * <min>*<max>DIGIT ( non-digit *OCTET )
84
+ * or
85
+ * <min>*<max>DIGIT
86
+ * grammar (RFC6265 S5.1.1).
87
+ *
88
+ * The "trailingOK" boolean controls if the grammar accepts a
89
+ * "( non-digit *OCTET )" trailer.
90
+ */
91
+ function parseDigits(token, minDigits, maxDigits, trailingOK) {
92
+ var count = 0;
93
+ while (count < token.length) {
94
+ var c = token.charCodeAt(count);
95
+ // "non-digit = %x00-2F / %x3A-FF"
96
+ if (c <= 0x2F || c >= 0x3A) {
97
+ break;
98
+ }
99
+ count++;
100
+ }
101
+
102
+ // constrain to a minimum and maximum number of digits.
103
+ if (count < minDigits || count > maxDigits) {
104
+ return null;
105
+ }
106
+
107
+ if (!trailingOK && count != token.length) {
108
+ return null;
109
+ }
110
+
111
+ return parseInt(token.substr(0,count), 10);
112
+ }
113
+
114
+ function parseTime(token) {
115
+ var parts = token.split(':');
116
+ var result = [0,0,0];
117
+
118
+ /* RF6256 S5.1.1:
119
+ * time = hms-time ( non-digit *OCTET )
120
+ * hms-time = time-field ":" time-field ":" time-field
121
+ * time-field = 1*2DIGIT
122
+ */
123
+
124
+ if (parts.length !== 3) {
125
+ return null;
126
+ }
95
127
 
96
- // RFC6265 S5.1.1 date parser:
128
+ for (var i = 0; i < 3; i++) {
129
+ // "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
130
+ // followed by "( non-digit *OCTET )" so therefore the last time-field can
131
+ // have a trailer
132
+ var trailingOK = (i == 2);
133
+ var num = parseDigits(parts[i], 1, 2, trailingOK);
134
+ if (num === null) {
135
+ return null;
136
+ }
137
+ result[i] = num;
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ function parseMonth(token) {
144
+ token = String(token).substr(0,3).toLowerCase();
145
+ var num = MONTH_TO_NUM[token];
146
+ return num >= 0 ? num : null;
147
+ }
148
+
149
+ /*
150
+ * RFC6265 S5.1.1 date parser (see RFC for full grammar)
151
+ */
97
152
  function parseDate(str) {
98
153
  if (!str) {
99
154
  return;
@@ -109,9 +164,9 @@ function parseDate(str) {
109
164
  }
110
165
 
111
166
  var hour = null;
112
- var minutes = null;
113
- var seconds = null;
114
- var day = null;
167
+ var minute = null;
168
+ var second = null;
169
+ var dayOfMonth = null;
115
170
  var month = null;
116
171
  var year = null;
117
172
 
@@ -129,22 +184,12 @@ function parseDate(str) {
129
184
  * the date-token, respectively. Skip the remaining sub-steps and continue
130
185
  * to the next date-token.
131
186
  */
132
- if (seconds === null) {
133
- result = TIME.exec(token);
187
+ if (second === null) {
188
+ result = parseTime(token);
134
189
  if (result) {
135
- hour = parseInt(result[1], 10);
136
- minutes = parseInt(result[2], 10);
137
- seconds = parseInt(result[3], 10);
138
- /* RFC6265 S5.1.1.5:
139
- * [fail if]
140
- * * the hour-value is greater than 23,
141
- * * the minute-value is greater than 59, or
142
- * * the second-value is greater than 59.
143
- */
144
- if(hour > 23 || minutes > 59 || seconds > 59) {
145
- return;
146
- }
147
-
190
+ hour = result[0];
191
+ minute = result[1];
192
+ second = result[2];
148
193
  continue;
149
194
  }
150
195
  }
@@ -154,16 +199,11 @@ function parseDate(str) {
154
199
  * the day-of-month-value to the number denoted by the date-token. Skip
155
200
  * the remaining sub-steps and continue to the next date-token.
156
201
  */
157
- if (day === null) {
158
- result = DAY_OF_MONTH.exec(token);
159
- if (result) {
160
- day = parseInt(result, 10);
161
- /* RFC6265 S5.1.1.5:
162
- * [fail if] the day-of-month-value is less than 1 or greater than 31
163
- */
164
- if(day < 1 || day > 31) {
165
- return;
166
- }
202
+ if (dayOfMonth === null) {
203
+ // "day-of-month = 1*2DIGIT ( non-digit *OCTET )"
204
+ result = parseDigits(token, 1, 2, true);
205
+ if (result !== null) {
206
+ dayOfMonth = result;
167
207
  continue;
168
208
  }
169
209
  }
@@ -174,47 +214,63 @@ function parseDate(str) {
174
214
  * continue to the next date-token.
175
215
  */
176
216
  if (month === null) {
177
- result = MONTH.exec(token);
178
- if (result) {
179
- month = MONTH_TO_NUM[result[1].toLowerCase()];
217
+ result = parseMonth(token);
218
+ if (result !== null) {
219
+ month = result;
180
220
  continue;
181
221
  }
182
222
  }
183
223
 
184
- /* 2.4. If the found-year flag is not set and the date-token matches the year
185
- * production, set the found-year flag and set the year-value to the number
186
- * denoted by the date-token. Skip the remaining sub-steps and continue to
187
- * the next date-token.
224
+ /* 2.4. If the found-year flag is not set and the date-token matches the
225
+ * year production, set the found-year flag and set the year-value to the
226
+ * number denoted by the date-token. Skip the remaining sub-steps and
227
+ * continue to the next date-token.
188
228
  */
189
229
  if (year === null) {
190
- result = YEAR.exec(token);
191
- if (result) {
192
- year = parseInt(result[0], 10);
230
+ // "year = 2*4DIGIT ( non-digit *OCTET )"
231
+ result = parseDigits(token, 2, 4, true);
232
+ if (result !== null) {
233
+ year = result;
193
234
  /* From S5.1.1:
194
235
  * 3. If the year-value is greater than or equal to 70 and less
195
236
  * than or equal to 99, increment the year-value by 1900.
196
237
  * 4. If the year-value is greater than or equal to 0 and less
197
238
  * than or equal to 69, increment the year-value by 2000.
198
239
  */
199
- if (70 <= year && year <= 99) {
240
+ if (year >= 70 && year <= 99) {
200
241
  year += 1900;
201
- } else if (0 <= year && year <= 69) {
242
+ } else if (year >= 0 && year <= 69) {
202
243
  year += 2000;
203
244
  }
204
-
205
- if (year < 1601) {
206
- return; // 5. ... the year-value is less than 1601
207
- }
208
245
  }
209
246
  }
210
247
  }
211
248
 
212
- if (seconds === null || day === null || month === null || year === null) {
213
- return; // 5. ... at least one of the found-day-of-month, found-month, found-
214
- // year, or found-time flags is not set,
249
+ /* RFC 6265 S5.1.1
250
+ * "5. Abort these steps and fail to parse the cookie-date if:
251
+ * * at least one of the found-day-of-month, found-month, found-
252
+ * year, or found-time flags is not set,
253
+ * * the day-of-month-value is less than 1 or greater than 31,
254
+ * * the year-value is less than 1601,
255
+ * * the hour-value is greater than 23,
256
+ * * the minute-value is greater than 59, or
257
+ * * the second-value is greater than 59.
258
+ * (Note that leap seconds cannot be represented in this syntax.)"
259
+ *
260
+ * So, in order as above:
261
+ */
262
+ if (
263
+ dayOfMonth === null || month === null || year === null || second === null ||
264
+ dayOfMonth < 1 || dayOfMonth > 31 ||
265
+ year < 1601 ||
266
+ hour > 23 ||
267
+ minute > 59 ||
268
+ second > 59
269
+ ) {
270
+ return;
215
271
  }
216
272
 
217
- return new Date(Date.UTC(year, month, day, hour, minutes, seconds));
273
+ return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));
218
274
  }
219
275
 
220
276
  function formatDate(date) {
@@ -321,32 +377,62 @@ function defaultPath(path) {
321
377
  return path.slice(0, rightSlash);
322
378
  }
323
379
 
380
+ function trimTerminator(str) {
381
+ for (var t = 0; t < TERMINATORS.length; t++) {
382
+ var terminatorIdx = str.indexOf(TERMINATORS[t]);
383
+ if (terminatorIdx !== -1) {
384
+ str = str.substr(0,terminatorIdx);
385
+ }
386
+ }
324
387
 
325
- function parse(str, options) {
326
- if (!options || typeof options !== 'object') {
327
- options = {};
388
+ return str;
389
+ }
390
+
391
+ function parseCookiePair(cookiePair, looseMode) {
392
+ cookiePair = trimTerminator(cookiePair);
393
+
394
+ var firstEq = cookiePair.indexOf('=');
395
+ if (looseMode) {
396
+ if (firstEq === 0) { // '=' is immediately at start
397
+ cookiePair = cookiePair.substr(1);
398
+ firstEq = cookiePair.indexOf('='); // might still need to split on '='
399
+ }
400
+ } else { // non-loose mode
401
+ if (firstEq <= 0) { // no '=' or is at start
402
+ return; // needs to have non-empty "cookie-name"
403
+ }
328
404
  }
329
- str = str.trim();
330
405
 
331
- // We use a regex to parse the "name-value-pair" part of S5.2
332
- var firstSemi = str.indexOf(';'); // S5.2 step 1
333
- var pairRe = options.loose ? LOOSE_COOKIE_PAIR : COOKIE_PAIR;
334
- var result = pairRe.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
406
+ var cookieName, cookieValue;
407
+ if (firstEq <= 0) {
408
+ cookieName = "";
409
+ cookieValue = cookiePair.trim();
410
+ } else {
411
+ cookieName = cookiePair.substr(0, firstEq).trim();
412
+ cookieValue = cookiePair.substr(firstEq+1).trim();
413
+ }
335
414
 
336
- // Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
337
- // constraints as well as trimming any whitespace.
338
- if (!result) {
415
+ if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {
339
416
  return;
340
417
  }
341
418
 
342
419
  var c = new Cookie();
343
- if (result[1]) {
344
- c.key = result[2].trim();
345
- } else {
346
- c.key = '';
420
+ c.key = cookieName;
421
+ c.value = cookieValue;
422
+ return c;
423
+ }
424
+
425
+ function parse(str, options) {
426
+ if (!options || typeof options !== 'object') {
427
+ options = {};
347
428
  }
348
- c.value = result[3].trim();
349
- if (CONTROL_CHARS.test(c.key) || CONTROL_CHARS.test(c.value)) {
429
+ str = str.trim();
430
+
431
+ // We use a regex to parse the "name-value-pair" part of S5.2
432
+ var firstSemi = str.indexOf(';'); // S5.2 step 1
433
+ var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);
434
+ var c = parseCookiePair(cookiePair, !!options.loose);
435
+ if (!c) {
350
436
  return;
351
437
  }
352
438
 
@@ -671,6 +757,12 @@ Cookie.prototype.inspect = function inspect() {
671
757
  '"';
672
758
  };
673
759
 
760
+ // Use the new custom inspection symbol to add the custom inspect function if
761
+ // available.
762
+ if (util.inspect.custom) {
763
+ Cookie.prototype[util.inspect.custom] = Cookie.prototype.inspect;
764
+ }
765
+
674
766
  Cookie.prototype.toJSON = function() {
675
767
  var obj = {};
676
768
 
@@ -1279,7 +1371,6 @@ CookieJar.deserializeSync = function(strOrObj, store) {
1279
1371
  };
1280
1372
  CookieJar.fromJSON = CookieJar.deserializeSync;
1281
1373
 
1282
- CAN_BE_SYNC.push('clone');
1283
1374
  CookieJar.prototype.clone = function(newStore, cb) {
1284
1375
  if (arguments.length === 1) {
1285
1376
  cb = newStore;
@@ -1290,10 +1381,61 @@ CookieJar.prototype.clone = function(newStore, cb) {
1290
1381
  if (err) {
1291
1382
  return cb(err);
1292
1383
  }
1293
- CookieJar.deserialize(newStore, serialized, cb);
1384
+ CookieJar.deserialize(serialized, newStore, cb);
1294
1385
  });
1295
1386
  };
1296
1387
 
1388
+ CAN_BE_SYNC.push('removeAllCookies');
1389
+ CookieJar.prototype.removeAllCookies = function(cb) {
1390
+ var store = this.store;
1391
+
1392
+ // Check that the store implements its own removeAllCookies(). The default
1393
+ // implementation in Store will immediately call the callback with a "not
1394
+ // implemented" Error.
1395
+ if (store.removeAllCookies instanceof Function &&
1396
+ store.removeAllCookies !== Store.prototype.removeAllCookies)
1397
+ {
1398
+ return store.removeAllCookies(cb);
1399
+ }
1400
+
1401
+ store.getAllCookies(function(err, cookies) {
1402
+ if (err) {
1403
+ return cb(err);
1404
+ }
1405
+
1406
+ if (cookies.length === 0) {
1407
+ return cb(null);
1408
+ }
1409
+
1410
+ var completedCount = 0;
1411
+ var removeErrors = [];
1412
+
1413
+ function removeCookieCb(removeErr) {
1414
+ if (removeErr) {
1415
+ removeErrors.push(removeErr);
1416
+ }
1417
+
1418
+ completedCount++;
1419
+
1420
+ if (completedCount === cookies.length) {
1421
+ return cb(removeErrors.length ? removeErrors[0] : null);
1422
+ }
1423
+ }
1424
+
1425
+ cookies.forEach(function(cookie) {
1426
+ store.removeCookie(cookie.domain, cookie.path, cookie.key, removeCookieCb);
1427
+ });
1428
+ });
1429
+ };
1430
+
1431
+ CookieJar.prototype._cloneSync = syncWrap('clone');
1432
+ CookieJar.prototype.cloneSync = function(newStore) {
1433
+ if (!newStore.synchronous) {
1434
+ throw new Error('CookieJar clone destination store is not synchronous; use async API instead.');
1435
+ }
1436
+ return this._cloneSync(newStore);
1437
+ };
1438
+
1297
1439
  // Use a closure to provide a true imperative API for synchronous stores.
1298
1440
  function syncWrap(method) {
1299
1441
  return function() {
@@ -1321,21 +1463,20 @@ CAN_BE_SYNC.forEach(function(method) {
1321
1463
  CookieJar.prototype[method+'Sync'] = syncWrap(method);
1322
1464
  });
1323
1465
 
1324
- module.exports = {
1325
- CookieJar: CookieJar,
1326
- Cookie: Cookie,
1327
- Store: Store,
1328
- MemoryCookieStore: MemoryCookieStore,
1329
- parseDate: parseDate,
1330
- formatDate: formatDate,
1331
- parse: parse,
1332
- fromJSON: fromJSON,
1333
- domainMatch: domainMatch,
1334
- defaultPath: defaultPath,
1335
- pathMatch: pathMatch,
1336
- getPublicSuffix: pubsuffix.getPublicSuffix,
1337
- cookieCompare: cookieCompare,
1338
- permuteDomain: require('./permuteDomain').permuteDomain,
1339
- permutePath: permutePath,
1340
- canonicalDomain: canonicalDomain
1341
- };
1466
+ exports.version = VERSION;
1467
+ exports.CookieJar = CookieJar;
1468
+ exports.Cookie = Cookie;
1469
+ exports.Store = Store;
1470
+ exports.MemoryCookieStore = MemoryCookieStore;
1471
+ exports.parseDate = parseDate;
1472
+ exports.formatDate = formatDate;
1473
+ exports.parse = parse;
1474
+ exports.fromJSON = fromJSON;
1475
+ exports.domainMatch = domainMatch;
1476
+ exports.defaultPath = defaultPath;
1477
+ exports.pathMatch = pathMatch;
1478
+ exports.getPublicSuffix = pubsuffix.getPublicSuffix;
1479
+ exports.cookieCompare = cookieCompare;
1480
+ exports.permuteDomain = require('./permuteDomain').permuteDomain;
1481
+ exports.permutePath = permutePath;
1482
+ exports.canonicalDomain = canonicalDomain;
package/lib/memstore.js CHANGED
@@ -50,6 +50,12 @@ MemoryCookieStore.prototype.inspect = function() {
50
50
  return "{ idx: "+util.inspect(this.idx, false, 2)+' }';
51
51
  };
52
52
 
53
+ // Use the new custom inspection symbol to add the custom inspect function if
54
+ // available.
55
+ if (util.inspect.custom) {
56
+ MemoryCookieStore.prototype[util.inspect.custom] = MemoryCookieStore.prototype.inspect;
57
+ }
58
+
53
59
  MemoryCookieStore.prototype.findCookie = function(domain, path, key, cb) {
54
60
  if (!this.idx[domain]) {
55
61
  return cb(null,undefined);
@@ -143,6 +149,11 @@ MemoryCookieStore.prototype.removeCookies = function(domain, path, cb) {
143
149
  return cb(null);
144
150
  };
145
151
 
152
+ MemoryCookieStore.prototype.removeAllCookies = function(cb) {
153
+ this.idx = {};
154
+ return cb(null);
155
+ }
156
+
146
157
  MemoryCookieStore.prototype.getAllCookies = function(cb) {
147
158
  var cookies = [];
148
159
  var idx = this.idx;
@@ -29,7 +29,7 @@
29
29
  * POSSIBILITY OF SUCH DAMAGE.
30
30
  */
31
31
  "use strict";
32
- var pubsuffix = require('./pubsuffix');
32
+ var pubsuffix = require('./pubsuffix-psl');
33
33
 
34
34
  // Gives the permutation of all possible domainMatch()es of a given domain. The
35
35
  // array is in shortest-to-longest order. Handy for indexing.