summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock24
-rw-r--r--Cargo.toml5
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/build.rs6
-rw-r--r--cli/dts/lib.deno.unstable.d.ts19
-rw-r--r--cli/main.rs1
-rw-r--r--cli/tsc.rs2
-rw-r--r--extensions/http/01_http.js (renamed from extensions/net/03_http.js)7
-rw-r--r--extensions/http/Cargo.toml25
-rw-r--r--extensions/http/README.md4
-rw-r--r--extensions/http/lib.deno_http.unstable.d.ts65
-rw-r--r--extensions/http/lib.rs (renamed from extensions/net/ops_http.rs)132
-rw-r--r--extensions/net/Cargo.toml9
-rw-r--r--extensions/net/lib.deno_net.unstable.d.ts44
-rw-r--r--extensions/net/lib.rs3
-rw-r--r--runtime/Cargo.toml2
-rw-r--r--runtime/build.rs1
-rw-r--r--runtime/js/40_http.js14
-rw-r--r--runtime/lib.rs1
-rw-r--r--runtime/ops/http.rs48
-rw-r--r--runtime/ops/mod.rs1
-rw-r--r--runtime/web_worker.rs2
-rw-r--r--runtime/worker.rs2
23 files changed, 270 insertions, 148 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 90650aa92..d1e00522f 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",
@@ -708,6 +709,21 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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 5e89d8ab8..d8ab443ce 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 3caddb69d..7fbd5b77d 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 f932d5eff..548fbb501 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 ac03e695c..199f05631 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -3,6 +3,7 @@
/// <reference no-default-lib="true" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.net_unstable" />
+/// <reference lib="deno.http_unstable" />
declare namespace Deno {
/**
@@ -1098,6 +1099,24 @@ declare namespace Deno {
write?: "inherit" | boolean | Array<string | URL>;
};
}
+
+ /** **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 93bae0220..77f8b34ba 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 593dd24fb..1b923aa3b 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
index db2d0a3b1..4bcdf1f07 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 000000000..8909301a6
--- /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 000000000..ab557017a
--- /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 000000000..30ffe121e
--- /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.
+
+/// <reference no-default-lib="true" />
+/// <reference lib="esnext" />
+
+declare namespace Deno {
+ export interface RequestEvent {
+ readonly request: Request;
+ respondWith(r: Response | Promise<Response>): Promise<void>;
+ }
+
+ export interface HttpConn extends AsyncIterable<RequestEvent> {
+ readonly rid: number;
+
+ nextRequest(): Promise<RequestEvent | null>;
+ 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
index 782ec91d0..a8d92ab46 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<OpPair> {
- 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<Box<dyn Future<Output = hyper::Result<()>>>>;
struct Conn {
scheme: &'static str,
+ addr: SocketAddr,
conn: Rc<RefCell<ConnFuture>>,
}
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<IO: AsyncRead + AsyncWrite + Unpin + Send + 'static>(
state: &mut OpState,
- tcp_stream_rid: ResourceId,
- _: (),
+ io: IO,
+ addr: SocketAddr,
+ scheme: &'static str,
) -> Result<ResourceId, AnyError> {
let deno_service = Service::default();
- if let Some(resource_rc) = state
- .resource_table
- .take::<TcpStreamResource>(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::<TlsStreamResource>(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 c6219cad4..352308925 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 c47558edc..adeeb1466 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<Response>): Promise<void>;
- }
-
- export interface HttpConn extends AsyncIterable<RequestEvent> {
- readonly rid: number;
-
- nextRequest(): Promise<RequestEvent | null>;
- 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 d1e836fce..f3281a2fb 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<P: NetPermissions + 'static>(unstable: bool) -> Extension {
ops_to_register.extend(io::init());
ops_to_register.extend(ops::init::<P>());
ops_to_register.extend(ops_tls::init::<P>());
- 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 a9ad9b384..65c9aa091 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 52433b70e..8c5772c67 100644
--- a/runtime/build.rs
+++ b/runtime/build.rs
@@ -60,6 +60,7 @@ fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
false, // No --unstable.
),
deno_net::init::<deno_net::NoNetPermissions>(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 000000000..d68b4f45c
--- /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 aa95aefbc..2358899d4 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 000000000..5b156fc11
--- /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<ResourceId, AnyError> {
+ if let Some(resource_rc) = state
+ .resource_table
+ .take::<TcpStreamResource>(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::<TlsStreamResource>(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 c94020780..82ccf0506 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 57a8142be..acafb086b 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 91810449d..41e63914d 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,
];