vercel.mjs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. // src/listener.ts
  2. import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "http2";
  3. // src/request.ts
  4. import { Http2ServerRequest } from "http2";
  5. import { Readable } from "stream";
  6. var RequestError = class extends Error {
  7. constructor(message, options) {
  8. super(message, options);
  9. this.name = "RequestError";
  10. }
  11. };
  12. var toRequestError = (e) => {
  13. if (e instanceof RequestError) {
  14. return e;
  15. }
  16. return new RequestError(e.message, { cause: e });
  17. };
  18. var GlobalRequest = global.Request;
  19. var Request = class extends GlobalRequest {
  20. constructor(input, options) {
  21. if (typeof input === "object" && getRequestCache in input) {
  22. input = input[getRequestCache]();
  23. }
  24. if (typeof options?.body?.getReader !== "undefined") {
  25. ;
  26. options.duplex ??= "half";
  27. }
  28. super(input, options);
  29. }
  30. };
  31. var newHeadersFromIncoming = (incoming) => {
  32. const headerRecord = [];
  33. const rawHeaders = incoming.rawHeaders;
  34. for (let i = 0; i < rawHeaders.length; i += 2) {
  35. const { [i]: key, [i + 1]: value } = rawHeaders;
  36. if (key.charCodeAt(0) !== /*:*/
  37. 58) {
  38. headerRecord.push([key, value]);
  39. }
  40. }
  41. return new Headers(headerRecord);
  42. };
  43. var wrapBodyStream = Symbol("wrapBodyStream");
  44. var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
  45. const init = {
  46. method,
  47. headers,
  48. signal: abortController.signal
  49. };
  50. if (method === "TRACE") {
  51. init.method = "GET";
  52. const req = new Request(url, init);
  53. Object.defineProperty(req, "method", {
  54. get() {
  55. return "TRACE";
  56. }
  57. });
  58. return req;
  59. }
  60. if (!(method === "GET" || method === "HEAD")) {
  61. if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
  62. init.body = new ReadableStream({
  63. start(controller) {
  64. controller.enqueue(incoming.rawBody);
  65. controller.close();
  66. }
  67. });
  68. } else if (incoming[wrapBodyStream]) {
  69. let reader;
  70. init.body = new ReadableStream({
  71. async pull(controller) {
  72. try {
  73. reader ||= Readable.toWeb(incoming).getReader();
  74. const { done, value } = await reader.read();
  75. if (done) {
  76. controller.close();
  77. } else {
  78. controller.enqueue(value);
  79. }
  80. } catch (error) {
  81. controller.error(error);
  82. }
  83. }
  84. });
  85. } else {
  86. init.body = Readable.toWeb(incoming);
  87. }
  88. }
  89. return new Request(url, init);
  90. };
  91. var getRequestCache = Symbol("getRequestCache");
  92. var requestCache = Symbol("requestCache");
  93. var incomingKey = Symbol("incomingKey");
  94. var urlKey = Symbol("urlKey");
  95. var headersKey = Symbol("headersKey");
  96. var abortControllerKey = Symbol("abortControllerKey");
  97. var getAbortController = Symbol("getAbortController");
  98. var requestPrototype = {
  99. get method() {
  100. return this[incomingKey].method || "GET";
  101. },
  102. get url() {
  103. return this[urlKey];
  104. },
  105. get headers() {
  106. return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
  107. },
  108. [getAbortController]() {
  109. this[getRequestCache]();
  110. return this[abortControllerKey];
  111. },
  112. [getRequestCache]() {
  113. this[abortControllerKey] ||= new AbortController();
  114. return this[requestCache] ||= newRequestFromIncoming(
  115. this.method,
  116. this[urlKey],
  117. this.headers,
  118. this[incomingKey],
  119. this[abortControllerKey]
  120. );
  121. }
  122. };
  123. [
  124. "body",
  125. "bodyUsed",
  126. "cache",
  127. "credentials",
  128. "destination",
  129. "integrity",
  130. "mode",
  131. "redirect",
  132. "referrer",
  133. "referrerPolicy",
  134. "signal",
  135. "keepalive"
  136. ].forEach((k) => {
  137. Object.defineProperty(requestPrototype, k, {
  138. get() {
  139. return this[getRequestCache]()[k];
  140. }
  141. });
  142. });
  143. ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
  144. Object.defineProperty(requestPrototype, k, {
  145. value: function() {
  146. return this[getRequestCache]()[k]();
  147. }
  148. });
  149. });
  150. Object.setPrototypeOf(requestPrototype, Request.prototype);
  151. var newRequest = (incoming, defaultHostname) => {
  152. const req = Object.create(requestPrototype);
  153. req[incomingKey] = incoming;
  154. const incomingUrl = incoming.url || "";
  155. if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
  156. (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
  157. if (incoming instanceof Http2ServerRequest) {
  158. throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
  159. }
  160. try {
  161. const url2 = new URL(incomingUrl);
  162. req[urlKey] = url2.href;
  163. } catch (e) {
  164. throw new RequestError("Invalid absolute URL", { cause: e });
  165. }
  166. return req;
  167. }
  168. const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
  169. if (!host) {
  170. throw new RequestError("Missing host header");
  171. }
  172. let scheme;
  173. if (incoming instanceof Http2ServerRequest) {
  174. scheme = incoming.scheme;
  175. if (!(scheme === "http" || scheme === "https")) {
  176. throw new RequestError("Unsupported scheme");
  177. }
  178. } else {
  179. scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
  180. }
  181. const url = new URL(`${scheme}://${host}${incomingUrl}`);
  182. if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
  183. throw new RequestError("Invalid host header");
  184. }
  185. req[urlKey] = url.href;
  186. return req;
  187. };
  188. // src/response.ts
  189. var responseCache = Symbol("responseCache");
  190. var getResponseCache = Symbol("getResponseCache");
  191. var cacheKey = Symbol("cache");
  192. var GlobalResponse = global.Response;
  193. var Response2 = class _Response {
  194. #body;
  195. #init;
  196. [getResponseCache]() {
  197. delete this[cacheKey];
  198. return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
  199. }
  200. constructor(body, init) {
  201. let headers;
  202. this.#body = body;
  203. if (init instanceof _Response) {
  204. const cachedGlobalResponse = init[responseCache];
  205. if (cachedGlobalResponse) {
  206. this.#init = cachedGlobalResponse;
  207. this[getResponseCache]();
  208. return;
  209. } else {
  210. this.#init = init.#init;
  211. headers = new Headers(init.#init.headers);
  212. }
  213. } else {
  214. this.#init = init;
  215. }
  216. if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
  217. ;
  218. this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
  219. }
  220. }
  221. get headers() {
  222. const cache = this[cacheKey];
  223. if (cache) {
  224. if (!(cache[2] instanceof Headers)) {
  225. cache[2] = new Headers(
  226. cache[2] || { "content-type": "text/plain; charset=UTF-8" }
  227. );
  228. }
  229. return cache[2];
  230. }
  231. return this[getResponseCache]().headers;
  232. }
  233. get status() {
  234. return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
  235. }
  236. get ok() {
  237. const status = this.status;
  238. return status >= 200 && status < 300;
  239. }
  240. };
  241. ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
  242. Object.defineProperty(Response2.prototype, k, {
  243. get() {
  244. return this[getResponseCache]()[k];
  245. }
  246. });
  247. });
  248. ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
  249. Object.defineProperty(Response2.prototype, k, {
  250. value: function() {
  251. return this[getResponseCache]()[k]();
  252. }
  253. });
  254. });
  255. Object.setPrototypeOf(Response2, GlobalResponse);
  256. Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
  257. // src/utils.ts
  258. async function readWithoutBlocking(readPromise) {
  259. return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
  260. }
  261. function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
  262. const cancel = (error) => {
  263. reader.cancel(error).catch(() => {
  264. });
  265. };
  266. writable.on("close", cancel);
  267. writable.on("error", cancel);
  268. (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
  269. return reader.closed.finally(() => {
  270. writable.off("close", cancel);
  271. writable.off("error", cancel);
  272. });
  273. function handleStreamError(error) {
  274. if (error) {
  275. writable.destroy(error);
  276. }
  277. }
  278. function onDrain() {
  279. reader.read().then(flow, handleStreamError);
  280. }
  281. function flow({ done, value }) {
  282. try {
  283. if (done) {
  284. writable.end();
  285. } else if (!writable.write(value)) {
  286. writable.once("drain", onDrain);
  287. } else {
  288. return reader.read().then(flow, handleStreamError);
  289. }
  290. } catch (e) {
  291. handleStreamError(e);
  292. }
  293. }
  294. }
  295. function writeFromReadableStream(stream, writable) {
  296. if (stream.locked) {
  297. throw new TypeError("ReadableStream is locked.");
  298. } else if (writable.destroyed) {
  299. return;
  300. }
  301. return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
  302. }
  303. var buildOutgoingHttpHeaders = (headers) => {
  304. const res = {};
  305. if (!(headers instanceof Headers)) {
  306. headers = new Headers(headers ?? void 0);
  307. }
  308. const cookies = [];
  309. for (const [k, v] of headers) {
  310. if (k === "set-cookie") {
  311. cookies.push(v);
  312. } else {
  313. res[k] = v;
  314. }
  315. }
  316. if (cookies.length > 0) {
  317. res["set-cookie"] = cookies;
  318. }
  319. res["content-type"] ??= "text/plain; charset=UTF-8";
  320. return res;
  321. };
  322. // src/utils/response/constants.ts
  323. var X_ALREADY_SENT = "x-hono-already-sent";
  324. // src/globals.ts
  325. import crypto from "crypto";
  326. if (typeof global.crypto === "undefined") {
  327. global.crypto = crypto;
  328. }
  329. // src/listener.ts
  330. var outgoingEnded = Symbol("outgoingEnded");
  331. var incomingDraining = Symbol("incomingDraining");
  332. var DRAIN_TIMEOUT_MS = 500;
  333. var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
  334. var drainIncoming = (incoming) => {
  335. const incomingWithDrainState = incoming;
  336. if (incoming.destroyed || incomingWithDrainState[incomingDraining]) {
  337. return;
  338. }
  339. incomingWithDrainState[incomingDraining] = true;
  340. if (incoming instanceof Http2ServerRequest2) {
  341. try {
  342. ;
  343. incoming.stream?.close?.(h2constants.NGHTTP2_NO_ERROR);
  344. } catch {
  345. }
  346. return;
  347. }
  348. let bytesRead = 0;
  349. const cleanup = () => {
  350. clearTimeout(timer);
  351. incoming.off("data", onData);
  352. incoming.off("end", cleanup);
  353. incoming.off("error", cleanup);
  354. };
  355. const forceClose = () => {
  356. cleanup();
  357. const socket = incoming.socket;
  358. if (socket && !socket.destroyed) {
  359. socket.destroySoon();
  360. }
  361. };
  362. const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
  363. timer.unref?.();
  364. const onData = (chunk) => {
  365. bytesRead += chunk.length;
  366. if (bytesRead > MAX_DRAIN_BYTES) {
  367. forceClose();
  368. }
  369. };
  370. incoming.on("data", onData);
  371. incoming.on("end", cleanup);
  372. incoming.on("error", cleanup);
  373. incoming.resume();
  374. };
  375. var handleRequestError = () => new Response(null, {
  376. status: 400
  377. });
  378. var handleFetchError = (e) => new Response(null, {
  379. status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
  380. });
  381. var handleResponseError = (e, outgoing) => {
  382. const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
  383. if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
  384. console.info("The user aborted a request.");
  385. } else {
  386. console.error(e);
  387. if (!outgoing.headersSent) {
  388. outgoing.writeHead(500, { "Content-Type": "text/plain" });
  389. }
  390. outgoing.end(`Error: ${err.message}`);
  391. outgoing.destroy(err);
  392. }
  393. };
  394. var flushHeaders = (outgoing) => {
  395. if ("flushHeaders" in outgoing && outgoing.writable) {
  396. outgoing.flushHeaders();
  397. }
  398. };
  399. var responseViaCache = async (res, outgoing) => {
  400. let [status, body, header] = res[cacheKey];
  401. let hasContentLength = false;
  402. if (!header) {
  403. header = { "content-type": "text/plain; charset=UTF-8" };
  404. } else if (header instanceof Headers) {
  405. hasContentLength = header.has("content-length");
  406. header = buildOutgoingHttpHeaders(header);
  407. } else if (Array.isArray(header)) {
  408. const headerObj = new Headers(header);
  409. hasContentLength = headerObj.has("content-length");
  410. header = buildOutgoingHttpHeaders(headerObj);
  411. } else {
  412. for (const key in header) {
  413. if (key.length === 14 && key.toLowerCase() === "content-length") {
  414. hasContentLength = true;
  415. break;
  416. }
  417. }
  418. }
  419. if (!hasContentLength) {
  420. if (typeof body === "string") {
  421. header["Content-Length"] = Buffer.byteLength(body);
  422. } else if (body instanceof Uint8Array) {
  423. header["Content-Length"] = body.byteLength;
  424. } else if (body instanceof Blob) {
  425. header["Content-Length"] = body.size;
  426. }
  427. }
  428. outgoing.writeHead(status, header);
  429. if (typeof body === "string" || body instanceof Uint8Array) {
  430. outgoing.end(body);
  431. } else if (body instanceof Blob) {
  432. outgoing.end(new Uint8Array(await body.arrayBuffer()));
  433. } else {
  434. flushHeaders(outgoing);
  435. await writeFromReadableStream(body, outgoing)?.catch(
  436. (e) => handleResponseError(e, outgoing)
  437. );
  438. }
  439. ;
  440. outgoing[outgoingEnded]?.();
  441. };
  442. var isPromise = (res) => typeof res.then === "function";
  443. var responseViaResponseObject = async (res, outgoing, options = {}) => {
  444. if (isPromise(res)) {
  445. if (options.errorHandler) {
  446. try {
  447. res = await res;
  448. } catch (err) {
  449. const errRes = await options.errorHandler(err);
  450. if (!errRes) {
  451. return;
  452. }
  453. res = errRes;
  454. }
  455. } else {
  456. res = await res.catch(handleFetchError);
  457. }
  458. }
  459. if (cacheKey in res) {
  460. return responseViaCache(res, outgoing);
  461. }
  462. const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
  463. if (res.body) {
  464. const reader = res.body.getReader();
  465. const values = [];
  466. let done = false;
  467. let currentReadPromise = void 0;
  468. if (resHeaderRecord["transfer-encoding"] !== "chunked") {
  469. let maxReadCount = 2;
  470. for (let i = 0; i < maxReadCount; i++) {
  471. currentReadPromise ||= reader.read();
  472. const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
  473. console.error(e);
  474. done = true;
  475. });
  476. if (!chunk) {
  477. if (i === 1) {
  478. await new Promise((resolve) => setTimeout(resolve));
  479. maxReadCount = 3;
  480. continue;
  481. }
  482. break;
  483. }
  484. currentReadPromise = void 0;
  485. if (chunk.value) {
  486. values.push(chunk.value);
  487. }
  488. if (chunk.done) {
  489. done = true;
  490. break;
  491. }
  492. }
  493. if (done && !("content-length" in resHeaderRecord)) {
  494. resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
  495. }
  496. }
  497. outgoing.writeHead(res.status, resHeaderRecord);
  498. values.forEach((value) => {
  499. ;
  500. outgoing.write(value);
  501. });
  502. if (done) {
  503. outgoing.end();
  504. } else {
  505. if (values.length === 0) {
  506. flushHeaders(outgoing);
  507. }
  508. await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
  509. }
  510. } else if (resHeaderRecord[X_ALREADY_SENT]) {
  511. } else {
  512. outgoing.writeHead(res.status, resHeaderRecord);
  513. outgoing.end();
  514. }
  515. ;
  516. outgoing[outgoingEnded]?.();
  517. };
  518. var getRequestListener = (fetchCallback, options = {}) => {
  519. const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
  520. if (options.overrideGlobalObjects !== false && global.Request !== Request) {
  521. Object.defineProperty(global, "Request", {
  522. value: Request
  523. });
  524. Object.defineProperty(global, "Response", {
  525. value: Response2
  526. });
  527. }
  528. return async (incoming, outgoing) => {
  529. let res, req;
  530. try {
  531. req = newRequest(incoming, options.hostname);
  532. let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
  533. if (!incomingEnded) {
  534. ;
  535. incoming[wrapBodyStream] = true;
  536. incoming.on("end", () => {
  537. incomingEnded = true;
  538. });
  539. if (incoming instanceof Http2ServerRequest2) {
  540. ;
  541. outgoing[outgoingEnded] = () => {
  542. if (!incomingEnded) {
  543. setTimeout(() => {
  544. if (!incomingEnded) {
  545. setTimeout(() => {
  546. drainIncoming(incoming);
  547. });
  548. }
  549. });
  550. }
  551. };
  552. }
  553. outgoing.on("finish", () => {
  554. if (!incomingEnded) {
  555. drainIncoming(incoming);
  556. }
  557. });
  558. }
  559. outgoing.on("close", () => {
  560. const abortController = req[abortControllerKey];
  561. if (abortController) {
  562. if (incoming.errored) {
  563. req[abortControllerKey].abort(incoming.errored.toString());
  564. } else if (!outgoing.writableFinished) {
  565. req[abortControllerKey].abort("Client connection prematurely closed.");
  566. }
  567. }
  568. if (!incomingEnded) {
  569. setTimeout(() => {
  570. if (!incomingEnded) {
  571. setTimeout(() => {
  572. drainIncoming(incoming);
  573. });
  574. }
  575. });
  576. }
  577. });
  578. res = fetchCallback(req, { incoming, outgoing });
  579. if (cacheKey in res) {
  580. return responseViaCache(res, outgoing);
  581. }
  582. } catch (e) {
  583. if (!res) {
  584. if (options.errorHandler) {
  585. res = await options.errorHandler(req ? e : toRequestError(e));
  586. if (!res) {
  587. return;
  588. }
  589. } else if (!req) {
  590. res = handleRequestError();
  591. } else {
  592. res = handleFetchError(e);
  593. }
  594. } else {
  595. return handleResponseError(e, outgoing);
  596. }
  597. }
  598. try {
  599. return await responseViaResponseObject(res, outgoing, options);
  600. } catch (e) {
  601. return handleResponseError(e, outgoing);
  602. }
  603. };
  604. };
  605. // src/vercel.ts
  606. var handle = (app) => {
  607. return getRequestListener(app.fetch);
  608. };
  609. export {
  610. handle
  611. };