Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*!
* 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");
}
var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\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 = new RegExp('^'+COOKIE_OCTET.source+'+$');
var CONTROL_CHARS = /[\x00-\x1F]/;
// Double quotes are part of the value (see: S4.1.1).
// '\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)
// '=' and ';' are attribute/values separators
// (see: https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L64)
var COOKIE_PAIR = /^(([^=;]+))\s*=\s*(("?)[^\n\r\0]*\3)/
// Used to parse non-RFC-compliant cookies like '=abc' when given the `loose`
// option in Cookie.parse:
var LOOSE_COOKIE_PAIR = /^((?:=)?([^=;]*)\s*=\s*)?(("?)[^\n\r\0]*\3)/;
// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
// Note ';' is \x3B
var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
// Used for checking whether or not there is a trailing semi-colon
var TRAILING_SEMICOLON = /;+$/;
var DAY_OF_MONTH = /^(\d{1,2})[^\d]*$/;
var TIME = /^(\d{1,2})[^\d]*:(\d{1,2})[^\d]*:(\d{1,2})[^\d]*$/;
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
};
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 YEAR = /^(\d{2}|\d{4})$/; // 2 to 4 digits
var MAX_TIME = 2147483647000; // 31-bit max
var MIN_TIME = 0; // 31-bit min
// RFC6265 S5.1.1 date parser:
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 minutes = null;
var seconds = null;
var day = null;
var month = null;
var year = null;
for (var i=0; i 23 || minutes > 59 || seconds > 59) {
return;
}
continue;
}
}
/* 2.2. If the found-day-of-month flag is not set and the date-token matches
* the day-of-month production, set the found-day-of- month flag and set
* the day-of-month-value to the number denoted by the date-token. Skip
* the remaining sub-steps and continue to the next date-token.
*/
if (day === null) {
result = DAY_OF_MONTH.exec(token);
if (result) {
day = parseInt(result, 10);
/* RFC6265 S5.1.1.5:
* [fail if] the day-of-month-value is less than 1 or greater than 31
*/
if(day < 1 || day > 31) {
return;
}
continue;
}
}
/* 2.3. If the found-month flag is not set and the date-token matches the
* month production, set the found-month flag and set the month-value to
* the month denoted by the date-token. Skip the remaining sub-steps and
* continue to the next date-token.
*/
if (month === null) {
result = MONTH.exec(token);
if (result) {
month = MONTH_TO_NUM[result[1].toLowerCase()];
continue;
}
}
/* 2.4. If the found-year flag is not set and the date-token matches the year
* production, set the found-year flag and set the year-value to the number
* denoted by the date-token. Skip the remaining sub-steps and continue to
* the next date-token.
*/
if (year === null) {
result = YEAR.exec(token);
if (result) {
year = parseInt(result[0], 10);
/* From S5.1.1:
* 3. If the year-value is greater than or equal to 70 and less
* than or equal to 99, increment the year-value by 1900.
* 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) {
year += 1900;
} else if (0 <= year && year <= 69) {
year += 2000;
}
if (year < 1601) {
return; // 5. ... the year-value is less than 1601
}
}
}
}
if (seconds === null || day === null || month === null || year === null) {
return; // 5. ... at least one of the found-day-of-month, found-month, found-
// year, or found-time flags is not set,
}
return new Date(Date.UTC(year, month, day, hour, minutes, seconds));
}
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 parse(str, options) {
if (!options || typeof options !== 'object') {
options = {};
}
str = str.trim();
// S4.1.1 Trailing semi-colons are not part of the specification.
var semiColonCheck = TRAILING_SEMICOLON.exec(str);
if (semiColonCheck) {
str = str.slice(0, semiColonCheck.index);
}
// We use a regex to parse the "name-value-pair" part of S5.2
var firstSemi = str.indexOf(';'); // S5.2 step 1
var pairRe = options.loose ? LOOSE_COOKIE_PAIR : COOKIE_PAIR;
var result = pairRe.exec(firstSemi === -1 ? str : str.substr(0,firstSemi));
// Rx satisfies the "the name string is empty" and "lacks a %x3D ("=")"
// constraints as well as trimming any whitespace.
if (!result) {
return;
}
var c = new Cookie();
if (result[1]) {
c.key = result[2].trim();
} else {
c.key = '';
}
c.value = result[3].trim();
if (CONTROL_CHARS.test(c.key) || CONTROL_CHARS.test(c.value)) {
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).replace(/^\s*;\s*/,'').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(/\s*;\s*/);
while (cookie_avs.length) {
var av = cookie_avs.shift();
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