import listen = Deno.listen;import Conn = Deno.Conn;import Reader = Deno.Reader;import { BufReader, BufWriter } from "https://deno.land/std@v0.3.1/io/bufio.ts";import { assert } from "https://deno.land/std@v0.3.1/testing/asserts.ts";import { defer, promiseInterrupter } from "./promises.ts";import { readRequest } from "./serveio.ts";import { createResponder, ServerResponder } from "./responder.ts";
export type ClientRequest = { url: string; method: string; headers: Headers; body?: Uint8Array | Reader;};
export type ServerResponse = { status: number; headers?: Headers; body?: Uint8Array | Reader;};
export type IncomingHttpRequest = { url: string; method: string; proto: string; headers: Headers; body?: Reader; trailers?: Headers; finalize: () => Promise<void>;};
export type ServerRequest = IncomingHttpRequest & { conn: Conn; bufWriter: BufWriter; bufReader: BufReader;} & ServerResponder;
export type IncomingHttpResponse = { proto: string; status: number; statusText: string; headers: Headers; body?: Reader; trailers?: Headers; finalize: () => Promise<void>;};
export type ClientResponse = IncomingHttpResponse & { conn: Conn; bufWriter: BufWriter; bufReader: BufReader;};
export type ServeOptions = { cancel?: Promise<void>; keepAliveTimeout?: number; readTimeout?: number;};
export async function* serve( addr: string, opts?: ServeOptions): AsyncIterableIterator<ServerRequest> { let cancel = defer().promise; let keepAliveTimeout = 7500; let readTimeout = 7500; if (opts) { if (opts.cancel) { cancel = opts.cancel; } if (opts.keepAliveTimeout !== void 0) { keepAliveTimeout = opts.keepAliveTimeout; } if (opts.readTimeout !== void 0) { readTimeout = opts.readTimeout; } } assert(keepAliveTimeout >= 0, "keepAliveTimeout must be >= 0"); const listener = listen("tcp", addr); let onRequestDeferred = defer<ServerRequest>(); const breakWhenCancelled = promiseInterrupter({ timeout: -1, cancel }); const handleRequest = ({ bufReader, bufWriter, conn }, forNext: boolean) => { readRequest(bufReader, { keepAliveTimeout: forNext ? keepAliveTimeout : readTimeout, readTimeout, cancel }) .then(req => { onRequestDeferred.resolve( Object.assign( req, { bufWriter, bufReader, conn }, createResponder(bufWriter) ) ); }) .catch(e => { conn.close(); }); }; (async function acceptRoutine() { while (true) { let conn: Conn; try { conn = await breakWhenCancelled(listener.accept()); } catch (unused) { break; } const bufReader = new BufReader(conn); const bufWriter = new BufWriter(conn); handleRequest({ conn, bufReader, bufWriter }, false); } })(); while (true) { let req: ServerRequest; try { req = await breakWhenCancelled(onRequestDeferred.promise); } catch (unused) { break; } onRequestDeferred = defer(); yield req; req .finalize() .then(() => handleRequest(req, true)) .catch(e => req.conn.close()); } listener.close();}