
node_modules.smrf-native.node_modules.tough-cookie.lib.cookie.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of libjoynr-js Show documentation
Show all versions of libjoynr-js Show documentation
JOYnr JavaScript libjoynr-js
The newest version!
/*!
* Copyright (c) 2015, Salesforce.com, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 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.
*
* 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.
*/
'use strict';
var net = require('net');
var urlParse = require('url').parse;
var pubsuffix = require('./pubsuffix');
var Store = require('./store').Store;
var MemoryCookieStore = require('./memstore').MemoryCookieStore;
var pathMatch = require('./pathMatch').pathMatch;
var VERSION = require('../package.json').version;
var punycode;
try {
punycode = require('punycode');
} catch(e) {
console.warn("cookie: can't load punycode; won't use punycode for domain normalization");
}
// From RFC6265 S4.1.1
// note that it excludes \x3B ";"
var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/;
var CONTROL_CHARS = /[\x00-\x1F]/;
// From Chromium // '\r', '\n' and '\0' should be treated as a terminator in
// the "relaxed" mode, see:
// https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60
var TERMINATORS = ['\n', '\r', '\0'];
// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
// Note ';' is \x3B
var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
// date-time parsing constants (RFC6265 S5.1.1)
var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
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
};
var NUM_TO_MONTH = [
'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
];
var NUM_TO_DAY = [
'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
];
var MAX_TIME = 2147483647000; // 31-bit max
var MIN_TIME = 0; // 31-bit min
/*
* Parses a Natural number (i.e., non-negative integer) with either the
* *DIGIT ( non-digit *OCTET )
* or
* *DIGIT
* grammar (RFC6265 S5.1.1).
*
* The "trailingOK" boolean controls if the grammar accepts a
* "( non-digit *OCTET )" trailer.
*/
function parseDigits(token, minDigits, maxDigits, trailingOK) {
var count = 0;
while (count < token.length) {
var c = token.charCodeAt(count);
// "non-digit = %x00-2F / %x3A-FF"
if (c <= 0x2F || c >= 0x3A) {
break;
}
count++;
}
// constrain to a minimum and maximum number of digits.
if (count < minDigits || count > maxDigits) {
return null;
}
if (!trailingOK && count != token.length) {
return null;
}
return parseInt(token.substr(0,count), 10);
}
function parseTime(token) {
var parts = token.split(':');
var result = [0,0,0];
/* RF6256 S5.1.1:
* time = hms-time ( non-digit *OCTET )
* hms-time = time-field ":" time-field ":" time-field
* time-field = 1*2DIGIT
*/
if (parts.length !== 3) {
return null;
}
for (var i = 0; i < 3; i++) {
// "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
// followed by "( non-digit *OCTET )" so therefore the last time-field can
// have a trailer
var trailingOK = (i == 2);
var num = parseDigits(parts[i], 1, 2, trailingOK);
if (num === null) {
return null;
}
result[i] = num;
}
return result;
}
function parseMonth(token) {
token = String(token).substr(0,3).toLowerCase();
var num = MONTH_TO_NUM[token];
return num >= 0 ? num : null;
}
/*
* RFC6265 S5.1.1 date parser (see RFC for full grammar)
*/
function parseDate(str) {
if (!str) {
return;
}
/* RFC6265 S5.1.1:
* 2. Process each date-token sequentially in the order the date-tokens
* appear in the cookie-date
*/
var tokens = str.split(DATE_DELIM);
if (!tokens) {
return;
}
var hour = null;
var minute = null;
var second = null;
var dayOfMonth = null;
var month = null;
var year = null;
for (var i=0; i= 70 && year <= 99) {
year += 1900;
} else if (year >= 0 && year <= 69) {
year += 2000;
}
}
}
}
/* RFC 6265 S5.1.1
* "5. Abort these steps and fail to parse the cookie-date if:
* * at least one of the found-day-of-month, found-month, found-
* year, or found-time flags is not set,
* * the day-of-month-value is less than 1 or greater than 31,
* * the year-value is less than 1601,
* * the hour-value is greater than 23,
* * the minute-value is greater than 59, or
* * the second-value is greater than 59.
* (Note that leap seconds cannot be represented in this syntax.)"
*
* So, in order as above:
*/
if (
dayOfMonth === null || month === null || year === null || second === null ||
dayOfMonth < 1 || dayOfMonth > 31 ||
year < 1601 ||
hour > 23 ||
minute > 59 ||
second > 59
) {
return;
}
return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));
}
function formatDate(date) {
var d = date.getUTCDate(); d = d >= 10 ? d : '0'+d;
var h = date.getUTCHours(); h = h >= 10 ? h : '0'+h;
var m = date.getUTCMinutes(); m = m >= 10 ? m : '0'+m;
var s = date.getUTCSeconds(); s = s >= 10 ? s : '0'+s;
return NUM_TO_DAY[date.getUTCDay()] + ', ' +
d+' '+ NUM_TO_MONTH[date.getUTCMonth()] +' '+ date.getUTCFullYear() +' '+
h+':'+m+':'+s+' GMT';
}
// S5.1.2 Canonicalized Host Names
function canonicalDomain(str) {
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)) {
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 (canonicalize !== false) {
str = canonicalDomain(str);
domStr = canonicalDomain(domStr);
}
/*
* "The domain string and the string are identical. (Note that both the
* domain string and the string will have been canonicalized to lower case at
* this point)"
*/
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;
}
/* "* 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)
}
// e.g "a.b.c".indexOf("b.c") === 2
// 5 === 3+2
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;
}
return true;
}
// RFC6265 S5.1.4 Paths and Path-Match
/*
* "The user agent MUST use an algorithm equivalent to the following algorithm
* to compute the default-path of a cookie:"
*
* Assumption: the path (and not query part or absolute uri) is passed in.
*/
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 "/";
}
// "3. If the uri-path contains no more than one %x2F ("/") character, output
// %x2F ("/") and skip the remaining step."
if (path === "/") {
return path;
}
var rightSlash = path.lastIndexOf("/");
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 ("/")."
return path.slice(0, rightSlash);
}
function trimTerminator(str) {
for (var t = 0; t < TERMINATORS.length; t++) {
var terminatorIdx = str.indexOf(TERMINATORS[t]);
if (terminatorIdx !== -1) {
str = str.substr(0,terminatorIdx);
}
}
return str;
}
function parseCookiePair(cookiePair, looseMode) {
cookiePair = trimTerminator(cookiePair);
var firstEq = cookiePair.indexOf('=');
if (looseMode) {
if (firstEq === 0) { // '=' is immediately at start
cookiePair = cookiePair.substr(1);
firstEq = cookiePair.indexOf('='); // might still need to split on '='
}
} else { // non-loose mode
if (firstEq <= 0) { // no '=' or is at start
return; // needs to have non-empty "cookie-name"
}
}
var cookieName, cookieValue;
if (firstEq <= 0) {
cookieName = "";
cookieValue = cookiePair.trim();
} else {
cookieName = cookiePair.substr(0, firstEq).trim();
cookieValue = cookiePair.substr(firstEq+1).trim();
}
if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {
return;
}
var c = new Cookie();
c.key = cookieName;
c.value = cookieValue;
return c;
}
function parse(str, options) {
if (!options || typeof options !== 'object') {
options = {};
}
str = str.trim();
// We use a regex to parse the "name-value-pair" part of S5.2
var firstSemi = str.indexOf(';'); // S5.2 step 1
var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);
var c = parseCookiePair(cookiePair, !!options.loose);
if (!c) {
return;
}
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
// "discard the first ";" and trim".
var unparsed = str.slice(firstSemi + 1).trim();
// "If the unparsed-attributes string is empty, skip the rest of these
// steps."
if (unparsed.length === 0) {
return c;
}
/*
* S5.2 says that when looping over the items "[p]rocess the attribute-name
* and attribute-value according to the requirements in the following
* subsections" for every item. Plus, for many of the individual attributes
* in S5.3 it says to use the "attribute-value of the last attribute in the
* cookie-attribute-list". Therefore, in this implementation, we overwrite
* the previous value.
*/
var cookie_avs = unparsed.split(';');
while (cookie_avs.length) {
var av = cookie_avs.shift().trim();
if (av.length === 0) { // happens if ";;" appears
continue;
}
var av_sep = av.indexOf('=');
var av_key, av_value;
if (av_sep === -1) {
av_key = av;
av_value = null;
} else {
av_key = av.substr(0,av_sep);
av_value = av.substr(av_sep+1);
}
av_key = av_key.trim().toLowerCase();
if (av_value) {
av_value = av_value.trim();
}
switch(av_key) {
case 'expires': // S5.2.1
if (av_value) {
var exp = parseDate(av_value);
// "If the attribute-value failed to parse as a cookie date, ignore the
// cookie-av."
if (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)
c.expires = exp;
}
}
break;
case 'max-age': // S5.2.2
if (av_value) {
// "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)) {
var delta = parseInt(av_value, 10);
// "If delta-seconds is less than or equal to zero (0), let expiry-time
// be the earliest representable date and time."
c.setMaxAge(delta);
}
}
break;
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) {
// S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E
// (".") character."
var domain = av_value.trim().replace(/^\./, '');
if (domain) {
// "Convert the cookie-domain to lower case."
c.domain = domain.toLowerCase();
}
}
break;
case 'path': // S5.2.4
/*
* "If the attribute-value is empty or if the first character of the
* attribute-value is not %x2F ("/"):
* Let cookie-path be the default-path.
* Otherwise:
* Let cookie-path be the attribute-value."
*
* We'll represent the default-path as null since it depends on the
* context of the parsing.
*/
c.path = av_value && av_value[0] === "/" ? av_value : null;
break;
case 'secure': // S5.2.5
/*
* "If the attribute-name case-insensitively matches the string "Secure",
* the user agent MUST append an attribute to the cookie-attribute-list
* with an attribute-name of Secure and an empty attribute-value."
*/
c.secure = true;
break;
case 'httponly': // S5.2.6 -- effectively the same as 'secure'
c.httpOnly = true;
break;
default:
c.extensions = c.extensions || [];
c.extensions.push(av);
break;
}
}
return c;
}
// avoid the V8 deoptimization monster!
function jsonParse(str) {
var obj;
try {
obj = JSON.parse(str);
} catch (e) {
return e;
}
return obj;
}
function fromJSON(str) {
if (!str) {
return null;
}
var obj;
if (typeof str === 'string') {
obj = jsonParse(str);
if (obj instanceof Error) {
return null;
}
} else {
// assume it's an Object
obj = str;
}
var c = new Cookie();
for (var i=0; i 1) {
var lindex = path.lastIndexOf('/');
if (lindex === 0) {
break;
}
path = path.substr(0,lindex);
permutations.push(path);
}
permutations.push('/');
return permutations;
}
function getCookieContext(url) {
if (url instanceof Object) {
return url;
}
// NOTE: decodeURI will throw on malformed URIs (see GH-32).
// Therefore, we will just skip decoding for such URIs.
try {
url = decodeURI(url);
}
catch(err) {
// Silently swallow error
}
return urlParse(url);
}
function Cookie(options) {
options = options || {};
Object.keys(options).forEach(function(prop) {
if (Cookie.prototype.hasOwnProperty(prop) &&
Cookie.prototype[prop] !== options[prop] &&
prop.substr(0,1) !== '_')
{
this[prop] = options[prop];
}
}, this);
this.creation = this.creation || new Date();
// used to break creation ties in cookieCompare():
Object.defineProperty(this, 'creationIndex', {
configurable: false,
enumerable: false, // important for assert.deepEqual checks
writable: true,
value: ++Cookie.cookiesCreated
});
}
Cookie.cookiesCreated = 0; // incremented each time a cookie is created
Cookie.parse = parse;
Cookie.fromJSON = fromJSON;
Cookie.prototype.key = "";
Cookie.prototype.value = "";
// the order in which the RFC has them:
Cookie.prototype.expires = "Infinity"; // coerces to literal Infinity
Cookie.prototype.maxAge = null; // takes precedence over expires for TTL
Cookie.prototype.domain = null;
Cookie.prototype.path = null;
Cookie.prototype.secure = false;
Cookie.prototype.httpOnly = false;
Cookie.prototype.extensions = null;
// set by the CookieJar:
Cookie.prototype.hostOnly = null; // boolean when set
Cookie.prototype.pathIsDefault = null; // boolean when set
Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
Cookie.prototype.lastAccessed = null; // Date when set
Object.defineProperty(Cookie.prototype, 'creationIndex', {
configurable: true,
enumerable: false,
writable: true,
value: 0
});
Cookie.serializableProperties = Object.keys(Cookie.prototype)
.filter(function(prop) {
return !(
Cookie.prototype[prop] instanceof Function ||
prop === 'creationIndex' ||
prop.substr(0,1) === '_'
);
});
Cookie.prototype.inspect = function inspect() {
var now = Date.now();
return 'Cookie="'+this.toString() +
'; hostOnly='+(this.hostOnly != null ? this.hostOnly : '?') +
'; aAge='+(this.lastAccessed ? (now-this.lastAccessed.getTime())+'ms' : '?') +
'; cAge='+(this.creation ? (now-this.creation.getTime())+'ms' : '?') +
'"';
};
Cookie.prototype.toJSON = function() {
var obj = {};
var props = Cookie.serializableProperties;
for (var i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy