Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: cookies().has() breaks in app-route #54112

Merged
merged 6 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
"@babel/traverse": "7.18.0",
"@babel/types": "7.18.0",
"@capsizecss/metrics": "1.1.0",
"@edge-runtime/cookies": "3.2.1",
"@edge-runtime/cookies": "3.3.0",
devjiwonchoi marked this conversation as resolved.
Show resolved Hide resolved
"@edge-runtime/ponyfill": "2.3.0",
"@edge-runtime/primitives": "3.0.1",
"@hapi/accept": "5.0.2",
Expand Down
24 changes: 22 additions & 2 deletions packages/next/src/compiled/@edge-runtime/cookies/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,35 @@ declare class ResponseCookies {
* {@link https://wicg.github.io/cookie-store/#CookieStore-getAll CookieStore#getAll} without the Promise.
*/
getAll(...args: [key: string] | [options: ResponseCookie] | []): ResponseCookie[];
has(name: string): boolean;
/**
* {@link https://wicg.github.io/cookie-store/#CookieStore-set CookieStore#set} without the Promise.
*/
set(...args: [key: string, value: string, cookie?: Partial<ResponseCookie>] | [options: ResponseCookie]): this;
/**
* {@link https://wicg.github.io/cookie-store/#CookieStore-delete CookieStore#delete} without the Promise.
*/
delete(...args: [key: string] | [options: ResponseCookie]): this;
delete(...args: [key: string] | [options: Omit<ResponseCookie, 'value' | 'expires'>]): this;
toString(): string;
}

export { CookieListItem, RequestCookie, RequestCookies, ResponseCookie, ResponseCookies };
declare function stringifyCookie(c: ResponseCookie | RequestCookie): string;
/** Parse a `Cookie` header value */
declare function parseCookie(cookie: string): Map<string, string>;
/** Parse a `Set-Cookie` header value */
declare function parseSetCookie(setCookie: string): undefined | ResponseCookie;
/**
* @source https://github.com/nfriedly/set-cookie-parser/blob/master/lib/set-cookie.js
*
* 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
*/
declare function splitCookiesString(cookiesString: string): string[];

export { CookieListItem, RequestCookie, RequestCookies, ResponseCookie, ResponseCookies, parseCookie, parseSetCookie, splitCookiesString, stringifyCookie };
141 changes: 76 additions & 65 deletions packages/next/src/compiled/@edge-runtime/cookies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
var src_exports = {};
__export(src_exports, {
RequestCookies: () => RequestCookies,
ResponseCookies: () => ResponseCookies
ResponseCookies: () => ResponseCookies,
parseCookie: () => parseCookie,
parseSetCookie: () => parseSetCookie,
splitCookiesString: () => splitCookiesString,
stringifyCookie: () => stringifyCookie
});
module.exports = __toCommonJS(src_exports);

// src/serialize.ts
function serialize(c) {
function stringifyCookie(c) {
var _a;
const attrs = [
"path" in c && c.path && `Path=${c.path}`,
Expand All @@ -39,7 +43,7 @@ function serialize(c) {
].filter(Boolean);
return `${c.name}=${encodeURIComponent((_a = c.value) != null ? _a : "")}; ${attrs.join("; ")}`;
}
function parseCookieString(cookie) {
function parseCookie(cookie) {
const map = /* @__PURE__ */ new Map();
for (const pair of cookie.split(/; */)) {
if (!pair)
Expand All @@ -57,11 +61,11 @@ function parseCookieString(cookie) {
}
return map;
}
function parseSetCookieString(setCookie) {
function parseSetCookie(setCookie) {
if (!setCookie) {
return void 0;
}
const [[name, value], ...attributes] = parseCookieString(setCookie);
const [[name, value], ...attributes] = parseCookie(setCookie);
const { domain, expires, httponly, maxage, path, samesite, secure } = Object.fromEntries(
attributes.map(([key, value2]) => [key.toLowerCase(), value2])
);
Expand Down Expand Up @@ -92,6 +96,57 @@ function parseSameSite(string) {
string = string.toLowerCase();
return SAME_SITE.includes(string) ? string : void 0;
}
function splitCookiesString(cookiesString) {
if (!cookiesString)
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 === ",") {
lastComma = pos;
pos += 1;
skipWhitespace();
nextStart = pos;
while (pos < cookiesString.length && notSpecialChar()) {
pos += 1;
}
if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
cookiesSeparatorFound = true;
pos = nextStart;
cookiesStrings.push(cookiesString.substring(start, lastComma));
start = pos;
} else {
pos = lastComma + 1;
}
} else {
pos += 1;
}
}
if (!cookiesSeparatorFound || pos >= cookiesString.length) {
cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
}
}
return cookiesStrings;
}

// src/request-cookies.ts
var RequestCookies = class {
Expand All @@ -101,7 +156,7 @@ var RequestCookies = class {
this._headers = requestHeaders;
const header = requestHeaders.get("cookie");
if (header) {
const parsed = parseCookieString(header);
const parsed = parseCookie(header);
for (const [name, value] of parsed) {
this._parsed.set(name, { name, value });
}
Expand Down Expand Up @@ -138,7 +193,7 @@ var RequestCookies = class {
map.set(name, { name, value });
this._headers.set(
"cookie",
Array.from(map).map(([_, value2]) => serialize(value2)).join("; ")
Array.from(map).map(([_, value2]) => stringifyCookie(value2)).join("; ")
);
return this;
}
Expand All @@ -150,7 +205,7 @@ var RequestCookies = class {
const result = !Array.isArray(names) ? map.delete(names) : names.map((name) => map.delete(name));
this._headers.set(
"cookie",
Array.from(map).map(([_, value]) => serialize(value)).join("; ")
Array.from(map).map(([_, value]) => stringifyCookie(value)).join("; ")
);
return result;
}
Expand Down Expand Up @@ -185,7 +240,7 @@ var ResponseCookies = class {
);
const cookieStrings = Array.isArray(setCookie) ? setCookie : splitCookiesString(setCookie);
for (const cookieString of cookieStrings) {
const parsed = parseSetCookieString(cookieString);
const parsed = parseSetCookie(cookieString);
if (parsed)
this._parsed.set(parsed.name, parsed);
}
Expand All @@ -209,6 +264,9 @@ var ResponseCookies = class {
const key = typeof args[0] === "string" ? args[0] : (_a = args[0]) == null ? void 0 : _a.name;
return all.filter((c) => c.name === key);
}
has(name) {
return this._parsed.has(name);
}
/**
* {@link https://wicg.github.io/cookie-store/#CookieStore-set CookieStore#set} without the Promise.
*/
Expand All @@ -223,20 +281,20 @@ var ResponseCookies = class {
* {@link https://wicg.github.io/cookie-store/#CookieStore-delete CookieStore#delete} without the Promise.
*/
delete(...args) {
const name = typeof args[0] === "string" ? args[0] : args[0].name;
return this.set({ name, value: "", expires: /* @__PURE__ */ new Date(0) });
const [name, path, domain] = typeof args[0] === "string" ? [args[0]] : [args[0].name, args[0].path, args[0].domain];
return this.set({ name, path, domain, value: "", expires: /* @__PURE__ */ new Date(0) });
}
[Symbol.for("edge-runtime.inspect.custom")]() {
return `ResponseCookies ${JSON.stringify(Object.fromEntries(this._parsed))}`;
}
toString() {
return [...this._parsed.values()].map(serialize).join("; ");
return [...this._parsed.values()].map(stringifyCookie).join("; ");
}
};
function replace(bag, headers) {
headers.delete("set-cookie");
for (const [, value] of bag) {
const serialized = serialize(value);
const serialized = stringifyCookie(value);
headers.append("set-cookie", serialized);
}
}
Expand All @@ -252,59 +310,12 @@ function normalizeCookie(cookie = { name: "", value: "" }) {
}
return cookie;
}
function splitCookiesString(cookiesString) {
if (!cookiesString)
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 === ",") {
lastComma = pos;
pos += 1;
skipWhitespace();
nextStart = pos;
while (pos < cookiesString.length && notSpecialChar()) {
pos += 1;
}
if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
cookiesSeparatorFound = true;
pos = nextStart;
cookiesStrings.push(cookiesString.substring(start, lastComma));
start = pos;
} else {
pos = lastComma + 1;
}
} else {
pos += 1;
}
}
if (!cookiesSeparatorFound || pos >= cookiesString.length) {
cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
}
}
return cookiesStrings;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
RequestCookies,
ResponseCookies
ResponseCookies,
parseCookie,
parseSetCookie,
splitCookiesString,
stringifyCookie
});
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"name":"@edge-runtime/cookies","version":"3.2.1","main":"./index.js","license":"MPL-2.0"}
{"name":"@edge-runtime/cookies","version":"3.3.0","main":"./index.js","license":"MPL-2.0"}