diff --git a/core/runtime/src/fetch/request.rs b/core/runtime/src/fetch/request.rs index 17fd3f4528e..0045e9905f2 100644 --- a/core/runtime/src/fetch/request.rs +++ b/core/runtime/src/fetch/request.rs @@ -62,9 +62,27 @@ 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()); + )?; + + // 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") + { + 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..2e38757f022 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,28 @@ fn request_constructor() { ]); } +#[test] +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#" + 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; + } + } + } + "#}), + ]); +} + #[test] fn request_clone_preserves_body_without_override() { run_test_actions([