Skip to content
This repository was archived by the owner on May 24, 2023. It is now read-only.

fix: Set origin and host #4

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 1 addition & 2 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ export {
export { join } from "https://deno.land/[email protected]/path/mod.ts";
export { chain, pick } from "https://deno.land/x/[email protected]/mod.ts";
export { createServerTimingMiddleware } from "https://deno.land/x/[email protected]/mod.ts";
export { setCookie } from "https://deno.land/[email protected]/http/mod.ts";
export type { Cookie } from "https://deno.land/[email protected]/http/mod.ts";
export { setCookie, getSetCookies } from "https://deno.land/[email protected]/http/mod.ts";
107 changes: 5 additions & 102 deletions proxy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Cookie, Request, setCookie } from "./deps.ts";
import { getSetCookies, Request, setCookie } from "./deps.ts";

const hopByHop = [
"Keep-Alive",
Expand All @@ -11,111 +11,14 @@ const hopByHop = [
"Proxy-Authenticate",
];

/**
* TODO: Remove this function once this PR is merged:
* https://github.com/denoland/deno_std/pull/3152/files
*/
function parseSetCookie(value: string): Cookie | null {
const attrs = value
.split(";")
.map((attr) => {
const [key, ...values] = attr.trim().split("=").map((keyOrValue) =>
keyOrValue.trim()
);
return [key, values.join("=")];
});
const cookie: Cookie = {
name: attrs[0][0],
value: attrs[0][1],
};

for (const [key, value] of attrs.slice(1)) {
switch (key.toLocaleLowerCase()) {
case "expires":
cookie.expires = new Date(value);
break;
case "max-age":
cookie.maxAge = Number(value);
if (cookie.maxAge < 0) {
console.warn(
"Max-Age must be an integer superior or equal to 0. Cookie ignored.",
);
return null;
}
break;
case "domain":
cookie.domain = value;
break;
case "path":
cookie.path = value;
break;
case "secure":
cookie.secure = true;
break;
case "httponly":
cookie.httpOnly = true;
break;
case "samesite":
cookie.sameSite = value as Cookie["sameSite"];
break;
default:
if (!Array.isArray(cookie.unparsed)) {
cookie.unparsed = [];
}
cookie.unparsed.push([key, value].join("="));
}
}
if (cookie.name.startsWith("__Secure-")) {
/** This requirement is mentioned in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie but not the RFC. */
if (!cookie.secure) {
console.warn(
"Cookies with names starting with `__Secure-` must be set with the secure flag. Cookie ignored.",
);
return null;
}
}
if (cookie.name.startsWith("__Host-")) {
if (!cookie.secure) {
console.warn(
"Cookies with names starting with `__Host-` must be set with the secure flag. Cookie ignored.",
);
return null;
}
if (cookie.domain !== undefined) {
console.warn(
"Cookies with names starting with `__Host-` must not have a domain specified. Cookie ignored.",
);
return null;
}
if (cookie.path !== "/") {
console.warn(
"Cookies with names starting with `__Host-` must have path be `/`. Cookie has been ignored.",
);
return null;
}
}
return cookie;
}

function getSetCookies(headers: Headers): Cookie[] {
if (!headers.has("set-cookie")) {
return [];
}
// deno-lint-ignore no-explicit-any
return [...(headers as any).entries()]
.filter(([key]) => key === "set-cookie")
.map(([_, value]) => value)
/** Parse each `set-cookie` header separately */
.map(parseSetCookie)
/** Skip empty cookies */
.filter(Boolean) as Cookie[];
}

export const proxy = async (to: string, req: Request) => {
export const proxy = async (to: URL, req: Request) => {
const url = new URL(req.url);
const headers = new Headers(req.headers);

hopByHop.forEach((h) => headers.delete(h));
headers.set("origin", to.origin);
headers.set("host", to.host);
headers.set("x-forwarded-host", url.host);

const response = await fetch(to, {
headers,
Expand Down
13 changes: 9 additions & 4 deletions server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,18 @@ router.get(
const { params, request } = context;
const { account, 0: catchall } = params;

const to =
`https://${account}.vtexcommercestable.com.br/api/${catchall}${request.url.search}`;
const to = new URL(
`/api/${catchall}${request.url.search}`,
`https://${account}.vtexcommercestable.com.br`,
);

const { status, body, headers } = await proxy(to, request);

// Fastly does not cache if a set-cookie is present
headers.delete("set-cookie");
// Delete all set-cookies from GET requests since fastly does
// not cache it
if (request.method === "GET") {
headers.delete("set-cookie");
}

context.response.headers = headers;
context.response.headers.set(
Expand Down