You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							221 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
	
	
							221 lines
						
					
					
						
							6.2 KiB
						
					
					
				| "use strict";
 | |
| 
 | |
| var defaultParseOptions = {
 | |
|   decodeValues: true,
 | |
|   map: false,
 | |
|   silent: false,
 | |
| };
 | |
| 
 | |
| function isNonEmptyString(str) {
 | |
|   return typeof str === "string" && !!str.trim();
 | |
| }
 | |
| 
 | |
| function parseString(setCookieValue, options) {
 | |
|   var parts = setCookieValue.split(";").filter(isNonEmptyString);
 | |
| 
 | |
|   var nameValuePairStr = parts.shift();
 | |
|   var parsed = parseNameValuePair(nameValuePairStr);
 | |
|   var name = parsed.name;
 | |
|   var value = parsed.value;
 | |
| 
 | |
|   options = options
 | |
|     ? Object.assign({}, defaultParseOptions, options)
 | |
|     : defaultParseOptions;
 | |
| 
 | |
|   try {
 | |
|     value = options.decodeValues ? decodeURIComponent(value) : value; // decode cookie value
 | |
|   } catch (e) {
 | |
|     console.error(
 | |
|       "set-cookie-parser encountered an error while decoding a cookie with value '" +
 | |
|         value +
 | |
|         "'. Set options.decodeValues to false to disable this feature.",
 | |
|       e
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   var cookie = {
 | |
|     name: name,
 | |
|     value: value,
 | |
|   };
 | |
| 
 | |
|   parts.forEach(function (part) {
 | |
|     var sides = part.split("=");
 | |
|     var key = sides.shift().trimLeft().toLowerCase();
 | |
|     var value = sides.join("=");
 | |
|     if (key === "expires") {
 | |
|       cookie.expires = new Date(value);
 | |
|     } else if (key === "max-age") {
 | |
|       cookie.maxAge = parseInt(value, 10);
 | |
|     } else if (key === "secure") {
 | |
|       cookie.secure = true;
 | |
|     } else if (key === "httponly") {
 | |
|       cookie.httpOnly = true;
 | |
|     } else if (key === "samesite") {
 | |
|       cookie.sameSite = value;
 | |
|     } else {
 | |
|       cookie[key] = value;
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   return cookie;
 | |
| }
 | |
| 
 | |
| function parseNameValuePair(nameValuePairStr) {
 | |
|   // Parses name-value-pair according to rfc6265bis draft
 | |
| 
 | |
|   var name = "";
 | |
|   var value = "";
 | |
|   var nameValueArr = nameValuePairStr.split("=");
 | |
|   if (nameValueArr.length > 1) {
 | |
|     name = nameValueArr.shift();
 | |
|     value = nameValueArr.join("="); // everything after the first =, joined by a "=" if there was more than one part
 | |
|   } else {
 | |
|     value = nameValuePairStr;
 | |
|   }
 | |
| 
 | |
|   return { name: name, value: value };
 | |
| }
 | |
| 
 | |
| function parse(input, options) {
 | |
|   options = options
 | |
|     ? Object.assign({}, defaultParseOptions, options)
 | |
|     : defaultParseOptions;
 | |
| 
 | |
|   if (!input) {
 | |
|     if (!options.map) {
 | |
|       return [];
 | |
|     } else {
 | |
|       return {};
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (input.headers && input.headers["set-cookie"]) {
 | |
|     // fast-path for node.js (which automatically normalizes header names to lower-case
 | |
|     input = input.headers["set-cookie"];
 | |
|   } else if (input.headers) {
 | |
|     // slow-path for other environments - see #25
 | |
|     var sch =
 | |
|       input.headers[
 | |
|         Object.keys(input.headers).find(function (key) {
 | |
|           return key.toLowerCase() === "set-cookie";
 | |
|         })
 | |
|       ];
 | |
|     // warn if called on a request-like object with a cookie header rather than a set-cookie header - see #34, 36
 | |
|     if (!sch && input.headers.cookie && !options.silent) {
 | |
|       console.warn(
 | |
|         "Warning: set-cookie-parser appears to have been called on a request object. It is designed to parse Set-Cookie headers from responses, not Cookie headers from requests. Set the option {silent: true} to suppress this warning."
 | |
|       );
 | |
|     }
 | |
|     input = sch;
 | |
|   }
 | |
|   if (!Array.isArray(input)) {
 | |
|     input = [input];
 | |
|   }
 | |
| 
 | |
|   options = options
 | |
|     ? Object.assign({}, defaultParseOptions, options)
 | |
|     : defaultParseOptions;
 | |
| 
 | |
|   if (!options.map) {
 | |
|     return input.filter(isNonEmptyString).map(function (str) {
 | |
|       return parseString(str, options);
 | |
|     });
 | |
|   } else {
 | |
|     var cookies = {};
 | |
|     return input.filter(isNonEmptyString).reduce(function (cookies, str) {
 | |
|       var cookie = parseString(str, options);
 | |
|       cookies[cookie.name] = cookie;
 | |
|       return cookies;
 | |
|     }, cookies);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
 | |
|   that are within a single set-cookie field-value, such as in the Expires portion.
 | |
| 
 | |
|   This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
 | |
|   Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
 | |
|   React Native's fetch does this for *every* header, including set-cookie.
 | |
| 
 | |
|   Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
 | |
|   Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
 | |
| */
 | |
| function splitCookiesString(cookiesString) {
 | |
|   if (Array.isArray(cookiesString)) {
 | |
|     return cookiesString;
 | |
|   }
 | |
|   if (typeof cookiesString !== "string") {
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   var cookiesStrings = [];
 | |
|   var pos = 0;
 | |
|   var start;
 | |
|   var ch;
 | |
|   var lastComma;
 | |
|   var nextStart;
 | |
|   var cookiesSeparatorFound;
 | |
| 
 | |
|   function skipWhitespace() {
 | |
|     while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
 | |
|       pos += 1;
 | |
|     }
 | |
|     return pos < cookiesString.length;
 | |
|   }
 | |
| 
 | |
|   function notSpecialChar() {
 | |
|     ch = cookiesString.charAt(pos);
 | |
| 
 | |
|     return ch !== "=" && ch !== ";" && ch !== ",";
 | |
|   }
 | |
| 
 | |
|   while (pos < cookiesString.length) {
 | |
|     start = pos;
 | |
|     cookiesSeparatorFound = false;
 | |
| 
 | |
|     while (skipWhitespace()) {
 | |
|       ch = cookiesString.charAt(pos);
 | |
|       if (ch === ",") {
 | |
|         // ',' is a cookie separator if we have later first '=', not ';' or ','
 | |
|         lastComma = pos;
 | |
|         pos += 1;
 | |
| 
 | |
|         skipWhitespace();
 | |
|         nextStart = pos;
 | |
| 
 | |
|         while (pos < cookiesString.length && notSpecialChar()) {
 | |
|           pos += 1;
 | |
|         }
 | |
| 
 | |
|         // currently special character
 | |
|         if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
 | |
|           // we found cookies separator
 | |
|           cookiesSeparatorFound = true;
 | |
|           // pos is inside the next cookie, so back up and return it.
 | |
|           pos = nextStart;
 | |
|           cookiesStrings.push(cookiesString.substring(start, lastComma));
 | |
|           start = pos;
 | |
|         } else {
 | |
|           // in param ',' or param separator ';',
 | |
|           // we continue from that comma
 | |
|           pos = lastComma + 1;
 | |
|         }
 | |
|       } else {
 | |
|         pos += 1;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!cookiesSeparatorFound || pos >= cookiesString.length) {
 | |
|       cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return cookiesStrings;
 | |
| }
 | |
| 
 | |
| module.exports = parse;
 | |
| module.exports.parse = parse;
 | |
| module.exports.parseString = parseString;
 | |
| module.exports.splitCookiesString = splitCookiesString;
 |