Skip to content

Instantly share code, notes, and snippets.

@yingziwu
Last active June 19, 2022 10:38
Show Gist options
  • Select an option

  • Save yingziwu/1ed1ad71f876638cde8790adc1cc2295 to your computer and use it in GitHub Desktop.

Select an option

Save yingziwu/1ed1ad71f876638cde8790adc1cc2295 to your computer and use it in GitHub Desktop.
A CORS proxy write by deno
import { serve } from "https://deno.land/std/http/server.ts";
function error(): Promise<Response> {
const response = new Response(null, {
status: 400,
});
return Promise.resolve(response);
}
function options(): Promise<Response> {
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Expose-Headers":
"Date, Etag, Content-Length, Accept-Ranges, Content-Range, Server, Location",
"Access-Control-Max-Age": "2073600",
};
const response = new Response(null, {
headers,
status: 204,
});
return Promise.resolve(response);
}
async function proxy(request: Request): Promise<Response> {
const { pathname } = new URL(request.url);
const url = pathname.replace(/^\//, "");
const urlTest = (url: string) => {
try {
new URL(url);
return true;
} catch (error) {
return false;
}
};
if (!urlTest(url)) {
return error();
}
const { host } = new URL(url);
async function getNewRequest(): Promise<Request> {
const getRequestBody = async (_req: Request): Promise<BodyInit | null> => {
if (!_req.body) {
return null;
}
const reader = _req.body.getReader();
const stream = await reader.read();
const body = stream.value;
return body ?? null;
};
const _headers = request.headers;
const headers: Record<string, string> = {};
[..._headers.entries()].forEach((kv) => {
const ignoreList = [
"content-length",
/^access\-control\-/,
/^cf\-/,
"x-forwarded-proto",
"x-real-ip",
];
const isIgnore = (name: string) => {
for (const i of ignoreList) {
if (typeof i === "string") {
if (i === name.toLocaleLowerCase()) {
return true;
}
}
if (i instanceof RegExp) {
if (i.test(name)) {
return true;
}
}
}
return false;
};
if (kv[0].toLowerCase() === "host") {
headers["host"] = host;
} else if (isIgnore(kv[0])) {
// pass
} else {
headers[kv[0]] = kv[1];
}
});
const init = {
body: await getRequestBody(request),
cache: request.cache,
headers,
keepalive: request.keepalive,
method: request.method,
redirect: "follow" as RequestRedirect,
};
const req = new Request(url, init);
return req;
}
async function getNewResponse(req: Request): Promise<Response> {
const resp = await fetch(req);
const getResponseHeaders = (_resp: Response): HeadersInit => {
const _headers = _resp.headers;
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Expose-Headers": [..._headers.keys()].join(", "),
"Access-Control-Max-Age": "2073600",
};
const headersMap = new Map(
[..._headers.entries()].map((kv) => [kv[0].toLowerCase(), kv[1]])
);
Object.entries(corsHeaders).forEach((kv) =>
headersMap.set(kv[0].toLowerCase(), kv[1])
);
const headers: Record<string, string> = {};
[...headersMap.entries()].forEach((kv) => (headers[kv[0]] = kv[1]));
return headers;
};
const respHeaders = getResponseHeaders(resp);
const respStatus = resp.status;
const respBody = await resp.blob();
const response = new Response(respBody, {
headers: respHeaders,
status: respStatus,
});
return response;
}
const newReq = await getNewRequest();
const newResp = await getNewResponse(newReq);
return newResp;
}
function log(request: Request, response: Response) {
const logObj = {
time: new Date().toISOString(),
request: {
url: request.url,
method: request.method,
headers: [...request.headers.entries()],
},
response: {
status: response.status,
headers: [...response.headers.entries()],
},
};
console.log(JSON.stringify(logObj));
}
async function handler(request: Request): Promise<Response> {
let response;
if (request.method === "OPTIONS") {
response = await options();
} else {
response = await proxy(request);
}
log(request, response);
return response;
}
serve(handler);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment