|
|
| import { Http2ServerRequest } from "http2";
|
| import { Readable } from "stream";
|
| var RequestError = class extends Error {
|
| constructor(message, options) {
|
| super(message, options);
|
| this.name = "RequestError";
|
| }
|
| };
|
| var toRequestError = (e) => {
|
| if (e instanceof RequestError) {
|
| return e;
|
| }
|
| return new RequestError(e.message, { cause: e });
|
| };
|
| var GlobalRequest = global.Request;
|
| var Request = class extends GlobalRequest {
|
| constructor(input, options) {
|
| if (typeof input === "object" && getRequestCache in input) {
|
| input = input[getRequestCache]();
|
| }
|
| if (typeof options?.body?.getReader !== "undefined") {
|
| ;
|
| options.duplex ??= "half";
|
| }
|
| super(input, options);
|
| }
|
| };
|
| var newHeadersFromIncoming = (incoming) => {
|
| const headerRecord = [];
|
| const rawHeaders = incoming.rawHeaders;
|
| for (let i = 0; i < rawHeaders.length; i += 2) {
|
| const { [i]: key, [i + 1]: value } = rawHeaders;
|
| if (key.charCodeAt(0) !==
|
| 58) {
|
| headerRecord.push([key, value]);
|
| }
|
| }
|
| return new Headers(headerRecord);
|
| };
|
| var wrapBodyStream = Symbol("wrapBodyStream");
|
| var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
| const init = {
|
| method,
|
| headers,
|
| signal: abortController.signal
|
| };
|
| if (method === "TRACE") {
|
| init.method = "GET";
|
| const req = new Request(url, init);
|
| Object.defineProperty(req, "method", {
|
| get() {
|
| return "TRACE";
|
| }
|
| });
|
| return req;
|
| }
|
| if (!(method === "GET" || method === "HEAD")) {
|
| if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
| init.body = new ReadableStream({
|
| start(controller) {
|
| controller.enqueue(incoming.rawBody);
|
| controller.close();
|
| }
|
| });
|
| } else if (incoming[wrapBodyStream]) {
|
| let reader;
|
| init.body = new ReadableStream({
|
| async pull(controller) {
|
| try {
|
| reader ||= Readable.toWeb(incoming).getReader();
|
| const { done, value } = await reader.read();
|
| if (done) {
|
| controller.close();
|
| } else {
|
| controller.enqueue(value);
|
| }
|
| } catch (error) {
|
| controller.error(error);
|
| }
|
| }
|
| });
|
| } else {
|
| init.body = Readable.toWeb(incoming);
|
| }
|
| }
|
| return new Request(url, init);
|
| };
|
| var getRequestCache = Symbol("getRequestCache");
|
| var requestCache = Symbol("requestCache");
|
| var incomingKey = Symbol("incomingKey");
|
| var urlKey = Symbol("urlKey");
|
| var headersKey = Symbol("headersKey");
|
| var abortControllerKey = Symbol("abortControllerKey");
|
| var getAbortController = Symbol("getAbortController");
|
| var requestPrototype = {
|
| get method() {
|
| return this[incomingKey].method || "GET";
|
| },
|
| get url() {
|
| return this[urlKey];
|
| },
|
| get headers() {
|
| return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
| },
|
| [getAbortController]() {
|
| this[getRequestCache]();
|
| return this[abortControllerKey];
|
| },
|
| [getRequestCache]() {
|
| this[abortControllerKey] ||= new AbortController();
|
| return this[requestCache] ||= newRequestFromIncoming(
|
| this.method,
|
| this[urlKey],
|
| this.headers,
|
| this[incomingKey],
|
| this[abortControllerKey]
|
| );
|
| }
|
| };
|
| [
|
| "body",
|
| "bodyUsed",
|
| "cache",
|
| "credentials",
|
| "destination",
|
| "integrity",
|
| "mode",
|
| "redirect",
|
| "referrer",
|
| "referrerPolicy",
|
| "signal",
|
| "keepalive"
|
| ].forEach((k) => {
|
| Object.defineProperty(requestPrototype, k, {
|
| get() {
|
| return this[getRequestCache]()[k];
|
| }
|
| });
|
| });
|
| ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
| Object.defineProperty(requestPrototype, k, {
|
| value: function() {
|
| return this[getRequestCache]()[k]();
|
| }
|
| });
|
| });
|
| Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), {
|
| value: function(depth, options, inspectFn) {
|
| const props = {
|
| method: this.method,
|
| url: this.url,
|
| headers: this.headers,
|
| nativeRequest: this[requestCache]
|
| };
|
| return `Request (lightweight) ${inspectFn(props, { ...options, depth: depth == null ? null : depth - 1 })}`;
|
| }
|
| });
|
| Object.setPrototypeOf(requestPrototype, Request.prototype);
|
| var newRequest = (incoming, defaultHostname) => {
|
| const req = Object.create(requestPrototype);
|
| req[incomingKey] = incoming;
|
| const incomingUrl = incoming.url || "";
|
| if (incomingUrl[0] !== "/" &&
|
| (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
| if (incoming instanceof Http2ServerRequest) {
|
| throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
| }
|
| try {
|
| const url2 = new URL(incomingUrl);
|
| req[urlKey] = url2.href;
|
| } catch (e) {
|
| throw new RequestError("Invalid absolute URL", { cause: e });
|
| }
|
| return req;
|
| }
|
| const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
| if (!host) {
|
| throw new RequestError("Missing host header");
|
| }
|
| let scheme;
|
| if (incoming instanceof Http2ServerRequest) {
|
| scheme = incoming.scheme;
|
| if (!(scheme === "http" || scheme === "https")) {
|
| throw new RequestError("Unsupported scheme");
|
| }
|
| } else {
|
| scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
| }
|
| const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
| if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
| throw new RequestError("Invalid host header");
|
| }
|
| req[urlKey] = url.href;
|
| return req;
|
| };
|
| export {
|
| GlobalRequest,
|
| Request,
|
| RequestError,
|
| abortControllerKey,
|
| getAbortController,
|
| newRequest,
|
| toRequestError,
|
| wrapBodyStream
|
| };
|
|
|