diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c9f10..9d6886e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Significantly improved performance of `net.request` and `net.serve` when handling large request bodies +- Improved performance of `net.request` and `net.serve` when handling large request bodies +- Improved performance and memory usage of `task.spawn`, `task.defer`, and `task.delay` + +### Fixed + +- Fixed accidental breakage of `net.request` in version `0.9.1` ## `0.9.1` - April 29th, 2025 diff --git a/crates/lune-std-net/src/client/rustls.rs b/crates/lune-std-net/src/client/rustls.rs index ea864ab..c69f11c 100644 --- a/crates/lune-std-net/src/client/rustls.rs +++ b/crates/lune-std-net/src/client/rustls.rs @@ -1,8 +1,22 @@ -use std::sync::{Arc, LazyLock}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, LazyLock, +}; -use rustls::ClientConfig; +use rustls::{crypto::ring, ClientConfig}; + +static PROVIDER_INITIALIZED: AtomicBool = AtomicBool::new(false); + +pub fn initialize_provider() { + if !PROVIDER_INITIALIZED.load(Ordering::Relaxed) { + PROVIDER_INITIALIZED.store(true, Ordering::Relaxed); + // Only errors if already installed, which is fine + ring::default_provider().install_default().ok(); + } +} pub static CLIENT_CONFIG: LazyLock> = LazyLock::new(|| { + initialize_provider(); rustls::ClientConfig::builder() .with_root_certificates(rustls::RootCertStore { roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(), diff --git a/crates/lune-std-net/src/lib.rs b/crates/lune-std-net/src/lib.rs index 812bf3b..ddf08ae 100644 --- a/crates/lune-std-net/src/lib.rs +++ b/crates/lune-std-net/src/lib.rs @@ -33,6 +33,8 @@ pub fn typedefs() -> String { Errors when out of memory. */ pub fn module(lua: Lua) -> LuaResult { + // No initial rustls setup is necessary, the respective + // functions lazily initialize anything there as needed TableBuilder::new(lua)? .with_async_function("request", net_request)? .with_async_function("socket", net_socket)? diff --git a/crates/lune/src/tests.rs b/crates/lune/src/tests.rs index bda0f38..253d46d 100644 --- a/crates/lune/src/tests.rs +++ b/crates/lune/src/tests.rs @@ -126,6 +126,7 @@ create_tests! { create_tests! { net_request_codes: "net/request/codes", net_request_compression: "net/request/compression", + net_request_https: "net/request/https", net_request_methods: "net/request/methods", net_request_query: "net/request/query", net_request_redirect: "net/request/redirect", diff --git a/tests/net/request/https.luau b/tests/net/request/https.luau new file mode 100644 index 0000000..8b43157 --- /dev/null +++ b/tests/net/request/https.luau @@ -0,0 +1,24 @@ +local task = require("@lune/task") + +local util = require("./util") +local pass = util.pass + +-- These are some public APIs that have, or most likely have, different +-- certificate authorities (CAs), plus are both free to use and stable. +-- This should be enough to ensure that rustls is configured correctly. +local servers = { + "https://www.googleapis.com/discovery/v1/apis", + "https://api.cloudflare.com/client/v4/ips", + "https://azure.microsoft.com/en-us/updates/feed/", + "https://acme-v02.api.letsencrypt.org/directory", + "https://ip-ranges.amazonaws.com/ip-ranges.json", + "https://api.github.com/zen", + "https://en.wikipedia.org/w/api.php", + "https://status.godaddy.com/api/v2/summary.json", +} + +for _, server in servers do + task.spawn(function() + pass("GET", server, server) + end) +end diff --git a/tests/net/request/util.luau b/tests/net/request/util.luau index e64d85c..cdd04c4 100644 --- a/tests/net/request/util.luau +++ b/tests/net/request/util.luau @@ -4,22 +4,38 @@ local stdio = require("@lune/stdio") local util = {} function util.pass(method, url, message) - local response = net.request({ + local success, response = pcall(net.request, { method = method, url = url, }) - if not response.ok then - error(string.format("%s failed!\nResponse: %s", message, stdio.format(response))) + if not success then + error(`{message} errored!\nError message: {tostring(response)}`) + elseif not response.ok then + error( + `{message} failed, but should have passed!` + .. `\nStatus code: {response.statusCode}` + .. `\nStatus message: {response.statusMessage}` + .. `\nResponse headers: {stdio.format(response.headers)}` + .. `\nResponse body: {response.body}` + ) end end function util.fail(method, url, message) - local response = net.request({ + local success, response = pcall(net.request, { method = method, url = url, }) - if response.ok then - error(string.format("%s passed!\nResponse: %s", message, stdio.format(response))) + if not success then + error(`{message} errored!\nError message: {tostring(response)}`) + elseif response.ok then + error( + `{message} passed, but should have failed!` + .. `\nStatus code: {response.statusCode}` + .. `\nStatus message: {response.statusMessage}` + .. `\nResponse headers: {stdio.format(response.headers)}` + .. `\nResponse body: {response.body}` + ) end end