Skip to main content
Module

std/http/cookie_map_test.ts

Deno standard library
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals, assertRejects, assertThrows,} from "../testing/asserts.ts";import { KeyStack } from "../crypto/keystack.ts";
import { CookieMap, cookieMapHeadersInitSymbol, mergeHeaders, SecureCookieMap,} from "./cookie_map.ts";
function isNode(): boolean { return "process" in globalThis && "global" in globalThis;}
function createHeaders(cookies?: string[]) { return new Headers( cookies ? [["cookie", cookies.join("; ")]] : undefined, );}
Deno.test({ name: "CookieMap - get cookie value", fn() { const request = createHeaders(["foo=bar"]); const response = createHeaders(); const cookies = new CookieMap(request, { response }); assertEquals(cookies.get("foo"), "bar"); assertEquals(cookies.get("bar"), undefined); assertEquals([...response], []); },});
Deno.test({ name: "CookieMap - set cookie", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); cookies.set("foo", "bar"); assertEquals([...response], [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "CookieMap - pass request and response", fn() { const request = new Request("http://localhost:8080/"); const response = new Response(null); const cookies = new CookieMap(request, { response }); cookies.set("foo", "bar"); assertEquals([...response.headers], [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "CookieMap - omit response", fn() { const request = createHeaders(); const cookies = new CookieMap(request); cookies.set("foo", "bar"); assertEquals(cookies[cookieMapHeadersInitSymbol](), [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "CookieMap - set multiple cookies", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); cookies.set("a", "a"); cookies.set("b", "b"); cookies.set("c", "c"); const expected = isNode() ? [[ "set-cookie", "a=a; path=/; httponly, b=b; path=/; httponly, c=c; path=/; httponly", ]] : [ ["set-cookie", "a=a; path=/; httponly"], ["set-cookie", "b=b; path=/; httponly"], ["set-cookie", "c=c; path=/; httponly"], ]; assertEquals([...response], expected); },});
Deno.test({ name: "CookieMap - set cookie with options", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); cookies.set("foo", "bar", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/foo", sameSite: "strict", }); assertEquals( response.get("set-cookie"), "foo=bar; path=/foo; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict", ); },});
Deno.test({ name: "CookieMap - set secure cookie", fn() { const request = createHeaders([]); const response = createHeaders(); const cookies = new CookieMap(request, { response, secure: true }); cookies.set("bar", "foo", { secure: true });
assertEquals( response.get("set-cookie"), "bar=foo; path=/; secure; httponly", ); },});
Deno.test({ name: "CookieMap - set secure cookie on insecure context fails", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); assertThrows( () => { cookies.set("bar", "foo", { secure: true }); }, TypeError, "Cannot send secure cookie over unencrypted connection.", ); },});
Deno.test({ name: "CookieMap - set secure cookie on insecure context with ignoreInsecure", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); cookies.set("bar", "foo", { secure: true, ignoreInsecure: true });
assertEquals( response.get("set-cookie"), "bar=foo; path=/; secure; httponly", ); },});
Deno.test({ name: "CookieMap - iterate cookies", fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new CookieMap(request, { response }); const actual = [...cookies]; assertEquals( actual, [["bar", "foo"], ["foo", "baz"], ["baz", "1234"]], ); },});
Deno.test({ name: "CookieMap - has", fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new CookieMap(request, { response }); assert(cookies.has("baz")); assert(!cookies.has("qat")); },});
Deno.test({ name: "CookieMap - size", fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new CookieMap(request, { response }); assertEquals(cookies.size, 3); },});
Deno.test({ name: "CookieMap - inspecting", fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); assertEquals( Deno.inspect(new CookieMap(request, { response })), `CookieMap []`, ); },});
Deno.test({ name: "CookieMap - set multiple cookies with options", fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new CookieMap(request, { response }); cookies.set("foo", "bar", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/foo", sameSite: "strict", }); cookies.set("a", "b", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/a", sameSite: "strict", }); cookies.set("foo", "baz", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: true, path: "/baz", sameSite: "strict", }); const expected = isNode() ? "foo=baz; path=/baz; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict" : "a=b; path=/a; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict, foo=baz; path=/baz; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict"; assertEquals(response.get("set-cookie"), expected); },});
Deno.test({ name: "SecureCookieMap - get cookie value", async fn() { const request = createHeaders(["foo=bar"]); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); assertEquals(await cookies.get("foo"), "bar"); assertEquals(await cookies.get("bar"), undefined); assertEquals([...response], []); },});
Deno.test({ name: "SecureCookieMap - pass request and response", async fn() { const request = new Request("http://localhost:8080/"); const response = new Response(null); const cookies = new SecureCookieMap(request, { response }); await cookies.set("foo", "bar"); assertEquals([...response.headers], [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "SecureCookieMap - omit response", async fn() { const request = createHeaders(); const cookies = new SecureCookieMap(request); await cookies.set("foo", "bar"); assertEquals(cookies[cookieMapHeadersInitSymbol](), [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "SecureCookieMap - get signed cookie", async fn() { const request = createHeaders( ["bar=foo", "bar.sig=S7GhXzJF3n4j8JwTupr7H-h25qtt_vs0stdETXZb-Ro"], ); const response = createHeaders(); const cookies = new SecureCookieMap( request, { response, keys: new KeyStack(["secret1"]) }, ); assertEquals(await cookies.get("bar"), "foo"); assertEquals([...response], []); },});
Deno.test({ name: "SecureCookieMap - get signed cookie requiring re-signing", async fn() { const request = createHeaders( ["bar=foo", "bar.sig=S7GhXzJF3n4j8JwTupr7H-h25qtt_vs0stdETXZb-Ro"], ); const response = createHeaders(); const cookies = new SecureCookieMap( request, { response, keys: new KeyStack(["secret2", "secret1"]) }, ); assertEquals(await cookies.get("bar"), "foo"); assertEquals([...response], [[ "set-cookie", "bar.sig=ar46bgP3n0ZRazFOfiZ4SyZVFxKUvG1-zQZCb9lbcPI; path=/; httponly", ]]); },});
Deno.test({ name: "SecureCookieMap - get invalid signed cookie", async fn() { const request = createHeaders( ["bar=foo", "bar.sig=tampered", "foo=baz"], ); const response = createHeaders(); const cookies = new SecureCookieMap( request, { response, keys: new KeyStack(["secret1"]) }, ); assertEquals(await cookies.get("bar"), undefined); assertEquals(await cookies.get("foo"), undefined); assertEquals([...response], [ [ "set-cookie", "bar.sig=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; httponly", ], ]); },});
Deno.test({ name: "SecureCookieMap - set cookie", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await cookies.set("foo", "bar"); assertEquals([...response], [ ["set-cookie", "foo=bar; path=/; httponly"], ]); },});
Deno.test({ name: "SecureCookieMap - set multiple cookies", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await cookies.set("a", "a"); await cookies.set("b", "b"); await cookies.set("c", "c"); const expected = isNode() ? [[ "set-cookie", "a=a; path=/; httponly, b=b; path=/; httponly, c=c; path=/; httponly", ]] : [ ["set-cookie", "a=a; path=/; httponly"], ["set-cookie", "b=b; path=/; httponly"], ["set-cookie", "c=c; path=/; httponly"], ]; assertEquals([...response], expected); },});
Deno.test({ name: "SecureCookieMap - set cookie with options", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await cookies.set("foo", "bar", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/foo", sameSite: "strict", }); assertEquals( response.get("set-cookie"), "foo=bar; path=/foo; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict", ); },});
Deno.test({ name: "SecureCookieMap - set signed cookie", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap( request, { response, keys: new KeyStack(["secret1"]) }, ); await cookies.set("bar", "foo");
assertEquals( response.get("set-cookie"), "bar=foo; path=/; httponly, bar.sig=S7GhXzJF3n4j8JwTupr7H-h25qtt_vs0stdETXZb-Ro; path=/; httponly", ); },});
Deno.test({ name: "SecureCookieMap - set secure cookie", async fn() { const request = createHeaders([]); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response, secure: true }); await cookies.set("bar", "foo", { secure: true });
assertEquals( response.get("set-cookie"), "bar=foo; path=/; secure; httponly", ); },});
Deno.test({ name: "SecureCookieMap - set secure cookie on insecure context fails", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await assertRejects( async () => { await cookies.set("bar", "foo", { secure: true }); }, TypeError, "Cannot send secure cookie over unencrypted connection.", ); },});
Deno.test({ name: "SecureCookieMap - set secure cookie on insecure context with ignoreInsecure", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await cookies.set("bar", "foo", { secure: true, ignoreInsecure: true });
assertEquals( response.get("set-cookie"), "bar=foo; path=/; secure; httponly", ); },});
Deno.test({ name: "SecureCookieMap - iterate cookies", async fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); const actual = []; for await (const cookie of cookies) { actual.push(cookie); } assertEquals( actual, [["bar", "foo"], ["foo", "baz"], ["baz", "1234"]], ); },});
Deno.test({ name: "SecureCookieMap - iterate signed cookie", async fn() { const request = createHeaders( ["bar=foo", "bar.sig=S7GhXzJF3n4j8JwTupr7H-h25qtt_vs0stdETXZb-Ro"], ); const response = createHeaders(); const cookies = new SecureCookieMap( request, { response, keys: new KeyStack(["secret1"]) }, ); const actual = []; for await (const cookie of cookies) { actual.push(cookie); } assertEquals(actual, [["bar", "foo"]]); },});
Deno.test({ name: "SecureCookieMap - has", async fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); assert(await cookies.has("baz")); assert(!await cookies.has("qat")); },});
Deno.test({ name: "SecureCookieMap - size", async fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); assertEquals(await cookies.size, 3); },});
Deno.test({ name: "SecureCookieMap - inspecting", fn() { const request = createHeaders( ["bar=foo", "foo=baz", "baz=1234"], ); const response = createHeaders(); assertEquals( Deno.inspect(new SecureCookieMap(request, { response })), `SecureCookieMap []`, ); },});
Deno.test({ name: "SecureCookieMap - set multiple cookies with options", async fn() { const request = createHeaders(); const response = createHeaders(); const cookies = new SecureCookieMap(request, { response }); await cookies.set("foo", "bar", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/foo", sameSite: "strict", }); await cookies.set("a", "b", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: false, path: "/a", sameSite: "strict", }); await cookies.set("foo", "baz", { domain: "*.example.com", expires: new Date("2020-01-01T00:00:00+00:00"), httpOnly: false, overwrite: true, path: "/baz", sameSite: "strict", }); const expected = isNode() ? "foo=baz; path=/baz; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict" : "a=b; path=/a; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict, foo=baz; path=/baz; expires=Wed, 01 Jan 2020 00:00:00 GMT; domain=*.example.com; samesite=strict"; assertEquals(response.get("set-cookie"), expected); },});
Deno.test({ name: "mergeHeaders() - passing cookies/mergable", async fn() { const request = createHeaders(); const secureCookies = new SecureCookieMap(request); await secureCookies.set("foo", "bar"); const cookies = new CookieMap(request); cookies.set("bar", "baz"); const headers = mergeHeaders(secureCookies, cookies); assertEquals([...headers], [ ["set-cookie", "foo=bar; path=/; httponly"], ["set-cookie", "bar=baz; path=/; httponly"], ]); },});
Deno.test({ name: "mergeHeaders() - passing headers", fn() { const request = createHeaders(); const cookies = new CookieMap(request); cookies.set("bar", "baz"); const upstreamHeaders = new Headers({ "Content-Type": "application/json" }); const headers = mergeHeaders(upstreamHeaders, cookies); assertEquals([...headers], [ ["content-type", "application/json"], ["set-cookie", "bar=baz; path=/; httponly"], ]); },});
Deno.test({ name: "mergeHeaders() - passing response object", fn() { const request = createHeaders(); const cookies = new CookieMap(request); cookies.set("bar", "baz"); const response = new Response(null, { headers: { "Content-Type": "application/json" }, }); const headers = mergeHeaders(response, cookies); assertEquals([...headers], [ ["content-type", "application/json"], ["set-cookie", "bar=baz; path=/; httponly"], ]); },});
Deno.test({ name: "mergeHeaders() - passing headers init", fn() { const request = createHeaders(); const cookies = new CookieMap(request); cookies.set("bar", "baz"); const headers = mergeHeaders( { "Content-Type": "application/json" }, [["vary", "accept"]], cookies, ); assertEquals([...headers], [ ["content-type", "application/json"], ["set-cookie", "bar=baz; path=/; httponly"], ["vary", "accept"], ]); },});