Skip to content

Commit

Permalink
feat(std/http): Check if cookie property is valid (denoland#7189)
Browse files Browse the repository at this point in the history
Co-authored-by: Nayeem Rahman <[email protected]>
  • Loading branch information
getspooky and nayeemrmn committed Nov 17, 2020
1 parent 4e99d8f commit f7afe2b
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
14 changes: 14 additions & 0 deletions std/http/cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ export interface Cookie {

export type SameSite = "Strict" | "Lax" | "None";

const FIELD_CONTENT_REGEXP = /^(?=[\x20-\x7E]*$)[^()@<>,;:\\"\[\]?={}\s]+$/;

function toString(cookie: Cookie): string {
if (!cookie.name) {
return "";
}
const out: string[] = [];
validateCookieName(cookie.name);
out.push(`${cookie.name}=${cookie.value}`);

// Fallback for invalid Set-Cookie
Expand Down Expand Up @@ -79,6 +82,17 @@ function toString(cookie: Cookie): string {
return out.join("; ");
}

/**
* Validate Cookie property.
* @param key Name of the cookie.
* @param value Value of the cookie.
*/
function validateCookieName(value: string | undefined | null): void {
if (value && !FIELD_CONTENT_REGEXP.test(value)) {
throw new TypeError(`Invalid cookie name: "${value}".`);
}
}

/**
* Parse the cookies of the Server Request
* @param req An object which has a `headers` property
Expand Down
36 changes: 35 additions & 1 deletion std/http/cookie_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { Response, ServerRequest } from "./server.ts";
import { deleteCookie, getCookies, setCookie } from "./cookie.ts";
import { assert, assertEquals } from "../testing/asserts.ts";
import { assert, assertEquals, assertThrows } from "../testing/asserts.ts";

Deno.test({
name: "Cookie parser",
Expand Down Expand Up @@ -31,6 +31,40 @@ Deno.test({
},
});

Deno.test({
name: "Cookie Name Validation",
fn(): void {
const res: Response = {};
const tokens = [
'"id"',
"id\t",
"i\td",
"i d",
"i;d",
"{id}",
"[id]",
'"',
"id\u0091",
];
res.headers = new Headers();
tokens.forEach((name) => {
assertThrows(
(): void => {
setCookie(res, {
name,
value: "Cat",
httpOnly: true,
secure: true,
maxAge: 3,
});
},
Error,
'Invalid cookie name: "' + name + '".',
);
});
},
});

Deno.test({
name: "Cookie Delete",
fn(): void {
Expand Down

0 comments on commit f7afe2b

Please sign in to comment.