From e57366a0dd599125e07d69d0f5147837988874ca Mon Sep 17 00:00:00 2001 From: HiteshShonak Date: Sat, 21 Mar 2026 10:04:06 +0530 Subject: [PATCH 1/3] fix(fetch): reject forbidden HTTP methods CONNECT, TRACE, and TRACK --- core/runtime/src/fetch/request.rs | 16 ++++++- core/runtime/src/fetch/tests/request.rs | 61 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/core/runtime/src/fetch/request.rs b/core/runtime/src/fetch/request.rs index 17fd3f4528e..9707c47528d 100644 --- a/core/runtime/src/fetch/request.rs +++ b/core/runtime/src/fetch/request.rs @@ -62,9 +62,21 @@ impl RequestInit { } if let Some(Convert(ref method)) = self.method.take() { - builder = builder.method(method.to_std_string().map_err( + let method = method.to_std_string().map_err( |_| js_error!(TypeError: "Request constructor: {} is an invalid method", method.to_std_string_escaped()), - )?.as_str()); + )?; + + if method.eq_ignore_ascii_case("CONNECT") + || method.eq_ignore_ascii_case("TRACE") + || method.eq_ignore_ascii_case("TRACK") + { + return Err(js_error!( + TypeError: "'{}' HTTP method is unsupported.", + method + )); + } + + builder = builder.method(method.as_str()); } if let Some(body) = &self.body { diff --git a/core/runtime/src/fetch/tests/request.rs b/core/runtime/src/fetch/tests/request.rs index 7d516258a0e..a374621b285 100644 --- a/core/runtime/src/fetch/tests/request.rs +++ b/core/runtime/src/fetch/tests/request.rs @@ -5,6 +5,7 @@ use crate::test::{TestAction, run_test_actions}; use boa_engine::{js_str, js_string}; use either::Either; use http::{Response, Uri}; +use indoc::indoc; #[test] fn request_constructor() { @@ -48,6 +49,66 @@ fn request_constructor() { ]); } +#[test] +fn request_constructor_connect_method_throws() { + run_test_actions([ + TestAction::inspect_context(|ctx| { + let fetcher = TestFetcher::default(); + crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); + }), + TestAction::run(indoc! {r#" + try { + new Request("http://unit.test", { method: "CONNECT" }); + throw Error("expected the call above to throw"); + } catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } + } + "#}), + ]); +} + +#[test] +fn request_constructor_trace_method_throws() { + run_test_actions([ + TestAction::inspect_context(|ctx| { + let fetcher = TestFetcher::default(); + crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); + }), + TestAction::run(indoc! {r#" + try { + new Request("http://unit.test", { method: "TRACE" }); + throw Error("expected the call above to throw"); + } catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } + } + "#}), + ]); +} + +#[test] +fn request_constructor_track_method_throws() { + run_test_actions([ + TestAction::inspect_context(|ctx| { + let fetcher = TestFetcher::default(); + crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); + }), + TestAction::run(indoc! {r#" + try { + new Request("http://unit.test", { method: "TRACK" }); + throw Error("expected the call above to throw"); + } catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } + } + "#}), + ]); +} + #[test] fn request_clone_preserves_body_without_override() { run_test_actions([ From 3190e5e6986b17df1c4e23dce597f413388bd3d8 Mon Sep 17 00:00:00 2001 From: HiteshShonak Date: Sat, 21 Mar 2026 10:40:33 +0530 Subject: [PATCH 2/3] fix(fetch): consolidate forbidden method tests into one --- core/runtime/src/fetch/tests/request.rs | 56 ++++--------------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/core/runtime/src/fetch/tests/request.rs b/core/runtime/src/fetch/tests/request.rs index a374621b285..2e38757f022 100644 --- a/core/runtime/src/fetch/tests/request.rs +++ b/core/runtime/src/fetch/tests/request.rs @@ -50,59 +50,21 @@ fn request_constructor() { } #[test] -fn request_constructor_connect_method_throws() { +fn request_constructor_forbidden_method_throws() { run_test_actions([ TestAction::inspect_context(|ctx| { let fetcher = TestFetcher::default(); crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); }), TestAction::run(indoc! {r#" - try { - new Request("http://unit.test", { method: "CONNECT" }); - throw Error("expected the call above to throw"); - } catch (e) { - if (!(e instanceof TypeError)) { - throw e; - } - } - "#}), - ]); -} - -#[test] -fn request_constructor_trace_method_throws() { - run_test_actions([ - TestAction::inspect_context(|ctx| { - let fetcher = TestFetcher::default(); - crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); - }), - TestAction::run(indoc! {r#" - try { - new Request("http://unit.test", { method: "TRACE" }); - throw Error("expected the call above to throw"); - } catch (e) { - if (!(e instanceof TypeError)) { - throw e; - } - } - "#}), - ]); -} - -#[test] -fn request_constructor_track_method_throws() { - run_test_actions([ - TestAction::inspect_context(|ctx| { - let fetcher = TestFetcher::default(); - crate::fetch::register(fetcher, None, ctx).expect("failed to register fetch"); - }), - TestAction::run(indoc! {r#" - try { - new Request("http://unit.test", { method: "TRACK" }); - throw Error("expected the call above to throw"); - } catch (e) { - if (!(e instanceof TypeError)) { - throw e; + for (const method of ["CONNECT", "TRACE", "TRACK", "connect"]) { + try { + new Request("http://unit.test", { method }); + throw Error("expected the call above to throw"); + } catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } } } "#}), From cc6dedf754e99f257e9c1641e6c6e5a6624580ff Mon Sep 17 00:00:00 2001 From: HiteshShonak Date: Fri, 10 Apr 2026 19:56:58 +0530 Subject: [PATCH 3/3] refactor(fetch): add spec comments to forbidden method check --- core/runtime/src/fetch/request.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/runtime/src/fetch/request.rs b/core/runtime/src/fetch/request.rs index 9707c47528d..0045e9905f2 100644 --- a/core/runtime/src/fetch/request.rs +++ b/core/runtime/src/fetch/request.rs @@ -66,6 +66,12 @@ impl RequestInit { |_| js_error!(TypeError: "Request constructor: {} is an invalid method", method.to_std_string_escaped()), )?; + // 25. If init["method"] exists, then: + // 1. Let method be init["method"]. + // 2. If method is not a method or method is a forbidden method, throw a TypeError. + // 3. Normalize method. + // 4. Set request's method to method. + // https://fetch.spec.whatwg.org/#dom-request if method.eq_ignore_ascii_case("CONNECT") || method.eq_ignore_ascii_case("TRACE") || method.eq_ignore_ascii_case("TRACK")