| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // src/adapter/aws-lambda/handler.ts
- import { decodeBase64, encodeBase64 } from "../../utils/encode.js";
- function sanitizeHeaderValue(value) {
- const hasNonAscii = /[^\x00-\x7F]/.test(value);
- if (!hasNonAscii) {
- return value;
- }
- return encodeURIComponent(value);
- }
- var getRequestContext = (event) => {
- return event.requestContext;
- };
- var streamToNodeStream = async (reader, writer) => {
- let readResult = await reader.read();
- while (!readResult.done) {
- writer.write(readResult.value);
- readResult = await reader.read();
- }
- writer.end();
- };
- var streamHandle = (app) => {
- return awslambda.streamifyResponse(
- async (event, responseStream, context) => {
- const processor = getProcessor(event);
- try {
- const req = processor.createRequest(event);
- const requestContext = getRequestContext(event);
- const res = await app.fetch(req, {
- event,
- requestContext,
- context
- });
- const headers = {};
- const cookies = [];
- res.headers.forEach((value, name) => {
- if (name === "set-cookie") {
- cookies.push(value);
- } else {
- headers[name] = value;
- }
- });
- const httpResponseMetadata = {
- statusCode: res.status,
- headers,
- cookies
- };
- responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
- if (res.body) {
- await streamToNodeStream(res.body.getReader(), responseStream);
- } else {
- responseStream.write("");
- }
- } catch (error) {
- console.error("Error processing request:", error);
- responseStream.write("Internal Server Error");
- } finally {
- responseStream.end();
- }
- }
- );
- };
- var handle = (app, { isContentTypeBinary } = { isContentTypeBinary: void 0 }) => {
- return async (event, lambdaContext) => {
- const processor = getProcessor(event);
- const req = processor.createRequest(event);
- const requestContext = getRequestContext(event);
- const res = await app.fetch(req, {
- event,
- requestContext,
- lambdaContext
- });
- return processor.createResult(event, res, { isContentTypeBinary });
- };
- };
- var EventProcessor = class {
- getHeaderValue(headers, key) {
- const value = headers ? Array.isArray(headers[key]) ? headers[key][0] : headers[key] : void 0;
- return value;
- }
- getDomainName(event) {
- if (event.requestContext && "domainName" in event.requestContext) {
- return event.requestContext.domainName;
- }
- const hostFromHeaders = this.getHeaderValue(event.headers, "host");
- if (hostFromHeaders) {
- return hostFromHeaders;
- }
- const multiValueHeaders = "multiValueHeaders" in event ? event.multiValueHeaders : {};
- const hostFromMultiValueHeaders = this.getHeaderValue(multiValueHeaders, "host");
- return hostFromMultiValueHeaders;
- }
- createRequest(event) {
- const queryString = this.getQueryString(event);
- const domainName = this.getDomainName(event);
- const path = this.getPath(event);
- const urlPath = `https://${domainName}${path}`;
- const url = queryString ? `${urlPath}?${queryString}` : urlPath;
- const headers = this.getHeaders(event);
- const method = this.getMethod(event);
- const requestInit = {
- headers,
- method
- };
- if (event.body) {
- requestInit.body = event.isBase64Encoded ? decodeBase64(event.body) : event.body;
- }
- return new Request(url, requestInit);
- }
- async createResult(event, res, options) {
- const contentType = res.headers.get("content-type");
- const isContentTypeBinary = options.isContentTypeBinary ?? defaultIsContentTypeBinary;
- let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
- if (!isBase64Encoded) {
- const contentEncoding = res.headers.get("content-encoding");
- isBase64Encoded = isContentEncodingBinary(contentEncoding);
- }
- const body = isBase64Encoded ? encodeBase64(await res.arrayBuffer()) : await res.text();
- const result = {
- body,
- statusCode: res.status,
- isBase64Encoded,
- ..."multiValueHeaders" in event && event.multiValueHeaders ? {
- multiValueHeaders: {}
- } : {
- headers: {}
- }
- };
- this.setCookies(event, res, result);
- if (result.multiValueHeaders) {
- res.headers.forEach((value, key) => {
- result.multiValueHeaders[key] = [value];
- });
- } else {
- res.headers.forEach((value, key) => {
- result.headers[key] = value;
- });
- }
- return result;
- }
- setCookies(_event, res, result) {
- if (res.headers.has("set-cookie")) {
- const cookies = res.headers.getSetCookie ? res.headers.getSetCookie() : Array.from(res.headers.entries()).filter(([k]) => k === "set-cookie").map(([, v]) => v);
- if (Array.isArray(cookies)) {
- this.setCookiesToResult(result, cookies);
- res.headers.delete("set-cookie");
- }
- }
- }
- };
- var EventV2Processor = class extends EventProcessor {
- getPath(event) {
- return event.rawPath;
- }
- getMethod(event) {
- return event.requestContext.http.method;
- }
- getQueryString(event) {
- return event.rawQueryString;
- }
- getCookies(event, headers) {
- if (Array.isArray(event.cookies)) {
- headers.set("Cookie", event.cookies.join("; "));
- }
- }
- setCookiesToResult(result, cookies) {
- result.cookies = cookies;
- }
- getHeaders(event) {
- const headers = new Headers();
- this.getCookies(event, headers);
- if (event.headers) {
- for (const [k, v] of Object.entries(event.headers)) {
- if (v) {
- headers.set(k, v);
- }
- }
- }
- return headers;
- }
- };
- var v2Processor = new EventV2Processor();
- var EventV1Processor = class extends EventProcessor {
- getPath(event) {
- return event.path;
- }
- getMethod(event) {
- return event.httpMethod;
- }
- getQueryString(event) {
- if (event.multiValueQueryStringParameters) {
- return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(
- ([key, values]) => values.map((value) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&")
- ).join("&");
- } else {
- return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value || "")}`).join("&");
- }
- }
- getCookies(_event, _headers) {
- }
- getHeaders(event) {
- const headers = new Headers();
- this.getCookies(event, headers);
- if (event.headers) {
- for (const [k, v] of Object.entries(event.headers)) {
- if (v) {
- headers.set(k, sanitizeHeaderValue(v));
- }
- }
- }
- if (event.multiValueHeaders) {
- for (const [k, values] of Object.entries(event.multiValueHeaders)) {
- if (values) {
- const foundK = headers.get(k);
- values.forEach((v) => {
- const sanitizedValue = sanitizeHeaderValue(v);
- return (!foundK || !foundK.includes(sanitizedValue)) && headers.append(k, sanitizedValue);
- });
- }
- }
- }
- return headers;
- }
- setCookiesToResult(result, cookies) {
- result.multiValueHeaders = {
- "set-cookie": cookies
- };
- }
- };
- var v1Processor = new EventV1Processor();
- var ALBProcessor = class extends EventProcessor {
- getHeaders(event) {
- const headers = new Headers();
- if (event.multiValueHeaders) {
- for (const [key, values] of Object.entries(event.multiValueHeaders)) {
- if (values && Array.isArray(values)) {
- const sanitizedValue = sanitizeHeaderValue(values.join("; "));
- headers.set(key, sanitizedValue);
- }
- }
- } else {
- for (const [key, value] of Object.entries(event.headers ?? {})) {
- if (value) {
- headers.set(key, sanitizeHeaderValue(value));
- }
- }
- }
- return headers;
- }
- getPath(event) {
- return event.path;
- }
- getMethod(event) {
- return event.httpMethod;
- }
- getQueryString(event) {
- if (event.multiValueQueryStringParameters) {
- return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
- } else {
- return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
- }
- }
- getCookies(event, headers) {
- let cookie;
- if (event.multiValueHeaders) {
- cookie = event.multiValueHeaders["cookie"]?.join("; ");
- } else {
- cookie = event.headers ? event.headers["cookie"] : void 0;
- }
- if (cookie) {
- headers.append("Cookie", cookie);
- }
- }
- setCookiesToResult(result, cookies) {
- if (result.multiValueHeaders) {
- result.multiValueHeaders["set-cookie"] = cookies;
- } else {
- result.headers["set-cookie"] = cookies.join(", ");
- }
- }
- };
- var albProcessor = new ALBProcessor();
- var LatticeV2Processor = class extends EventProcessor {
- getPath(event) {
- return event.path;
- }
- getMethod(event) {
- return event.method;
- }
- getQueryString() {
- return "";
- }
- getHeaders(event) {
- const headers = new Headers();
- if (event.headers) {
- for (const [k, values] of Object.entries(event.headers)) {
- if (values) {
- const foundK = headers.get(k);
- values.forEach((v) => {
- const sanitizedValue = sanitizeHeaderValue(v);
- return (!foundK || !foundK.includes(sanitizedValue)) && headers.append(k, sanitizedValue);
- });
- }
- }
- }
- return headers;
- }
- getCookies() {
- }
- setCookiesToResult(result, cookies) {
- result.headers = {
- ...result.headers,
- "set-cookie": cookies.join(", ")
- };
- }
- };
- var latticeV2Processor = new LatticeV2Processor();
- var getProcessor = (event) => {
- if (isProxyEventALB(event)) {
- return albProcessor;
- }
- if (isProxyEventV2(event)) {
- return v2Processor;
- }
- if (isLatticeEventV2(event)) {
- return latticeV2Processor;
- }
- return v1Processor;
- };
- var isProxyEventALB = (event) => {
- if (event.requestContext) {
- return Object.hasOwn(event.requestContext, "elb");
- }
- return false;
- };
- var isProxyEventV2 = (event) => {
- return Object.hasOwn(event, "rawPath");
- };
- var isLatticeEventV2 = (event) => {
- if (event.requestContext) {
- return Object.hasOwn(event.requestContext, "serviceArn");
- }
- return false;
- };
- var defaultIsContentTypeBinary = (contentType) => {
- return !/^text\/(?:plain|html|css|javascript|csv)|(?:\/|\+)(?:json|xml)\s*(?:;|$)/.test(
- contentType
- );
- };
- var isContentEncodingBinary = (contentEncoding) => {
- if (contentEncoding === null) {
- return false;
- }
- return /^(gzip|deflate|compress|br)/.test(contentEncoding);
- };
- export {
- ALBProcessor,
- EventProcessor,
- EventV1Processor,
- EventV2Processor,
- LatticeV2Processor,
- defaultIsContentTypeBinary,
- getProcessor,
- handle,
- isContentEncodingBinary,
- streamHandle
- };
|