tough-cookie 1.2.0 → 2.2.1
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 +8 -55
- package/README.md +192 -122
- package/lib/cookie.js +314 -60
- package/lib/memstore.js +31 -3
- package/lib/pubsuffix.js +2 -2
- package/lib/store.js +5 -1
- package/package.json +38 -4
- package/.editorconfig +0 -12
- package/.jshintrc +0 -70
- package/.npmignore +0 -4
- package/.travis.yml +0 -9
- package/generate-pubsuffix.js +0 -293
- package/public-suffix.txt +0 -10079
- package/test/api_test.js +0 -372
- package/test/cookie_jar_test.js +0 -468
- package/test/cookie_sorting_test.js +0 -90
- package/test/cookie_to_json_test.js +0 -164
- package/test/cookie_to_string_test.js +0 -162
- package/test/date_test.js +0 -79
- package/test/domain_and_path_test.js +0 -201
- package/test/ietf_data/dates/bsd-examples.json +0 -168
- package/test/ietf_data/dates/examples.json +0 -48
- package/test/ietf_data/parser.json +0 -1959
- package/test/ietf_test.js +0 -106
- package/test/lifetime_test.js +0 -97
- package/test/parsing_test.js +0 -294
- package/test/regression_test.js +0 -143
package/lib/cookie.js
CHANGED
|
@@ -35,6 +35,7 @@ var pubsuffix = require('./pubsuffix');
|
|
|
35
35
|
var Store = require('./store').Store;
|
|
36
36
|
var MemoryCookieStore = require('./memstore').MemoryCookieStore;
|
|
37
37
|
var pathMatch = require('./pathMatch').pathMatch;
|
|
38
|
+
var VERSION = require('../package.json').version;
|
|
38
39
|
|
|
39
40
|
var punycode;
|
|
40
41
|
try {
|
|
@@ -48,14 +49,20 @@ var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
|
|
|
48
49
|
// From RFC6265 S4.1.1
|
|
49
50
|
// note that it excludes \x3B ";"
|
|
50
51
|
var COOKIE_OCTET = /[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/;
|
|
51
|
-
var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'
|
|
52
|
+
var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'+$');
|
|
53
|
+
|
|
54
|
+
var CONTROL_CHARS = /[\x00-\x1F]/;
|
|
52
55
|
|
|
53
56
|
// Double quotes are part of the value (see: S4.1.1).
|
|
54
57
|
// '\r', '\n' and '\0' should be treated as a terminator in the "relaxed" mode
|
|
55
58
|
// (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60)
|
|
56
59
|
// '=' and ';' are attribute/values separators
|
|
57
60
|
// (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L64)
|
|
58
|
-
var COOKIE_PAIR = /^([^=;]+)\s*=\s*(("?)[^\n\r\0]*\3)
|
|
61
|
+
var COOKIE_PAIR = /^(([^=;]+))\s*=\s*(("?)[^\n\r\0]*\3)/
|
|
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]*\3)/;
|
|
59
66
|
|
|
60
67
|
// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
|
|
61
68
|
// Note ';' is \x3B
|
|
@@ -84,8 +91,6 @@ var YEAR = /^(\d{2}|\d{4})$/; // 2 to 4 digits
|
|
|
84
91
|
var MAX_TIME = 2147483647000; // 31-bit max
|
|
85
92
|
var MIN_TIME = 0; // 31-bit min
|
|
86
93
|
|
|
87
|
-
var cookiesCreated = 0; // Number of cookies created in runtime
|
|
88
|
-
|
|
89
94
|
|
|
90
95
|
// RFC6265 S5.1.1 date parser:
|
|
91
96
|
function parseDate(str) {
|
|
@@ -316,7 +321,10 @@ function defaultPath(path) {
|
|
|
316
321
|
}
|
|
317
322
|
|
|
318
323
|
|
|
319
|
-
function parse(str) {
|
|
324
|
+
function parse(str, options) {
|
|
325
|
+
if (!options || typeof options !== 'object') {
|
|
326
|
+
options = {};
|
|
327
|
+
}
|
|
320
328
|
str = str.trim();
|
|
321
329
|
|
|
322
330
|
// S4.1.1 Trailing semi-colons are not part of the specification.
|
|
@@ -327,7 +335,8 @@ function parse(str) {
|
|
|
327
335
|
|
|
328
336
|
// We use a regex to parse the "name-value-pair" part of S5.2
|
|
329
337
|
var firstSemi = str.indexOf(';'); // S5.2 step 1
|
|
330
|
-
var
|
|
338
|
+
var pairRe = options.loose ? LOOSE_COOKIE_PAIR : COOKIE_PAIR;
|
|
339
|
+
var result = pairRe.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
|
|
331
340
|
|
|
332
341
|
// Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
|
|
333
342
|
// constraints as well as trimming any whitespace.
|
|
@@ -336,8 +345,15 @@ function parse(str) {
|
|
|
336
345
|
}
|
|
337
346
|
|
|
338
347
|
var c = new Cookie();
|
|
339
|
-
|
|
340
|
-
|
|
348
|
+
if (result[1]) {
|
|
349
|
+
c.key = result[2].trim();
|
|
350
|
+
} else {
|
|
351
|
+
c.key = '';
|
|
352
|
+
}
|
|
353
|
+
c.value = result[3].trim();
|
|
354
|
+
if (CONTROL_CHARS.test(c.key) || CONTROL_CHARS.test(c.value)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
341
357
|
|
|
342
358
|
if (firstSemi === -1) {
|
|
343
359
|
return c;
|
|
@@ -458,47 +474,60 @@ function parse(str) {
|
|
|
458
474
|
}
|
|
459
475
|
}
|
|
460
476
|
|
|
461
|
-
// ensure a default date for sorting:
|
|
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();
|
|
467
477
|
return c;
|
|
468
478
|
}
|
|
469
479
|
|
|
480
|
+
// avoid the V8 deoptimization monster!
|
|
481
|
+
function jsonParse(str) {
|
|
482
|
+
var obj;
|
|
483
|
+
try {
|
|
484
|
+
obj = JSON.parse(str);
|
|
485
|
+
} catch (e) {
|
|
486
|
+
return e;
|
|
487
|
+
}
|
|
488
|
+
return obj;
|
|
489
|
+
}
|
|
490
|
+
|
|
470
491
|
function fromJSON(str) {
|
|
471
492
|
if (!str) {
|
|
472
493
|
return null;
|
|
473
494
|
}
|
|
474
495
|
|
|
475
496
|
var obj;
|
|
476
|
-
|
|
477
|
-
obj =
|
|
478
|
-
|
|
479
|
-
|
|
497
|
+
if (typeof str === 'string') {
|
|
498
|
+
obj = jsonParse(str);
|
|
499
|
+
if (obj instanceof Error) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
// assume it's an Object
|
|
504
|
+
obj = str;
|
|
480
505
|
}
|
|
481
506
|
|
|
482
507
|
var c = new Cookie();
|
|
483
|
-
for (var i=0; i<
|
|
484
|
-
var prop =
|
|
485
|
-
if (obj[prop]
|
|
486
|
-
|
|
508
|
+
for (var i=0; i<Cookie.serializableProperties.length; i++) {
|
|
509
|
+
var prop = Cookie.serializableProperties[i];
|
|
510
|
+
if (obj[prop] === undefined ||
|
|
511
|
+
obj[prop] === Cookie.prototype[prop])
|
|
512
|
+
{
|
|
513
|
+
continue; // leave as prototype default
|
|
487
514
|
}
|
|
515
|
+
|
|
488
516
|
if (prop === 'expires' ||
|
|
489
517
|
prop === 'creation' ||
|
|
490
518
|
prop === 'lastAccessed')
|
|
491
519
|
{
|
|
492
|
-
|
|
520
|
+
if (obj[prop] === null) {
|
|
521
|
+
c[prop] = null;
|
|
522
|
+
} else {
|
|
523
|
+
c[prop] = obj[prop] == "Infinity" ?
|
|
524
|
+
"Infinity" : new Date(obj[prop]);
|
|
525
|
+
}
|
|
493
526
|
} else {
|
|
494
527
|
c[prop] = obj[prop];
|
|
495
528
|
}
|
|
496
529
|
}
|
|
497
530
|
|
|
498
|
-
|
|
499
|
-
// ensure a default date for sorting:
|
|
500
|
-
c.creation = c.creation || new Date();
|
|
501
|
-
|
|
502
531
|
return c;
|
|
503
532
|
}
|
|
504
533
|
|
|
@@ -512,23 +541,28 @@ function fromJSON(str) {
|
|
|
512
541
|
*/
|
|
513
542
|
|
|
514
543
|
function cookieCompare(a,b) {
|
|
544
|
+
var cmp = 0;
|
|
545
|
+
|
|
515
546
|
// descending for length: b CMP a
|
|
516
|
-
var
|
|
517
|
-
|
|
518
|
-
|
|
547
|
+
var aPathLen = a.path ? a.path.length : 0;
|
|
548
|
+
var bPathLen = b.path ? b.path.length : 0;
|
|
549
|
+
cmp = bPathLen - aPathLen;
|
|
550
|
+
if (cmp !== 0) {
|
|
551
|
+
return cmp;
|
|
519
552
|
}
|
|
520
553
|
|
|
554
|
+
// ascending for time: a CMP b
|
|
521
555
|
var aTime = a.creation ? a.creation.getTime() : MAX_TIME;
|
|
522
556
|
var bTime = b.creation ? b.creation.getTime() : MAX_TIME;
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
if(aTime === bTime && aTime === a._initialCreationTime && bTime === b._initialCreationTime) {
|
|
527
|
-
return a._creationRuntimeIdx - b._creationRuntimeIdx;
|
|
557
|
+
cmp = aTime - bTime;
|
|
558
|
+
if (cmp !== 0) {
|
|
559
|
+
return cmp;
|
|
528
560
|
}
|
|
529
561
|
|
|
530
|
-
//
|
|
531
|
-
|
|
562
|
+
// break ties for the same millisecond (precision of JavaScript's clock)
|
|
563
|
+
cmp = a.creationIndex - b.creationIndex;
|
|
564
|
+
|
|
565
|
+
return cmp;
|
|
532
566
|
}
|
|
533
567
|
|
|
534
568
|
// Gives the permutation of all possible pathMatch()es of a given path. The
|
|
@@ -569,17 +603,31 @@ function getCookieContext(url) {
|
|
|
569
603
|
return urlParse(url);
|
|
570
604
|
}
|
|
571
605
|
|
|
572
|
-
function Cookie
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
606
|
+
function Cookie(options) {
|
|
607
|
+
options = options || {};
|
|
608
|
+
|
|
609
|
+
Object.keys(options).forEach(function(prop) {
|
|
610
|
+
if (Cookie.prototype.hasOwnProperty(prop) &&
|
|
611
|
+
Cookie.prototype[prop] !== options[prop] &&
|
|
612
|
+
prop.substr(0,1) !== '_')
|
|
613
|
+
{
|
|
614
|
+
this[prop] = options[prop];
|
|
579
615
|
}
|
|
580
|
-
}
|
|
616
|
+
}, this);
|
|
617
|
+
|
|
618
|
+
this.creation = this.creation || new Date();
|
|
619
|
+
|
|
620
|
+
// used to break creation ties in cookieCompare():
|
|
621
|
+
Object.defineProperty(this, 'creationIndex', {
|
|
622
|
+
configurable: false,
|
|
623
|
+
enumerable: false, // important for assert.deepEqual checks
|
|
624
|
+
writable: true,
|
|
625
|
+
value: ++Cookie.cookiesCreated
|
|
626
|
+
});
|
|
581
627
|
}
|
|
582
628
|
|
|
629
|
+
Cookie.cookiesCreated = 0; // incremented each time a cookie is created
|
|
630
|
+
|
|
583
631
|
Cookie.parse = parse;
|
|
584
632
|
Cookie.fromJSON = fromJSON;
|
|
585
633
|
|
|
@@ -599,17 +647,22 @@ Cookie.prototype.extensions = null;
|
|
|
599
647
|
Cookie.prototype.hostOnly = null; // boolean when set
|
|
600
648
|
Cookie.prototype.pathIsDefault = null; // boolean when set
|
|
601
649
|
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()
|
|
604
650
|
Cookie.prototype.lastAccessed = null; // Date when set
|
|
651
|
+
Object.defineProperty(Cookie.prototype, 'creationIndex', {
|
|
652
|
+
configurable: true,
|
|
653
|
+
enumerable: false,
|
|
654
|
+
writable: true,
|
|
655
|
+
value: 0
|
|
656
|
+
});
|
|
605
657
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
return
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
658
|
+
Cookie.serializableProperties = Object.keys(Cookie.prototype)
|
|
659
|
+
.filter(function(prop) {
|
|
660
|
+
return !(
|
|
661
|
+
Cookie.prototype[prop] instanceof Function ||
|
|
662
|
+
prop === 'creationIndex' ||
|
|
663
|
+
prop.substr(0,1) === '_'
|
|
664
|
+
);
|
|
665
|
+
});
|
|
613
666
|
|
|
614
667
|
Cookie.prototype.inspect = function inspect() {
|
|
615
668
|
var now = Date.now();
|
|
@@ -620,6 +673,46 @@ Cookie.prototype.inspect = function inspect() {
|
|
|
620
673
|
'"';
|
|
621
674
|
};
|
|
622
675
|
|
|
676
|
+
Cookie.prototype.toJSON = function() {
|
|
677
|
+
var obj = {};
|
|
678
|
+
|
|
679
|
+
var props = Cookie.serializableProperties;
|
|
680
|
+
for (var i=0; i<props.length; i++) {
|
|
681
|
+
var prop = props[i];
|
|
682
|
+
if (this[prop] === Cookie.prototype[prop]) {
|
|
683
|
+
continue; // leave as prototype default
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (prop === 'expires' ||
|
|
687
|
+
prop === 'creation' ||
|
|
688
|
+
prop === 'lastAccessed')
|
|
689
|
+
{
|
|
690
|
+
if (this[prop] === null) {
|
|
691
|
+
obj[prop] = null;
|
|
692
|
+
} else {
|
|
693
|
+
obj[prop] = this[prop] == "Infinity" ? // intentionally not ===
|
|
694
|
+
"Infinity" : this[prop].toISOString();
|
|
695
|
+
}
|
|
696
|
+
} else if (prop === 'maxAge') {
|
|
697
|
+
if (this[prop] !== null) {
|
|
698
|
+
// again, intentionally not ===
|
|
699
|
+
obj[prop] = (this[prop] == Infinity || this[prop] == -Infinity) ?
|
|
700
|
+
this[prop].toString() : this[prop];
|
|
701
|
+
}
|
|
702
|
+
} else {
|
|
703
|
+
if (this[prop] !== Cookie.prototype[prop]) {
|
|
704
|
+
obj[prop] = this[prop];
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return obj;
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
Cookie.prototype.clone = function() {
|
|
713
|
+
return fromJSON(this.toJSON());
|
|
714
|
+
};
|
|
715
|
+
|
|
623
716
|
Cookie.prototype.validate = function validate() {
|
|
624
717
|
if (!COOKIE_OCTETS.test(this.value)) {
|
|
625
718
|
return false;
|
|
@@ -669,6 +762,9 @@ Cookie.prototype.cookieString = function cookieString() {
|
|
|
669
762
|
if (val == null) {
|
|
670
763
|
val = '';
|
|
671
764
|
}
|
|
765
|
+
if (this.key === '') {
|
|
766
|
+
return val;
|
|
767
|
+
}
|
|
672
768
|
return this.key+'='+val;
|
|
673
769
|
};
|
|
674
770
|
|
|
@@ -744,7 +840,7 @@ Cookie.prototype.TTL = function TTL(now) {
|
|
|
744
840
|
// elsewhere)
|
|
745
841
|
Cookie.prototype.expiryTime = function expiryTime(now) {
|
|
746
842
|
if (this.maxAge != null) {
|
|
747
|
-
var relativeTo = this.creation ||
|
|
843
|
+
var relativeTo = now || this.creation || new Date();
|
|
748
844
|
var age = (this.maxAge <= 0) ? -Infinity : this.maxAge*1000;
|
|
749
845
|
return relativeTo.getTime() + age;
|
|
750
846
|
}
|
|
@@ -782,10 +878,17 @@ Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() {
|
|
|
782
878
|
return canonicalDomain(this.domain);
|
|
783
879
|
};
|
|
784
880
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
881
|
+
function CookieJar(store, options) {
|
|
882
|
+
if (typeof options === "boolean") {
|
|
883
|
+
options = {rejectPublicSuffixes: options};
|
|
884
|
+
} else if (options == null) {
|
|
885
|
+
options = {};
|
|
886
|
+
}
|
|
887
|
+
if (options.rejectPublicSuffixes != null) {
|
|
888
|
+
this.rejectPublicSuffixes = options.rejectPublicSuffixes;
|
|
889
|
+
}
|
|
890
|
+
if (options.looseMode != null) {
|
|
891
|
+
this.enableLooseMode = options.looseMode;
|
|
789
892
|
}
|
|
790
893
|
|
|
791
894
|
if (!store) {
|
|
@@ -795,6 +898,7 @@ function CookieJar(store, rejectPublicSuffixes) {
|
|
|
795
898
|
}
|
|
796
899
|
CookieJar.prototype.store = null;
|
|
797
900
|
CookieJar.prototype.rejectPublicSuffixes = true;
|
|
901
|
+
CookieJar.prototype.enableLooseMode = false;
|
|
798
902
|
var CAN_BE_SYNC = [];
|
|
799
903
|
|
|
800
904
|
CAN_BE_SYNC.push('setCookie');
|
|
@@ -807,10 +911,14 @@ CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
|
807
911
|
}
|
|
808
912
|
|
|
809
913
|
var host = canonicalDomain(context.hostname);
|
|
914
|
+
var loose = this.enableLooseMode;
|
|
915
|
+
if (options.loose != null) {
|
|
916
|
+
loose = options.loose;
|
|
917
|
+
}
|
|
810
918
|
|
|
811
919
|
// S5.3 step 1
|
|
812
920
|
if (!(cookie instanceof Cookie)) {
|
|
813
|
-
cookie = Cookie.parse(cookie);
|
|
921
|
+
cookie = Cookie.parse(cookie, { loose: loose });
|
|
814
922
|
}
|
|
815
923
|
if (!cookie) {
|
|
816
924
|
err = new Error("Cookie failed to parse");
|
|
@@ -895,6 +1003,7 @@ CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
|
|
|
895
1003
|
return cb(options.ignoreError ? null : err);
|
|
896
1004
|
}
|
|
897
1005
|
cookie.creation = oldCookie.creation; // step 11.3
|
|
1006
|
+
cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker
|
|
898
1007
|
cookie.lastAccessed = now;
|
|
899
1008
|
// Step 11.4 (delete cookie) is implied by just setting the new one:
|
|
900
1009
|
store.updateCookie(oldCookie, cookie, next); // step 12
|
|
@@ -1041,6 +1150,151 @@ CookieJar.prototype.getSetCookieStrings = function(/*..., cb*/) {
|
|
|
1041
1150
|
this.getCookies.apply(this,args);
|
|
1042
1151
|
};
|
|
1043
1152
|
|
|
1153
|
+
CAN_BE_SYNC.push('serialize');
|
|
1154
|
+
CookieJar.prototype.serialize = function(cb) {
|
|
1155
|
+
var type = this.store.constructor.name;
|
|
1156
|
+
if (type === 'Object') {
|
|
1157
|
+
type = null;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// update README.md "Serialization Format" if you change this, please!
|
|
1161
|
+
var serialized = {
|
|
1162
|
+
// The version of tough-cookie that serialized this jar. Generally a good
|
|
1163
|
+
// practice since future versions can make data import decisions based on
|
|
1164
|
+
// known past behavior. When/if this matters, use `semver`.
|
|
1165
|
+
version: 'tough-cookie@'+VERSION,
|
|
1166
|
+
|
|
1167
|
+
// add the store type, to make humans happy:
|
|
1168
|
+
storeType: type,
|
|
1169
|
+
|
|
1170
|
+
// CookieJar configuration:
|
|
1171
|
+
rejectPublicSuffixes: !!this.rejectPublicSuffixes,
|
|
1172
|
+
|
|
1173
|
+
// this gets filled from getAllCookies:
|
|
1174
|
+
cookies: []
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
if (!(this.store.getAllCookies &&
|
|
1178
|
+
typeof this.store.getAllCookies === 'function'))
|
|
1179
|
+
{
|
|
1180
|
+
return cb(new Error('store does not support getAllCookies and cannot be serialized'));
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
this.store.getAllCookies(function(err,cookies) {
|
|
1184
|
+
if (err) {
|
|
1185
|
+
return cb(err);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
serialized.cookies = cookies.map(function(cookie) {
|
|
1189
|
+
// convert to serialized 'raw' cookies
|
|
1190
|
+
cookie = (cookie instanceof Cookie) ? cookie.toJSON() : cookie;
|
|
1191
|
+
|
|
1192
|
+
// Remove the index so new ones get assigned during deserialization
|
|
1193
|
+
delete cookie.creationIndex;
|
|
1194
|
+
|
|
1195
|
+
return cookie;
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
return cb(null, serialized);
|
|
1199
|
+
});
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
// well-known name that JSON.stringify calls
|
|
1203
|
+
CookieJar.prototype.toJSON = function() {
|
|
1204
|
+
return this.serializeSync();
|
|
1205
|
+
};
|
|
1206
|
+
|
|
1207
|
+
// use the class method CookieJar.deserialize instead of calling this directly
|
|
1208
|
+
CAN_BE_SYNC.push('_importCookies');
|
|
1209
|
+
CookieJar.prototype._importCookies = function(serialized, cb) {
|
|
1210
|
+
var jar = this;
|
|
1211
|
+
var cookies = serialized.cookies;
|
|
1212
|
+
if (!cookies || !Array.isArray(cookies)) {
|
|
1213
|
+
return cb(new Error('serialized jar has no cookies array'));
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
function putNext(err) {
|
|
1217
|
+
if (err) {
|
|
1218
|
+
return cb(err);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
if (!cookies.length) {
|
|
1222
|
+
return cb(err, jar);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
var cookie;
|
|
1226
|
+
try {
|
|
1227
|
+
cookie = fromJSON(cookies.shift());
|
|
1228
|
+
} catch (e) {
|
|
1229
|
+
return cb(e);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
if (cookie === null) {
|
|
1233
|
+
return putNext(null); // skip this cookie
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
jar.store.putCookie(cookie, putNext);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
putNext();
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
CookieJar.deserialize = function(strOrObj, store, cb) {
|
|
1243
|
+
if (arguments.length !== 3) {
|
|
1244
|
+
// store is optional
|
|
1245
|
+
cb = store;
|
|
1246
|
+
store = null;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
var serialized;
|
|
1250
|
+
if (typeof strOrObj === 'string') {
|
|
1251
|
+
serialized = jsonParse(strOrObj);
|
|
1252
|
+
if (serialized instanceof Error) {
|
|
1253
|
+
return cb(serialized);
|
|
1254
|
+
}
|
|
1255
|
+
} else {
|
|
1256
|
+
serialized = strOrObj;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
|
|
1260
|
+
jar._importCookies(serialized, function(err) {
|
|
1261
|
+
if (err) {
|
|
1262
|
+
return cb(err);
|
|
1263
|
+
}
|
|
1264
|
+
cb(null, jar);
|
|
1265
|
+
});
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
CookieJar.deserializeSync = function(strOrObj, store) {
|
|
1269
|
+
var serialized = typeof strOrObj === 'string' ?
|
|
1270
|
+
JSON.parse(strOrObj) : strOrObj;
|
|
1271
|
+
var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
|
|
1272
|
+
|
|
1273
|
+
// catch this mistake early:
|
|
1274
|
+
if (!jar.store.synchronous) {
|
|
1275
|
+
throw new Error('CookieJar store is not synchronous; use async API instead.');
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
jar._importCookiesSync(serialized);
|
|
1279
|
+
return jar;
|
|
1280
|
+
};
|
|
1281
|
+
CookieJar.fromJSON = CookieJar.deserializeSync;
|
|
1282
|
+
|
|
1283
|
+
CAN_BE_SYNC.push('clone');
|
|
1284
|
+
CookieJar.prototype.clone = function(newStore, cb) {
|
|
1285
|
+
if (arguments.length === 1) {
|
|
1286
|
+
cb = newStore;
|
|
1287
|
+
newStore = null;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
this.serialize(function(err,serialized) {
|
|
1291
|
+
if (err) {
|
|
1292
|
+
return cb(err);
|
|
1293
|
+
}
|
|
1294
|
+
CookieJar.deserialize(newStore, serialized, cb);
|
|
1295
|
+
});
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1044
1298
|
// Use a closure to provide a true imperative API for synchronous stores.
|
|
1045
1299
|
function syncWrap(method) {
|
|
1046
1300
|
return function() {
|
package/lib/memstore.js
CHANGED
|
@@ -41,6 +41,8 @@ function MemoryCookieStore() {
|
|
|
41
41
|
util.inherits(MemoryCookieStore, Store);
|
|
42
42
|
exports.MemoryCookieStore = MemoryCookieStore;
|
|
43
43
|
MemoryCookieStore.prototype.idx = null;
|
|
44
|
+
|
|
45
|
+
// Since it's just a struct in RAM, this Store is synchronous
|
|
44
46
|
MemoryCookieStore.prototype.synchronous = true;
|
|
45
47
|
|
|
46
48
|
// force a default depth:
|
|
@@ -116,21 +118,21 @@ MemoryCookieStore.prototype.putCookie = function(cookie, cb) {
|
|
|
116
118
|
cb(null);
|
|
117
119
|
};
|
|
118
120
|
|
|
119
|
-
MemoryCookieStore.prototype.updateCookie = function
|
|
121
|
+
MemoryCookieStore.prototype.updateCookie = function(oldCookie, newCookie, cb) {
|
|
120
122
|
// updateCookie() may avoid updating cookies that are identical. For example,
|
|
121
123
|
// lastAccessed may not be important to some stores and an equality
|
|
122
124
|
// comparison could exclude that field.
|
|
123
125
|
this.putCookie(newCookie,cb);
|
|
124
126
|
};
|
|
125
127
|
|
|
126
|
-
MemoryCookieStore.prototype.removeCookie = function
|
|
128
|
+
MemoryCookieStore.prototype.removeCookie = function(domain, path, key, cb) {
|
|
127
129
|
if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) {
|
|
128
130
|
delete this.idx[domain][path][key];
|
|
129
131
|
}
|
|
130
132
|
cb(null);
|
|
131
133
|
};
|
|
132
134
|
|
|
133
|
-
MemoryCookieStore.prototype.removeCookies = function
|
|
135
|
+
MemoryCookieStore.prototype.removeCookies = function(domain, path, cb) {
|
|
134
136
|
if (this.idx[domain]) {
|
|
135
137
|
if (path) {
|
|
136
138
|
delete this.idx[domain][path];
|
|
@@ -140,3 +142,29 @@ MemoryCookieStore.prototype.removeCookies = function removeCookies(domain, path,
|
|
|
140
142
|
}
|
|
141
143
|
return cb(null);
|
|
142
144
|
};
|
|
145
|
+
|
|
146
|
+
MemoryCookieStore.prototype.getAllCookies = function(cb) {
|
|
147
|
+
var cookies = [];
|
|
148
|
+
var idx = this.idx;
|
|
149
|
+
|
|
150
|
+
var domains = Object.keys(idx);
|
|
151
|
+
domains.forEach(function(domain) {
|
|
152
|
+
var paths = Object.keys(idx[domain]);
|
|
153
|
+
paths.forEach(function(path) {
|
|
154
|
+
var keys = Object.keys(idx[domain][path]);
|
|
155
|
+
keys.forEach(function(key) {
|
|
156
|
+
if (key !== null) {
|
|
157
|
+
cookies.push(idx[domain][path][key]);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Sort by creationIndex so deserializing retains the creation order.
|
|
164
|
+
// When implementing your own store, this SHOULD retain the order too
|
|
165
|
+
cookies.sort(function(a,b) {
|
|
166
|
+
return (a.creationIndex||0) - (b.creationIndex||0);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
cb(null, cookies);
|
|
170
|
+
};
|