From f649960f87a408124b5b0d6f55f3be7f5724a4e7 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Mon, 12 Jul 2021 12:44:49 +0200 Subject: [PATCH] refactor: deno_http op crate (#11335) --- Cargo.lock | 24 +++- Cargo.toml | 5 + cli/Cargo.toml | 1 + cli/build.rs | 6 + cli/dts/lib.deno.unstable.d.ts | 19 +++ cli/main.rs | 1 + cli/tsc.rs | 2 + .../{net/03_http.js => http/01_http.js} | 7 +- extensions/http/Cargo.toml | 25 ++++ extensions/http/README.md | 4 + extensions/http/lib.deno_http.unstable.d.ts | 65 +++++++++ extensions/{net/ops_http.rs => http/lib.rs} | 132 +++++++----------- extensions/net/Cargo.toml | 9 +- extensions/net/lib.deno_net.unstable.d.ts | 44 ------ extensions/net/lib.rs | 3 - runtime/Cargo.toml | 2 + runtime/build.rs | 1 + runtime/js/40_http.js | 14 ++ runtime/lib.rs | 1 + runtime/ops/http.rs | 48 +++++++ runtime/ops/mod.rs | 1 + runtime/web_worker.rs | 2 + runtime/worker.rs | 2 + 23 files changed, 270 insertions(+), 148 deletions(-) rename extensions/{net/03_http.js => http/01_http.js} (98%) create mode 100644 extensions/http/Cargo.toml create mode 100644 extensions/http/README.md create mode 100644 extensions/http/lib.deno_http.unstable.d.ts rename extensions/{net/ops_http.rs => http/lib.rs} (85%) create mode 100644 runtime/js/40_http.js create mode 100644 runtime/ops/http.rs diff --git a/Cargo.lock b/Cargo.lock index 90650aa92f..d1e00522f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,6 +551,7 @@ dependencies = [ "deno_crypto", "deno_doc", "deno_fetch", + "deno_http", "deno_lint", "deno_net", "deno_runtime", @@ -707,6 +708,21 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "deno_http" +version = "0.1.0" +dependencies = [ + "base64 0.13.0", + "bytes", + "deno_core", + "deno_websocket", + "hyper", + "ring", + "serde", + "tokio", + "tokio-util", +] + [[package]] name = "deno_lint" version = "0.9.0" @@ -731,19 +747,12 @@ dependencies = [ name = "deno_net" version = "0.1.0" dependencies = [ - "base64 0.13.0", - "bytes", "deno_core", - "deno_websocket", - "http", - "hyper", "lazy_static", "log", - "ring", "rustls", "serde", "tokio", - "tokio-util", "trust-dns-proto", "trust-dns-resolver", "webpki", @@ -760,6 +769,7 @@ dependencies = [ "deno_core", "deno_crypto", "deno_fetch", + "deno_http", "deno_net", "deno_timers", "deno_url", diff --git a/Cargo.toml b/Cargo.toml index 5e89d8ab8f..d8ab443ce2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "extensions/console", "extensions/crypto", "extensions/fetch", + "extensions/http", "extensions/net", "extensions/timers", "extensions/url", @@ -55,6 +56,8 @@ opt-level = 3 opt-level = 3 [profile.bench.package.deno_runtime] opt-level = 3 +[profile.bench.package.deno_http] +opt-level = 3 [profile.bench.package.deno_net] opt-level = 3 [profile.bench.package.rusty_v8] @@ -81,6 +84,8 @@ opt-level = 3 opt-level = 3 [profile.release.package.deno_runtime] opt-level = 3 +[profile.release.package.deno_http] +opt-level = 3 [profile.release.package.deno_net] opt-level = 3 [profile.release.package.rusty_v8] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3caddb69d3..7fbd5b77d0 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -25,6 +25,7 @@ deno_console = { version = "0.10.0", path = "../extensions/console" } deno_core = { version = "0.92.0", path = "../core" } deno_crypto = { version = "0.24.0", path = "../extensions/crypto" } deno_fetch = { version = "0.32.0", path = "../extensions/fetch" } +deno_http = { version = "0.1.0", path = "../extensions/http" } deno_net = { version = "0.1.0", path = "../extensions/net" } deno_timers = { version = "0.8.0", path = "../extensions/timers" } deno_url = { version = "0.10.0", path = "../extensions/url" } diff --git a/cli/build.rs b/cli/build.rs index f932d5eff3..548fbb501a 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -71,6 +71,8 @@ fn create_compiler_snapshot( op_crate_libs.insert("deno.net", deno_net::get_declaration()); op_crate_libs .insert("deno.net_unstable", deno_net::get_unstable_declaration()); + op_crate_libs + .insert("deno.http_unstable", deno_http::get_unstable_declaration()); // ensure we invalidate the build properly. for (_, path) in op_crate_libs.iter() { @@ -313,6 +315,10 @@ fn main() { "cargo:rustc-env=DENO_NET_UNSTABLE_LIB_PATH={}", deno_net::get_unstable_declaration().display() ); + println!( + "cargo:rustc-env=DENO_HTTP_UNSTABLE_LIB_PATH={}", + deno_http::get_unstable_declaration().display() + ); println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index ac03e695cb..199f05631c 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -3,6 +3,7 @@ /// /// /// +/// declare namespace Deno { /** @@ -1098,6 +1099,24 @@ declare namespace Deno { write?: "inherit" | boolean | Array; }; } + + /** **UNSTABLE**: new API, yet to be vetted. + * + * Services HTTP requests given a TCP or TLS socket. + * + * ```ts + * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" }); + * const httpConn = Deno.serveHttp(conn); + * const e = await httpConn.nextRequest(); + * if (e) { + * e.respondWith(new Response("Hello World")); + * } + * ``` + * + * If `httpConn.nextRequest()` encounters an error or returns `null` + * then the underlying HttpConn resource is closed automatically. + */ + export function serveHttp(conn: Conn): HttpConn; } declare function fetch( diff --git a/cli/main.rs b/cli/main.rs index 93bae02206..77f8b34ba4 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -348,6 +348,7 @@ pub fn get_types(unstable: bool) -> String { if unstable { types.push(crate::tsc::UNSTABLE_NS_LIB); types.push(crate::tsc::DENO_NET_UNSTABLE_LIB); + types.push(crate::tsc::DENO_HTTP_UNSTABLE_LIB); } types.join("\n") diff --git a/cli/tsc.rs b/cli/tsc.rs index 593dd24fb7..1b923aa3b0 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -47,6 +47,8 @@ pub static DENO_BROADCAST_CHANNEL_LIB: &str = pub static DENO_NET_LIB: &str = include_str!(env!("DENO_NET_LIB_PATH")); pub static DENO_NET_UNSTABLE_LIB: &str = include_str!(env!("DENO_NET_UNSTABLE_LIB_PATH")); +pub static DENO_HTTP_UNSTABLE_LIB: &str = + include_str!(env!("DENO_HTTP_UNSTABLE_LIB_PATH")); pub static SHARED_GLOBALS_LIB: &str = include_str!("dts/lib.deno.shared_globals.d.ts"); pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts"); diff --git a/extensions/net/03_http.js b/extensions/http/01_http.js similarity index 98% rename from extensions/net/03_http.js rename to extensions/http/01_http.js index db2d0a3b12..4bcdf1f075 100644 --- a/extensions/net/03_http.js +++ b/extensions/http/01_http.js @@ -32,11 +32,6 @@ Uint8Array, } = window.__bootstrap.primordials; - function serveHttp(conn) { - const rid = core.opSync("op_http_start", conn.rid); - return new HttpConn(rid); - } - const connErrorSymbol = Symbol("connError"); class HttpConn { @@ -373,7 +368,7 @@ } window.__bootstrap.http = { - serveHttp, + HttpConn, upgradeWebSocket, }; })(this); diff --git a/extensions/http/Cargo.toml b/extensions/http/Cargo.toml new file mode 100644 index 0000000000..8909301a64 --- /dev/null +++ b/extensions/http/Cargo.toml @@ -0,0 +1,25 @@ +# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +[package] +name = "deno_http" +version = "0.1.0" +edition = "2018" +description = "HTTP server implementation for Deno" +authors = ["the Deno authors"] +license = "MIT" +readme = "README.md" +repository = "https://github.com/denoland/deno" + +[lib] +path = "lib.rs" + +[dependencies] +base64 = "0.13.0" +bytes = "1" +deno_core = { version = "0.92.0", path = "../../core" } +deno_websocket = { version = "0.15.1", path = "../websocket" } +hyper = { version = "0.14.9", features = ["server", "stream", "http1", "http2", "runtime"] } +ring = "0.16.20" +serde = { version = "1.0.125", features = ["derive"] } +tokio = { version = "1.8.0", features = ["full"] } +tokio-util = "0.6.7" diff --git a/extensions/http/README.md b/extensions/http/README.md new file mode 100644 index 0000000000..ab557017a5 --- /dev/null +++ b/extensions/http/README.md @@ -0,0 +1,4 @@ +# deno_http + +This crate implements server-side HTTP based on primitives from the +[Fetch API](https://fetch.spec.whatwg.org/). diff --git a/extensions/http/lib.deno_http.unstable.d.ts b/extensions/http/lib.deno_http.unstable.d.ts new file mode 100644 index 0000000000..30ffe121e2 --- /dev/null +++ b/extensions/http/lib.deno_http.unstable.d.ts @@ -0,0 +1,65 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +/// +/// + +declare namespace Deno { + export interface RequestEvent { + readonly request: Request; + respondWith(r: Response | Promise): Promise; + } + + export interface HttpConn extends AsyncIterable { + readonly rid: number; + + nextRequest(): Promise; + close(): void; + } + + export interface WebSocketUpgrade { + response: Response; + websocket: WebSocket; + } + + export interface UpgradeWebSocketOptions { + protocol?: string; + } + + /** **UNSTABLE**: new API, yet to be vetted. + * + * Used to upgrade an incoming HTTP request to a WebSocket. + * + * Given a request, returns a pair of WebSocket and Response. The original + * request must be responded to with the returned response for the websocket + * upgrade to be successful. + * + * ```ts + * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" }); + * const httpConn = Deno.serveHttp(conn); + * const e = await httpConn.nextRequest(); + * if (e) { + * const { websocket, response } = Deno.upgradeWebSocket(e.request); + * websocket.onopen = () => { + * websocket.send("Hello World!"); + * }; + * websocket.onmessage = (e) => { + * console.log(e.data); + * websocket.close(); + * }; + * websocket.onclose = () => console.log("WebSocket has been closed."); + * websocket.onerror = (e) => console.error("WebSocket error:", e.message); + * e.respondWith(response); + * } + * ``` + * + * If the request body is disturbed (read from) before the upgrade is + * completed, upgrading fails. + * + * This operation does not yet consume the request or open the websocket. This + * only happens once the returned response has been passed to `respondWith`. + */ + export function upgradeWebSocket( + request: Request, + options?: UpgradeWebSocketOptions, + ): WebSocketUpgrade; +} diff --git a/extensions/net/ops_http.rs b/extensions/http/lib.rs similarity index 85% rename from extensions/net/ops_http.rs rename to extensions/http/lib.rs index 782ec91d01..a8d92ab463 100644 --- a/extensions/net/ops_http.rs +++ b/extensions/http/lib.rs @@ -1,7 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use crate::io::TcpStreamResource; -use crate::io::TlsStreamResource; use deno_core::error::bad_resource_id; use deno_core::error::null_opbuf; use deno_core::error::type_error; @@ -10,13 +8,14 @@ use deno_core::futures::future::poll_fn; use deno_core::futures::FutureExt; use deno_core::futures::Stream; use deno_core::futures::StreamExt; +use deno_core::include_js_files; use deno_core::op_async; use deno_core::op_sync; use deno_core::AsyncRefCell; use deno_core::ByteString; use deno_core::CancelHandle; use deno_core::CancelTryFuture; -use deno_core::OpPair; +use deno_core::Extension; use deno_core::OpState; use deno_core::RcRef; use deno_core::Resource; @@ -35,31 +34,43 @@ use std::borrow::Cow; use std::cell::RefCell; use std::future::Future; use std::net::SocketAddr; +use std::path::PathBuf; use std::pin::Pin; use std::rc::Rc; use std::task::Context; use std::task::Poll; +use tokio::io::AsyncRead; use tokio::io::AsyncReadExt; +use tokio::io::AsyncWrite; use tokio::sync::oneshot; use tokio_util::io::StreamReader; -pub fn init() -> Vec { - vec![ - ("op_http_start", op_sync(op_http_start)), - ("op_http_request_next", op_async(op_http_request_next)), - ("op_http_request_read", op_async(op_http_request_read)), - ("op_http_response", op_async(op_http_response)), - ("op_http_response_write", op_async(op_http_response_write)), - ("op_http_response_close", op_async(op_http_response_close)), - ( - "op_http_websocket_accept_header", - op_sync(op_http_websocket_accept_header), - ), - ( - "op_http_upgrade_websocket", - op_async(op_http_upgrade_websocket), - ), - ] +pub fn get_unstable_declaration() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_http.unstable.d.ts") +} + +pub fn init() -> Extension { + Extension::builder() + .js(include_js_files!( + prefix "deno:extensions/http", + "01_http.js", + )) + .ops(vec![ + ("op_http_request_next", op_async(op_http_request_next)), + ("op_http_request_read", op_async(op_http_request_read)), + ("op_http_response", op_async(op_http_response)), + ("op_http_response_write", op_async(op_http_response_write)), + ("op_http_response_close", op_async(op_http_response_close)), + ( + "op_http_websocket_accept_header", + op_sync(op_http_websocket_accept_header), + ), + ( + "op_http_upgrade_websocket", + op_async(op_http_upgrade_websocket), + ), + ]) + .build() } struct ServiceInner { @@ -106,13 +117,13 @@ type ConnFuture = Pin>>>; struct Conn { scheme: &'static str, + addr: SocketAddr, conn: Rc>, } struct ConnResource { hyper_connection: Conn, deno_service: Service, - addr: SocketAddr, cancel: CancelHandle, } @@ -221,7 +232,7 @@ async fn op_http_request_next( } else if let Some(host) = req.headers().get("HOST") { Cow::Borrowed(host.to_str()?) } else { - Cow::Owned(conn_resource.addr.to_string()) + Cow::Owned(conn_resource.hyper_connection.addr.to_string()) }; let path = req.uri().path_and_query().map_or("/", |p| p.as_str()); format!("{}://{}{}", scheme, host, path) @@ -299,69 +310,30 @@ fn should_ignore_error(e: &AnyError) -> bool { false } -fn op_http_start( +pub fn start_http( state: &mut OpState, - tcp_stream_rid: ResourceId, - _: (), + io: IO, + addr: SocketAddr, + scheme: &'static str, ) -> Result { let deno_service = Service::default(); - if let Some(resource_rc) = state - .resource_table - .take::(tcp_stream_rid) - { - let resource = Rc::try_unwrap(resource_rc) - .expect("Only a single use of this resource should happen"); - let (read_half, write_half) = resource.into_inner(); - let tcp_stream = read_half.reunite(write_half)?; - let addr = tcp_stream.local_addr()?; - let hyper_connection = Http::new() - .with_executor(LocalExecutor) - .serve_connection(tcp_stream, deno_service.clone()) - .with_upgrades(); - let conn = Pin::new(Box::new(hyper_connection)); - let conn_resource = ConnResource { - hyper_connection: Conn { - conn: Rc::new(RefCell::new(conn)), - scheme: "http", - }, - deno_service, + let hyper_connection = Http::new() + .with_executor(LocalExecutor) + .serve_connection(io, deno_service.clone()) + .with_upgrades(); + let conn = Pin::new(Box::new(hyper_connection)); + let conn_resource = ConnResource { + hyper_connection: Conn { + scheme, addr, - cancel: CancelHandle::default(), - }; - let rid = state.resource_table.add(conn_resource); - return Ok(rid); - } - - if let Some(resource_rc) = state - .resource_table - .take::(tcp_stream_rid) - { - let resource = Rc::try_unwrap(resource_rc) - .expect("Only a single use of this resource should happen"); - let (read_half, write_half) = resource.into_inner(); - let tls_stream = read_half.reunite(write_half); - let addr = tls_stream.get_ref().0.local_addr()?; - - let hyper_connection = Http::new() - .with_executor(LocalExecutor) - .serve_connection(tls_stream, deno_service.clone()) - .with_upgrades(); - let conn = Pin::new(Box::new(hyper_connection)); - let conn_resource = ConnResource { - hyper_connection: Conn { - conn: Rc::new(RefCell::new(conn)), - scheme: "https", - }, - deno_service, - addr, - cancel: CancelHandle::default(), - }; - let rid = state.resource_table.add(conn_resource); - return Ok(rid); - } - - Err(bad_resource_id()) + conn: Rc::new(RefCell::new(conn)), + }, + deno_service, + cancel: CancelHandle::default(), + }; + let rid = state.resource_table.add(conn_resource); + Ok(rid) } // We use a tuple instead of struct to avoid serialization overhead of the keys. diff --git a/extensions/net/Cargo.toml b/extensions/net/Cargo.toml index c6219cad4e..3523089259 100644 --- a/extensions/net/Cargo.toml +++ b/extensions/net/Cargo.toml @@ -15,19 +15,12 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.92.0", path = "../../core" } -deno_websocket = { version = "0.15.0", path = "../websocket" } -base64 = "0.13.0" -bytes = "1" log = "0.4.14" lazy_static = "1.4.0" -http = "0.2.4" -hyper = { version = "0.14.10", features = ["server", "stream", "http1", "http2", "runtime"] } -ring = "0.16.20" -rustls = "0.19.1" +rustls = "0.19.0" serde = { version = "1.0.126", features = ["derive"] } tokio = { version = "1.8.1", features = ["full"] } -tokio-util = { version = "0.6", features = ["io"] } webpki = "0.21.4" webpki-roots = "0.21.1" trust-dns-proto = "0.20.3" diff --git a/extensions/net/lib.deno_net.unstable.d.ts b/extensions/net/lib.deno_net.unstable.d.ts index c47558edc9..adeeb14666 100644 --- a/extensions/net/lib.deno_net.unstable.d.ts +++ b/extensions/net/lib.deno_net.unstable.d.ts @@ -229,48 +229,4 @@ declare namespace Deno { */ alpnProtocols?: string[]; } - - export interface RequestEvent { - readonly request: Request; - respondWith(r: Response | Promise): Promise; - } - - export interface HttpConn extends AsyncIterable { - readonly rid: number; - - nextRequest(): Promise; - close(): void; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Services HTTP requests given a TCP or TLS socket. - * - * ```ts - * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" }); - * const httpConn = Deno.serveHttp(conn); - * const e = await httpConn.nextRequest(); - * if (e) { - * e.respondWith(new Response("Hello World")); - * } - * ``` - * - * If `httpConn.nextRequest()` encounters an error or returns `null` - * then the underlying HttpConn resource is closed automatically. - */ - export function serveHttp(conn: Conn): HttpConn; - - export interface WebSocketUpgrade { - response: Response; - websocket: WebSocket; - } - - export interface UpgradeWebSocketOptions { - protocol?: string; - } - - export function upgradeWebSocket( - request: Request, - options?: UpgradeWebSocketOptions, - ): WebSocketUpgrade; } diff --git a/extensions/net/lib.rs b/extensions/net/lib.rs index d1e836fce3..f3281a2fb6 100644 --- a/extensions/net/lib.rs +++ b/extensions/net/lib.rs @@ -2,7 +2,6 @@ pub mod io; pub mod ops; -pub mod ops_http; pub mod ops_tls; #[cfg(unix)] pub mod ops_unix; @@ -94,14 +93,12 @@ pub fn init(unstable: bool) -> Extension { ops_to_register.extend(io::init()); ops_to_register.extend(ops::init::

()); ops_to_register.extend(ops_tls::init::

()); - ops_to_register.extend(ops_http::init()); Extension::builder() .js(include_js_files!( prefix "deno:extensions/net", "01_net.js", "02_tls.js", - "03_http.js", "04_net_unstable.js", )) .ops(ops_to_register) diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index a9ad9b384b..65c9aa0914 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -23,6 +23,7 @@ deno_console = { version = "0.10.1", path = "../extensions/console" } deno_core = { version = "0.92.0", path = "../core" } deno_crypto = { version = "0.24.1", path = "../extensions/crypto" } deno_fetch = { version = "0.32.1", path = "../extensions/fetch" } +deno_http = { version = "0.1.0", path = "../extensions/http" } deno_net = { version = "0.1.0", path = "../extensions/net" } deno_timers = { version = "0.8.1", path = "../extensions/timers" } deno_url = { version = "0.10.1", path = "../extensions/url" } @@ -42,6 +43,7 @@ deno_console = { version = "0.10.1", path = "../extensions/console" } deno_core = { version = "0.92.0", path = "../core" } deno_crypto = { version = "0.24.1", path = "../extensions/crypto" } deno_fetch = { version = "0.32.1", path = "../extensions/fetch" } +deno_http = { version = "0.1.0", path = "../extensions/http" } deno_net = { version = "0.1.0", path = "../extensions/net" } deno_timers = { version = "0.8.1", path = "../extensions/timers" } deno_url = { version = "0.10.1", path = "../extensions/url" } diff --git a/runtime/build.rs b/runtime/build.rs index 52433b70e3..8c5772c67d 100644 --- a/runtime/build.rs +++ b/runtime/build.rs @@ -60,6 +60,7 @@ fn create_runtime_snapshot(snapshot_path: &Path, files: Vec) { false, // No --unstable. ), deno_net::init::(false), // No --unstable. + deno_http::init(), ]; let js_runtime = JsRuntime::new(RuntimeOptions { diff --git a/runtime/js/40_http.js b/runtime/js/40_http.js new file mode 100644 index 0000000000..d68b4f45ce --- /dev/null +++ b/runtime/js/40_http.js @@ -0,0 +1,14 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +"use strict"; + +((window) => { + const core = window.__bootstrap.core; + const { HttpConn } = window.__bootstrap.http; + + function serveHttp(conn) { + const rid = core.opSync("op_http_start", conn.rid); + return new HttpConn(rid); + } + + window.__bootstrap.http.serveHttp = serveHttp; +})(globalThis); diff --git a/runtime/lib.rs b/runtime/lib.rs index aa95aefbca..2358899d4a 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -4,6 +4,7 @@ pub use deno_broadcast_channel; pub use deno_console; pub use deno_crypto; pub use deno_fetch; +pub use deno_http; pub use deno_net; pub use deno_timers; pub use deno_url; diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs new file mode 100644 index 0000000000..5b156fc11c --- /dev/null +++ b/runtime/ops/http.rs @@ -0,0 +1,48 @@ +use std::rc::Rc; + +use deno_core::error::bad_resource_id; +use deno_core::error::AnyError; +use deno_core::op_sync; +use deno_core::Extension; +use deno_core::OpState; +use deno_core::ResourceId; +use deno_net::io::TcpStreamResource; +use deno_net::io::TlsStreamResource; + +pub fn init() -> Extension { + Extension::builder() + .ops(vec![("op_http_start", op_sync(op_http_start))]) + .build() +} + +fn op_http_start( + state: &mut OpState, + tcp_stream_rid: ResourceId, + _: (), +) -> Result { + if let Some(resource_rc) = state + .resource_table + .take::(tcp_stream_rid) + { + let resource = Rc::try_unwrap(resource_rc) + .expect("Only a single use of this resource should happen"); + let (read_half, write_half) = resource.into_inner(); + let tcp_stream = read_half.reunite(write_half)?; + let addr = tcp_stream.local_addr()?; + return deno_http::start_http(state, tcp_stream, addr, "http"); + } + + if let Some(resource_rc) = state + .resource_table + .take::(tcp_stream_rid) + { + let resource = Rc::try_unwrap(resource_rc) + .expect("Only a single use of this resource should happen"); + let (read_half, write_half) = resource.into_inner(); + let tls_stream = read_half.reunite(write_half); + let addr = tls_stream.get_ref().0.local_addr()?; + return deno_http::start_http(state, tls_stream, addr, "https"); + } + + Err(bad_resource_id()) +} diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs index c940207802..82ccf05060 100644 --- a/runtime/ops/mod.rs +++ b/runtime/ops/mod.rs @@ -2,6 +2,7 @@ pub mod fs; pub mod fs_events; +pub mod http; pub mod io; pub mod os; pub mod permissions; diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 57a8142be9..acafb086b8 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -339,6 +339,8 @@ impl WebWorker { ops::process::init(), ops::signal::init(), ops::tty::init(), + deno_http::init(), + ops::http::init(), ops::io::init_stdio(), ] } else { diff --git a/runtime/worker.rs b/runtime/worker.rs index 91810449d3..41e63914df 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -130,6 +130,8 @@ impl MainWorker { ops::process::init(), ops::signal::init(), ops::tty::init(), + deno_http::init(), + ops::http::init(), // Permissions ext (worker specific state) perm_ext, ];