diff --git a/Libraries/LibWeb/HTML/Location.cpp b/Libraries/LibWeb/HTML/Location.cpp
index 205ee42135b..be75a40a7c7 100644
--- a/Libraries/LibWeb/HTML/Location.cpp
+++ b/Libraries/LibWeb/HTML/Location.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2023, Andreas Kling
* Copyright (c) 2022-2023, Linus Groh
+ * Copyright (c) 2025, Shannon Booth
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -99,7 +100,7 @@ WebIDL::ExceptionOr Location::navigate(URL::URL url, Bindings::NavigationH
}
// 4. Navigate navigable to url using sourceDocument, with exceptionsEnabled set to true and historyHandling set to historyHandling.
- TRY(navigable->navigate({ .url = url,
+ TRY(navigable->navigate({ .url = move(url),
.source_document = source_document,
.exceptions_enabled = true,
.history_handling = history_handling }));
@@ -235,10 +236,32 @@ WebIDL::ExceptionOr Location::host() const
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.serialized_host(), *url.port()));
}
-WebIDL::ExceptionOr Location::set_host(String const&)
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-host
+WebIDL::ExceptionOr Location::set_host(String const& value)
{
- auto& vm = this->vm();
- return vm.throw_completion(JS::ErrorType::NotImplemented, "Location.host setter");
+ // 1. If this's relevant Document is null, then return.
+ auto const relevant_document = this->relevant_document();
+ if (!relevant_document)
+ return {};
+
+ // 2. If this's relevant Document's origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
+ if (!relevant_document->origin().is_same_origin_domain(entry_settings_object().origin()))
+ return WebIDL::SecurityError::create(realm(), "Location's relevant document is not same origin-domain with the entry settings object's origin"_string);
+
+ // 3. Let copyURL be a copy of this's url.
+ auto copy_url = this->url();
+
+ // 4. If copyURL has an opaque path, then return.
+ if (copy_url.has_an_opaque_path())
+ return {};
+
+ // 5. Basic URL parse the given value, with copyURL as url and host state as state override.
+ (void)URL::Parser::basic_parse(value, {}, ©_url, URL::Parser::State::Host);
+
+ // 6. Location-object navigate this to copyURL.
+ TRY(navigate(copy_url));
+
+ return {};
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-hostname
@@ -259,10 +282,32 @@ WebIDL::ExceptionOr Location::hostname() const
return url.serialized_host();
}
-WebIDL::ExceptionOr Location::set_hostname(String const&)
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-hostname
+WebIDL::ExceptionOr Location::set_hostname(String const& value)
{
- auto& vm = this->vm();
- return vm.throw_completion(JS::ErrorType::NotImplemented, "Location.hostname setter");
+ // 1. If this's relevant Document is null, then return.
+ auto const relevant_document = this->relevant_document();
+ if (!relevant_document)
+ return {};
+
+ // 2. If this's relevant Document's origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
+ if (!relevant_document->origin().is_same_origin_domain(entry_settings_object().origin()))
+ return WebIDL::SecurityError::create(realm(), "Location's relevant document is not same origin-domain with the entry settings object's origin"_string);
+
+ // 3. Let copyURL be a copy of this's url.
+ auto copy_url = this->url();
+
+ // 4. If copyURL has an opaque path, then return.
+ if (copy_url.has_an_opaque_path())
+ return {};
+
+ // 5. Basic URL parse the given value, with copyURL as url and hostname state as state override.
+ (void)URL::Parser::basic_parse(value, {}, ©_url, URL::Parser::State::Hostname);
+
+ // 6. Location-object navigate this to copyURL.
+ TRY(navigate(copy_url));
+
+ return {};
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-port
@@ -283,10 +328,38 @@ WebIDL::ExceptionOr Location::port() const
return String::number(*url.port());
}
-WebIDL::ExceptionOr Location::set_port(String const&)
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-port
+WebIDL::ExceptionOr Location::set_port(String const& value)
{
- auto& vm = this->vm();
- return vm.throw_completion(JS::ErrorType::NotImplemented, "Location.port setter");
+ // 1. If this's relevant Document is null, then return.
+ auto const relevant_document = this->relevant_document();
+ if (!relevant_document)
+ return {};
+
+ // 2. If this's relevant Document's origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
+ if (!relevant_document->origin().is_same_origin_domain(entry_settings_object().origin()))
+ return WebIDL::SecurityError::create(realm(), "Location's relevant document is not same origin-domain with the entry settings object's origin"_string);
+
+ // 3. Let copyURL be a copy of this's url.
+ auto copy_url = this->url();
+
+ // 4. If copyURL cannot have a username/password/port, then return.
+ if (copy_url.cannot_have_a_username_or_password_or_port())
+ return {};
+
+ // 5. If the given value is the empty string, then set copyURL's port to null.
+ if (value.is_empty()) {
+ copy_url.set_port({});
+ }
+ // 5. Otherwise, basic URL parse the given value, with copyURL as url and port state as state override.
+ else {
+ (void)URL::Parser::basic_parse(value, {}, ©_url, URL::Parser::State::Port);
+ }
+
+ // 6. Location-object navigate this to copyURL.
+ TRY(navigate(copy_url));
+
+ return {};
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-pathname
@@ -301,10 +374,35 @@ WebIDL::ExceptionOr Location::pathname() const
return url().serialize_path();
}
-WebIDL::ExceptionOr Location::set_pathname(String const&)
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-search
+WebIDL::ExceptionOr Location::set_pathname(String const& value)
{
- auto& vm = this->vm();
- return vm.throw_completion(JS::ErrorType::NotImplemented, "Location.pathname setter");
+ // 1. If this's relevant Document is null, then return.
+ auto const relevant_document = this->relevant_document();
+ if (!relevant_document)
+ return {};
+
+ // 2. If this's relevant Document's origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
+ if (!relevant_document->origin().is_same_origin_domain(entry_settings_object().origin()))
+ return WebIDL::SecurityError::create(realm(), "Location's relevant document is not same origin-domain with the entry settings object's origin"_string);
+
+ // 3. Let copyURL be a copy of this's url.
+ auto copy_url = this->url();
+
+ // 4. If copyURL has an opaque path, then return.
+ if (copy_url.has_an_opaque_path())
+ return {};
+
+ // 5. Set copyURL's path to the empty list.
+ copy_url.set_paths({});
+
+ // 6. Basic URL parse the given value, with copyURL as url and path start state as state override.
+ (void)URL::Parser::basic_parse(value, {}, ©_url, URL::Parser::State::PathStart);
+
+ // 7. Location-object navigate this to copyURL.
+ TRY(navigate(copy_url));
+
+ return {};
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-search