diff options
author | Matt Mastracci <matthew@mastracci.com> | 2023-04-27 00:58:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-27 00:58:18 +0200 |
commit | e2761df3fe2a457948948dcd38fb4f7e02cd350e (patch) | |
tree | 2924535980a53ff044b7ba9f6fc40522c1554679 /cli | |
parent | a8b4e346b4477e340f36a59f83a0974afd541f4b (diff) |
fix(ext/http): internal upgradeHttpRaw works with "Deno.serve()" API (#18859)
Fix internal "upgradeHttpRaw" API restoring capability to upgrade HTTP
connection in polyfilles "node:http" API.
Diffstat (limited to 'cli')
-rw-r--r-- | cli/bench/testdata/deno_upgrade_http.js | 12 | ||||
-rw-r--r-- | cli/tests/unit/serve_test.ts | 84 | ||||
-rw-r--r-- | cli/tsc/dts/lib.deno.unstable.d.ts | 19 |
3 files changed, 84 insertions, 31 deletions
diff --git a/cli/bench/testdata/deno_upgrade_http.js b/cli/bench/testdata/deno_upgrade_http.js deleted file mode 100644 index a959846ce..000000000 --- a/cli/bench/testdata/deno_upgrade_http.js +++ /dev/null @@ -1,12 +0,0 @@ -const { serve, upgradeHttpRaw } = Deno; -const u8 = Deno[Deno.internal].core.encode( - "HTTP/1.1 101 Switching Protocols\r\n\r\n", -); - -async function handler(req) { - const [conn, _firstPacket] = upgradeHttpRaw(req); - await conn.write(u8); - await conn.close(); -} - -serve({ hostname: "127.0.0.1", port: 9000 }, handler); diff --git a/cli/tests/unit/serve_test.ts b/cli/tests/unit/serve_test.ts index 6158f587e..5d5d0428f 100644 --- a/cli/tests/unit/serve_test.ts +++ b/cli/tests/unit/serve_test.ts @@ -17,6 +17,11 @@ import { } from "./test_util.ts"; import { consoleSize } from "../../../runtime/js/40_tty.js"; +const { + upgradeHttpRaw, + // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol +} = Deno[Deno.internal]; + function createOnErrorCb(ac: AbortController): (err: unknown) => Response { return (err) => { console.error(err); @@ -805,6 +810,85 @@ Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() { Deno.test( { permissions: { net: true } }, + async function httpServerWebSocketRaw() { + const ac = new AbortController(); + const listeningPromise = deferred(); + const server = Deno.serve({ + handler: async (request) => { + const { conn, response } = upgradeHttpRaw(request); + const buf = new Uint8Array(1024); + let read; + + // Write our fake HTTP upgrade + await conn.write( + new TextEncoder().encode( + "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgraded\r\n\r\nExtra", + ), + ); + + // Upgrade data + read = await conn.read(buf); + assertEquals( + new TextDecoder().decode(buf.subarray(0, read!)), + "Upgrade data", + ); + // Read the packet to echo + read = await conn.read(buf); + // Echo + await conn.write(buf.subarray(0, read!)); + + conn.close(); + return response; + }, + port: 4501, + signal: ac.signal, + onListen: onListen(listeningPromise), + onError: createOnErrorCb(ac), + }); + + await listeningPromise; + + const conn = await Deno.connect({ port: 4501 }); + await conn.write( + new TextEncoder().encode( + "GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\nUpgrade data", + ), + ); + const buf = new Uint8Array(1024); + let len; + + // Headers + let headers = ""; + for (let i = 0; i < 2; i++) { + len = await conn.read(buf); + headers += new TextDecoder().decode(buf.subarray(0, len!)); + if (headers.endsWith("Extra")) { + break; + } + } + assertMatch( + headers, + /HTTP\/1\.1 101 Switching Protocols[ ,.A-Za-z:0-9\r\n]*Extra/im, + ); + + // Data to echo + await conn.write(new TextEncoder().encode("buffer data")); + + // Echo + len = await conn.read(buf); + assertEquals( + new TextDecoder().decode(buf.subarray(0, len!)), + "buffer data", + ); + + conn.close(); + ac.abort(); + await server; + }, +); + +Deno.test( + { permissions: { net: true } }, async function httpServerWebSocketUpgradeTwice() { const ac = new AbortController(); const listeningPromise = deferred(); diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index dc3bfcfc0..f169e0254 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -1518,25 +1518,6 @@ declare namespace Deno { /** **UNSTABLE**: New API, yet to be vetted. * - * Allows "hijacking" the connection that the request is associated with. - * This can be used to implement protocols that build on top of HTTP (eg. - * {@linkcode WebSocket}). - * - * Unlike {@linkcode Deno.upgradeHttp} this function does not require that you - * respond to the request with a {@linkcode Response} object. Instead this - * function returns the underlying connection and first packet received - * immediately, and then the caller is responsible for writing the response to - * the connection. - * - * This method can only be called on requests originating the - * {@linkcode Deno.serve} server. - * - * @category HTTP Server - */ - export function upgradeHttpRaw(request: Request): [Deno.Conn, Uint8Array]; - - /** **UNSTABLE**: New API, yet to be vetted. - * * Open a new {@linkcode Deno.Kv} connection to persist data. * * When a path is provided, the database will be persisted to disk at that |