handler.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. var __defProp = Object.defineProperty;
  2. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  3. var __getOwnPropNames = Object.getOwnPropertyNames;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __export = (target, all) => {
  6. for (var name in all)
  7. __defProp(target, name, { get: all[name], enumerable: true });
  8. };
  9. var __copyProps = (to, from, except, desc) => {
  10. if (from && typeof from === "object" || typeof from === "function") {
  11. for (let key of __getOwnPropNames(from))
  12. if (!__hasOwnProp.call(to, key) && key !== except)
  13. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  14. }
  15. return to;
  16. };
  17. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  18. var handler_exports = {};
  19. __export(handler_exports, {
  20. ALBProcessor: () => ALBProcessor,
  21. EventProcessor: () => EventProcessor,
  22. EventV1Processor: () => EventV1Processor,
  23. EventV2Processor: () => EventV2Processor,
  24. LatticeV2Processor: () => LatticeV2Processor,
  25. defaultIsContentTypeBinary: () => defaultIsContentTypeBinary,
  26. getProcessor: () => getProcessor,
  27. handle: () => handle,
  28. isContentEncodingBinary: () => isContentEncodingBinary,
  29. streamHandle: () => streamHandle
  30. });
  31. module.exports = __toCommonJS(handler_exports);
  32. var import_encode = require("../../utils/encode");
  33. function sanitizeHeaderValue(value) {
  34. const hasNonAscii = /[^\x00-\x7F]/.test(value);
  35. if (!hasNonAscii) {
  36. return value;
  37. }
  38. return encodeURIComponent(value);
  39. }
  40. const getRequestContext = (event) => {
  41. return event.requestContext;
  42. };
  43. const streamToNodeStream = async (reader, writer) => {
  44. let readResult = await reader.read();
  45. while (!readResult.done) {
  46. writer.write(readResult.value);
  47. readResult = await reader.read();
  48. }
  49. writer.end();
  50. };
  51. const streamHandle = (app) => {
  52. return awslambda.streamifyResponse(
  53. async (event, responseStream, context) => {
  54. const processor = getProcessor(event);
  55. try {
  56. const req = processor.createRequest(event);
  57. const requestContext = getRequestContext(event);
  58. const res = await app.fetch(req, {
  59. event,
  60. requestContext,
  61. context
  62. });
  63. const headers = {};
  64. const cookies = [];
  65. res.headers.forEach((value, name) => {
  66. if (name === "set-cookie") {
  67. cookies.push(value);
  68. } else {
  69. headers[name] = value;
  70. }
  71. });
  72. const httpResponseMetadata = {
  73. statusCode: res.status,
  74. headers,
  75. cookies
  76. };
  77. responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
  78. if (res.body) {
  79. await streamToNodeStream(res.body.getReader(), responseStream);
  80. } else {
  81. responseStream.write("");
  82. }
  83. } catch (error) {
  84. console.error("Error processing request:", error);
  85. responseStream.write("Internal Server Error");
  86. } finally {
  87. responseStream.end();
  88. }
  89. }
  90. );
  91. };
  92. const handle = (app, { isContentTypeBinary } = { isContentTypeBinary: void 0 }) => {
  93. return async (event, lambdaContext) => {
  94. const processor = getProcessor(event);
  95. const req = processor.createRequest(event);
  96. const requestContext = getRequestContext(event);
  97. const res = await app.fetch(req, {
  98. event,
  99. requestContext,
  100. lambdaContext
  101. });
  102. return processor.createResult(event, res, { isContentTypeBinary });
  103. };
  104. };
  105. class EventProcessor {
  106. getHeaderValue(headers, key) {
  107. const value = headers ? Array.isArray(headers[key]) ? headers[key][0] : headers[key] : void 0;
  108. return value;
  109. }
  110. getDomainName(event) {
  111. if (event.requestContext && "domainName" in event.requestContext) {
  112. return event.requestContext.domainName;
  113. }
  114. const hostFromHeaders = this.getHeaderValue(event.headers, "host");
  115. if (hostFromHeaders) {
  116. return hostFromHeaders;
  117. }
  118. const multiValueHeaders = "multiValueHeaders" in event ? event.multiValueHeaders : {};
  119. const hostFromMultiValueHeaders = this.getHeaderValue(multiValueHeaders, "host");
  120. return hostFromMultiValueHeaders;
  121. }
  122. createRequest(event) {
  123. const queryString = this.getQueryString(event);
  124. const domainName = this.getDomainName(event);
  125. const path = this.getPath(event);
  126. const urlPath = `https://${domainName}${path}`;
  127. const url = queryString ? `${urlPath}?${queryString}` : urlPath;
  128. const headers = this.getHeaders(event);
  129. const method = this.getMethod(event);
  130. const requestInit = {
  131. headers,
  132. method
  133. };
  134. if (event.body) {
  135. requestInit.body = event.isBase64Encoded ? (0, import_encode.decodeBase64)(event.body) : event.body;
  136. }
  137. return new Request(url, requestInit);
  138. }
  139. async createResult(event, res, options) {
  140. const contentType = res.headers.get("content-type");
  141. const isContentTypeBinary = options.isContentTypeBinary ?? defaultIsContentTypeBinary;
  142. let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
  143. if (!isBase64Encoded) {
  144. const contentEncoding = res.headers.get("content-encoding");
  145. isBase64Encoded = isContentEncodingBinary(contentEncoding);
  146. }
  147. const body = isBase64Encoded ? (0, import_encode.encodeBase64)(await res.arrayBuffer()) : await res.text();
  148. const result = {
  149. body,
  150. statusCode: res.status,
  151. isBase64Encoded,
  152. ..."multiValueHeaders" in event && event.multiValueHeaders ? {
  153. multiValueHeaders: {}
  154. } : {
  155. headers: {}
  156. }
  157. };
  158. this.setCookies(event, res, result);
  159. if (result.multiValueHeaders) {
  160. res.headers.forEach((value, key) => {
  161. result.multiValueHeaders[key] = [value];
  162. });
  163. } else {
  164. res.headers.forEach((value, key) => {
  165. result.headers[key] = value;
  166. });
  167. }
  168. return result;
  169. }
  170. setCookies(_event, res, result) {
  171. if (res.headers.has("set-cookie")) {
  172. const cookies = res.headers.getSetCookie ? res.headers.getSetCookie() : Array.from(res.headers.entries()).filter(([k]) => k === "set-cookie").map(([, v]) => v);
  173. if (Array.isArray(cookies)) {
  174. this.setCookiesToResult(result, cookies);
  175. res.headers.delete("set-cookie");
  176. }
  177. }
  178. }
  179. }
  180. class EventV2Processor extends EventProcessor {
  181. getPath(event) {
  182. return event.rawPath;
  183. }
  184. getMethod(event) {
  185. return event.requestContext.http.method;
  186. }
  187. getQueryString(event) {
  188. return event.rawQueryString;
  189. }
  190. getCookies(event, headers) {
  191. if (Array.isArray(event.cookies)) {
  192. headers.set("Cookie", event.cookies.join("; "));
  193. }
  194. }
  195. setCookiesToResult(result, cookies) {
  196. result.cookies = cookies;
  197. }
  198. getHeaders(event) {
  199. const headers = new Headers();
  200. this.getCookies(event, headers);
  201. if (event.headers) {
  202. for (const [k, v] of Object.entries(event.headers)) {
  203. if (v) {
  204. headers.set(k, v);
  205. }
  206. }
  207. }
  208. return headers;
  209. }
  210. }
  211. const v2Processor = new EventV2Processor();
  212. class EventV1Processor extends EventProcessor {
  213. getPath(event) {
  214. return event.path;
  215. }
  216. getMethod(event) {
  217. return event.httpMethod;
  218. }
  219. getQueryString(event) {
  220. if (event.multiValueQueryStringParameters) {
  221. return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(
  222. ([key, values]) => values.map((value) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&")
  223. ).join("&");
  224. } else {
  225. return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value || "")}`).join("&");
  226. }
  227. }
  228. getCookies(_event, _headers) {
  229. }
  230. getHeaders(event) {
  231. const headers = new Headers();
  232. this.getCookies(event, headers);
  233. if (event.headers) {
  234. for (const [k, v] of Object.entries(event.headers)) {
  235. if (v) {
  236. headers.set(k, sanitizeHeaderValue(v));
  237. }
  238. }
  239. }
  240. if (event.multiValueHeaders) {
  241. for (const [k, values] of Object.entries(event.multiValueHeaders)) {
  242. if (values) {
  243. const foundK = headers.get(k);
  244. values.forEach((v) => {
  245. const sanitizedValue = sanitizeHeaderValue(v);
  246. return (!foundK || !foundK.includes(sanitizedValue)) && headers.append(k, sanitizedValue);
  247. });
  248. }
  249. }
  250. }
  251. return headers;
  252. }
  253. setCookiesToResult(result, cookies) {
  254. result.multiValueHeaders = {
  255. "set-cookie": cookies
  256. };
  257. }
  258. }
  259. const v1Processor = new EventV1Processor();
  260. class ALBProcessor extends EventProcessor {
  261. getHeaders(event) {
  262. const headers = new Headers();
  263. if (event.multiValueHeaders) {
  264. for (const [key, values] of Object.entries(event.multiValueHeaders)) {
  265. if (values && Array.isArray(values)) {
  266. const sanitizedValue = sanitizeHeaderValue(values.join("; "));
  267. headers.set(key, sanitizedValue);
  268. }
  269. }
  270. } else {
  271. for (const [key, value] of Object.entries(event.headers ?? {})) {
  272. if (value) {
  273. headers.set(key, sanitizeHeaderValue(value));
  274. }
  275. }
  276. }
  277. return headers;
  278. }
  279. getPath(event) {
  280. return event.path;
  281. }
  282. getMethod(event) {
  283. return event.httpMethod;
  284. }
  285. getQueryString(event) {
  286. if (event.multiValueQueryStringParameters) {
  287. return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
  288. } else {
  289. return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
  290. }
  291. }
  292. getCookies(event, headers) {
  293. let cookie;
  294. if (event.multiValueHeaders) {
  295. cookie = event.multiValueHeaders["cookie"]?.join("; ");
  296. } else {
  297. cookie = event.headers ? event.headers["cookie"] : void 0;
  298. }
  299. if (cookie) {
  300. headers.append("Cookie", cookie);
  301. }
  302. }
  303. setCookiesToResult(result, cookies) {
  304. if (result.multiValueHeaders) {
  305. result.multiValueHeaders["set-cookie"] = cookies;
  306. } else {
  307. result.headers["set-cookie"] = cookies.join(", ");
  308. }
  309. }
  310. }
  311. const albProcessor = new ALBProcessor();
  312. class LatticeV2Processor extends EventProcessor {
  313. getPath(event) {
  314. return event.path;
  315. }
  316. getMethod(event) {
  317. return event.method;
  318. }
  319. getQueryString() {
  320. return "";
  321. }
  322. getHeaders(event) {
  323. const headers = new Headers();
  324. if (event.headers) {
  325. for (const [k, values] of Object.entries(event.headers)) {
  326. if (values) {
  327. const foundK = headers.get(k);
  328. values.forEach((v) => {
  329. const sanitizedValue = sanitizeHeaderValue(v);
  330. return (!foundK || !foundK.includes(sanitizedValue)) && headers.append(k, sanitizedValue);
  331. });
  332. }
  333. }
  334. }
  335. return headers;
  336. }
  337. getCookies() {
  338. }
  339. setCookiesToResult(result, cookies) {
  340. result.headers = {
  341. ...result.headers,
  342. "set-cookie": cookies.join(", ")
  343. };
  344. }
  345. }
  346. const latticeV2Processor = new LatticeV2Processor();
  347. const getProcessor = (event) => {
  348. if (isProxyEventALB(event)) {
  349. return albProcessor;
  350. }
  351. if (isProxyEventV2(event)) {
  352. return v2Processor;
  353. }
  354. if (isLatticeEventV2(event)) {
  355. return latticeV2Processor;
  356. }
  357. return v1Processor;
  358. };
  359. const isProxyEventALB = (event) => {
  360. if (event.requestContext) {
  361. return Object.hasOwn(event.requestContext, "elb");
  362. }
  363. return false;
  364. };
  365. const isProxyEventV2 = (event) => {
  366. return Object.hasOwn(event, "rawPath");
  367. };
  368. const isLatticeEventV2 = (event) => {
  369. if (event.requestContext) {
  370. return Object.hasOwn(event.requestContext, "serviceArn");
  371. }
  372. return false;
  373. };
  374. const defaultIsContentTypeBinary = (contentType) => {
  375. return !/^text\/(?:plain|html|css|javascript|csv)|(?:\/|\+)(?:json|xml)\s*(?:;|$)/.test(
  376. contentType
  377. );
  378. };
  379. const isContentEncodingBinary = (contentEncoding) => {
  380. if (contentEncoding === null) {
  381. return false;
  382. }
  383. return /^(gzip|deflate|compress|br)/.test(contentEncoding);
  384. };
  385. // Annotate the CommonJS export names for ESM import in node:
  386. 0 && (module.exports = {
  387. ALBProcessor,
  388. EventProcessor,
  389. EventV1Processor,
  390. EventV2Processor,
  391. LatticeV2Processor,
  392. defaultIsContentTypeBinary,
  393. getProcessor,
  394. handle,
  395. isContentEncodingBinary,
  396. streamHandle
  397. });