diff options
Diffstat (limited to 'deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js')
-rw-r--r-- | deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js | 376 |
1 files changed, 268 insertions, 108 deletions
diff --git a/deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js b/deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js index 1d8615b58..c93e927ae 100644 --- a/deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js +++ b/deps/npm/node_modules/request/node_modules/tough-cookie/lib/cookie.js @@ -19,10 +19,11 @@ * IN THE SOFTWARE. */ -/*jshint regexp:false */ +'use strict'; var net = require('net'); var urlParse = require('url').parse; var pubsuffix = require('./pubsuffix'); +var Store = require('./store').Store; var punycode; try { @@ -39,11 +40,11 @@ var TOKEN = /[\x21\x23-\x26\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/ // From RFC6265 S4.1.1 // note that it excludes \x3B ";" var COOKIE_OCTET = /[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/; -var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/; +var COOKIE_OCTETS = new RegExp('^'+COOKIE_OCTET.source+'$'); // The name/key cannot be empty but the value can (S5.2): -var COOKIE_PAIR_STRICT = new RegExp('^('+TOKEN.source+'+)=("?)('+COOKIE_OCTET.source+'*)\\2'); -var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2/; +var COOKIE_PAIR_STRICT = new RegExp('^('+TOKEN.source+'+)=("?)('+COOKIE_OCTET.source+'*)\\2$'); +var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/; // RFC6265 S4.1.1 defines extension-av as 'any CHAR except CTLs or ";"' // Note ';' is \x3B @@ -70,7 +71,8 @@ var STRICT_TIME = /^(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/; var MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$/i; var MONTH_TO_NUM = { - jan:0, feb:1, mar:2, apr:3, may:4, jun:5, jul:6, aug:7, sep:8, oct:9, nov:10, dec:11 + jan:0, feb:1, mar:2, apr:3, may:4, jun:5, + jul:6, aug:7, sep:8, oct:9, nov:10, dec:11 }; var NUM_TO_MONTH = [ 'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec' @@ -79,17 +81,17 @@ var NUM_TO_DAY = [ 'Sun','Mon','Tue','Wed','Thu','Fri','Sat' ]; -var YEAR = /^([1-9][0-9]{1,3})$/; // 2 to 4 digits (will check range when parsing) +var YEAR = /^([1-9][0-9]{1,3})$/; // 2 to 4 digits var MAX_TIME = 2147483647000; // 31-bit max -var MAX_DATE = new Date(CookieJar.MAX_TIME); // 31-bit max var MIN_TIME = 0; // 31-bit min -var MIN_DATE = new Date(CookieJar.MIN_TIME); // 31-bit min // RFC6265 S5.1.1 date parser: function parseDate(str,strict) { - if (!str) return; + if (!str) { + return; + } var found_time, found_dom, found_month, found_year; /* RFC6265 S5.1.1: @@ -97,14 +99,18 @@ function parseDate(str,strict) { * appear in the cookie-date */ var tokens = str.split(DATE_DELIM); - if (!tokens) return; + if (!tokens) { + return; + } var date = new Date(); date.setMilliseconds(0); for (var i=0; i<tokens.length; i++) { var token = tokens[i].trim(); - if (!token.length) continue; + if (!token.length) { + continue; + } var result; @@ -168,13 +174,15 @@ function parseDate(str,strict) { * 4. If the year-value is greater than or equal to 0 and less * than or equal to 69, increment the year-value by 2000. */ - if (70 <= year && year <= 99) + if (70 <= year && year <= 99) { year += 1900; - else if (0 <= year && year <= 69) + } else if (0 <= year && year <= 69) { year += 2000; + } - if (year < 1601) + if (year < 1601) { return; // 5. ... the year-value is less than 1601 + } found_year = true; date.setUTCFullYear(year); @@ -203,19 +211,24 @@ function formatDate(date) { // S5.1.2 Canonicalized Host Names function canonicalDomain(str) { - if (str == null) return null; + if (str == null) { + return null; + } str = str.trim().replace(/^\./,''); // S4.1.2.3 & S5.2.3: ignore leading . // convert to IDN if any non-ASCII characters - if (punycode && /[^\u0001-\u007f]/.test(str)) + if (punycode && /[^\u0001-\u007f]/.test(str)) { str = punycode.toASCII(str); + } return str.toLowerCase(); } // S5.1.3 Domain Matching function domainMatch(str, domStr, canonicalize) { - if (str == null || domStr == null) return null; + if (str == null || domStr == null) { + return null; + } if (canonicalize !== false) { str = canonicalDomain(str); domStr = canonicalDomain(domStr); @@ -226,25 +239,35 @@ function domainMatch(str, domStr, canonicalize) { * domain string and the string will have been canonicalized to lower case at * this point)" */ - if (str == domStr) return true; + if (str == domStr) { + return true; + } /* "All of the following [three] conditions hold:" (order adjusted from the RFC) */ /* "* The string is a host name (i.e., not an IP address)." */ - if (net.isIP(str)) return false; + if (net.isIP(str)) { + return false; + } /* "* The domain string is a suffix of the string" */ var idx = str.indexOf(domStr); - if (idx <= 0) return false; // it's a non-match (-1) or prefix (0) + if (idx <= 0) { + return false; // it's a non-match (-1) or prefix (0) + } // e.g "a.b.c".indexOf("b.c") === 2 // 5 === 3+2 - if (str.length !== domStr.length + idx) // it's not a suffix + if (str.length !== domStr.length + idx) { // it's not a suffix return false; + } /* "* The last character of the string that is not included in the domain * string is a %x2E (".") character." */ - if (str.substr(idx-1,1) !== '.') return false; + if (str.substr(idx-1,1) !== '.') { + return false; + } + return true; } @@ -260,14 +283,20 @@ function domainMatch(str, domStr, canonicalize) { function defaultPath(path) { // "2. If the uri-path is empty or if the first character of the uri-path is not // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps. - if (!path || path.substr(0,1) !== "/") return "/"; + if (!path || path.substr(0,1) !== "/") { + return "/"; + } // "3. If the uri-path contains no more than one %x2F ("/") character, output // %x2F ("/") and skip the remaining step." - if (path === "/") return path; + if (path === "/") { + return path; + } var rightSlash = path.lastIndexOf("/"); - if (rightSlash === 0) return "/"; + if (rightSlash === 0) { + return "/"; + } // "4. Output the characters of the uri-path from the first character up to, // but not including, the right-most %x2F ("/")." @@ -280,21 +309,24 @@ function defaultPath(path) { */ function pathMatch(reqPath,cookiePath) { // "o The cookie-path and the request-path are identical." - if (cookiePath === reqPath) + if (cookiePath === reqPath) { return true; + } var idx = reqPath.indexOf(cookiePath); if (idx === 0) { // "o The cookie-path is a prefix of the request-path, and the last // character of the cookie-path is %x2F ("/")." - if (cookiePath.substr(-1) === "/") + if (cookiePath.substr(-1) === "/") { return true; + } // " o The cookie-path is a prefix of the request-path, and the first // character of the request-path that is not included in the cookie- path // is a %x2F ("/") character." - if (reqPath.substr(cookiePath.length,1) === "/") + if (reqPath.substr(cookiePath.length,1) === "/") { return true; + } } return false; @@ -307,7 +339,9 @@ function parse(str, strict) { // If we are not in strict mode we remove the trailing semi-colons. var semiColonCheck = TRAILING_SEMICOLON.exec(str); if (semiColonCheck) { - if (strict) return; + if (strict) { + return; + } str = str.slice(0, semiColonCheck.index); } @@ -318,13 +352,17 @@ function parse(str, strict) { // Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")" // constraints as well as trimming any whitespace. - if (!result) return; + if (!result) { + return; + } var c = new Cookie(); c.key = result[1]; // the regexp should trim() already c.value = result[3]; // [2] is quotes or empty-string - if (firstSemi === -1) return c; + if (firstSemi === -1) { + return c; + } // S5.2.3 "unparsed-attributes consist of the remainder of the set-cookie-string // (including the %x3B (";") in question)." plus later on in the same section @@ -333,7 +371,9 @@ function parse(str, strict) { // "If the unparsed-attributes string is empty, skip the rest of these // steps." - if (unparsed.length === 0) return c; + if (unparsed.length === 0) { + return c; + } /* * S5.2 says that when looping over the items "[p]rocess the attribute-name @@ -347,7 +387,9 @@ function parse(str, strict) { while (cookie_avs.length) { var av = cookie_avs.shift(); - if (strict && !EXTENSION_AV.test(av)) return; + if (strict && !EXTENSION_AV.test(av)) { + return; + } var av_sep = av.indexOf('='); var av_key, av_value; @@ -360,28 +402,32 @@ function parse(str, strict) { } av_key = av_key.trim().toLowerCase(); - if (av_value) av_value = av_value.trim(); + if (av_value) { + av_value = av_value.trim(); + } switch(av_key) { case 'expires': // S5.2.1 - if (!av_value) { if(strict){return}else{break;} } + if (!av_value) {if(strict){return;}else{break;} } var exp = parseDate(av_value,strict); // "If the attribute-value failed to parse as a cookie date, ignore the // cookie-av." - if (exp == null) { if(strict){return}else{break;} } + if (exp == null) { if(strict){return;}else{break;} } c.expires = exp; // over and underflow not realistically a concern: V8's getTime() seems to // store something larger than a 32-bit time_t (even with 32-bit node) break; case 'max-age': // S5.2.2 - if (!av_value) { if(strict){return}else{break;} } + if (!av_value) { if(strict){return;}else{break;} } // "If the first character of the attribute-value is not a DIGIT or a "-" // character ...[or]... If the remainder of attribute-value contains a // non-DIGIT character, ignore the cookie-av." - if (!/^-?[0-9]+$/.test(av_value)) { if(strict){return}else{break;} } + if (!/^-?[0-9]+$/.test(av_value)) { if(strict){return;}else{break;} } var delta = parseInt(av_value,10); - if (strict && delta <= 0) return; // S4.1.1 + if (strict && delta <= 0) { + return; // S4.1.1 + } // "If delta-seconds is less than or equal to zero (0), let expiry-time // be the earliest representable date and time." c.setMaxAge(delta); @@ -390,11 +436,11 @@ function parse(str, strict) { case 'domain': // S5.2.3 // "If the attribute-value is empty, the behavior is undefined. However, // the user agent SHOULD ignore the cookie-av entirely." - if (!av_value) { if(strict){return}else{break;} } + if (!av_value) { if(strict){return;}else{break;} } // S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E // (".") character." var domain = av_value.trim().replace(/^\./,''); - if (!domain) { if(strict){return}else{break;} } // see "is empty" above + if (!domain) { if(strict){return;}else{break;} } // see "is empty" above // "Convert the cookie-domain to lower case." c.domain = domain.toLowerCase(); break; @@ -410,7 +456,9 @@ function parse(str, strict) { * We'll represent the default-path as null since it depends on the * context of the parsing. */ - if (!av_value || av_value.substr(0,1) != "/") { if(strict){return}else{break;} } + if (!av_value || av_value.substr(0,1) != "/") { + if(strict){return;}else{break;} + } c.path = av_value; break; @@ -420,12 +468,12 @@ function parse(str, strict) { * the user agent MUST append an attribute to the cookie-attribute-list * with an attribute-name of Secure and an empty attribute-value." */ - if (av_value != null) { if(strict){return} } + if (av_value != null) { if(strict){return;} } c.secure = true; break; case 'httponly': // S5.2.6 -- effectively the same as 'secure' - if (av_value != null) { if(strict){return} } + if (av_value != null) { if(strict){return;} } c.httpOnly = true; break; @@ -442,7 +490,9 @@ function parse(str, strict) { } function fromJSON(str) { - if (!str) return null; + if (!str) { + return null; + } var obj; try { @@ -454,7 +504,9 @@ function fromJSON(str) { var c = new Cookie(); for (var i=0; i<numCookieProperties; i++) { var prop = cookieProperties[i]; - if (obj[prop] == null) continue; + if (obj[prop] == null) { + continue; + } if (prop === 'expires' || prop === 'creation' || prop === 'lastAccessed') @@ -484,7 +536,9 @@ function fromJSON(str) { function cookieCompare(a,b) { // descending for length: b CMP a var deltaLen = (b.path ? b.path.length : 0) - (a.path ? a.path.length : 0); - if (deltaLen !== 0) return deltaLen; + if (deltaLen !== 0) { + return deltaLen; + } // ascending for time: a CMP b return (a.creation ? a.creation.getTime() : MAX_TIME) - (b.creation ? b.creation.getTime() : MAX_TIME); @@ -494,8 +548,12 @@ function cookieCompare(a,b) { // array is in shortest-to-longest order. Handy for indexing. function permuteDomain(domain) { var pubSuf = pubsuffix.getPublicSuffix(domain); - if (!pubSuf) return null; - if (pubSuf == domain) return [domain]; + if (!pubSuf) { + return null; + } + if (pubSuf == domain) { + return [domain]; + } var prefix = domain.slice(0,-(pubSuf.length+1)); // ".example.com" var parts = prefix.split('.').reverse(); @@ -511,14 +569,18 @@ function permuteDomain(domain) { // Gives the permutation of all possible pathMatch()es of a given path. The // array is in longest-to-shortest order. Handy for indexing. function permutePath(path) { - var origPath = path; - if (path === '/') return ['/']; - if (path.lastIndexOf('/') === path.length-1) + if (path === '/') { + return ['/']; + } + if (path.lastIndexOf('/') === path.length-1) { path = path.substr(0,path.length-1); + } var permutations = [path]; while (path.length > 1) { var lindex = path.lastIndexOf('/'); - if (lindex === 0) break; + if (lindex === 0) { + break; + } path = path.substr(0,lindex); permutations.push(path); } @@ -528,7 +590,9 @@ function permutePath(path) { function Cookie (opts) { - if (typeof opts !== "object") return; + if (typeof opts !== "object") { + return; + } Object.keys(opts).forEach(function (key) { if (Cookie.prototype.hasOwnProperty(key)) { this[key] = opts[key] || Cookie.prototype[key]; @@ -558,7 +622,9 @@ Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse Cookie.prototype.lastAccessed = null; // Date when set var cookieProperties = Object.freeze(Object.keys(Cookie.prototype).map(function(p) { - if (p instanceof Function) return; + if (p instanceof Function) { + return; + } return p; })); var numCookieProperties = cookieProperties.length; @@ -573,46 +639,55 @@ Cookie.prototype.inspect = function inspect() { }; Cookie.prototype.validate = function validate() { - if (!COOKIE_OCTETS.test(this.value)) + if (!COOKIE_OCTETS.test(this.value)) { return false; - if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires,true)) + } + if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires,true)) { return false; - if (this.maxAge != null && this.maxAge <= 0) + } + if (this.maxAge != null && this.maxAge <= 0) { return false; // "Max-Age=" non-zero-digit *DIGIT - if (this.path != null && !PATH_VALUE.test(this.path)) + } + if (this.path != null && !PATH_VALUE.test(this.path)) { return false; + } var cdomain = this.cdomain(); if (cdomain) { - if (cdomain.match(/\.$/)) + if (cdomain.match(/\.$/)) { return false; // S4.1.2.3 suggests that this is bad. domainMatch() tests confirm this + } var suffix = pubsuffix.getPublicSuffix(cdomain); - if (suffix == null) // it's a public suffix + if (suffix == null) { // it's a public suffix return false; + } } return true; }; Cookie.prototype.setExpires = function setExpires(exp) { - if (exp instanceof Date) this.expires = exp; - else this.expires = parseDate(exp) || "Infinity"; + if (exp instanceof Date) { + this.expires = exp; + } else { + this.expires = parseDate(exp) || "Infinity"; + } }; Cookie.prototype.setMaxAge = function setMaxAge(age) { - if (age === Infinity || age === -Infinity) + if (age === Infinity || age === -Infinity) { this.maxAge = age.toString(); // so JSON.stringify() works - else + } else { this.maxAge = age; + } }; // gives Cookie header format Cookie.prototype.cookieString = function cookieString() { var val = this.value; - if (val == null) val = ''; - if (!val.length || COOKIE_OCTETS.test(val)) - return this.key+'='+val; - else - return this.key+'="'+val+'"'; + if (val == null) { + val = ''; + } + return this.key+'='+val; }; // gives Set-Cookie header format @@ -620,22 +695,30 @@ Cookie.prototype.toString = function toString() { var str = this.cookieString(); if (this.expires != Infinity) { - if (this.expires instanceof Date) + if (this.expires instanceof Date) { str += '; Expires='+formatDate(this.expires); - else + } else { str += '; Expires='+this.expires; + } } - if (this.maxAge != null && this.maxAge != Infinity) + if (this.maxAge != null && this.maxAge != Infinity) { str += '; Max-Age='+this.maxAge; + } - if (this.domain && !this.hostOnly) + if (this.domain && !this.hostOnly) { str += '; Domain='+this.domain; - if (this.path) + } + if (this.path) { str += '; Path='+this.path; + } - if (this.secure) str += '; Secure'; - if (this.httpOnly) str += '; HttpOnly'; + if (this.secure) { + str += '; Secure'; + } + if (this.httpOnly) { + str += '; HttpOnly'; + } if (this.extensions) { this.extensions.forEach(function(ext) { str += '; '+ext; @@ -665,8 +748,9 @@ Cookie.prototype.TTL = function TTL(now) { expires = parseDate(expires) || Infinity; } - if (expires == Infinity) + if (expires == Infinity) { return Infinity; + } return expires.getTime() - (now || Date.now()); } @@ -683,7 +767,9 @@ Cookie.prototype.expiryTime = function expiryTime(now) { return relativeTo.getTime() + age; } - if (this.expires == Infinity) return Infinity; + if (this.expires == Infinity) { + return Infinity; + } return this.expires.getTime(); }; @@ -691,9 +777,13 @@ Cookie.prototype.expiryTime = function expiryTime(now) { // elsewhere), except it returns a Date Cookie.prototype.expiryDate = function expiryDate(now) { var millisec = this.expiryTime(now); - if (millisec == Infinity) return new Date(MAX_TIME); - else if (millisec == -Infinity) return new Date(MIN_TIME); - else return new Date(millisec); + if (millisec == Infinity) { + return new Date(MAX_TIME); + } else if (millisec == -Infinity) { + return new Date(MIN_TIME); + } else { + return new Date(millisec); + } }; // This replaces the "persistent-flag" parts of S5.3 step 3 @@ -704,14 +794,19 @@ Cookie.prototype.isPersistent = function isPersistent() { // Mostly S5.1.2 and S5.2.3: Cookie.prototype.cdomain = Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() { - if (this.domain == null) return null; + if (this.domain == null) { + return null; + } return canonicalDomain(this.domain); }; var memstore; function CookieJar(store, rejectPublicSuffixes) { - if (rejectPublicSuffixes != null) this.rejectPublicSuffixes = rejectPublicSuffixes; + if (rejectPublicSuffixes != null) { + this.rejectPublicSuffixes = rejectPublicSuffixes; + } + if (!store) { memstore = memstore || require('./memstore'); store = new memstore.MemoryCookieStore(); @@ -720,8 +815,10 @@ function CookieJar(store, rejectPublicSuffixes) { } CookieJar.prototype.store = null; CookieJar.prototype.rejectPublicSuffixes = true; +var CAN_BE_SYNC = []; -CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { +CAN_BE_SYNC.push('setCookie'); +CookieJar.prototype.setCookie = function(cookie, url, options, cb) { var err; var context = (url instanceof Object) ? url : urlParse(url); if (options instanceof Function) { @@ -732,8 +829,9 @@ CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { var host = canonicalDomain(context.hostname); // S5.3 step 1 - if (!(cookie instanceof Cookie)) + if (!(cookie instanceof Cookie)) { cookie = Cookie.parse(cookie, options.strict === true); + } if (!cookie) { err = new Error("Cookie failed to parse"); return cb(options.ignoreError ? null : err); @@ -762,8 +860,9 @@ CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { return cb(options.ignoreError ? null : err); } - if (cookie.hostOnly == null) // don't reset if already set + if (cookie.hostOnly == null) { // don't reset if already set cookie.hostOnly = false; + } } else { cookie.hostOnly = true; @@ -776,8 +875,9 @@ CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { cookie.path = defaultPath(context.pathname); cookie.pathIsDefault = true; } else { - if (cookie.path.length > 1 && cookie.path.substr(-1) == '/') + if (cookie.path.length > 1 && cookie.path.substr(-1) == '/') { cookie.path = cookie.path.slice(0,-1); + } } // S5.3 step 8: NOOP; secure attribute @@ -792,17 +892,22 @@ CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { var store = this.store; if (!store.updateCookie) { - store.updateCookie = function stubUpdateCookie(oldCookie, newCookie, cb) { + store.updateCookie = function(oldCookie, newCookie, cb) { this.putCookie(newCookie, cb); }; } - store.findCookie(cookie.domain, cookie.path, cookie.key, function(err,oldCookie) { - if (err) return cb(err); + function withCookie(err, oldCookie) { + if (err) { + return cb(err); + } var next = function(err) { - if (err) return cb(err); - else cb(null, cookie); + if (err) { + return cb(err); + } else { + cb(null, cookie); + } }; if (oldCookie) { @@ -821,11 +926,14 @@ CookieJar.prototype.setCookie = function setCookie(cookie, url, options, cb) { cookie.creation = cookie.lastAccessed = now; store.putCookie(cookie, next); // step 12 } - }); + } + + store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie); }; // RFC6365 S5.4 -CookieJar.prototype.getCookies = function getCookies(url, options, cb) { +CAN_BE_SYNC.push('getCookies'); +CookieJar.prototype.getCookies = function(url, options, cb) { var context = (url instanceof Object) ? url : urlParse(url); if (options instanceof Function) { cb = options; @@ -843,7 +951,9 @@ CookieJar.prototype.getCookies = function getCookies(url, options, cb) { } var http = options.http; - if (http == null) http = true; + if (http == null) { + http = true; + } var now = options.now || Date.now(); var expireCheck = options.expire !== false; @@ -858,24 +968,31 @@ CookieJar.prototype.getCookies = function getCookies(url, options, cb) { // The cookie's host-only-flag is false and the canonicalized // request-host domain-matches the cookie's domain." if (c.hostOnly) { - if (c.domain != host) return false; + if (c.domain != host) { + return false; + } } else { - if (!domainMatch(host, c.domain, false)) return false; + if (!domainMatch(host, c.domain, false)) { + return false; + } } // "The request-uri's path path-matches the cookie's path." - if (!allPaths && !pathMatch(path, c.path)) + if (!allPaths && !pathMatch(path, c.path)) { return false; + } // "If the cookie's secure-only-flag is true, then the request-uri's // scheme must denote a "secure" protocol" - if (c.secure && !secure) + if (c.secure && !secure) { return false; + } // "If the cookie's http-only-flag is true, then exclude the cookie if the // cookie-string is being generated for a "non-HTTP" API" - if (c.httpOnly && !http) + if (c.httpOnly && !http) { return false; + } // deferred from S5.3 // non-RFC: allow retention of expired cookies by choice @@ -888,50 +1005,93 @@ CookieJar.prototype.getCookies = function getCookies(url, options, cb) { } store.findCookies(host, allPaths ? null : path, function(err,cookies) { - if (err) return cb(err); + if (err) { + return cb(err); + } cookies = cookies.filter(matchingCookie); // sorting of S5.4 part 2 - if (options.sort !== false) + if (options.sort !== false) { cookies = cookies.sort(cookieCompare); + } // S5.4 part 3 var now = new Date(); - cookies.forEach(function(c) { c.lastAccessed = now }); + cookies.forEach(function(c) { + c.lastAccessed = now; + }); // TODO persist lastAccessed cb(null,cookies); }); }; +CAN_BE_SYNC.push('getCookieString'); CookieJar.prototype.getCookieString = function(/*..., cb*/) { var args = Array.prototype.slice.call(arguments,0); var cb = args.pop(); var next = function(err,cookies) { - if (err) cb(err); - else cb(null, cookies.map(function(c){return c.cookieString()}).join('; ')); + if (err) { + cb(err); + } else { + cb(null, cookies.map(function(c){ + return c.cookieString(); + }).join('; ')); + } }; args.push(next); this.getCookies.apply(this,args); }; +CAN_BE_SYNC.push('getSetCookieStrings'); CookieJar.prototype.getSetCookieStrings = function(/*..., cb*/) { var args = Array.prototype.slice.call(arguments,0); var cb = args.pop(); var next = function(err,cookies) { - if (err) cb(err); - else cb(null, cookies.map(function(c){return c.toString()})); + if (err) { + cb(err); + } else { + cb(null, cookies.map(function(c){ + return c.toString(); + })); + } }; args.push(next); this.getCookies.apply(this,args); }; +// Use a closure to provide a true imperative API for synchronous stores. +function syncWrap(method) { + return function() { + if (!this.store.synchronous) { + throw new Error('CookieJar store is not synchronous; use async API instead.'); + } + + var args = Array.prototype.slice.call(arguments); + var syncErr, syncResult; + args.push(function syncCb(err, result) { + syncErr = err; + syncResult = result; + }); + this[method].apply(this, args); + + if (syncErr) { + throw syncErr; + } + return syncResult; + }; +} +// wrap all declared CAN_BE_SYNC methods in the sync wrapper +CAN_BE_SYNC.forEach(function(method) { + CookieJar.prototype[method+'Sync'] = syncWrap(method); +}); module.exports = { CookieJar: CookieJar, Cookie: Cookie, + Store: Store, parseDate: parseDate, formatDate: formatDate, parse: parse, |