summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2021-06-29 01:43:03 +0200
committerGitHub <noreply@github.com>2021-06-29 01:43:03 +0200
commit38a7128cdd6f3308ba3c13cfb0b0d4ef925a44c3 (patch)
tree8f0c86028d9ba0266f1846e7f3611f7049cb43a8
parent30cba2484815f712502ae8937a25afa13aba0818 (diff)
feat: Add "deno_net" extension (#11150)
This commits moves implementation of net related APIs available on "Deno" namespace to "deno_net" extension. Following APIs were moved: - Deno.listen() - Deno.connect() - Deno.listenTls() - Deno.serveHttp() - Deno.shutdown() - Deno.resolveDns() - Deno.listenDatagram() - Deno.startTls() - Deno.Conn - Deno.Listener - Deno.DatagramConn
-rw-r--r--Cargo.lock29
-rw-r--r--Cargo.toml1
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/build.rs11
-rw-r--r--cli/dts/lib.deno.ns.d.ts144
-rw-r--r--cli/dts/lib.deno.unstable.d.ts257
-rw-r--r--cli/main.rs2
-rw-r--r--cli/tests/integration/mod.rs6
-rw-r--r--cli/tsc.rs3
-rw-r--r--core/core.js19
-rw-r--r--extensions/net/01_net.js (renamed from runtime/js/30_net.js)24
-rw-r--r--extensions/net/02_tls.js (renamed from runtime/js/40_tls.js)0
-rw-r--r--extensions/net/03_http.js (renamed from runtime/js/40_http.js)10
-rw-r--r--extensions/net/04_net_unstable.js (renamed from runtime/js/40_net_unstable.js)0
-rw-r--r--extensions/net/Cargo.toml31
-rw-r--r--extensions/net/README.md30
-rw-r--r--extensions/net/io.rs232
-rw-r--r--extensions/net/lib.deno_net.d.ts149
-rw-r--r--extensions/net/lib.deno_net.unstable.d.ts262
-rw-r--r--extensions/net/lib.rs113
-rw-r--r--extensions/net/ops.rs (renamed from runtime/ops/net.rs)96
-rw-r--r--extensions/net/ops_http.rs (renamed from runtime/ops/http.rs)28
-rw-r--r--extensions/net/ops_tls.rs (renamed from runtime/ops/tls.rs)71
-rw-r--r--extensions/net/ops_unix.rs (renamed from runtime/ops/net_unix.rs)21
-rw-r--r--extensions/net/resolve_addr.rs (renamed from runtime/resolve_addr.rs)0
-rw-r--r--runtime/Cargo.toml9
-rw-r--r--runtime/build.rs1
-rw-r--r--runtime/js/01_errors.js17
-rw-r--r--runtime/lib.rs2
-rw-r--r--runtime/ops/io.rs129
-rw-r--r--runtime/ops/mod.rs5
-rw-r--r--runtime/permissions.rs17
-rw-r--r--runtime/web_worker.rs4
-rw-r--r--runtime/worker.rs4
34 files changed, 1049 insertions, 679 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5e7fed272..8c946a9de 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -536,6 +536,7 @@ dependencies = [
"deno_doc",
"deno_fetch",
"deno_lint",
+ "deno_net",
"deno_runtime",
"deno_timers",
"deno_url",
@@ -703,16 +704,36 @@ dependencies = [
]
[[package]]
+name = "deno_net"
+version = "0.1.0"
+dependencies = [
+ "bytes",
+ "deno_core",
+ "http",
+ "hyper",
+ "lazy_static",
+ "log",
+ "rustls",
+ "serde",
+ "tokio",
+ "tokio-util",
+ "trust-dns-proto",
+ "trust-dns-resolver",
+ "webpki",
+ "webpki-roots",
+]
+
+[[package]]
name = "deno_runtime"
version = "0.18.0"
dependencies = [
"atty",
- "bytes",
"deno_broadcast_channel",
"deno_console",
"deno_core",
"deno_crypto",
"deno_fetch",
+ "deno_net",
"deno_timers",
"deno_url",
"deno_web",
@@ -735,18 +756,12 @@ dependencies = [
"percent-encoding",
"regex",
"ring",
- "rustls",
"serde",
"sys-info",
"termcolor",
"test_util",
"tokio",
- "tokio-util",
- "trust-dns-proto",
- "trust-dns-resolver",
"uuid",
- "webpki",
- "webpki-roots",
"winapi 0.3.9",
"winres",
]
diff --git a/Cargo.toml b/Cargo.toml
index 178d9de9c..d7025513c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,6 +12,7 @@ members = [
"extensions/console",
"extensions/crypto",
"extensions/fetch",
+ "extensions/net",
"extensions/timers",
"extensions/url",
"extensions/web",
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 8052f06a5..c46bfb17a 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_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" }
deno_web = { version = "0.41.0", path = "../extensions/web" }
diff --git a/cli/build.rs b/cli/build.rs
index 5e872ab2c..f932d5eff 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -68,6 +68,9 @@ fn create_compiler_snapshot(
"deno.broadcast_channel",
deno_broadcast_channel::get_declaration(),
);
+ op_crate_libs.insert("deno.net", deno_net::get_declaration());
+ op_crate_libs
+ .insert("deno.net_unstable", deno_net::get_unstable_declaration());
// ensure we invalidate the build properly.
for (_, path) in op_crate_libs.iter() {
@@ -302,6 +305,14 @@ fn main() {
"cargo:rustc-env=DENO_BROADCAST_CHANNEL_LIB_PATH={}",
deno_broadcast_channel::get_declaration().display()
);
+ println!(
+ "cargo:rustc-env=DENO_NET_LIB_PATH={}",
+ deno_net::get_declaration().display()
+ );
+ println!(
+ "cargo:rustc-env=DENO_NET_UNSTABLE_LIB_PATH={}",
+ deno_net::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.ns.d.ts b/cli/dts/lib.deno.ns.d.ts
index e83858586..e1c558f37 100644
--- a/cli/dts/lib.deno.ns.d.ts
+++ b/cli/dts/lib.deno.ns.d.ts
@@ -2,6 +2,7 @@
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
+/// <reference lib="deno.net" />
/** Deno provides extra properties on `import.meta`. These are included here
* to ensure that these are still available when using the Deno namespace in
@@ -1784,149 +1785,6 @@ declare namespace Deno {
* Requires `allow-write` permission. */
export function truncate(name: string, len?: number): Promise<void>;
- export interface NetAddr {
- transport: "tcp" | "udp";
- hostname: string;
- port: number;
- }
-
- export interface UnixAddr {
- transport: "unix" | "unixpacket";
- path: string;
- }
-
- export type Addr = NetAddr | UnixAddr;
-
- /** A generic network listener for stream-oriented protocols. */
- export interface Listener extends AsyncIterable<Conn> {
- /** Waits for and resolves to the next connection to the `Listener`. */
- accept(): Promise<Conn>;
- /** Close closes the listener. Any pending accept promises will be rejected
- * with errors. */
- close(): void;
- /** Return the address of the `Listener`. */
- readonly addr: Addr;
-
- /** Return the rid of the `Listener`. */
- readonly rid: number;
-
- [Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
- }
-
- export interface Conn extends Reader, Writer, Closer {
- /** The local address of the connection. */
- readonly localAddr: Addr;
- /** The remote address of the connection. */
- readonly remoteAddr: Addr;
- /** The resource ID of the connection. */
- readonly rid: number;
- /** Shuts down (`shutdown(2)`) the write side of the connection. Most
- * callers should just use `close()`. */
- closeWrite(): Promise<void>;
- }
-
- export interface ListenOptions {
- /** The port to listen on. */
- port: number;
- /** A literal IP address or host name that can be resolved to an IP address.
- * If not specified, defaults to `0.0.0.0`. */
- hostname?: string;
- }
-
- /** Listen announces on the local transport address.
- *
- * ```ts
- * const listener1 = Deno.listen({ port: 80 })
- * const listener2 = Deno.listen({ hostname: "192.0.2.1", port: 80 })
- * const listener3 = Deno.listen({ hostname: "[2001:db8::1]", port: 80 });
- * const listener4 = Deno.listen({ hostname: "golang.org", port: 80, transport: "tcp" });
- * ```
- *
- * Requires `allow-net` permission. */
- export function listen(
- options: ListenOptions & { transport?: "tcp" },
- ): Listener;
-
- export interface ListenTlsOptions extends ListenOptions {
- /** Server certificate file. */
- certFile: string;
- /** Server public key file. */
- keyFile: string;
-
- transport?: "tcp";
- }
-
- /** Listen announces on the local transport address over TLS (transport layer
- * security).
- *
- * ```ts
- * const lstnr = Deno.listenTls({ port: 443, certFile: "./server.crt", keyFile: "./server.key" });
- * ```
- *
- * Requires `allow-net` permission. */
- export function listenTls(options: ListenTlsOptions): Listener;
-
- export interface ConnectOptions {
- /** The port to connect to. */
- port: number;
- /** A literal IP address or host name that can be resolved to an IP address.
- * If not specified, defaults to `127.0.0.1`. */
- hostname?: string;
- transport?: "tcp";
- }
-
- /**
- * Connects to the hostname (default is "127.0.0.1") and port on the named
- * transport (default is "tcp"), and resolves to the connection (`Conn`).
- *
- * ```ts
- * const conn1 = await Deno.connect({ port: 80 });
- * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 });
- * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 });
- * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" });
- * ```
- *
- * Requires `allow-net` permission for "tcp". */
- export function connect(options: ConnectOptions): Promise<Conn>;
-
- export interface ConnectTlsOptions {
- /** The port to connect to. */
- port: number;
- /** A literal IP address or host name that can be resolved to an IP address.
- * If not specified, defaults to `127.0.0.1`. */
- hostname?: string;
- /** Server certificate file. */
- certFile?: string;
- }
-
- /** Establishes a secure connection over TLS (transport layer security) using
- * an optional cert file, hostname (default is "127.0.0.1") and port. The
- * cert file is optional and if not included Mozilla's root certificates will
- * be used (see also https://github.com/ctz/webpki-roots for specifics)
- *
- * ```ts
- * const conn1 = await Deno.connectTls({ port: 80 });
- * const conn2 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "192.0.2.1", port: 80 });
- * const conn3 = await Deno.connectTls({ hostname: "[2001:db8::1]", port: 80 });
- * const conn4 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "golang.org", port: 80});
- * ```
- *
- * Requires `allow-net` permission.
- */
- export function connectTls(options: ConnectTlsOptions): Promise<Conn>;
-
- /** Shutdown socket send operations.
- *
- * Matches behavior of POSIX shutdown(3).
- *
- * ```ts
- * const listener = Deno.listen({ port: 80 });
- * const conn = await listener.accept();
- * Deno.shutdown(conn.rid);
- * ```
- */
- export function shutdown(rid: number): Promise<void>;
-
export interface Metrics {
opsDispatched: number;
opsDispatchedSync: number;
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts
index 1d01a748e..ac03e695c 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -2,6 +2,7 @@
/// <reference no-default-lib="true" />
/// <reference lib="deno.ns" />
+/// <reference lib="deno.net_unstable" />
declare namespace Deno {
/**
@@ -812,232 +813,6 @@ declare namespace Deno {
mtime: number | Date,
): Promise<void>;
- /** The type of the resource record.
- * Only the listed types are supported currently. */
- export type RecordType =
- | "A"
- | "AAAA"
- | "ANAME"
- | "CNAME"
- | "MX"
- | "PTR"
- | "SRV"
- | "TXT";
-
- export interface ResolveDnsOptions {
- /** The name server to be used for lookups.
- * If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
- nameServer?: {
- /** The IP address of the name server */
- ipAddr: string;
- /** The port number the query will be sent to.
- * If not specified, defaults to 53. */
- port?: number;
- };
- }
-
- /** If `resolveDns` is called with "MX" record type specified, it will return an array of this interface. */
- export interface MXRecord {
- preference: number;
- exchange: string;
- }
-
- /** If `resolveDns` is called with "SRV" record type specified, it will return an array of this interface. */
- export interface SRVRecord {
- priority: number;
- weight: number;
- port: number;
- target: string;
- }
-
- export function resolveDns(
- query: string,
- recordType: "A" | "AAAA" | "ANAME" | "CNAME" | "PTR",
- options?: ResolveDnsOptions,
- ): Promise<string[]>;
-
- export function resolveDns(
- query: string,
- recordType: "MX",
- options?: ResolveDnsOptions,
- ): Promise<MXRecord[]>;
-
- export function resolveDns(
- query: string,
- recordType: "SRV",
- options?: ResolveDnsOptions,
- ): Promise<SRVRecord[]>;
-
- export function resolveDns(
- query: string,
- recordType: "TXT",
- options?: ResolveDnsOptions,
- ): Promise<string[][]>;
-
- /** ** UNSTABLE**: new API, yet to be vetted.
- *
- * Performs DNS resolution against the given query, returning resolved records.
- * Fails in the cases such as:
- * - the query is in invalid format
- * - the options have an invalid parameter, e.g. `nameServer.port` is beyond the range of 16-bit unsigned integer
- * - timed out
- *
- * ```ts
- * const a = await Deno.resolveDns("example.com", "A");
- *
- * const aaaa = await Deno.resolveDns("example.com", "AAAA", {
- * nameServer: { ipAddr: "8.8.8.8", port: 1234 },
- * });
- * ```
- *
- * Requires `allow-net` permission.
- */
- export function resolveDns(
- query: string,
- recordType: RecordType,
- options?: ResolveDnsOptions,
- ): Promise<string[] | MXRecord[] | SRVRecord[] | string[][]>;
-
- /** **UNSTABLE**: new API, yet to be vetted.
- *
- * A generic transport listener for message-oriented protocols. */
- export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> {
- /** **UNSTABLE**: new API, yet to be vetted.
- *
- * Waits for and resolves to the next message to the `UDPConn`. */
- receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>;
- /** UNSTABLE: new API, yet to be vetted.
- *
- * Sends a message to the target. */
- send(p: Uint8Array, addr: Addr): Promise<number>;
- /** UNSTABLE: new API, yet to be vetted.
- *
- * Close closes the socket. Any pending message promises will be rejected
- * with errors. */
- close(): void;
- /** Return the address of the `UDPConn`. */
- readonly addr: Addr;
- [Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]>;
- }
-
- export interface UnixListenOptions {
- /** A Path to the Unix Socket. */
- path: string;
- }
-
- /** **UNSTABLE**: new API, yet to be vetted.
- *
- * Listen announces on the local transport address.
- *
- * ```ts
- * const listener = Deno.listen({ path: "/foo/bar.sock", transport: "unix" })
- * ```
- *
- * Requires `allow-read` and `allow-write` permission. */
- export function listen(
- options: UnixListenOptions & { transport: "unix" },
- ): Listener;
-
- /** **UNSTABLE**: new API, yet to be vetted
- *
- * Listen announces on the local transport address.
- *
- * ```ts
- * const listener1 = Deno.listenDatagram({
- * port: 80,
- * transport: "udp"
- * });
- * const listener2 = Deno.listenDatagram({
- * hostname: "golang.org",
- * port: 80,
- * transport: "udp"
- * });
- * ```
- *
- * Requires `allow-net` permission. */
- export function listenDatagram(
- options: ListenOptions & { transport: "udp" },
- ): DatagramConn;
-
- /** **UNSTABLE**: new API, yet to be vetted
- *
- * Listen announces on the local transport address.
- *
- * ```ts
- * const listener = Deno.listenDatagram({
- * path: "/foo/bar.sock",
- * transport: "unixpacket"
- * });
- * ```
- *
- * Requires `allow-read` and `allow-write` permission. */
- export function listenDatagram(
- options: UnixListenOptions & { transport: "unixpacket" },
- ): DatagramConn;
-
- export interface UnixConnectOptions {
- transport: "unix";
- path: string;
- }
-
- /** **UNSTABLE**: The unix socket transport is unstable as a new API yet to
- * be vetted. The TCP transport is considered stable.
- *
- * Connects to the hostname (default is "127.0.0.1") and port on the named
- * transport (default is "tcp"), and resolves to the connection (`Conn`).
- *
- * ```ts
- * const conn1 = await Deno.connect({ port: 80 });
- * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 });
- * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 });
- * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" });
- * const conn5 = await Deno.connect({ path: "/foo/bar.sock", transport: "unix" });
- * ```
- *
- * Requires `allow-net` permission for "tcp" and `allow-read` for "unix". */
- export function connect(
- options: ConnectOptions | UnixConnectOptions,
- ): Promise<Conn>;
-
- export interface StartTlsOptions {
- /** A literal IP address or host name that can be resolved to an IP address.
- * If not specified, defaults to `127.0.0.1`. */
- hostname?: string;
- /** Server certificate file. */
- certFile?: string;
- }
-
- /** **UNSTABLE**: new API, yet to be vetted.
- *
- * Start TLS handshake from an existing connection using
- * an optional cert file, hostname (default is "127.0.0.1"). The
- * cert file is optional and if not included Mozilla's root certificates will
- * be used (see also https://github.com/ctz/webpki-roots for specifics)
- * Using this function requires that the other end of the connection is
- * prepared for TLS handshake.
- *
- * ```ts
- * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" });
- * const tlsConn = await Deno.startTls(conn, { certFile: "./certs/my_custom_root_CA.pem", hostname: "localhost" });
- * ```
- *
- * Requires `allow-net` permission.
- */
- export function startTls(
- conn: Conn,
- options?: StartTlsOptions,
- ): Promise<Conn>;
-
- export interface ListenTlsOptions {
- /** **UNSTABLE**: new API, yet to be vetted.
- *
- * Application-Layer Protocol Negotiation (ALPN) protocols to announce to
- * the client. If not specified, no ALPN extension will be included in the
- * TLS handshake.
- */
- alpnProtocols?: string[];
- }
-
/** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal
* enum.
*
@@ -1182,36 +957,6 @@ declare namespace Deno {
bytesReceived: number;
}
- 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;
-
/** **UNSTABLE**: New option, yet to be vetted. */
export interface TestDefinition {
/** Specifies the permissions that should be used to run the test.
diff --git a/cli/main.rs b/cli/main.rs
index 38db7d13f..f1cf67ac4 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -334,12 +334,14 @@ pub fn get_types(unstable: bool) -> String {
crate::tsc::DENO_WEBSTORAGE_LIB,
crate::tsc::DENO_CRYPTO_LIB,
crate::tsc::DENO_BROADCAST_CHANNEL_LIB,
+ crate::tsc::DENO_NET_LIB,
crate::tsc::SHARED_GLOBALS_LIB,
crate::tsc::WINDOW_LIB,
];
if unstable {
types.push(crate::tsc::UNSTABLE_NS_LIB);
+ types.push(crate::tsc::DENO_NET_UNSTABLE_LIB);
}
types.join("\n")
diff --git a/cli/tests/integration/mod.rs b/cli/tests/integration/mod.rs
index fab2f20a5..c11d26dc9 100644
--- a/cli/tests/integration/mod.rs
+++ b/cli/tests/integration/mod.rs
@@ -2,9 +2,9 @@
use crate::itest;
use deno_core::url;
-use deno_runtime::ops::tls::rustls;
-use deno_runtime::ops::tls::webpki;
-use deno_runtime::ops::tls::TlsStream;
+use deno_runtime::deno_net::ops_tls::rustls;
+use deno_runtime::deno_net::ops_tls::webpki;
+use deno_runtime::deno_net::ops_tls::TlsStream;
use std::fs;
use std::io::BufReader;
use std::io::Cursor;
diff --git a/cli/tsc.rs b/cli/tsc.rs
index 3e7974a97..59b4ac81a 100644
--- a/cli/tsc.rs
+++ b/cli/tsc.rs
@@ -44,6 +44,9 @@ pub static DENO_WEBSTORAGE_LIB: &str =
pub static DENO_CRYPTO_LIB: &str = include_str!(env!("DENO_CRYPTO_LIB_PATH"));
pub static DENO_BROADCAST_CHANNEL_LIB: &str =
include_str!(env!("DENO_BROADCAST_CHANNEL_LIB_PATH"));
+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 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/core/core.js b/core/core.js
index 8e06a3e45..9ce563869 100644
--- a/core/core.js
+++ b/core/core.js
@@ -132,6 +132,23 @@
opSync("op_print", str, isErr);
}
+ // Some "extensions" rely on "BadResource" and "Interrupted" errors in the
+ // JS code (eg. "deno_net") so they are provided in "Deno.core" but later
+ // reexported on "Deno.errors"
+ class BadResource extends Error {
+ constructor(msg) {
+ super(msg);
+ this.name = "BadResource";
+ }
+ }
+
+ class Interrupted extends Error {
+ constructor(msg) {
+ super(msg);
+ this.name = "Interrupted";
+ }
+ }
+
// Provide bootstrap namespace
window.__bootstrap = {};
// Extra Deno.core.* exports
@@ -146,5 +163,7 @@
registerErrorClass,
handleAsyncMsgFromRust,
syncOpsCache,
+ BadResource,
+ Interrupted,
});
})(this);
diff --git a/runtime/js/30_net.js b/extensions/net/01_net.js
index 2d4b1e48e..9a531bd94 100644
--- a/runtime/js/30_net.js
+++ b/extensions/net/01_net.js
@@ -3,11 +3,25 @@
((window) => {
const core = window.Deno.core;
- const { errors } = window.__bootstrap.errors;
- const { read, write } = window.__bootstrap.io;
+ const { BadResource } = core;
+
+ async function read(
+ rid,
+ buffer,
+ ) {
+ if (buffer.length === 0) {
+ return 0;
+ }
+ const nread = await core.opAsync("op_net_read_async", rid, buffer);
+ return nread === 0 ? null : nread;
+ }
+
+ async function write(rid, data) {
+ return await core.opAsync("op_net_write_async", rid, data);
+ }
function shutdown(rid) {
- return core.opAsync("op_shutdown", rid);
+ return core.opAsync("op_net_shutdown", rid);
}
function opAccept(rid, transport) {
@@ -104,7 +118,7 @@
try {
conn = await this.accept();
} catch (error) {
- if (error instanceof errors.BadResource) {
+ if (error instanceof BadResource) {
return { value: undefined, done: true };
}
throw error;
@@ -171,7 +185,7 @@
try {
yield await this.receive();
} catch (err) {
- if (err instanceof errors.BadResource) {
+ if (err instanceof BadResource) {
break;
}
throw err;
diff --git a/runtime/js/40_tls.js b/extensions/net/02_tls.js
index 4fafe9079..4fafe9079 100644
--- a/runtime/js/40_tls.js
+++ b/extensions/net/02_tls.js
diff --git a/runtime/js/40_http.js b/extensions/net/03_http.js
index 5aa57238b..d5054bd1a 100644
--- a/runtime/js/40_http.js
+++ b/extensions/net/03_http.js
@@ -5,8 +5,8 @@
const { InnerBody } = window.__bootstrap.fetchBody;
const { Response, fromInnerRequest, toInnerResponse, newInnerRequest } =
window.__bootstrap.fetch;
- const errors = window.__bootstrap.errors.errors;
const core = window.Deno.core;
+ const { BadResource, Interrupted } = core;
const { ReadableStream } = window.__bootstrap.streams;
const abortSignal = window.__bootstrap.abortSignal;
@@ -42,9 +42,9 @@
// a generic `BadResource` error. Instead store this error and replace
// those with it.
this[connErrorSymbol] = error;
- if (error instanceof errors.BadResource) {
+ if (error instanceof BadResource) {
return null;
- } else if (error instanceof errors.Interrupted) {
+ } else if (error instanceof Interrupted) {
return null;
} else if (error.message.includes("connection closed")) {
return null;
@@ -159,7 +159,7 @@
], respBody instanceof Uint8Array ? respBody : null);
} catch (error) {
const connError = httpConn[connErrorSymbol];
- if (error instanceof errors.BadResource && connError != null) {
+ if (error instanceof BadResource && connError != null) {
// deno-lint-ignore no-ex-assign
error = new connError.constructor(connError.message);
}
@@ -192,7 +192,7 @@
);
} catch (error) {
const connError = httpConn[connErrorSymbol];
- if (error instanceof errors.BadResource && connError != null) {
+ if (error instanceof BadResource && connError != null) {
// deno-lint-ignore no-ex-assign
error = new connError.constructor(connError.message);
}
diff --git a/runtime/js/40_net_unstable.js b/extensions/net/04_net_unstable.js
index ca265bfaa..ca265bfaa 100644
--- a/runtime/js/40_net_unstable.js
+++ b/extensions/net/04_net_unstable.js
diff --git a/extensions/net/Cargo.toml b/extensions/net/Cargo.toml
new file mode 100644
index 000000000..9d5e97bbb
--- /dev/null
+++ b/extensions/net/Cargo.toml
@@ -0,0 +1,31 @@
+# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+[package]
+name = "deno_net"
+version = "0.1.0"
+edition = "2018"
+description = "Networking for Deno"
+authors = ["the Deno authors"]
+license = "MIT"
+readme = "README.md"
+repository = "https://github.com/denoland/deno"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+deno_core = { version = "0.92.0", path = "../../core" }
+
+bytes = "1"
+log = "0.4.14"
+lazy_static = "1.4.0"
+http = "0.2.3"
+hyper = { version = "0.14.9", features = ["server", "stream", "http1", "http2", "runtime"] }
+rustls = "0.19.0"
+serde = { version = "1.0.125", features = ["derive"] }
+tokio = { version = "1.7.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"
+trust-dns-resolver = { version = "0.20.3", features = ["tokio-runtime", "serde-config"] }
diff --git a/extensions/net/README.md b/extensions/net/README.md
new file mode 100644
index 000000000..cdd8923e1
--- /dev/null
+++ b/extensions/net/README.md
@@ -0,0 +1,30 @@
+# deno_net
+
+This crate implements networking APIs.
+
+This crate depends on following extensions:
+
+- "deno_web"
+- "deno_fetch"
+
+Following ops are provided:
+
+- "op_net_read_async"
+- "op_net_write_async"
+- "op_net_shutdown"
+- "op_accept"
+- "op_connect"
+- "op_listen"
+- "op_datagram_receive"
+- "op_datagram_send"
+- "op_dns_resolve"
+- "op_start_tls"
+- "op_connect_tls"
+- "op_listen_tls"
+- "op_accept_tls"
+- "op_http_start"
+- "op_http_request_next"
+- "op_http_request_read"
+- "op_http_response"
+- "op_http_response_write"
+- "op_http_response_close"
diff --git a/extensions/net/io.rs b/extensions/net/io.rs
new file mode 100644
index 000000000..fc10d7e99
--- /dev/null
+++ b/extensions/net/io.rs
@@ -0,0 +1,232 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+use crate::ops_tls as tls;
+use deno_core::error::null_opbuf;
+use deno_core::error::AnyError;
+use deno_core::error::{bad_resource_id, not_supported};
+use deno_core::op_async;
+use deno_core::AsyncMutFuture;
+use deno_core::AsyncRefCell;
+use deno_core::CancelHandle;
+use deno_core::CancelTryFuture;
+use deno_core::OpPair;
+use deno_core::OpState;
+use deno_core::RcRef;
+use deno_core::Resource;
+use deno_core::ResourceId;
+use deno_core::ZeroCopyBuf;
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::rc::Rc;
+use tokio::io::AsyncRead;
+use tokio::io::AsyncReadExt;
+use tokio::io::AsyncWrite;
+use tokio::io::AsyncWriteExt;
+use tokio::net::tcp;
+
+#[cfg(unix)]
+use tokio::net::unix;
+
+pub fn init() -> Vec<OpPair> {
+ vec![
+ ("op_net_read_async", op_async(op_read_async)),
+ ("op_net_write_async", op_async(op_write_async)),
+ ("op_net_shutdown", op_async(op_shutdown)),
+ ]
+}
+
+/// A full duplex resource has a read and write ends that are completely
+/// independent, like TCP/Unix sockets and TLS streams.
+#[derive(Debug)]
+pub struct FullDuplexResource<R, W> {
+ rd: AsyncRefCell<R>,
+ wr: AsyncRefCell<W>,
+ // When a full-duplex resource is closed, all pending 'read' ops are
+ // canceled, while 'write' ops are allowed to complete. Therefore only
+ // 'read' futures should be attached to this cancel handle.
+ cancel_handle: CancelHandle,
+}
+
+impl<R, W> FullDuplexResource<R, W>
+where
+ R: AsyncRead + Unpin + 'static,
+ W: AsyncWrite + Unpin + 'static,
+{
+ pub fn new((rd, wr): (R, W)) -> Self {
+ Self {
+ rd: rd.into(),
+ wr: wr.into(),
+ cancel_handle: Default::default(),
+ }
+ }
+
+ pub fn into_inner(self) -> (R, W) {
+ (self.rd.into_inner(), self.wr.into_inner())
+ }
+
+ pub fn rd_borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<R> {
+ RcRef::map(self, |r| &r.rd).borrow_mut()
+ }
+
+ pub fn wr_borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<W> {
+ RcRef::map(self, |r| &r.wr).borrow_mut()
+ }
+
+ pub fn cancel_handle(self: &Rc<Self>) -> RcRef<CancelHandle> {
+ RcRef::map(self, |r| &r.cancel_handle)
+ }
+
+ pub fn cancel_read_ops(&self) {
+ self.cancel_handle.cancel()
+ }
+
+ pub async fn read(
+ self: &Rc<Self>,
+ buf: &mut [u8],
+ ) -> Result<usize, AnyError> {
+ let mut rd = self.rd_borrow_mut().await;
+ let nread = rd.read(buf).try_or_cancel(self.cancel_handle()).await?;
+ Ok(nread)
+ }
+
+ pub async fn write(self: &Rc<Self>, buf: &[u8]) -> Result<usize, AnyError> {
+ let mut wr = self.wr_borrow_mut().await;
+ let nwritten = wr.write(buf).await?;
+ Ok(nwritten)
+ }
+
+ pub async fn shutdown(self: &Rc<Self>) -> Result<(), AnyError> {
+ let mut wr = self.wr_borrow_mut().await;
+ wr.shutdown().await?;
+ Ok(())
+ }
+}
+
+pub type TcpStreamResource =
+ FullDuplexResource<tcp::OwnedReadHalf, tcp::OwnedWriteHalf>;
+
+impl Resource for TcpStreamResource {
+ fn name(&self) -> Cow<str> {
+ "tcpStream".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ self.cancel_read_ops();
+ }
+}
+
+pub type TlsStreamResource = FullDuplexResource<tls::ReadHalf, tls::WriteHalf>;
+
+impl Resource for TlsStreamResource {
+ fn name(&self) -> Cow<str> {
+ "tlsStream".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ self.cancel_read_ops();
+ }
+}
+
+#[cfg(unix)]
+pub type UnixStreamResource =
+ FullDuplexResource<unix::OwnedReadHalf, unix::OwnedWriteHalf>;
+
+#[cfg(not(unix))]
+pub struct UnixStreamResource;
+
+#[cfg(not(unix))]
+impl UnixStreamResource {
+ pub async fn read(
+ self: &Rc<Self>,
+ _buf: &mut [u8],
+ ) -> Result<usize, AnyError> {
+ unreachable!()
+ }
+ pub async fn write(self: &Rc<Self>, _buf: &[u8]) -> Result<usize, AnyError> {
+ unreachable!()
+ }
+ pub async fn shutdown(self: &Rc<Self>) -> Result<(), AnyError> {
+ unreachable!()
+ }
+ pub fn cancel_read_ops(&self) {
+ unreachable!()
+ }
+}
+
+impl Resource for UnixStreamResource {
+ fn name(&self) -> Cow<str> {
+ "unixStream".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ self.cancel_read_ops();
+ }
+}
+
+async fn op_read_async(
+ state: Rc<RefCell<OpState>>,
+ rid: ResourceId,
+ buf: Option<ZeroCopyBuf>,
+) -> Result<u32, AnyError> {
+ let buf = &mut buf.ok_or_else(null_opbuf)?;
+ let resource = state
+ .borrow()
+ .resource_table
+ .get_any(rid)
+ .ok_or_else(bad_resource_id)?;
+ let nread = if let Some(s) = resource.downcast_rc::<TcpStreamResource>() {
+ s.read(buf).await?
+ } else if let Some(s) = resource.downcast_rc::<TlsStreamResource>() {
+ s.read(buf).await?
+ } else if let Some(s) = resource.downcast_rc::<UnixStreamResource>() {
+ s.read(buf).await?
+ } else {
+ return Err(not_supported());
+ };
+ Ok(nread as u32)
+}
+
+async fn op_write_async(
+ state: Rc<RefCell<OpState>>,
+ rid: ResourceId,
+ buf: Option<ZeroCopyBuf>,
+) -> Result<u32, AnyError> {
+ let buf = &buf.ok_or_else(null_opbuf)?;
+ let resource = state
+ .borrow()
+ .resource_table
+ .get_any(rid)
+ .ok_or_else(bad_resource_id)?;
+ let nwritten = if let Some(s) = resource.downcast_rc::<TcpStreamResource>() {
+ s.write(buf).await?
+ } else if let Some(s) = resource.downcast_rc::<TlsStreamResource>() {
+ s.write(buf).await?
+ } else if let Some(s) = resource.downcast_rc::<UnixStreamResource>() {
+ s.write(buf).await?
+ } else {
+ return Err(not_supported());
+ };
+ Ok(nwritten as u32)
+}
+
+async fn op_shutdown(
+ state: Rc<RefCell<OpState>>,
+ rid: ResourceId,
+ _: (),
+) -> Result<(), AnyError> {
+ let resource = state
+ .borrow()
+ .resource_table
+ .get_any(rid)
+ .ok_or_else(bad_resource_id)?;
+ if let Some(s) = resource.downcast_rc::<TcpStreamResource>() {
+ s.shutdown().await?;
+ } else if let Some(s) = resource.downcast_rc::<TlsStreamResource>() {
+ s.shutdown().await?;
+ } else if let Some(s) = resource.downcast_rc::<UnixStreamResource>() {
+ s.shutdown().await?;
+ } else {
+ return Err(not_supported());
+ }
+ Ok(())
+}
diff --git a/extensions/net/lib.deno_net.d.ts b/extensions/net/lib.deno_net.d.ts
new file mode 100644
index 000000000..25397f960
--- /dev/null
+++ b/extensions/net/lib.deno_net.d.ts
@@ -0,0 +1,149 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+/// <reference no-default-lib="true" />
+/// <reference lib="esnext" />
+
+declare namespace Deno {
+ export interface NetAddr {
+ transport: "tcp" | "udp";
+ hostname: string;
+ port: number;
+ }
+
+ export interface UnixAddr {
+ transport: "unix" | "unixpacket";
+ path: string;
+ }
+
+ export type Addr = NetAddr | UnixAddr;
+
+ /** A generic network listener for stream-oriented protocols. */
+ export interface Listener extends AsyncIterable<Conn> {
+ /** Waits for and resolves to the next connection to the `Listener`. */
+ accept(): Promise<Conn>;
+ /** Close closes the listener. Any pending accept promises will be rejected
+ * with errors. */
+ close(): void;
+ /** Return the address of the `Listener`. */
+ readonly addr: Addr;
+
+ /** Return the rid of the `Listener`. */
+ readonly rid: number;
+
+ [Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
+ }
+
+ export interface Conn extends Reader, Writer, Closer {
+ /** The local address of the connection. */
+ readonly localAddr: Addr;
+ /** The remote address of the connection. */
+ readonly remoteAddr: Addr;
+ /** The resource ID of the connection. */
+ readonly rid: number;
+ /** Shuts down (`shutdown(2)`) the write side of the connection. Most
+ * callers should just use `close()`. */
+ closeWrite(): Promise<void>;
+ }
+
+ export interface ListenOptions {
+ /** The port to listen on. */
+ port: number;
+ /** A literal IP address or host name that can be resolved to an IP address.
+ * If not specified, defaults to `0.0.0.0`. */
+ hostname?: string;
+ }
+
+ /** Listen announces on the local transport address.
+ *
+ * ```ts
+ * const listener1 = Deno.listen({ port: 80 })
+ * const listener2 = Deno.listen({ hostname: "192.0.2.1", port: 80 })
+ * const listener3 = Deno.listen({ hostname: "[2001:db8::1]", port: 80 });
+ * const listener4 = Deno.listen({ hostname: "golang.org", port: 80, transport: "tcp" });
+ * ```
+ *
+ * Requires `allow-net` permission. */
+ export function listen(
+ options: ListenOptions & { transport?: "tcp" },
+ ): Listener;
+
+ export interface ListenTlsOptions extends ListenOptions {
+ /** Server certificate file. */
+ certFile: string;
+ /** Server public key file. */
+ keyFile: string;
+
+ transport?: "tcp";
+ }
+
+ /** Listen announces on the local transport address over TLS (transport layer
+ * security).
+ *
+ * ```ts
+ * const lstnr = Deno.listenTls({ port: 443, certFile: "./server.crt", keyFile: "./server.key" });
+ * ```
+ *
+ * Requires `allow-net` permission. */
+ export function listenTls(options: ListenTlsOptions): Listener;
+
+ export interface ConnectOptions {
+ /** The port to connect to. */
+ port: number;
+ /** A literal IP address or host name that can be resolved to an IP address.
+ * If not specified, defaults to `127.0.0.1`. */
+ hostname?: string;
+ transport?: "tcp";
+ }
+
+ /**
+ * Connects to the hostname (default is "127.0.0.1") and port on the named
+ * transport (default is "tcp"), and resolves to the connection (`Conn`).
+ *
+ * ```ts
+ * const conn1 = await Deno.connect({ port: 80 });
+ * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 });
+ * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 });
+ * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" });
+ * ```
+ *
+ * Requires `allow-net` permission for "tcp". */
+ export function connect(options: ConnectOptions): Promise<Conn>;
+
+ export interface ConnectTlsOptions {
+ /** The port to connect to. */
+ port: number;
+ /** A literal IP address or host name that can be resolved to an IP address.
+ * If not specified, defaults to `127.0.0.1`. */
+ hostname?: string;
+ /** Server certificate file. */
+ certFile?: string;
+ }
+
+ /** Establishes a secure connection over TLS (transport layer security) using
+ * an optional cert file, hostname (default is "127.0.0.1") and port. The
+ * cert file is optional and if not included Mozilla's root certificates will
+ * be used (see also https://github.com/ctz/webpki-roots for specifics)
+ *
+ * ```ts
+ * const conn1 = await Deno.connectTls({ port: 80 });
+ * const conn2 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "192.0.2.1", port: 80 });
+ * const conn3 = await Deno.connectTls({ hostname: "[2001:db8::1]", port: 80 });
+ * const conn4 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "golang.org", port: 80});
+ * ```
+ *
+ * Requires `allow-net` permission.
+ */
+ export function connectTls(options: ConnectTlsOptions): Promise<Conn>;
+
+ /** Shutdown socket send operations.
+ *
+ * Matches behavior of POSIX shutdown(3).
+ *
+ * ```ts
+ * const listener = Deno.listen({ port: 80 });
+ * const conn = await listener.accept();
+ * Deno.shutdown(conn.rid);
+ * ```
+ */
+ export function shutdown(rid: number): Promise<void>;
+}
diff --git a/extensions/net/lib.deno_net.unstable.d.ts b/extensions/net/lib.deno_net.unstable.d.ts
new file mode 100644
index 000000000..905a7acc1
--- /dev/null
+++ b/extensions/net/lib.deno_net.unstable.d.ts
@@ -0,0 +1,262 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+/// <reference no-default-lib="true" />
+/// <reference lib="esnext" />
+
+declare namespace Deno {
+ /** The type of the resource record.
+ * Only the listed types are supported currently. */
+ export type RecordType =
+ | "A"
+ | "AAAA"
+ | "ANAME"
+ | "CNAME"
+ | "MX"
+ | "PTR"
+ | "SRV"
+ | "TXT";
+
+ export interface ResolveDnsOptions {
+ /** The name server to be used for lookups.
+ * If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
+ nameServer?: {
+ /** The IP address of the name server */
+ ipAddr: string;
+ /** The port number the query will be sent to.
+ * If not specified, defaults to 53. */
+ port?: number;
+ };
+ }
+
+ /** If `resolveDns` is called with "MX" record type specified, it will return an array of this interface. */
+ export interface MXRecord {
+ preference: number;
+ exchange: string;
+ }
+
+ /** If `resolveDns` is called with "SRV" record type specified, it will return an array of this interface. */
+ export interface SRVRecord {
+ priority: number;
+ weight: number;
+ port: number;
+ target: string;
+ }
+
+ export function resolveDns(
+ query: string,
+ recordType: "A" | "AAAA" | "ANAME" | "CNAME" | "PTR",
+ options?: ResolveDnsOptions,
+ ): Promise<string[]>;
+
+ export function resolveDns(
+ query: string,
+ recordType: "MX",
+ options?: ResolveDnsOptions,
+ ): Promise<MXRecord[]>;
+
+ export function resolveDns(
+ query: string,
+ recordType: "SRV",
+ options?: ResolveDnsOptions,
+ ): Promise<SRVRecord[]>;
+
+ export function resolveDns(
+ query: string,
+ recordType: "TXT",
+ options?: ResolveDnsOptions,
+ ): Promise<string[][]>;
+
+ /** ** UNSTABLE**: new API, yet to be vetted.
+*
+* Performs DNS resolution against the given query, returning resolved records.
+* Fails in the cases such as:
+* - the query is in invalid format
+* - the options have an invalid parameter, e.g. `nameServer.port` is beyond the range of 16-bit unsigned integer
+* - timed out
+*
+* ```ts
+* const a = await Deno.resolveDns("example.com", "A");
+*
+* const aaaa = await Deno.resolveDns("example.com", "AAAA", {
+* nameServer: { ipAddr: "8.8.8.8", port: 1234 },
+* });
+* ```
+*
+* Requires `allow-net` permission.
+ */
+ export function resolveDns(
+ query: string,
+ recordType: RecordType,
+ options?: ResolveDnsOptions,
+ ): Promise<string[] | MXRecord[] | SRVRecord[] | string[][]>;
+
+ /** **UNSTABLE**: new API, yet to be vetted.
+*
+* A generic transport listener for message-oriented protocols. */
+ export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> {
+ /** **UNSTABLE**: new API, yet to be vetted.
+ *
+ * Waits for and resolves to the next message to the `UDPConn`. */
+ receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>;
+ /** UNSTABLE: new API, yet to be vetted.
+ *
+ * Sends a message to the target. */
+ send(p: Uint8Array, addr: Addr): Promise<number>;
+ /** UNSTABLE: new API, yet to be vetted.
+ *
+ * Close closes the socket. Any pending message promises will be rejected
+ * with errors. */
+ close(): void;
+ /** Return the address of the `UDPConn`. */
+ readonly addr: Addr;
+ [Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]>;
+ }
+
+ export interface UnixListenOptions {
+ /** A Path to the Unix Socket. */
+ path: string;
+ }
+
+ /** **UNSTABLE**: new API, yet to be vetted.
+*
+* Listen announces on the local transport address.
+*
+* ```ts
+* const listener = Deno.listen({ path: "/foo/bar.sock", transport: "unix" })
+* ```
+*
+* Requires `allow-read` and `allow-write` permission. */
+ export function listen(
+ options: UnixListenOptions & { transport: "unix" },
+ ): Listener;
+
+ /** **UNSTABLE**: new API, yet to be vetted
+*
+* Listen announces on the local transport address.
+*
+* ```ts
+* const listener1 = Deno.listenDatagram({
+* port: 80,
+* transport: "udp"
+* });
+* const listener2 = Deno.listenDatagram({
+* hostname: "golang.org",
+* port: 80,
+* transport: "udp"
+* });
+* ```
+*
+* Requires `allow-net` permission. */
+ export function listenDatagram(
+ options: ListenOptions & { transport: "udp" },
+ ): DatagramConn;
+
+ /** **UNSTABLE**: new API, yet to be vetted
+*
+* Listen announces on the local transport address.
+*
+* ```ts
+* const listener = Deno.listenDatagram({
+* path: "/foo/bar.sock",
+* transport: "unixpacket"
+* });
+* ```
+*
+* Requires `allow-read` and `allow-write` permission. */
+ export function listenDatagram(
+ options: UnixListenOptions & { transport: "unixpacket" },
+ ): DatagramConn;
+
+ export interface UnixConnectOptions {
+ transport: "unix";
+ path: string;
+ }
+
+ /** **UNSTABLE**: The unix socket transport is unstable as a new API yet to
+* be vetted. The TCP transport is considered stable.
+*
+* Connects to the hostname (default is "127.0.0.1") and port on the named
+* transport (default is "tcp"), and resolves to the connection (`Conn`).
+*
+* ```ts
+* const conn1 = await Deno.connect({ port: 80 });
+* const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 });
+* const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 });
+* const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" });
+* const conn5 = await Deno.connect({ path: "/foo/bar.sock", transport: "unix" });
+* ```
+*
+* Requires `allow-net` permission for "tcp" and `allow-read` for "unix". */
+ export function connect(
+ options: ConnectOptions | UnixConnectOptions,
+ ): Promise<Conn>;
+
+ export interface StartTlsOptions {
+ /** A literal IP address or host name that can be resolved to an IP address.
+ * If not specified, defaults to `127.0.0.1`. */
+ hostname?: string;
+ /** Server certificate file. */
+ certFile?: string;
+ }
+
+ /** **UNSTABLE**: new API, yet to be vetted.
+*
+* Start TLS handshake from an existing connection using
+* an optional cert file, hostname (default is "127.0.0.1"). The
+* cert file is optional and if not included Mozilla's root certificates will
+* be used (see also https://github.com/ctz/webpki-roots for specifics)
+* Using this function requires that the other end of the connection is
+* prepared for TLS handshake.
+*
+* ```ts
+* const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" });
+* const tlsConn = await Deno.startTls(conn, { certFile: "./certs/my_custom_root_CA.pem", hostname: "localhost" });
+* ```
+*
+* Requires `allow-net` permission.
+ */
+ export function startTls(
+ conn: Conn,
+ options?: StartTlsOptions,
+ ): Promise<Conn>;
+
+ export interface ListenTlsOptions {
+ /** **UNSTABLE**: new API, yet to be vetted.
+ *
+ * Application-Layer Protocol Negotiation (ALPN) protocols to announce to
+ * the client. If not specified, no ALPN extension will be included in the
+ * TLS handshake.
+ */
+ 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;
+}
diff --git a/extensions/net/lib.rs b/extensions/net/lib.rs
new file mode 100644
index 000000000..d1e836fce
--- /dev/null
+++ b/extensions/net/lib.rs
@@ -0,0 +1,113 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+pub mod io;
+pub mod ops;
+pub mod ops_http;
+pub mod ops_tls;
+#[cfg(unix)]
+pub mod ops_unix;
+pub mod resolve_addr;
+
+use deno_core::error::AnyError;
+use deno_core::include_js_files;
+use deno_core::Extension;
+use deno_core::OpState;
+use std::cell::RefCell;
+use std::path::Path;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+pub trait NetPermissions {
+ fn check_net<T: AsRef<str>>(
+ &mut self,
+ _host: &(T, Option<u16>),
+ ) -> Result<(), AnyError>;
+ fn check_read(&mut self, _p: &Path) -> Result<(), AnyError>;
+ fn check_write(&mut self, _p: &Path) -> Result<(), AnyError>;
+}
+
+/// For use with this crate when the user does not want permission checks.
+pub struct NoNetPermissions;
+
+impl NetPermissions for NoNetPermissions {
+ fn check_net<T: AsRef<str>>(
+ &mut self,
+ _host: &(T, Option<u16>),
+ ) -> Result<(), AnyError> {
+ Ok(())
+ }
+
+ fn check_read(&mut self, _p: &Path) -> Result<(), AnyError> {
+ Ok(())
+ }
+
+ fn check_write(&mut self, _p: &Path) -> Result<(), AnyError> {
+ Ok(())
+ }
+}
+
+/// `UnstableChecker` is a struct so it can be placed inside `GothamState`;
+/// using type alias for a bool could work, but there's a high chance
+/// that there might be another type alias pointing to a bool, which
+/// would override previously used alias.
+pub struct UnstableChecker {
+ pub unstable: bool,
+}
+
+impl UnstableChecker {
+ /// Quits the process if the --unstable flag was not provided.
+ ///
+ /// This is intentionally a non-recoverable check so that people cannot probe
+ /// for unstable APIs from stable programs.
+ // NOTE(bartlomieju): keep in sync with `cli/program_state.rs`
+ pub fn check_unstable(&self, api_name: &str) {
+ if !self.unstable {
+ eprintln!(
+ "Unstable API '{}'. The --unstable flag must be provided.",
+ api_name
+ );
+ std::process::exit(70);
+ }
+ }
+}
+/// Helper for checking unstable features. Used for sync ops.
+pub fn check_unstable(state: &OpState, api_name: &str) {
+ state.borrow::<UnstableChecker>().check_unstable(api_name)
+}
+
+/// Helper for checking unstable features. Used for async ops.
+pub fn check_unstable2(state: &Rc<RefCell<OpState>>, api_name: &str) {
+ let state = state.borrow();
+ state.borrow::<UnstableChecker>().check_unstable(api_name)
+}
+
+pub fn get_declaration() -> PathBuf {
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_net.d.ts")
+}
+
+pub fn get_unstable_declaration() -> PathBuf {
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_net.unstable.d.ts")
+}
+
+pub fn init<P: NetPermissions + 'static>(unstable: bool) -> Extension {
+ let mut ops_to_register = vec![];
+ 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)
+ .state(move |state| {
+ state.put(UnstableChecker { unstable });
+ Ok(())
+ })
+ .build()
+}
diff --git a/runtime/ops/net.rs b/extensions/net/ops.rs
index c9195aab7..a02bbf91a 100644
--- a/runtime/ops/net.rs
+++ b/extensions/net/ops.rs
@@ -1,8 +1,9 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-use crate::ops::io::TcpStreamResource;
-use crate::permissions::Permissions;
+
+use crate::io::TcpStreamResource;
use crate::resolve_addr::resolve_addr;
use crate::resolve_addr::resolve_addr_sync;
+use crate::NetPermissions;
use deno_core::error::bad_resource;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
@@ -14,7 +15,7 @@ use deno_core::op_sync;
use deno_core::AsyncRefCell;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
-use deno_core::Extension;
+use deno_core::OpPair;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
@@ -39,23 +40,21 @@ use trust_dns_resolver::system_conf;
use trust_dns_resolver::AsyncResolver;
#[cfg(unix)]
-use super::net_unix;
+use super::ops_unix as net_unix;
#[cfg(unix)]
-use crate::ops::io::UnixStreamResource;
+use crate::io::UnixStreamResource;
#[cfg(unix)]
use std::path::Path;
-pub fn init() -> Extension {
- Extension::builder()
- .ops(vec![
- ("op_accept", op_async(op_accept)),
- ("op_connect", op_async(op_connect)),
- ("op_listen", op_sync(op_listen)),
- ("op_datagram_receive", op_async(op_datagram_receive)),
- ("op_datagram_send", op_async(op_datagram_send)),
- ("op_dns_resolve", op_async(op_dns_resolve)),
- ])
- .build()
+pub fn init<P: NetPermissions + 'static>() -> Vec<OpPair> {
+ vec![
+ ("op_accept", op_async(op_accept)),
+ ("op_connect", op_async(op_connect::<P>)),
+ ("op_listen", op_sync(op_listen::<P>)),
+ ("op_datagram_receive", op_async(op_datagram_receive)),
+ ("op_datagram_send", op_async(op_datagram_send::<P>)),
+ ("op_dns_resolve", op_async(op_dns_resolve::<P>)),
+ ]
}
#[derive(Serialize)]
@@ -216,11 +215,14 @@ struct SendArgs {
transport_args: ArgsEnum,
}
-async fn op_datagram_send(
+async fn op_datagram_send<NP>(
state: Rc<RefCell<OpState>>,
args: SendArgs,
zero_copy: Option<ZeroCopyBuf>,
-) -> Result<usize, AnyError> {
+) -> Result<usize, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
let zero_copy = zero_copy.ok_or_else(null_opbuf)?;
let zero_copy = zero_copy.clone();
@@ -232,9 +234,8 @@ async fn op_datagram_send(
} if transport == "udp" => {
{
let mut s = state.borrow_mut();
- s.borrow_mut::<Permissions>()
- .net
- .check(&(&args.hostname, Some(args.port)))?;
+ s.borrow_mut::<NP>()
+ .check_net(&(&args.hostname, Some(args.port)))?;
}
let addr = resolve_addr(&args.hostname, args.port)
.await?
@@ -259,7 +260,7 @@ async fn op_datagram_send(
let address_path = Path::new(&args.path);
{
let mut s = state.borrow_mut();
- s.borrow_mut::<Permissions>().write.check(&address_path)?;
+ s.borrow_mut::<NP>().check_write(&address_path)?;
}
let resource = state
.borrow()
@@ -285,11 +286,14 @@ struct ConnectArgs {
transport_args: ArgsEnum,
}
-async fn op_connect(
+async fn op_connect<NP>(
state: Rc<RefCell<OpState>>,
args: ConnectArgs,
_: (),
-) -> Result<OpConn, AnyError> {
+) -> Result<OpConn, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
match args {
ConnectArgs {
transport,
@@ -298,9 +302,8 @@ async fn op_connect(
{
let mut state_ = state.borrow_mut();
state_
- .borrow_mut::<Permissions>()
- .net
- .check(&(&args.hostname, Some(args.port)))?;
+ .borrow_mut::<NP>()
+ .check_net(&(&args.hostname, Some(args.port)))?;
}
let addr = resolve_addr(&args.hostname, args.port)
.await?
@@ -335,14 +338,8 @@ async fn op_connect(
super::check_unstable2(&state, "Deno.connect");
{
let mut state_ = state.borrow_mut();
- state_
- .borrow_mut::<Permissions>()
- .read
- .check(&address_path)?;
- state_
- .borrow_mut::<Permissions>()
- .write
- .check(&address_path)?;
+ state_.borrow_mut::<NP>().check_read(&address_path)?;
+ state_.borrow_mut::<NP>().check_write(&address_path)?;
}
let path = args.path;
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
@@ -451,11 +448,14 @@ fn listen_udp(
Ok((rid, local_addr))
}
-fn op_listen(
+fn op_listen<NP>(
state: &mut OpState,
args: ListenArgs,
_: (),
-) -> Result<OpConn, AnyError> {
+) -> Result<OpConn, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
match args {
ListenArgs {
transport,
@@ -466,9 +466,8 @@ fn op_listen(
super::check_unstable(state, "Deno.listenDatagram");
}
state
- .borrow_mut::<Permissions>()
- .net
- .check(&(&args.hostname, Some(args.port)))?;
+ .borrow_mut::<NP>()
+ .check_net(&(&args.hostname, Some(args.port)))?;
}
let addr = resolve_addr_sync(&args.hostname, args.port)?
.next()
@@ -512,9 +511,9 @@ fn op_listen(
if transport == "unixpacket" {
super::check_unstable(state, "Deno.listenDatagram");
}
- let permissions = state.borrow_mut::<Permissions>();
- permissions.read.check(&address_path)?;
- permissions.write.check(&address_path)?;
+ let permissions = state.borrow_mut::<NP>();
+ permissions.check_read(&address_path)?;
+ permissions.check_write(&address_path)?;
}
let (rid, local_addr) = if transport == "unix" {
net_unix::listen_unix(state, &address_path)?
@@ -592,11 +591,14 @@ pub struct NameServer {
port: u16,
}
-async fn op_dns_resolve(
+async fn op_dns_resolve<NP>(
state: Rc<RefCell<OpState>>,
args: ResolveAddrArgs,
_: (),
-) -> Result<Vec<DnsReturnRecord>, AnyError> {
+) -> Result<Vec<DnsReturnRecord>, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
let ResolveAddrArgs {
query,
record_type,
@@ -621,14 +623,14 @@ async fn op_dns_resolve(
{
let mut s = state.borrow_mut();
- let perm = s.borrow_mut::<Permissions>();
+ let perm = s.borrow_mut::<NP>();
// Checks permission against the name servers which will be actually queried.
for ns in config.name_servers() {
let socker_addr = &ns.socket_addr;
let ip = socker_addr.ip().to_string();
let port = socker_addr.port();
- perm.net.check(&(ip, Some(port)))?;
+ perm.check_net(&(ip, Some(port)))?;
}
}
diff --git a/runtime/ops/http.rs b/extensions/net/ops_http.rs
index 01658c802..54e06c3a7 100644
--- a/runtime/ops/http.rs
+++ b/extensions/net/ops_http.rs
@@ -1,8 +1,8 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-use crate::ops::io::TcpStreamResource;
-use crate::ops::io::TlsStreamResource;
-use crate::ops::tls::TlsStream;
+use crate::io::TcpStreamResource;
+use crate::io::TlsStreamResource;
+use crate::ops_tls::TlsStream;
use deno_core::error::bad_resource_id;
use deno_core::error::null_opbuf;
use deno_core::error::type_error;
@@ -17,7 +17,7 @@ use deno_core::AsyncRefCell;
use deno_core::ByteString;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
-use deno_core::Extension;
+use deno_core::OpPair;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
@@ -46,17 +46,15 @@ use tokio::net::TcpStream;
use tokio::sync::oneshot;
use tokio_util::io::StreamReader;
-pub fn init() -> Extension {
- Extension::builder()
- .ops(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)),
- ])
- .build()
+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)),
+ ]
}
struct ServiceInner {
diff --git a/runtime/ops/tls.rs b/extensions/net/ops_tls.rs
index c3f554856..701c5d1a1 100644
--- a/runtime/ops/tls.rs
+++ b/extensions/net/ops_tls.rs
@@ -3,14 +3,14 @@
pub use rustls;
pub use webpki;
-use crate::ops::io::TcpStreamResource;
-use crate::ops::io::TlsStreamResource;
-use crate::ops::net::IpAddr;
-use crate::ops::net::OpAddr;
-use crate::ops::net::OpConn;
-use crate::permissions::Permissions;
+use crate::io::TcpStreamResource;
+use crate::io::TlsStreamResource;
+use crate::ops::IpAddr;
+use crate::ops::OpAddr;
+use crate::ops::OpConn;
use crate::resolve_addr::resolve_addr;
use crate::resolve_addr::resolve_addr_sync;
+use crate::NetPermissions;
use deno_core::error::bad_resource;
use deno_core::error::bad_resource_id;
use deno_core::error::custom_error;
@@ -31,7 +31,7 @@ use deno_core::op_sync;
use deno_core::AsyncRefCell;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
-use deno_core::Extension;
+use deno_core::OpPair;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
@@ -662,15 +662,13 @@ impl Write for ImplementWriteTrait<'_, TcpStream> {
}
}
-pub fn init() -> Extension {
- Extension::builder()
- .ops(vec![
- ("op_start_tls", op_async(op_start_tls)),
- ("op_connect_tls", op_async(op_connect_tls)),
- ("op_listen_tls", op_sync(op_listen_tls)),
- ("op_accept_tls", op_async(op_accept_tls)),
- ])
- .build()
+pub fn init<P: NetPermissions + 'static>() -> Vec<OpPair> {
+ vec![
+ ("op_start_tls", op_async(op_start_tls::<P>)),
+ ("op_connect_tls", op_async(op_connect_tls::<P>)),
+ ("op_listen_tls", op_sync(op_listen_tls::<P>)),
+ ("op_accept_tls", op_async(op_accept_tls)),
+ ]
}
#[derive(Deserialize)]
@@ -690,11 +688,14 @@ struct StartTlsArgs {
hostname: String,
}
-async fn op_start_tls(
+async fn op_start_tls<NP>(
state: Rc<RefCell<OpState>>,
args: StartTlsArgs,
_: (),
-) -> Result<OpConn, AnyError> {
+) -> Result<OpConn, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
let rid = args.rid;
let hostname = match &*args.hostname {
"" => "localhost",
@@ -705,10 +706,10 @@ async fn op_start_tls(
{
super::check_unstable2(&state, "Deno.startTls");
let mut s = state.borrow_mut();
- let permissions = s.borrow_mut::<Permissions>();
- permissions.net.check(&(hostname, Some(0)))?;
+ let permissions = s.borrow_mut::<NP>();
+ permissions.check_net(&(hostname, Some(0)))?;
if let Some(path) = cert_file {
- permissions.read.check(Path::new(path))?;
+ permissions.check_read(Path::new(path))?;
}
}
@@ -763,11 +764,14 @@ async fn op_start_tls(
})
}
-async fn op_connect_tls(
+async fn op_connect_tls<NP>(
state: Rc<RefCell<OpState>>,
args: ConnectTlsArgs,
_: (),
-) -> Result<OpConn, AnyError> {
+) -> Result<OpConn, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
assert_eq!(args.transport, "tcp");
let hostname = match &*args.hostname {
"" => "localhost",
@@ -778,10 +782,10 @@ async fn op_connect_tls(
{
let mut s = state.borrow_mut();
- let permissions = s.borrow_mut::<Permissions>();
- permissions.net.check(&(hostname, Some(port)))?;
+ let permissions = s.borrow_mut::<NP>();
+ permissions.check_net(&(hostname, Some(port)))?;
if let Some(path) = cert_file {
- permissions.read.check(Path::new(path))?;
+ permissions.check_read(Path::new(path))?;
}
}
@@ -912,11 +916,14 @@ pub struct ListenTlsArgs {
alpn_protocols: Option<Vec<String>>,
}
-fn op_listen_tls(
+fn op_listen_tls<NP>(
state: &mut OpState,
args: ListenTlsArgs,
_: (),
-) -> Result<OpConn, AnyError> {
+) -> Result<OpConn, AnyError>
+where
+ NP: NetPermissions + 'static,
+{
assert_eq!(args.transport, "tcp");
let hostname = &*args.hostname;
let port = args.port;
@@ -924,10 +931,10 @@ fn op_listen_tls(
let key_file = &*args.key_file;
{
- let permissions = state.borrow_mut::<Permissions>();
- permissions.net.check(&(hostname, Some(port)))?;
- permissions.read.check(Path::new(cert_file))?;
- permissions.read.check(Path::new(key_file))?;
+ let permissions = state.borrow_mut::<NP>();
+ permissions.check_net(&(hostname, Some(port)))?;
+ permissions.check_read(Path::new(cert_file))?;
+ permissions.check_read(Path::new(key_file))?;
}
let mut tls_config = ServerConfig::new(NoClientAuth::new());
diff --git a/runtime/ops/net_unix.rs b/extensions/net/ops_unix.rs
index d56dc76d9..9dfcc231e 100644
--- a/runtime/ops/net_unix.rs
+++ b/extensions/net/ops_unix.rs
@@ -1,12 +1,11 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-use super::utils::into_string;
-use crate::ops::io::UnixStreamResource;
-use crate::ops::net::AcceptArgs;
-use crate::ops::net::OpAddr;
-use crate::ops::net::OpConn;
-use crate::ops::net::OpPacket;
-use crate::ops::net::ReceiveArgs;
+use crate::io::UnixStreamResource;
+use crate::ops::AcceptArgs;
+use crate::ops::OpAddr;
+use crate::ops::OpConn;
+use crate::ops::OpPacket;
+use crate::ops::ReceiveArgs;
use deno_core::error::bad_resource;
use deno_core::error::custom_error;
use deno_core::error::null_opbuf;
@@ -29,6 +28,14 @@ use tokio::net::UnixDatagram;
use tokio::net::UnixListener;
pub use tokio::net::UnixStream;
+/// A utility function to map OsStrings to Strings
+pub fn into_string(s: std::ffi::OsString) -> Result<String, AnyError> {
+ s.into_string().map_err(|s| {
+ let message = format!("File name or path {:?} is not valid UTF-8", s);
+ custom_error("InvalidData", message)
+ })
+}
+
struct UnixListenerResource {
listener: AsyncRefCell<UnixListener>,
cancel: CancelHandle,
diff --git a/runtime/resolve_addr.rs b/extensions/net/resolve_addr.rs
index ebf1374d1..ebf1374d1 100644
--- a/runtime/resolve_addr.rs
+++ b/extensions/net/resolve_addr.rs
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index bf1c24847..b3f152706 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -23,6 +23,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_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" }
deno_web = { version = "0.41.0", path = "../extensions/web" }
@@ -41,6 +42,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_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" }
deno_web = { version = "0.41.0", path = "../extensions/web" }
@@ -50,7 +52,6 @@ deno_websocket = { version = "0.15.0", path = "../extensions/websocket" }
deno_webstorage = { version = "0.5.0", path = "../extensions/webstorage" }
atty = "0.2.14"
-bytes = "1"
dlopen = "0.1.8"
encoding_rs = "0.8.28"
filetime = "0.2.14"
@@ -64,17 +65,11 @@ notify = "5.0.0-pre.7"
percent-encoding = "2.1.0"
regex = "1.4.3"
ring = "0.16.20"
-rustls = "0.19.0"
serde = { version = "1.0.125", features = ["derive"] }
sys-info = "0.9.0"
termcolor = "1.1.2"
tokio = { version = "1.7.1", features = ["full"] }
-tokio-util = { version = "0.6", features = ["io"] }
uuid = { version = "0.8.2", features = ["v4"] }
-webpki = "0.21.4"
-webpki-roots = "0.21.1"
-trust-dns-proto = "0.20.3"
-trust-dns-resolver = { version = "0.20.3", features = ["tokio-runtime", "serde-config"] }
[target.'cfg(windows)'.dependencies]
fwdansi = "1.1.0"
diff --git a/runtime/build.rs b/runtime/build.rs
index 7d086b045..3e8f8e5b0 100644
--- a/runtime/build.rs
+++ b/runtime/build.rs
@@ -59,6 +59,7 @@ fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
deno_broadcast_channel::InMemoryBroadcastChannel::default(),
false, // No --unstable.
),
+ deno_net::init::<deno_net::NoNetPermissions>(false), // No --unstable.
];
let js_runtime = JsRuntime::new(RuntimeOptions {
diff --git a/runtime/js/01_errors.js b/runtime/js/01_errors.js
index a46a0a149..d59bd7adb 100644
--- a/runtime/js/01_errors.js
+++ b/runtime/js/01_errors.js
@@ -2,6 +2,9 @@
"use strict";
((window) => {
+ const core = window.Deno.core;
+ const { BadResource, Interrupted } = core;
+
class NotFound extends Error {
constructor(msg) {
super(msg);
@@ -86,13 +89,6 @@
}
}
- class Interrupted extends Error {
- constructor(msg) {
- super(msg);
- this.name = "Interrupted";
- }
- }
-
class WriteZero extends Error {
constructor(msg) {
super(msg);
@@ -107,13 +103,6 @@
}
}
- class BadResource extends Error {
- constructor(msg) {
- super(msg);
- this.name = "BadResource";
- }
- }
-
class Http extends Error {
constructor(msg) {
super(msg);
diff --git a/runtime/lib.rs b/runtime/lib.rs
index 63829c2d2..aa95aefbc 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_net;
pub use deno_timers;
pub use deno_url;
pub use deno_web;
@@ -20,7 +21,6 @@ pub mod js;
pub mod metrics;
pub mod ops;
pub mod permissions;
-pub mod resolve_addr;
pub mod tokio_util;
pub mod web_worker;
pub mod worker;
diff --git a/runtime/ops/io.rs b/runtime/ops/io.rs
index 18279c0eb..e18846466 100644
--- a/runtime/ops/io.rs
+++ b/runtime/ops/io.rs
@@ -1,6 +1,5 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-use crate::ops::tls;
use deno_core::error::null_opbuf;
use deno_core::error::resource_unavailable;
use deno_core::error::AnyError;
@@ -17,6 +16,9 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
+use deno_net::io::TcpStreamResource;
+use deno_net::io::TlsStreamResource;
+use deno_net::io::UnixStreamResource;
use std::borrow::Cow;
use std::cell::RefCell;
use std::io::Read;
@@ -26,13 +28,10 @@ use tokio::io::AsyncRead;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWrite;
use tokio::io::AsyncWriteExt;
-use tokio::net::tcp;
use tokio::process;
#[cfg(unix)]
use std::os::unix::io::FromRawFd;
-#[cfg(unix)]
-use tokio::net::unix;
#[cfg(windows)]
use std::os::windows::io::FromRawHandle;
@@ -238,70 +237,6 @@ where
}
}
-/// A full duplex resource has a read and write ends that are completely
-/// independent, like TCP/Unix sockets and TLS streams.
-#[derive(Debug)]
-pub struct FullDuplexResource<R, W> {
- rd: AsyncRefCell<R>,
- wr: AsyncRefCell<W>,
- // When a full-duplex resource is closed, all pending 'read' ops are
- // canceled, while 'write' ops are allowed to complete. Therefore only
- // 'read' futures should be attached to this cancel handle.
- cancel_handle: CancelHandle,
-}
-
-impl<R, W> FullDuplexResource<R, W>
-where
- R: AsyncRead + Unpin + 'static,
- W: AsyncWrite + Unpin + 'static,
-{
- pub fn new((rd, wr): (R, W)) -> Self {
- Self {
- rd: rd.into(),
- wr: wr.into(),
- cancel_handle: Default::default(),
- }
- }
-
- pub fn into_inner(self) -> (R, W) {
- (self.rd.into_inner(), self.wr.into_inner())
- }
-
- pub fn rd_borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<R> {
- RcRef::map(self, |r| &r.rd).borrow_mut()
- }
-
- pub fn wr_borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<W> {
- RcRef::map(self, |r| &r.wr).borrow_mut()
- }
-
- pub fn cancel_handle(self: &Rc<Self>) -> RcRef<CancelHandle> {
- RcRef::map(self, |r| &r.cancel_handle)
- }
-
- pub fn cancel_read_ops(&self) {
- self.cancel_handle.cancel()
- }
-
- async fn read(self: &Rc<Self>, buf: &mut [u8]) -> Result<usize, AnyError> {
- let mut rd = self.rd_borrow_mut().await;
- let nread = rd.read(buf).try_or_cancel(self.cancel_handle()).await?;
- Ok(nread)
- }
-
- async fn write(self: &Rc<Self>, buf: &[u8]) -> Result<usize, AnyError> {
- let mut wr = self.wr_borrow_mut().await;
- let nwritten = wr.write(buf).await?;
- Ok(nwritten)
- }
-
- async fn shutdown(self: &Rc<Self>) -> Result<(), AnyError> {
- let mut wr = self.wr_borrow_mut().await;
- wr.shutdown().await?;
- Ok(())
- }
-}
-
pub type ChildStdinResource = WriteOnlyResource<process::ChildStdin>;
impl Resource for ChildStdinResource {
@@ -334,64 +269,6 @@ impl Resource for ChildStderrResource {
}
}
-pub type TcpStreamResource =
- FullDuplexResource<tcp::OwnedReadHalf, tcp::OwnedWriteHalf>;
-
-impl Resource for TcpStreamResource {
- fn name(&self) -> Cow<str> {
- "tcpStream".into()
- }
-
- fn close(self: Rc<Self>) {
- self.cancel_read_ops();
- }
-}
-
-pub type TlsStreamResource = FullDuplexResource<tls::ReadHalf, tls::WriteHalf>;
-
-impl Resource for TlsStreamResource {
- fn name(&self) -> Cow<str> {
- "tlsStream".into()
- }
-
- fn close(self: Rc<Self>) {
- self.cancel_read_ops();
- }
-}
-
-#[cfg(unix)]
-pub type UnixStreamResource =
- FullDuplexResource<unix::OwnedReadHalf, unix::OwnedWriteHalf>;
-
-#[cfg(not(unix))]
-struct UnixStreamResource;
-
-#[cfg(not(unix))]
-impl UnixStreamResource {
- async fn read(self: &Rc<Self>, _buf: &mut [u8]) -> Result<usize, AnyError> {
- unreachable!()
- }
- async fn write(self: &Rc<Self>, _buf: &[u8]) -> Result<usize, AnyError> {
- unreachable!()
- }
- async fn shutdown(self: &Rc<Self>) -> Result<(), AnyError> {
- unreachable!()
- }
- fn cancel_read_ops(&self) {
- unreachable!()
- }
-}
-
-impl Resource for UnixStreamResource {
- fn name(&self) -> Cow<str> {
- "unixStream".into()
- }
-
- fn close(self: Rc<Self>) {
- self.cancel_read_ops();
- }
-}
-
#[derive(Debug, Default)]
pub struct StdFileResource {
pub fs_file:
diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs
index b05a91180..c94020780 100644
--- a/runtime/ops/mod.rs
+++ b/runtime/ops/mod.rs
@@ -2,18 +2,13 @@
pub mod fs;
pub mod fs_events;
-pub mod http;
pub mod io;
-pub mod net;
-#[cfg(unix)]
-mod net_unix;
pub mod os;
pub mod permissions;
pub mod plugin;
pub mod process;
pub mod runtime;
pub mod signal;
-pub mod tls;
pub mod tty;
mod utils;
pub mod web_worker;
diff --git a/runtime/permissions.rs b/runtime/permissions.rs
index f8385e201..d78e20076 100644
--- a/runtime/permissions.rs
+++ b/runtime/permissions.rs
@@ -962,6 +962,23 @@ impl Permissions {
}
}
+impl deno_net::NetPermissions for Permissions {
+ fn check_net<T: AsRef<str>>(
+ &mut self,
+ host: &(T, Option<u16>),
+ ) -> Result<(), AnyError> {
+ self.net.check(host)
+ }
+
+ fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
+ self.read.check(path)
+ }
+
+ fn check_write(&mut self, path: &Path) -> Result<(), AnyError> {
+ self.write.check(path)
+ }
+}
+
impl deno_fetch::FetchPermissions for Permissions {
fn check_net_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
self.net.check_url(url)
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index a3a062221..ac87d285b 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -330,14 +330,12 @@ impl WebWorker {
vec![
ops::fs_events::init(),
ops::fs::init(),
- ops::net::init(),
+ deno_net::init::<Permissions>(options.unstable),
ops::os::init(),
- ops::http::init(),
ops::permissions::init(),
ops::plugin::init(),
ops::process::init(),
ops::signal::init(),
- ops::tls::init(),
ops::tty::init(),
ops::io::init_stdio(),
]
diff --git a/runtime/worker.rs b/runtime/worker.rs
index 9dfdcc825..567e75253 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -120,16 +120,14 @@ impl MainWorker {
ops::worker_host::init(options.create_web_worker_cb.clone()),
ops::fs_events::init(),
ops::fs::init(),
- ops::http::init(),
ops::io::init(),
ops::io::init_stdio(),
- ops::net::init(),
+ deno_net::init::<Permissions>(options.unstable),
ops::os::init(),
ops::permissions::init(),
ops::plugin::init(),
ops::process::init(),
ops::signal::init(),
- ops::tls::init(),
ops::tty::init(),
// Permissions ext (worker specific state)
perm_ext,