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
			| 
								 
											3 years ago
										 
									 | 
							
								"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;
							 |