diff --git a/Cargo.lock b/Cargo.lock index e24d69a60d..a45559008f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -923,8 +923,8 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.49" -source = "git+https://github.com/lexmount/curl-rust?rev=dc8c170e4370772c0085c08a67dda0fa86efca70#dc8c170e4370772c0085c08a67dda0fa86efca70" +version = "0.4.51" +source = "git+https://github.com/lexmount/curl-rust?rev=9d40ca90d8f19ccfd11afe7dd49bc32aab79435c#9d40ca90d8f19ccfd11afe7dd49bc32aab79435c" dependencies = [ "curl-sys", "libc", @@ -932,13 +932,13 @@ dependencies = [ "openssl-sys", "schannel", "socket2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "curl-sys" -version = "0.4.87+curl-8.19.0" -source = "git+https://github.com/lexmount/curl-rust?rev=dc8c170e4370772c0085c08a67dda0fa86efca70#dc8c170e4370772c0085c08a67dda0fa86efca70" +version = "0.4.91+curl-8.23.0" +source = "git+https://github.com/lexmount/curl-rust?rev=9d40ca90d8f19ccfd11afe7dd49bc32aab79435c#9d40ca90d8f19ccfd11afe7dd49bc32aab79435c" dependencies = [ "brotlic-sys", "cc", @@ -948,7 +948,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d870d4d9d9..d44af54335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,8 +104,8 @@ fontique = { git = "https://github.com/lexmount/parley", rev = "a18cfc3ba6638d44 subsetter = { git = "https://github.com/lexmount/subsetter", rev = "8d3815245835af309559c3b4a872d6a0a54913a9" } url = { git = "https://github.com/lexmount/rust-url", rev = "ca9fcad2b99f20c30c28a618ad78410f6fd31161" } xml5ever = { path = "vendor/xml5ever-0.39.0" } -curl = { git = "https://github.com/lexmount/curl-rust", rev = "dc8c170e4370772c0085c08a67dda0fa86efca70" } -curl-sys = { git = "https://github.com/lexmount/curl-rust", rev = "dc8c170e4370772c0085c08a67dda0fa86efca70" } +curl = { git = "https://github.com/lexmount/curl-rust", rev = "9d40ca90d8f19ccfd11afe7dd49bc32aab79435c" } +curl-sys = { git = "https://github.com/lexmount/curl-rust", rev = "9d40ca90d8f19ccfd11afe7dd49bc32aab79435c" } cookie = { git = "https://github.com/ldm0/cookie-rs", branch = "priority" } v8 = { path = "vendor/v8-152.2.0" } deno_v8 = { path = "vendor/deno_v8-0.3.0" } diff --git a/moli-curl/Cargo.toml b/moli-curl/Cargo.toml index 3f02f95d01..c8bb97b3fd 100644 --- a/moli-curl/Cargo.toml +++ b/moli-curl/Cargo.toml @@ -8,8 +8,8 @@ edition = "2024" anyhow = "1.0.100" cidr = "0.3.2" crossbeam-channel = "0.5.15" -curl = { version = "0.4.49", default-features = false, features = ["brotli", "http2", "poll_7_68_0", "ssl", "static-curl", "websocket"] } -curl-sys = { version = "0.4.87", default-features = false } +curl = { version = "0.4.51", default-features = false, features = ["apple-sectrust", "brotli", "http2", "poll_7_68_0", "ssl", "static-curl", "websocket"] } +curl-sys = { version = "0.4.91", default-features = false } moli-header-field = { path = "../moli-header-field" } moli-dns-resolver = { path = "../moli-dns-resolver" } openssl-sys = { version = "0.9", features = ["aws-lc"] } diff --git a/moli-curl/src/proxy.rs b/moli-curl/src/proxy.rs index 0288698d27..b2bf697ada 100644 --- a/moli-curl/src/proxy.rs +++ b/moli-curl/src/proxy.rs @@ -88,9 +88,10 @@ impl SelectedProxy { if url.host().is_none() { bail!("proxy URL `{raw}` is missing a host"); } - // libcurl's parse_proxy() defaults to 443 for HTTPS and 1080 for - // HTTP/SOCKS (see CURLOPT_PROXYPORT). Read the explicit port from the - // original authority because `url::Url` deliberately drops explicit + // Keep Moli's default ports: 443 for HTTPS and 1080 for HTTP/SOCKS. + // Newer libcurl uses scheme defaults for implicit ports (80 for HTTP), + // so pass our chosen endpoint explicitly below. Read explicit ports + // from the original authority because `url::Url` deliberately drops // default ports such as `:80` and `:443`. let default_port = match scheme { ProxyScheme::Https => 443, @@ -574,7 +575,16 @@ mod tests { .append(&format!("{host}:{origin_port}:127.0.0.1")) .unwrap(); easy.resolve(resolve).unwrap(); - easy.perform().unwrap(); + let result = easy.perform(); + // Newer libcurl rejects a hostname with two trailing dots + // before applying proxy routing. Keep that case in the matrix + // without comparing NO_PROXY decisions for an invalid URL. + if host == "api.example.test.." { + let error = result.expect_err("double trailing dots are rejected"); + assert!(error.is_url_malformed(), "{error}"); + continue; + } + result.unwrap_or_else(|error| panic!("{host}, NO_PROXY={no_proxy:?}: {error}")); let connected_port = easy.primary_port().unwrap(); assert!(connected_port == origin_port || connected_port == proxy_port); let curl_uses_proxy = connected_port == proxy_port; @@ -727,32 +737,36 @@ mod tests { } } - for raw in [ - "http://proxy.invalid", - "https://proxy.invalid", - "http://proxy.invalid:80", - "https://proxy.invalid:443", - "http://proxy.invalid:8080", - "https://proxy.invalid:8443", - "socks5h://proxy.invalid", - "socks4a://proxy.invalid", + for (raw, curl_port) in [ + ("http://proxy.invalid", 80), + ("https://proxy.invalid", 443), + ("http://proxy.invalid:80", 80), + ("https://proxy.invalid:443", 443), + ("http://proxy.invalid:8080", 8080), + ("https://proxy.invalid:8443", 8443), + ("socks5h://proxy.invalid", 1080), + ("socks4a://proxy.invalid", 1080), ] { let proxy = SelectedProxy::parse(raw).unwrap(); - for curl_proxy in [raw, proxy.curl_url()] { + // libcurl's implicit HTTP port is 80; Moli deliberately preserves + // 1080 by normalizing the proxy URL to an explicit port. Check the + // raw transport behavior and the normalized Moli endpoint. + for (curl_proxy, port) in [(raw, curl_port), (proxy.curl_url(), proxy.endpoint_port())] + { let mut easy = Easy2::new(RefuseSockets::default()); easy.url("http://origin.invalid/proxy-port").unwrap(); easy.proxy(curl_proxy).unwrap(); easy.noproxy("").unwrap(); easy.timeout(Duration::from_secs(1)).unwrap(); let mut dns = crate::CurlDnsResolution::resolve_endpoint( - DnsTarget::new(proxy.endpoint_host(), proxy.endpoint_port()), + DnsTarget::new(proxy.endpoint_host(), port), Vec::new(), ); dns.install(&mut easy, &[IpAddr::from([127, 0, 0, 1])]) .unwrap(); - // Let the linked libcurl interpret both URLs. Only Moli's - // chosen port has a DNS pin for this reserved hostname, so + // Let the linked libcurl interpret both URLs. Only the + // expected port has a DNS pin for this reserved hostname, so // reaching open_socket proves that libcurl selected it too. // Refuse the socket before any connection or TLS handshake. let error = easy.perform().expect_err("test refuses every socket"); diff --git a/moli-fetch/Cargo.toml b/moli-fetch/Cargo.toml index 654074764b..a048d19183 100644 --- a/moli-fetch/Cargo.toml +++ b/moli-fetch/Cargo.toml @@ -13,8 +13,8 @@ moli-header-field = { path = "../moli-header-field" } anyhow = "1.0.100" cidr = "0.3.2" crossbeam-channel = "0.5.15" -curl = { version = "0.4.49", default-features = false, features = ["brotli", "http2", "poll_7_68_0", "ssl", "static-curl"] } -curl-sys = { version = "0.4.87", default-features = false } +curl = { version = "0.4.51", default-features = false, features = ["brotli", "http2", "poll_7_68_0", "ssl", "static-curl"] } +curl-sys = { version = "0.4.91", default-features = false } http = "1" moli-browser-profile = { path = "../moli-browser-profile" } moli-cookie-jar = { path = "../moli-cookie-jar" } diff --git a/moli-renderer-v8/Cargo.toml b/moli-renderer-v8/Cargo.toml index 7e194383ba..da507adf0d 100644 --- a/moli-renderer-v8/Cargo.toml +++ b/moli-renderer-v8/Cargo.toml @@ -93,7 +93,7 @@ moli-webmcp = { path = "../moli-webmcp" } moli-window-features = { path = "../moli-window-features" } moli-websocket = { path = "../moli-websocket" } moli-xpath = { path = "../moli-xpath" } -curl = { version = "0.4.49", default-features = false, features = ["brotli", "http2", "poll_7_68_0", "ssl", "static-curl"] } +curl = { version = "0.4.51", default-features = false, features = ["brotli", "http2", "poll_7_68_0", "ssl", "static-curl"] } http = "1" httpdate = "1.0.3" html-escape = "0.2.13" diff --git a/moli-renderer-v8/src/script_vm/tests/dom_xhr/forms.rs b/moli-renderer-v8/src/script_vm/tests/dom_xhr/forms.rs index 02645fd6df..7ef1ba92b7 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_xhr/forms.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_xhr/forms.rs @@ -2559,7 +2559,7 @@ async fn child_click_uses_pre_dispatch_button_activation_target_after_dom_remova ); assert_eq!( server.finish_targets().await, - vec!["/path/does_not_exist.html"] + vec!["/path/does_not_exist.html?"] ); } @@ -2818,7 +2818,7 @@ async fn programmatic_form_submit_keeps_successive_distinct_child_targets() { assert!( requests .iter() - .all(|request| request == "GET /path/formaction.html HTTP/1.1"), + .all(|request| request == "GET /path/formaction.html? HTTP/1.1"), "unexpected multi-target form requests: {requests:?}" ); }