From 8476bbff9af28408bc6a9b0a7b2303cb3803422e Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Thu, 12 Sep 2024 10:46:48 +1000 Subject: [PATCH] feat: stabilize `Deno.createHttpClient()` (#25569) Closes #25518 --- cli/main.rs | 7 - cli/tsc/99_main_compiler.js | 3 - cli/tsc/dts/lib.deno.ns.d.ts | 122 ++++++++++++++++ cli/tsc/dts/lib.deno.unstable.d.ts | 135 ------------------ ext/http/http_next.rs | 7 - runtime/js/90_deno_ns.js | 2 + runtime/lib.rs | 2 +- runtime/ops/http.rs | 2 - tests/integration/js_unit_tests.rs | 3 +- tests/integration/node_unit_tests.rs | 1 - tests/integration/run_tests.rs | 11 -- tests/specs/run/045_proxy/proxy_test.ts | 1 - tests/specs/run/unstable/__test__.jsonc | 5 - tests/specs/run/unstable/http.out | 7 - tests/specs/run/unstable/http.ts | 1 - tests/testdata/run/unstable_http.disabled.out | 4 - tests/testdata/run/unstable_http.enabled.out | 4 - tests/testdata/run/unstable_http.js | 11 -- tools/lint.js | 2 +- 19 files changed, 127 insertions(+), 203 deletions(-) delete mode 100644 tests/specs/run/unstable/http.out delete mode 100644 tests/specs/run/unstable/http.ts delete mode 100644 tests/testdata/run/unstable_http.disabled.out delete mode 100644 tests/testdata/run/unstable_http.enabled.out delete mode 100644 tests/testdata/run/unstable_http.js diff --git a/cli/main.rs b/cli/main.rs index 6caeaa5dde..ca233d43cd 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -364,13 +364,6 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec { "Run again with `--unstable-cron` flag to enable this API.", ), ]; - } else if msg.contains("createHttpClient is not a function") { - return vec![ - FixSuggestion::info("Deno.createHttpClient() is an unstable API."), - FixSuggestion::hint( - "Run again with `--unstable-http` flag to enable this API.", - ), - ]; } else if msg.contains("WebSocketStream is not defined") { return vec![ FixSuggestion::info("new WebSocketStream() is an unstable API."), diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 4044c5fc16..03729b8928 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -32,9 +32,7 @@ delete Object.prototype.__proto__; /** @type {ReadonlySet} */ const unstableDenoProps = new Set([ "AtomicOperation", - "CreateHttpClientOptions", "DatagramConn", - "HttpClient", "Kv", "KvListIterator", "KvU64", @@ -44,7 +42,6 @@ delete Object.prototype.__proto__; "UnsafeFnPointer", "UnixConnectOptions", "UnixListenOptions", - "createHttpClient", "dlopen", "listen", "listenDatagram", diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index 2bc3b36a36..0d5e3eaa19 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -6087,4 +6087,126 @@ declare namespace Deno { filename: string | URL, symbols: S, ): DynamicLibrary; + + /** + * A custom `HttpClient` for use with {@linkcode fetch} function. This is + * designed to allow custom certificates or proxies to be used with `fetch()`. + * + * @example ```ts + * const caCert = await Deno.readTextFile("./ca.pem"); + * const client = Deno.createHttpClient({ caCerts: [ caCert ] }); + * const req = await fetch("https://myserver.com", { client }); + * ``` + * + * @category Fetch + */ + export interface HttpClient extends Disposable { + /** Close the HTTP client. */ + close(): void; + } + + /** + * The options used when creating a {@linkcode Deno.HttpClient}. + * + * @category Fetch + */ + export interface CreateHttpClientOptions { + /** A list of root certificates that will be used in addition to the + * default root certificates to verify the peer's certificate. + * + * Must be in PEM format. */ + caCerts?: string[]; + /** A HTTP proxy to use for new connections. */ + proxy?: Proxy; + /** Sets the maximum number of idle connections per host allowed in the pool. */ + poolMaxIdlePerHost?: number; + /** Set an optional timeout for idle sockets being kept-alive. + * Set to false to disable the timeout. */ + poolIdleTimeout?: number | false; + /** + * Whether HTTP/1.1 is allowed or not. + * + * @default {true} + */ + http1?: boolean; + /** Whether HTTP/2 is allowed or not. + * + * @default {true} + */ + http2?: boolean; + /** Whether setting the host header is allowed or not. + * + * @default {false} + */ + allowHost?: boolean; + } + + /** + * The definition of a proxy when specifying + * {@linkcode Deno.CreateHttpClientOptions}. + * + * @category Fetch + */ + export interface Proxy { + /** The string URL of the proxy server to use. */ + url: string; + /** The basic auth credentials to be used against the proxy server. */ + basicAuth?: BasicAuth; + } + + /** + * Basic authentication credentials to be used with a {@linkcode Deno.Proxy} + * server when specifying {@linkcode Deno.CreateHttpClientOptions}. + * + * @category Fetch + */ + export interface BasicAuth { + /** The username to be used against the proxy server. */ + username: string; + /** The password to be used against the proxy server. */ + password: string; + } + + /** Create a custom HttpClient to use with {@linkcode fetch}. This is an + * extension of the web platform Fetch API which allows Deno to use custom + * TLS certificates and connect via a proxy while using `fetch()`. + * + * @example ```ts + * const caCert = await Deno.readTextFile("./ca.pem"); + * const client = Deno.createHttpClient({ caCerts: [ caCert ] }); + * const response = await fetch("https://myserver.com", { client }); + * ``` + * + * @example ```ts + * const client = Deno.createHttpClient({ + * proxy: { url: "http://myproxy.com:8080" } + * }); + * const response = await fetch("https://myserver.com", { client }); + * ``` + * + * @category Fetch + */ + export function createHttpClient( + options: CreateHttpClientOptions, + ): HttpClient; + + /** + * Create a custom HttpClient to use with {@linkcode fetch}. This is an + * extension of the web platform Fetch API which allows Deno to use custom + * TLS certificates and connect via a proxy while using `fetch()`. + * + * @example ```ts + * const caCert = await Deno.readTextFile("./ca.pem"); + * // Load a client key and certificate that we'll use to connect + * const key = await Deno.readTextFile("./key.key"); + * const cert = await Deno.readTextFile("./cert.crt"); + * const client = Deno.createHttpClient({ caCerts: [ caCert ], key, cert }); + * const response = await fetch("https://myserver.com", { client }); + * ``` + * + * @category Fetch + */ + export function createHttpClient( + options: CreateHttpClientOptions & TlsCertifiedKeyPem, + ): HttpClient; } diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 88f78b8a55..34531ef390 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -36,141 +36,6 @@ declare namespace Deno { present(): void; } - /** **UNSTABLE**: New API, yet to be vetted. - * - * A custom `HttpClient` for use with {@linkcode fetch} function. This is - * designed to allow custom certificates or proxies to be used with `fetch()`. - * - * @example ```ts - * const caCert = await Deno.readTextFile("./ca.pem"); - * const client = Deno.createHttpClient({ caCerts: [ caCert ] }); - * const req = await fetch("https://myserver.com", { client }); - * ``` - * - * @category Fetch - * @experimental - */ - export interface HttpClient extends Disposable { - /** Close the HTTP client. */ - close(): void; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * The options used when creating a {@linkcode Deno.HttpClient}. - * - * @category Fetch - * @experimental - */ - export interface CreateHttpClientOptions { - /** A list of root certificates that will be used in addition to the - * default root certificates to verify the peer's certificate. - * - * Must be in PEM format. */ - caCerts?: string[]; - /** A HTTP proxy to use for new connections. */ - proxy?: Proxy; - /** Sets the maximum number of idle connections per host allowed in the pool. */ - poolMaxIdlePerHost?: number; - /** Set an optional timeout for idle sockets being kept-alive. - * Set to false to disable the timeout. */ - poolIdleTimeout?: number | false; - /** - * Whether HTTP/1.1 is allowed or not. - * - * @default {true} - */ - http1?: boolean; - /** Whether HTTP/2 is allowed or not. - * - * @default {true} - */ - http2?: boolean; - /** Whether setting the host header is allowed or not. - * - * @default {false} - */ - allowHost?: boolean; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * The definition of a proxy when specifying - * {@linkcode Deno.CreateHttpClientOptions}. - * - * @category Fetch - * @experimental - */ - export interface Proxy { - /** The string URL of the proxy server to use. */ - url: string; - /** The basic auth credentials to be used against the proxy server. */ - basicAuth?: BasicAuth; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Basic authentication credentials to be used with a {@linkcode Deno.Proxy} - * server when specifying {@linkcode Deno.CreateHttpClientOptions}. - * - * @category Fetch - * @experimental - */ - export interface BasicAuth { - /** The username to be used against the proxy server. */ - username: string; - /** The password to be used against the proxy server. */ - password: string; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Create a custom HttpClient to use with {@linkcode fetch}. This is an - * extension of the web platform Fetch API which allows Deno to use custom - * TLS certificates and connect via a proxy while using `fetch()`. - * - * @example ```ts - * const caCert = await Deno.readTextFile("./ca.pem"); - * const client = Deno.createHttpClient({ caCerts: [ caCert ] }); - * const response = await fetch("https://myserver.com", { client }); - * ``` - * - * @example ```ts - * const client = Deno.createHttpClient({ - * proxy: { url: "http://myproxy.com:8080" } - * }); - * const response = await fetch("https://myserver.com", { client }); - * ``` - * - * @category Fetch - * @experimental - */ - export function createHttpClient( - options: CreateHttpClientOptions, - ): HttpClient; - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Create a custom HttpClient to use with {@linkcode fetch}. This is an - * extension of the web platform Fetch API which allows Deno to use custom - * TLS certificates and connect via a proxy while using `fetch()`. - * - * @example ```ts - * const caCert = await Deno.readTextFile("./ca.pem"); - * // Load a client key and certificate that we'll use to connect - * const key = await Deno.readTextFile("./key.key"); - * const cert = await Deno.readTextFile("./cert.crt"); - * const client = Deno.createHttpClient({ caCerts: [ caCert ], key, cert }); - * const response = await fetch("https://myserver.com", { client }); - * ``` - * - * @category Fetch - * @experimental - */ - export function createHttpClient( - options: CreateHttpClientOptions & TlsCertifiedKeyPem, - ): HttpClient; - /** **UNSTABLE**: New API, yet to be vetted. * * Represents membership of a IPv4 multicast group. diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index 9ff449a093..efe1b88c93 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -90,13 +90,6 @@ static USE_WRITEV: Lazy = Lazy::new(|| { false }); -// NOTE(bartlomieju): currently we don't have any unstable HTTP features, -// but let's keep this const here, because: -// a) we still need to support `--unstable-http` flag to not break user's CLI; -// b) we might add more unstable features in the future. -#[allow(dead_code)] -pub const UNSTABLE_FEATURE_NAME: &str = "http"; - /// All HTTP/2 connections start with this byte string. /// /// In HTTP/2, each endpoint is required to send a connection preface as a final confirmation diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js index f2de16627a..51b00fa023 100644 --- a/runtime/js/90_deno_ns.js +++ b/runtime/js/90_deno_ns.js @@ -126,6 +126,8 @@ const denoNs = { uid: os.uid, Command: process.Command, ChildProcess: process.ChildProcess, + httpClient: httpClient.httpClient, + createHttpClient: httpClient.createHttpClient, }; // NOTE(bartlomieju): keep IDs in sync with `cli/main.rs` diff --git a/runtime/lib.rs b/runtime/lib.rs index c8ab099f18..ed3f9fbc6a 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -83,7 +83,7 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[ UnstableGranularFlag { name: ops::http::UNSTABLE_FEATURE_NAME, help_text: "Enable unstable HTTP APIs", - show_in_help: true, + show_in_help: false, id: 5, }, UnstableGranularFlag { diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs index cde2d5858a..a195a759ee 100644 --- a/runtime/ops/http.rs +++ b/runtime/ops/http.rs @@ -57,8 +57,6 @@ fn op_http_start( .resource_table .take::(tcp_stream_rid) { - super::check_unstable(state, UNSTABLE_FEATURE_NAME, "Deno.serveHttp"); - // This UNIX socket might be used somewhere else. If it's the case, we cannot proceed with the // process of starting a HTTP server on top of this UNIX socket, so we just return a bad // resource error. See also: https://github.com/denoland/deno/pull/16242 diff --git a/tests/integration/js_unit_tests.rs b/tests/integration/js_unit_tests.rs index be2af84a82..5efb0f2686 100644 --- a/tests/integration/js_unit_tests.rs +++ b/tests/integration/js_unit_tests.rs @@ -122,9 +122,8 @@ fn js_unit_test(test: String) { .arg("--no-lock") // TODO(bartlomieju): would be better if we could apply this unstable // flag to particular files, but there's many of them that rely on unstable - // net APIs (`reusePort` in `listen` and `listenTls`; `listenDatagram`, `createHttpClient`) + // net APIs (`reusePort` in `listen` and `listenTls`; `listenDatagram`) .arg("--unstable-net") - .arg("--unstable-http") .arg("--location=http://127.0.0.1:4545/") .arg("--no-prompt"); diff --git a/tests/integration/node_unit_tests.rs b/tests/integration/node_unit_tests.rs index 3bec6bb7df..c8b5b25fb3 100644 --- a/tests/integration/node_unit_tests.rs +++ b/tests/integration/node_unit_tests.rs @@ -112,7 +112,6 @@ fn node_unit_test(test: String) { .arg(deno_config_path()) .arg("--no-lock") .arg("--unstable-broadcast-channel") - .arg("--unstable-http") .arg("--unstable-net") // TODO(kt3k): This option is required to pass tls_test.ts, // but this shouldn't be necessary. tls.connect currently doesn't diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 6f85aaf0b8..7140c2cfa8 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -1829,17 +1829,6 @@ itest!(unstable_cron_enabled { output: "run/unstable_cron.enabled.out", }); -itest!(unstable_http_disabled { - args: "run --quiet --reload --allow-read run/unstable_http.js", - output: "run/unstable_http.disabled.out", -}); - -itest!(unstable_http_enabled { - args: - "run --quiet --reload --allow-read --unstable-http run/unstable_http.js", - output: "run/unstable_http.enabled.out", -}); - itest!(unstable_net_disabled { args: "run --quiet --reload --allow-read run/unstable_net.js", output: "run/unstable_net.disabled.out", diff --git a/tests/specs/run/045_proxy/proxy_test.ts b/tests/specs/run/045_proxy/proxy_test.ts index 8ef7cf3da1..22115a3aa8 100644 --- a/tests/specs/run/045_proxy/proxy_test.ts +++ b/tests/specs/run/045_proxy/proxy_test.ts @@ -108,7 +108,6 @@ async function testFetchProgrammaticProxy() { "--quiet", "--reload", "--allow-net=localhost:4545,localhost:4555", - "--unstable-http", "programmatic_proxy_client.ts", ], }).output(); diff --git a/tests/specs/run/unstable/__test__.jsonc b/tests/specs/run/unstable/__test__.jsonc index 5748c5461a..3ddcdb583c 100644 --- a/tests/specs/run/unstable/__test__.jsonc +++ b/tests/specs/run/unstable/__test__.jsonc @@ -10,11 +10,6 @@ "exitCode": 1, "output": "cron.out" }, - "http": { - "args": "run http.ts", - "exitCode": 1, - "output": "http.out" - }, "http_wss": { "args": "run http_wss.ts", "exitCode": 1, diff --git a/tests/specs/run/unstable/http.out b/tests/specs/run/unstable/http.out deleted file mode 100644 index 55e143c25c..0000000000 --- a/tests/specs/run/unstable/http.out +++ /dev/null @@ -1,7 +0,0 @@ -error: Uncaught (in promise) TypeError: Deno.createHttpClient is not a function -Deno.createHttpClient(); - ^ - at [WILDCARD]http.ts:1:6 - - info: Deno.createHttpClient() is an unstable API. - hint: Run again with `--unstable-http` flag to enable this API. diff --git a/tests/specs/run/unstable/http.ts b/tests/specs/run/unstable/http.ts deleted file mode 100644 index 568d6a7ccb..0000000000 --- a/tests/specs/run/unstable/http.ts +++ /dev/null @@ -1 +0,0 @@ -Deno.createHttpClient(); diff --git a/tests/testdata/run/unstable_http.disabled.out b/tests/testdata/run/unstable_http.disabled.out deleted file mode 100644 index 3562f72fdd..0000000000 --- a/tests/testdata/run/unstable_http.disabled.out +++ /dev/null @@ -1,4 +0,0 @@ -main undefined -main undefined -worker undefined -worker undefined diff --git a/tests/testdata/run/unstable_http.enabled.out b/tests/testdata/run/unstable_http.enabled.out deleted file mode 100644 index f7aa776e9e..0000000000 --- a/tests/testdata/run/unstable_http.enabled.out +++ /dev/null @@ -1,4 +0,0 @@ -main [class HttpClient] -main [Function: createHttpClient] -worker [class HttpClient] -worker [Function: createHttpClient] diff --git a/tests/testdata/run/unstable_http.js b/tests/testdata/run/unstable_http.js deleted file mode 100644 index 7ad09aec57..0000000000 --- a/tests/testdata/run/unstable_http.js +++ /dev/null @@ -1,11 +0,0 @@ -const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main"; - -console.log(scope, Deno.HttpClient); -console.log(scope, Deno.createHttpClient); - -if (scope === "worker") { - postMessage("done"); -} else { - const worker = new Worker(`${import.meta.url}#worker`, { type: "module" }); - worker.onmessage = () => Deno.exit(0); -} diff --git a/tools/lint.js b/tools/lint.js index c76589c666..0d7160c3f9 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -220,7 +220,7 @@ async function ensureNoNewITests() { "pm_tests.rs": 0, "publish_tests.rs": 0, "repl_tests.rs": 0, - "run_tests.rs": 338, + "run_tests.rs": 336, "shared_library_tests.rs": 0, "task_tests.rs": 4, "test_tests.rs": 74,