set-cookie.cjs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Generated automatically from lib/set-cookie.js; see build-cjs.js
  2. var defaultParseOptions = {
  3. decodeValues: true,
  4. map: false,
  5. silent: false,
  6. split: "auto", // auto = split strings but not arrays
  7. };
  8. function isForbiddenKey(key) {
  9. return typeof key !== "string" || key in {};
  10. }
  11. function createNullObj() {
  12. return Object.create(null);
  13. }
  14. function isNonEmptyString(str) {
  15. return typeof str === "string" && !!str.trim();
  16. }
  17. function parseString(setCookieValue, options) {
  18. var parts = setCookieValue.split(";").filter(isNonEmptyString);
  19. var nameValuePairStr = parts.shift();
  20. var parsed = parseNameValuePair(nameValuePairStr);
  21. var name = parsed.name;
  22. var value = parsed.value;
  23. options = options
  24. ? Object.assign({}, defaultParseOptions, options)
  25. : defaultParseOptions;
  26. if (isForbiddenKey(name)) {
  27. return null;
  28. }
  29. try {
  30. value = options.decodeValues ? decodeURIComponent(value) : value; // decode cookie value
  31. } catch (e) {
  32. console.error(
  33. "set-cookie-parser: failed to decode cookie value. Set options.decodeValues=false to disable decoding.",
  34. e
  35. );
  36. }
  37. var cookie = createNullObj();
  38. cookie.name = name;
  39. cookie.value = value;
  40. parts.forEach(function (part) {
  41. var sides = part.split("=");
  42. var key = sides.shift().trimLeft().toLowerCase();
  43. if (isForbiddenKey(key)) {
  44. return;
  45. }
  46. var value = sides.join("=");
  47. if (key === "expires") {
  48. cookie.expires = new Date(value);
  49. } else if (key === "max-age") {
  50. var n = parseInt(value, 10);
  51. if (!Number.isNaN(n)) cookie.maxAge = n;
  52. } else if (key === "secure") {
  53. cookie.secure = true;
  54. } else if (key === "httponly") {
  55. cookie.httpOnly = true;
  56. } else if (key === "samesite") {
  57. cookie.sameSite = value;
  58. } else if (key === "partitioned") {
  59. cookie.partitioned = true;
  60. } else if (key) {
  61. cookie[key] = value;
  62. }
  63. });
  64. return cookie;
  65. }
  66. function parseNameValuePair(nameValuePairStr) {
  67. // Parses name-value-pair according to rfc6265bis draft
  68. var name = "";
  69. var value = "";
  70. var nameValueArr = nameValuePairStr.split("=");
  71. if (nameValueArr.length > 1) {
  72. name = nameValueArr.shift();
  73. value = nameValueArr.join("="); // everything after the first =, joined by a "=" if there was more than one part
  74. } else {
  75. value = nameValuePairStr;
  76. }
  77. return { name: name, value: value };
  78. }
  79. function parseSetCookie(input, options) {
  80. options = options
  81. ? Object.assign({}, defaultParseOptions, options)
  82. : defaultParseOptions;
  83. if (!input) {
  84. if (!options.map) {
  85. return [];
  86. } else {
  87. return createNullObj();
  88. }
  89. }
  90. if (input.headers) {
  91. if (typeof input.headers.getSetCookie === "function") {
  92. // for fetch responses - they combine headers of the same type in the headers array,
  93. // but getSetCookie returns an uncombined array
  94. input = input.headers.getSetCookie();
  95. } else if (input.headers["set-cookie"]) {
  96. // fast-path for node.js (which automatically normalizes header names to lower-case)
  97. input = input.headers["set-cookie"];
  98. } else {
  99. // slow-path for other environments - see #25
  100. var sch =
  101. input.headers[
  102. Object.keys(input.headers).find(function (key) {
  103. return key.toLowerCase() === "set-cookie";
  104. })
  105. ];
  106. // warn if called on a request-like object with a cookie header rather than a set-cookie header - see #34, 36
  107. if (!sch && input.headers.cookie && !options.silent) {
  108. console.warn(
  109. "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."
  110. );
  111. }
  112. input = sch;
  113. }
  114. }
  115. var split = options.split;
  116. var isArray = Array.isArray(input);
  117. if (split === "auto") {
  118. split = !isArray;
  119. }
  120. if (!isArray) {
  121. input = [input];
  122. }
  123. input = input.filter(isNonEmptyString);
  124. if (split) {
  125. input = input.map(splitCookiesString).flat();
  126. }
  127. if (!options.map) {
  128. return input
  129. .map(function (str) {
  130. return parseString(str, options);
  131. })
  132. .filter(Boolean);
  133. } else {
  134. var cookies = createNullObj();
  135. return input.reduce(function (cookies, str) {
  136. var cookie = parseString(str, options);
  137. if (cookie && !isForbiddenKey(cookie.name)) {
  138. cookies[cookie.name] = cookie;
  139. }
  140. return cookies;
  141. }, cookies);
  142. }
  143. }
  144. /*
  145. Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
  146. that are within a single set-cookie field-value, such as in the Expires portion.
  147. This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
  148. Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
  149. React Native's fetch does this for *every* header, including set-cookie.
  150. Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
  151. Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
  152. */
  153. function splitCookiesString(cookiesString) {
  154. if (Array.isArray(cookiesString)) {
  155. return cookiesString;
  156. }
  157. if (typeof cookiesString !== "string") {
  158. return [];
  159. }
  160. var cookiesStrings = [];
  161. var pos = 0;
  162. var start;
  163. var ch;
  164. var lastComma;
  165. var nextStart;
  166. var cookiesSeparatorFound;
  167. function skipWhitespace() {
  168. while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
  169. pos += 1;
  170. }
  171. return pos < cookiesString.length;
  172. }
  173. function notSpecialChar() {
  174. ch = cookiesString.charAt(pos);
  175. return ch !== "=" && ch !== ";" && ch !== ",";
  176. }
  177. while (pos < cookiesString.length) {
  178. start = pos;
  179. cookiesSeparatorFound = false;
  180. while (skipWhitespace()) {
  181. ch = cookiesString.charAt(pos);
  182. if (ch === ",") {
  183. // ',' is a cookie separator if we have later first '=', not ';' or ','
  184. lastComma = pos;
  185. pos += 1;
  186. skipWhitespace();
  187. nextStart = pos;
  188. while (pos < cookiesString.length && notSpecialChar()) {
  189. pos += 1;
  190. }
  191. // currently special character
  192. if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
  193. // we found cookies separator
  194. cookiesSeparatorFound = true;
  195. // pos is inside the next cookie, so back up and return it.
  196. pos = nextStart;
  197. cookiesStrings.push(cookiesString.substring(start, lastComma));
  198. start = pos;
  199. } else {
  200. // in param ',' or param separator ';',
  201. // we continue from that comma
  202. pos = lastComma + 1;
  203. }
  204. } else {
  205. pos += 1;
  206. }
  207. }
  208. if (!cookiesSeparatorFound || pos >= cookiesString.length) {
  209. cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
  210. }
  211. }
  212. return cookiesStrings;
  213. }
  214. // named export for CJS
  215. parseSetCookie.parseSetCookie = parseSetCookie;
  216. // for backwards compatibility
  217. parseSetCookie.parse = parseSetCookie;
  218. parseSetCookie.parseString = parseString;
  219. parseSetCookie.splitCookiesString = splitCookiesString;
  220. module.exports = parseSetCookie;