mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: update Deno.serve
function signature (#15563)
This commit changes the `Deno.serve` function signature to be more versatile and easier to use. It is now a drop in replacement for std/http's `serve`. The input validation has also been reworked.
This commit is contained in:
parent
f0993f413b
commit
4ef08a58df
8 changed files with 253 additions and 148 deletions
|
@ -7,4 +7,4 @@ const [hostname, port] = addr.split(":");
|
|||
const app = new Hono();
|
||||
app.get("/", (c) => c.text("Hello, World!"));
|
||||
|
||||
Deno.serve({ fetch: app.fetch, port: Number(port), hostname });
|
||||
Deno.serve(app.fetch, { port: Number(port), hostname });
|
||||
|
|
|
@ -6,9 +6,9 @@ const { serve } = Deno;
|
|||
|
||||
const path = new URL("../testdata/128k.bin", import.meta.url).pathname;
|
||||
|
||||
function fetch() {
|
||||
function handler() {
|
||||
const file = Deno.openSync(path);
|
||||
return new Response(file.readable);
|
||||
}
|
||||
|
||||
serve({ fetch, hostname, port: Number(port) });
|
||||
serve(handler, { hostname, port: Number(port) });
|
||||
|
|
|
@ -4,12 +4,8 @@ const addr = Deno.args[0] || "127.0.0.1:4500";
|
|||
const [hostname, port] = addr.split(":");
|
||||
const { serve } = Deno;
|
||||
|
||||
function fetch() {
|
||||
function handler() {
|
||||
return new Response("Hello World");
|
||||
}
|
||||
|
||||
serve({
|
||||
fetch,
|
||||
hostname,
|
||||
port,
|
||||
});
|
||||
serve(handler, { hostname, port });
|
||||
|
|
|
@ -18,12 +18,6 @@ const headers = {
|
|||
},
|
||||
};
|
||||
|
||||
serve(
|
||||
{
|
||||
fetch: async () => {
|
||||
return new Response(await renderToReadableStream(<App />), headers);
|
||||
},
|
||||
hostname,
|
||||
port,
|
||||
},
|
||||
);
|
||||
serve({ hostname, port }, async () => {
|
||||
return new Response(await renderToReadableStream(<App />), headers);
|
||||
});
|
||||
|
|
8
cli/bench/testdata/deno_upgrade_http.js
vendored
8
cli/bench/testdata/deno_upgrade_http.js
vendored
|
@ -1,14 +1,10 @@
|
|||
const { serve, upgradeHttp } = Deno;
|
||||
const u8 = Deno.core.encode("HTTP/1.1 101 Switching Protocols\r\n\r\n");
|
||||
|
||||
async function fetch(req) {
|
||||
async function handler(req) {
|
||||
const [conn, _firstPacket] = upgradeHttp(req);
|
||||
await conn.write(u8);
|
||||
await conn.close();
|
||||
}
|
||||
|
||||
serve({
|
||||
fetch,
|
||||
hostname: "127.0.0.1",
|
||||
port: 9000,
|
||||
});
|
||||
serve(handler, { hostname: "127.0.0.1", port: 9000 });
|
||||
|
|
97
cli/dts/lib.deno.unstable.d.ts
vendored
97
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -1231,26 +1231,20 @@ declare namespace Deno {
|
|||
export function unrefTimer(id: number): void;
|
||||
|
||||
/**
|
||||
* A handler for HTTP requests. Consumes a request and returns a response.
|
||||
*
|
||||
* If a handler throws, the server calling the handler will assume the impact
|
||||
* of the error is isolated to the individual request. It will catch the error
|
||||
* and if necessary will close the underlying connection.
|
||||
*
|
||||
* @category HTTP Server
|
||||
*/
|
||||
export interface ServeInit extends Partial<Deno.ListenOptions> {
|
||||
/**
|
||||
* A handler for HTTP requests. Consumes a request and returns a response.
|
||||
*
|
||||
* Handler allows `void` or `Promise<void>` return type to enable
|
||||
* request upgrades using `Deno.upgradeHttp()` API. It is callers responsibility
|
||||
* to write response manually to the returned connection. Failing to do so
|
||||
* (or not returning a response without an upgrade) will cause the connection
|
||||
* to hang.
|
||||
*
|
||||
* If a handler throws, the server calling the handler will assume the impact
|
||||
* of the error is isolated to the individual request. It will catch the error
|
||||
* and close the underlying connection.
|
||||
*/
|
||||
fetch: (
|
||||
request: Request,
|
||||
) => Response | Promise<Response> | void | Promise<void>;
|
||||
export type ServeHandler = (request: Request) => Response | Promise<Response>;
|
||||
|
||||
/**
|
||||
* @category HTTP Server
|
||||
*/
|
||||
export interface ServeOptions extends Partial<Deno.ListenOptions> {
|
||||
/** An AbortSignal to close the server and all connections. */
|
||||
signal?: AbortSignal;
|
||||
|
||||
|
@ -1264,7 +1258,7 @@ declare namespace Deno {
|
|||
/**
|
||||
* @category HTTP Server
|
||||
*/
|
||||
export interface ServeTlsInit extends ServeInit {
|
||||
export interface ServeTlsOptions extends ServeOptions {
|
||||
/** Server private key in PEM format */
|
||||
cert: string;
|
||||
|
||||
|
@ -1272,7 +1266,17 @@ declare namespace Deno {
|
|||
key: string;
|
||||
}
|
||||
|
||||
/** Serves HTTP requests with the given handler.
|
||||
/**
|
||||
* @category HTTP Server
|
||||
*/
|
||||
export interface ServeInit {
|
||||
/** The handler to invoke to process each incoming request. */
|
||||
handler: ServeHandler;
|
||||
}
|
||||
|
||||
/** **UNSTABLE**: new API, yet to be vetted.
|
||||
*
|
||||
* Serves HTTP requests with the given handler.
|
||||
*
|
||||
* You can specify an object with a port and hostname option, which is the
|
||||
* address to listen on. The default is port 9000 on hostname "127.0.0.1".
|
||||
|
@ -1280,69 +1284,64 @@ declare namespace Deno {
|
|||
* The below example serves with the port 9000.
|
||||
*
|
||||
* ```ts
|
||||
* Deno.serve({
|
||||
* fetch: (_req) => new Response("Hello, world")
|
||||
* });
|
||||
* Deno.serve((_req) => new Response("Hello, world"));
|
||||
* ```
|
||||
*
|
||||
* You can change the listening address by the `hostname` and `port` options.
|
||||
* The below example serves with the port 3000.
|
||||
* You can change the address to listen on using the `hostname` and `port`
|
||||
* options. The below example serves on port 3000.
|
||||
*
|
||||
* ```ts
|
||||
* Deno.serve({
|
||||
* fetch: (_req) => new Response("Hello, world"),
|
||||
* port: 3000
|
||||
* });
|
||||
* Deno.serve({ port: 3000 }, (_req) => new Response("Hello, world"));
|
||||
* ```
|
||||
*
|
||||
* You can close the server by passing a `signal` option. To wait for the server
|
||||
* to close, await the promise returned from the `Deno.serve` API.
|
||||
* You can stop the server with an AbortSignal. The abort signal needs to be
|
||||
* passed as the `signal` option in the options bag. The server aborts when
|
||||
* the abort signal is aborted. To wait for the server to close, await the
|
||||
* promise returned from the `Deno.serve` API.
|
||||
*
|
||||
* ```ts
|
||||
* const ac = new AbortController();
|
||||
*
|
||||
* Deno.serve({
|
||||
* fetch: (_req) => new Response("Hello, world"),
|
||||
* signal: ac.signal
|
||||
* }).then(() => {
|
||||
* console.log("Server closed");
|
||||
* });
|
||||
* Deno.serve({ signal: ac.signal }, (_req) => new Response("Hello, world"))
|
||||
* .then(() => console.log("Server closed"));
|
||||
*
|
||||
* console.log("Closing server...");
|
||||
* ac.abort();
|
||||
* ```
|
||||
*
|
||||
* `Deno.serve` function prints the message `Listening on http://<hostname>:<port>/`
|
||||
* on start-up by default. If you like to change this message, you can specify
|
||||
* `onListen` option to override it.
|
||||
* By default `Deno.serve` prints the message `Listening on http://<hostname>:<port>/`
|
||||
* on start up. If you like to change this behaviour, you can specify a custom
|
||||
* `onListen` callback.
|
||||
*
|
||||
* ```ts
|
||||
* Deno.serve({
|
||||
* fetch: (_req) => new Response("Hello, world"),
|
||||
* onListen({ port, hostname }) {
|
||||
* console.log(`Server started at http://${hostname}:${port}`);
|
||||
* // ... more info specific to your server ..
|
||||
* },
|
||||
* handler: (_req) => new Response("Hello, world"),
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* To enable TLS you must specify `key` and `cert` options.
|
||||
* To enable TLS you must specify the `key` and `cert` options.
|
||||
*
|
||||
* ```ts
|
||||
* const cert = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n";
|
||||
* const key = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n";
|
||||
* Deno.serve({
|
||||
* fetch: (_req) => new Response("Hello, world"),
|
||||
* cert,
|
||||
* key
|
||||
* });
|
||||
*
|
||||
* @param options The options. See `ServeInit` and `ServeTlsInit` documentation for details.
|
||||
* Deno.serve({ cert, key }, (_req) => new Response("Hello, world"));
|
||||
*
|
||||
* @category HTTP Server
|
||||
*/
|
||||
export function serve(
|
||||
options?: ServeInit | ServeTlsInit,
|
||||
handler: ServeHandler,
|
||||
options?: ServeOptions | ServeTlsOptions,
|
||||
): Promise<void>;
|
||||
export function serve(
|
||||
options: ServeOptions | ServeTlsOptions,
|
||||
handler: ServeHandler,
|
||||
): Promise<void>;
|
||||
export function serve(
|
||||
options: ServeInit & (ServeOptions | ServeTlsOptions),
|
||||
): Promise<void>;
|
||||
|
||||
/** **UNSTABLE**: new API, yet to be vetter.
|
||||
|
|
|
@ -12,11 +12,9 @@ import {
|
|||
assert,
|
||||
assertEquals,
|
||||
assertRejects,
|
||||
assertStrictEquals,
|
||||
assertThrows,
|
||||
Deferred,
|
||||
deferred,
|
||||
delay,
|
||||
fail,
|
||||
} from "./test_util.ts";
|
||||
|
||||
|
@ -37,10 +35,10 @@ function onListen<T>(
|
|||
}
|
||||
|
||||
Deno.test(async function httpServerInvalidHostname() {
|
||||
assertThrows(
|
||||
await assertRejects(
|
||||
() =>
|
||||
Deno.serve({
|
||||
fetch: (_req) => new Response("ok"),
|
||||
handler: (_req) => new Response("ok"),
|
||||
hostname: "localhost",
|
||||
}),
|
||||
TypeError,
|
||||
|
@ -54,7 +52,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerBasic() {
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
// FIXME(bartlomieju):
|
||||
// make sure that request can be inspected
|
||||
console.log(request);
|
||||
|
@ -84,11 +82,103 @@ Deno.test({ permissions: { net: true } }, async function httpServerBasic() {
|
|||
await server;
|
||||
});
|
||||
|
||||
Deno.test({ permissions: { net: true } }, async function httpServerOverload1() {
|
||||
const ac = new AbortController();
|
||||
const promise = deferred();
|
||||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
port: 4501,
|
||||
signal: ac.signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
onError: createOnErrorCb(ac),
|
||||
}, async (request) => {
|
||||
// FIXME(bartlomieju):
|
||||
// make sure that request can be inspected
|
||||
console.log(request);
|
||||
assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/");
|
||||
assertEquals(await request.text(), "");
|
||||
promise.resolve();
|
||||
return new Response("Hello World", { headers: { "foo": "bar" } });
|
||||
});
|
||||
|
||||
await listeningPromise;
|
||||
const resp = await fetch("http://127.0.0.1:4501/", {
|
||||
headers: { "connection": "close" },
|
||||
});
|
||||
await promise;
|
||||
const clone = resp.clone();
|
||||
const text = await resp.text();
|
||||
assertEquals(text, "Hello World");
|
||||
assertEquals(resp.headers.get("foo"), "bar");
|
||||
const cloneText = await clone.text();
|
||||
assertEquals(cloneText, "Hello World");
|
||||
ac.abort();
|
||||
await server;
|
||||
});
|
||||
|
||||
Deno.test({ permissions: { net: true } }, async function httpServerOverload2() {
|
||||
const ac = new AbortController();
|
||||
const promise = deferred();
|
||||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve(async (request) => {
|
||||
// FIXME(bartlomieju):
|
||||
// make sure that request can be inspected
|
||||
console.log(request);
|
||||
assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/");
|
||||
assertEquals(await request.text(), "");
|
||||
promise.resolve();
|
||||
return new Response("Hello World", { headers: { "foo": "bar" } });
|
||||
}, {
|
||||
port: 4501,
|
||||
signal: ac.signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
onError: createOnErrorCb(ac),
|
||||
});
|
||||
|
||||
await listeningPromise;
|
||||
const resp = await fetch("http://127.0.0.1:4501/", {
|
||||
headers: { "connection": "close" },
|
||||
});
|
||||
await promise;
|
||||
const clone = resp.clone();
|
||||
const text = await resp.text();
|
||||
assertEquals(text, "Hello World");
|
||||
assertEquals(resp.headers.get("foo"), "bar");
|
||||
const cloneText = await clone.text();
|
||||
assertEquals(cloneText, "Hello World");
|
||||
ac.abort();
|
||||
await server;
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
{ permissions: { net: true } },
|
||||
async function httpServerErrorOverloadMissingHandler() {
|
||||
// @ts-ignore - testing invalid overload
|
||||
await assertRejects(() => Deno.serve(), TypeError, "handler");
|
||||
// @ts-ignore - testing invalid overload
|
||||
await assertRejects(() => Deno.serve({}), TypeError, "handler");
|
||||
await assertRejects(
|
||||
// @ts-ignore - testing invalid overload
|
||||
() => Deno.serve({ handler: undefined }),
|
||||
TypeError,
|
||||
"handler",
|
||||
);
|
||||
await assertRejects(
|
||||
// @ts-ignore - testing invalid overload
|
||||
() => Deno.serve(undefined, { handler: () => {} }),
|
||||
TypeError,
|
||||
"handler",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test({ permissions: { net: true } }, async function httpServerPort0() {
|
||||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch() {
|
||||
handler() {
|
||||
return new Response("Hello World");
|
||||
},
|
||||
port: 0,
|
||||
|
@ -120,7 +210,7 @@ Deno.test(
|
|||
|
||||
try {
|
||||
const server = Deno.serve({
|
||||
fetch() {
|
||||
handler() {
|
||||
return new Response("Hello World");
|
||||
},
|
||||
hostname: "0.0.0.0",
|
||||
|
@ -145,7 +235,7 @@ Deno.test(
|
|||
|
||||
let headers: Headers;
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
await request.text();
|
||||
headers = request.headers;
|
||||
promise.resolve();
|
||||
|
@ -182,7 +272,7 @@ Deno.test(
|
|||
|
||||
let req: Request;
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
await request.text();
|
||||
req = request;
|
||||
promise.resolve();
|
||||
|
@ -226,7 +316,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: (request) => {
|
||||
handler: (request) => {
|
||||
assertEquals(request.body, null);
|
||||
promise.resolve();
|
||||
return new Response("", { headers: {} });
|
||||
|
@ -270,7 +360,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
const ac = new AbortController();
|
||||
const server = Deno.serve({
|
||||
fetch: (request) => {
|
||||
handler: (request) => {
|
||||
assert(!request.body);
|
||||
return new Response(stream.readable);
|
||||
},
|
||||
|
@ -300,7 +390,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
const ac = new AbortController();
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
const reqBody = await request.text();
|
||||
assertEquals("hello world", reqBody);
|
||||
return new Response("yo");
|
||||
|
@ -328,7 +418,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerClose() {
|
|||
const ac = new AbortController();
|
||||
const listeningPromise = deferred();
|
||||
const server = Deno.serve({
|
||||
fetch: () => new Response("ok"),
|
||||
handler: () => new Response("ok"),
|
||||
port: 4501,
|
||||
signal: ac.signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
|
@ -348,7 +438,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
const listeningPromise = deferred();
|
||||
const server = Deno.serve({
|
||||
fetch: () => new Response(new Blob([])),
|
||||
handler: () => new Response(new Blob([])),
|
||||
port: 4501,
|
||||
signal: ac.signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
|
@ -369,7 +459,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() {
|
|||
const ac = new AbortController();
|
||||
const listeningPromise = deferred();
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
const {
|
||||
response,
|
||||
socket,
|
||||
|
@ -409,7 +499,7 @@ Deno.test(
|
|||
|
||||
let headers: Headers;
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
headers = request.headers;
|
||||
promise.resolve();
|
||||
return new Response("");
|
||||
|
@ -448,7 +538,7 @@ Deno.test(
|
|||
let headers: Headers;
|
||||
let text: string;
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
headers = request.headers;
|
||||
text = await request.text();
|
||||
promise.resolve();
|
||||
|
@ -493,7 +583,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
promise.resolve();
|
||||
return new Response("");
|
||||
},
|
||||
|
@ -643,7 +733,7 @@ Deno.test(
|
|||
}
|
||||
|
||||
const finished = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
promise.resolve();
|
||||
return new Response(periodicStream());
|
||||
},
|
||||
|
@ -674,7 +764,7 @@ Deno.test(
|
|||
const promise = deferred();
|
||||
const ac = new AbortController();
|
||||
const server = Deno.serve({
|
||||
fetch: (request) => {
|
||||
handler: (request) => {
|
||||
assertEquals(request.headers.get("X-Header-Test"), "á");
|
||||
promise.resolve();
|
||||
return new Response("hello", { headers: { "X-Header-Test": "Æ" } });
|
||||
|
@ -720,7 +810,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
// FIXME:
|
||||
// assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/");
|
||||
assertEquals(await request.text(), "");
|
||||
|
@ -774,7 +864,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(await request.text(), "");
|
||||
assertEquals(request.headers.get("cookie"), "foo=bar, bar=foo");
|
||||
promise.resolve();
|
||||
|
@ -817,7 +907,7 @@ Deno.test(
|
|||
file.close();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
const f = await Deno.open(tmpFile, { read: true });
|
||||
promise.resolve();
|
||||
return new Response(f.readable);
|
||||
|
@ -853,7 +943,7 @@ Deno.test(
|
|||
const port = 4501;
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
promise.resolve();
|
||||
return new Response("ok");
|
||||
},
|
||||
|
@ -888,7 +978,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.body, null);
|
||||
promise.resolve();
|
||||
return new Response(new Uint8Array([128]));
|
||||
|
@ -918,7 +1008,7 @@ Deno.test("upgradeHttp tcp", async () => {
|
|||
const promise2 = deferred();
|
||||
const ac = new AbortController();
|
||||
const signal = ac.signal;
|
||||
const fetch = async (req: Request) => {
|
||||
const handler = async (req: Request) => {
|
||||
const [conn, _] = await Deno.upgradeHttp(req);
|
||||
|
||||
await conn.write(
|
||||
|
@ -938,7 +1028,7 @@ Deno.test("upgradeHttp tcp", async () => {
|
|||
conn.close();
|
||||
};
|
||||
const server = Deno.serve({
|
||||
fetch,
|
||||
handler: handler as any,
|
||||
port: 4501,
|
||||
signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
|
@ -980,7 +1070,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "GET");
|
||||
assertEquals(request.headers.get("host"), "deno.land");
|
||||
promise.resolve();
|
||||
|
@ -1014,7 +1104,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "GET");
|
||||
assertEquals(request.headers.get("server"), "hello\tworld");
|
||||
promise.resolve();
|
||||
|
@ -1048,7 +1138,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "GET");
|
||||
assertEquals(await request.text(), "");
|
||||
promise.resolve();
|
||||
|
@ -1084,7 +1174,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "POST");
|
||||
assertEquals(await request.text(), "I'm a good request.");
|
||||
promise.resolve();
|
||||
|
@ -1130,7 +1220,7 @@ function createServerLengthTest(name: string, testCase: TestCase) {
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "GET");
|
||||
promise.resolve();
|
||||
return new Response(testCase.body, testCase.headers ?? {});
|
||||
|
@ -1262,7 +1352,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "GET");
|
||||
promises[reqCount].resolve();
|
||||
reqCount++;
|
||||
|
@ -1325,7 +1415,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "POST");
|
||||
assertEquals(request.headers.get("content-length"), "5");
|
||||
assertEquals(await request.text(), "hello");
|
||||
|
@ -1361,7 +1451,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
const listeningPromise = deferred();
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
throw new Error("unreachable");
|
||||
},
|
||||
port: 4503,
|
||||
|
@ -1401,7 +1491,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(request.method, "POST");
|
||||
assertEquals(await request.text(), "qwert");
|
||||
promise.resolve();
|
||||
|
@ -1438,7 +1528,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (r) => {
|
||||
handler: async (r) => {
|
||||
promise.resolve();
|
||||
assertEquals(await r.text(), "12345");
|
||||
return new Response("ok");
|
||||
|
@ -1474,7 +1564,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
promise.resolve();
|
||||
return new Response("foo bar baz");
|
||||
},
|
||||
|
@ -1522,7 +1612,7 @@ Deno.test(
|
|||
await file.write(data);
|
||||
file.close();
|
||||
const server = Deno.serve({
|
||||
fetch: async () => {
|
||||
handler: async () => {
|
||||
const f = await Deno.open(tmpFile, { read: true });
|
||||
promise.resolve();
|
||||
return new Response(f.readable, { status: 200 });
|
||||
|
@ -1557,7 +1647,7 @@ Deno.test(
|
|||
file.close();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (request) => {
|
||||
handler: async (request) => {
|
||||
assertEquals(new Uint8Array(await request.arrayBuffer()), data);
|
||||
promise.resolve();
|
||||
return new Response("ok");
|
||||
|
@ -1594,7 +1684,7 @@ Deno.test(
|
|||
const port = 4501;
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => new Response("Hello World"),
|
||||
handler: () => new Response("Hello World"),
|
||||
hostname,
|
||||
port,
|
||||
signal: ac.signal,
|
||||
|
@ -1629,7 +1719,7 @@ Deno.test(
|
|||
const promise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (req) => {
|
||||
handler: async (req) => {
|
||||
assertEquals(await req.text(), "");
|
||||
promise.resolve();
|
||||
return new Response("ok");
|
||||
|
@ -1664,7 +1754,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
throw new Error("oops");
|
||||
},
|
||||
port: 4503,
|
||||
|
@ -1713,7 +1803,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
promise.resolve();
|
||||
return new Response(null, { status: 304 });
|
||||
},
|
||||
|
@ -1757,7 +1847,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (req) => {
|
||||
handler: async (req) => {
|
||||
promise.resolve();
|
||||
assertEquals(await req.text(), "hello");
|
||||
return new Response(null, { status: 304 });
|
||||
|
@ -1818,7 +1908,7 @@ Deno.test(
|
|||
const ac = new AbortController();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: async (req) => {
|
||||
handler: async (req) => {
|
||||
promise.resolve();
|
||||
assertEquals(await req.text(), "");
|
||||
return new Response(null, { status: 304 });
|
||||
|
@ -1872,7 +1962,7 @@ for (const [name, req] of badRequests) {
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => {
|
||||
handler: () => {
|
||||
throw new Error("oops");
|
||||
},
|
||||
port: 4503,
|
||||
|
@ -1917,7 +2007,7 @@ Deno.test(
|
|||
const listeningPromise = deferred();
|
||||
|
||||
const server = Deno.serve({
|
||||
fetch: () => new Response(null),
|
||||
handler: () => new Response(null),
|
||||
port: 4503,
|
||||
signal: ac.signal,
|
||||
onListen: onListen(listeningPromise),
|
||||
|
@ -1957,7 +2047,7 @@ Deno.test(
|
|||
let reqCount = -1;
|
||||
let timerId: number | undefined;
|
||||
const server = Deno.serve({
|
||||
fetch: async (req) => {
|
||||
handler: async (req) => {
|
||||
reqCount++;
|
||||
if (reqCount === 0) {
|
||||
const msg = new TextEncoder().encode("data: hello\r\n\r\n");
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
} = window.__bootstrap.webSocket;
|
||||
const { _ws } = window.__bootstrap.http;
|
||||
const {
|
||||
Function,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
PromiseResolve,
|
||||
TypedArrayPrototypeSubarray,
|
||||
TypeError,
|
||||
Uint8Array,
|
||||
|
@ -185,48 +187,76 @@
|
|||
return hostname === "0.0.0.0" ? "localhost" : hostname;
|
||||
}
|
||||
|
||||
function serve(opts = {}) {
|
||||
if (!("fetch" in opts)) {
|
||||
throw new TypeError("Options is missing 'fetch' handler");
|
||||
async function serve(arg1, arg2) {
|
||||
let options = undefined;
|
||||
let handler = undefined;
|
||||
if (arg1 instanceof Function) {
|
||||
handler = arg1;
|
||||
options = arg2;
|
||||
} else if (arg2 instanceof Function) {
|
||||
handler = arg2;
|
||||
options = arg1;
|
||||
} else {
|
||||
options = arg1;
|
||||
}
|
||||
if ("cert" in opts && !("key" in opts)) {
|
||||
throw new TypeError("Options is missing 'key' field");
|
||||
if (handler === undefined) {
|
||||
if (options === undefined) {
|
||||
throw new TypeError(
|
||||
"No handler was provided, so an options bag is mandatory.",
|
||||
);
|
||||
}
|
||||
handler = options.handler;
|
||||
}
|
||||
if ("key" in opts && !("cert" in opts)) {
|
||||
throw new TypeError("Options is missing 'cert' field");
|
||||
if (!(handler instanceof Function)) {
|
||||
throw new TypeError("A handler function must be provided.");
|
||||
}
|
||||
opts = { hostname: "127.0.0.1", port: 9000, ...opts };
|
||||
const handler = opts.fetch;
|
||||
delete opts.fetch;
|
||||
const signal = opts.signal;
|
||||
delete opts.signal;
|
||||
const onError = opts.onError ?? function (error) {
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const signal = options.signal;
|
||||
|
||||
const onError = options.onError ?? function (error) {
|
||||
console.error(error);
|
||||
return new Response("Internal Server Error", { status: 500 });
|
||||
};
|
||||
delete opts.onError;
|
||||
const onListen = opts.onListen ?? function ({ port }) {
|
||||
|
||||
const onListen = options.onListen ?? function ({ port }) {
|
||||
console.log(
|
||||
`Listening on http://${hostnameForDisplay(opts.hostname)}:${port}/`,
|
||||
`Listening on http://${
|
||||
hostnameForDisplay(listenOpts.hostname)
|
||||
}:${port}/`,
|
||||
);
|
||||
};
|
||||
delete opts.onListen;
|
||||
const serverId = core.ops.op_flash_serve(opts);
|
||||
|
||||
const listenOpts = {
|
||||
hostname: options.hostname ?? "127.0.0.1",
|
||||
port: options.port ?? 9000,
|
||||
};
|
||||
if (options.cert || options.key) {
|
||||
if (!options.cert || !options.key) {
|
||||
throw new TypeError(
|
||||
"Both cert and key must be provided to enable HTTPS.",
|
||||
);
|
||||
}
|
||||
listenOpts.cert = options.cert;
|
||||
listenOpts.key = options.key;
|
||||
}
|
||||
|
||||
const serverId = core.ops.op_flash_serve(listenOpts);
|
||||
const serverPromise = core.opAsync("op_flash_drive_server", serverId);
|
||||
|
||||
core.opAsync("op_flash_wait_for_listening", serverId).then((port) => {
|
||||
onListen({ hostname: opts.hostname, port });
|
||||
onListen({ hostname: listenOpts.hostname, port });
|
||||
});
|
||||
|
||||
const server = {
|
||||
id: serverId,
|
||||
transport: opts.cert && opts.key ? "https" : "http",
|
||||
hostname: opts.hostname,
|
||||
port: opts.port,
|
||||
transport: listenOpts.cert && listenOpts.key ? "https" : "http",
|
||||
hostname: listenOpts.hostname,
|
||||
port: listenOpts.port,
|
||||
closed: false,
|
||||
finished: (async () => {
|
||||
return await serverPromise;
|
||||
})(),
|
||||
finished: PromiseResolve(serverPromise),
|
||||
async close() {
|
||||
if (server.closed) {
|
||||
return;
|
||||
|
@ -520,7 +550,7 @@
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
return server.serve().catch(console.error);
|
||||
return await server.serve().catch(console.error);
|
||||
}
|
||||
|
||||
function createRequestBodyStream(serverId, token) {
|
||||
|
|
Loading…
Reference in a new issue