opusdev/vector-similarity-api
1
1/*!2 * cookie3 * Copyright(c) 2012-2014 Roman Shtylman4 * Copyright(c) 2015 Douglas Christopher Wilson5 * MIT Licensed6 */7 8'use strict';9 10/**11 * Module exports.12 * @public13 */14 15exports.parse = parse;16exports.serialize = serialize;17 18/**19 * Module variables.20 * @private21 */22 23var __toString = Object.prototype.toString24var __hasOwnProperty = Object.prototype.hasOwnProperty25 26/**27 * RegExp to match cookie-name in RFC 6265 sec 4.1.128 * This refers out to the obsoleted definition of token in RFC 2616 sec 2.229 * which has been replaced by the token definition in RFC 7230 appendix B.30 *31 * cookie-name = token32 * token = 1*tchar33 * tchar = "!" / "#" / "$" / "%" / "&" / "'" /34 * "*" / "+" / "-" / "." / "^" / "_" /35 * "`" / "|" / "~" / DIGIT / ALPHA36 */37 38var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;39 40/**41 * RegExp to match cookie-value in RFC 6265 sec 4.1.142 *43 * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )44 * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E45 * ; US-ASCII characters excluding CTLs,46 * ; whitespace DQUOTE, comma, semicolon,47 * ; and backslash48 */49 50var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;51 52/**53 * RegExp to match domain-value in RFC 6265 sec 4.1.154 *55 * domain-value = <subdomain>56 * ; defined in [RFC1034], Section 3.5, as57 * ; enhanced by [RFC1123], Section 2.158 * <subdomain> = <label> | <subdomain> "." <label>59 * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]60 * Labels must be 63 characters or less.61 * 'let-dig' not 'letter' in the first char, per RFC112362 * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>63 * <let-dig-hyp> = <let-dig> | "-"64 * <let-dig> = <letter> | <digit>65 * <letter> = any one of the 52 alphabetic characters A through Z in66 * upper case and a through z in lower case67 * <digit> = any one of the ten digits 0 through 968 *69 * Keep support for leading dot: https://github.com/jshttp/cookie/issues/17370 *71 * > (Note that a leading %x2E ("."), if present, is ignored even though that72 * character is not permitted, but a trailing %x2E ("."), if present, will73 * cause the user agent to ignore the attribute.)74 */75 76var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;77 78/**79 * RegExp to match path-value in RFC 6265 sec 4.1.180 *81 * path-value = <any CHAR except CTLs or ";">82 * CHAR = %x01-7F83 * ; defined in RFC 5234 appendix B.184 */85 86var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;87 88/**89 * Parse a cookie header.90 *91 * Parse the given cookie header string into an object92 * The object has the various cookies as keys(names) => values93 *94 * @param {string} str95 * @param {object} [opt]96 * @return {object}97 * @public98 */99 100function parse(str, opt) {101 if (typeof str !== 'string') {102 throw new TypeError('argument str must be a string');103 }104 105 var obj = {};106 var len = str.length;107 // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.108 if (len < 2) return obj;109 110 var dec = (opt && opt.decode) || decode;111 var index = 0;112 var eqIdx = 0;113 var endIdx = 0;114 115 do {116 eqIdx = str.indexOf('=', index);117 if (eqIdx === -1) break; // No more cookie pairs.118 119 endIdx = str.indexOf(';', index);120 121 if (endIdx === -1) {122 endIdx = len;123 } else if (eqIdx > endIdx) {124 // backtrack on prior semicolon125 index = str.lastIndexOf(';', eqIdx - 1) + 1;126 continue;127 }128 129 var keyStartIdx = startIndex(str, index, eqIdx);130 var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);131 var key = str.slice(keyStartIdx, keyEndIdx);132 133 // only assign once134 if (!__hasOwnProperty.call(obj, key)) {135 var valStartIdx = startIndex(str, eqIdx + 1, endIdx);136 var valEndIdx = endIndex(str, endIdx, valStartIdx);137 138 if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) {139 valStartIdx++;140 valEndIdx--;141 }142 143 var val = str.slice(valStartIdx, valEndIdx);144 obj[key] = tryDecode(val, dec);145 }146 147 index = endIdx + 1148 } while (index < len);149 150 return obj;151}152 153function startIndex(str, index, max) {154 do {155 var code = str.charCodeAt(index);156 if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index;157 } while (++index < max);158 return max;159}160 161function endIndex(str, index, min) {162 while (index > min) {163 var code = str.charCodeAt(--index);164 if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index + 1;165 }166 return min;167}168 169/**170 * Serialize data into a cookie header.171 *172 * Serialize a name value pair into a cookie string suitable for173 * http headers. An optional options object specifies cookie parameters.174 *175 * serialize('foo', 'bar', { httpOnly: true })176 * => "foo=bar; httpOnly"177 *178 * @param {string} name179 * @param {string} val180 * @param {object} [opt]181 * @return {string}182 * @public183 */184 185function serialize(name, val, opt) {186 var enc = (opt && opt.encode) || encodeURIComponent;187 188 if (typeof enc !== 'function') {189 throw new TypeError('option encode is invalid');190 }191 192 if (!cookieNameRegExp.test(name)) {193 throw new TypeError('argument name is invalid');194 }195 196 var value = enc(val);197 198 if (!cookieValueRegExp.test(value)) {199 throw new TypeError('argument val is invalid');200 }201 202 var str = name + '=' + value;203 if (!opt) return str;204 205 if (null != opt.maxAge) {206 var maxAge = Math.floor(opt.maxAge);207 208 if (!isFinite(maxAge)) {209 throw new TypeError('option maxAge is invalid')210 }211 212 str += '; Max-Age=' + maxAge;213 }214 215 if (opt.domain) {216 if (!domainValueRegExp.test(opt.domain)) {217 throw new TypeError('option domain is invalid');218 }219 220 str += '; Domain=' + opt.domain;221 }222 223 if (opt.path) {224 if (!pathValueRegExp.test(opt.path)) {225 throw new TypeError('option path is invalid');226 }227 228 str += '; Path=' + opt.path;229 }230 231 if (opt.expires) {232 var expires = opt.expires233 234 if (!isDate(expires) || isNaN(expires.valueOf())) {235 throw new TypeError('option expires is invalid');236 }237 238 str += '; Expires=' + expires.toUTCString()239 }240 241 if (opt.httpOnly) {242 str += '; HttpOnly';243 }244 245 if (opt.secure) {246 str += '; Secure';247 }248 249 if (opt.partitioned) {250 str += '; Partitioned'251 }252 253 if (opt.priority) {254 var priority = typeof opt.priority === 'string'255 ? opt.priority.toLowerCase() : opt.priority;256 257 switch (priority) {258 case 'low':259 str += '; Priority=Low'260 break261 case 'medium':262 str += '; Priority=Medium'263 break264 case 'high':265 str += '; Priority=High'266 break267 default:268 throw new TypeError('option priority is invalid')269 }270 }271 272 if (opt.sameSite) {273 var sameSite = typeof opt.sameSite === 'string'274 ? opt.sameSite.toLowerCase() : opt.sameSite;275 276 switch (sameSite) {277 case true:278 str += '; SameSite=Strict';279 break;280 case 'lax':281 str += '; SameSite=Lax';282 break;283 case 'strict':284 str += '; SameSite=Strict';285 break;286 case 'none':287 str += '; SameSite=None';288 break;289 default:290 throw new TypeError('option sameSite is invalid');291 }292 }293 294 return str;295}296 297/**298 * URL-decode string value. Optimized to skip native call when no %.299 *300 * @param {string} str301 * @returns {string}302 */303 304function decode (str) {305 return str.indexOf('%') !== -1306 ? decodeURIComponent(str)307 : str308}309 310/**311 * Determine if value is a Date.312 *313 * @param {*} val314 * @private315 */316 317function isDate (val) {318 return __toString.call(val) === '[object Date]';319}320 321/**322 * Try decoding a string using a decoding function.323 *324 * @param {string} str325 * @param {function} decode326 * @private327 */328 329function tryDecode(str, decode) {330 try {331 return decode(str);332 } catch (e) {333 return str;334 }335}336 