diff --git a/Tests/LibURL/TestURL.cpp b/Tests/LibURL/TestURL.cpp
index 7548aa8ff3..72d9e1a99c 100644
--- a/Tests/LibURL/TestURL.cpp
+++ b/Tests/LibURL/TestURL.cpp
@@ -456,8 +456,8 @@ TEST_CASE(username_and_password)
URL::URL url(url_with_username_and_password);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
- EXPECT_EQ(MUST(url.username()), "username"sv);
- EXPECT_EQ(MUST(url.password()), "password"sv);
+ EXPECT_EQ(url.username(), "username"sv);
+ EXPECT_EQ(url.password(), "password"sv);
}
{
@@ -465,8 +465,10 @@ TEST_CASE(username_and_password)
URL::URL url(url_with_percent_encoded_credentials);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
- EXPECT_EQ(MUST(url.username()), "username!$%"sv);
- EXPECT_EQ(MUST(url.password()), "password!$%"sv);
+ EXPECT_EQ(url.username(), "username%21%24%25");
+ EXPECT_EQ(url.password(), "password%21%24%25");
+ EXPECT_EQ(URL::percent_decode(url.username()), "username!$%"sv);
+ EXPECT_EQ(URL::percent_decode(url.password()), "password!$%"sv);
}
{
@@ -475,8 +477,8 @@ TEST_CASE(username_and_password)
URL::URL url(url_with_long_username);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
- EXPECT_EQ(MUST(url.username()), username);
- EXPECT(MUST(url.password()).is_empty());
+ EXPECT_EQ(url.username(), username);
+ EXPECT(url.password().is_empty());
}
{
@@ -485,8 +487,8 @@ TEST_CASE(username_and_password)
URL::URL url(url_with_long_password);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
- EXPECT(MUST(url.username()).is_empty());
- EXPECT_EQ(MUST(url.password()), password);
+ EXPECT(url.username().is_empty());
+ EXPECT_EQ(url.password(), password);
}
}
diff --git a/Tests/LibWeb/Text/expected/HTML/link-element-username-password-percent-encoded.txt b/Tests/LibWeb/Text/expected/HTML/link-element-username-password-percent-encoded.txt
new file mode 100644
index 0000000000..a427f8e6ef
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/HTML/link-element-username-password-percent-encoded.txt
@@ -0,0 +1,2 @@
+ user%20name
+pa%40ss%3Aword
diff --git a/Tests/LibWeb/Text/expected/URL/url.txt b/Tests/LibWeb/Text/expected/URL/url.txt
index f5744299e8..391aa406b5 100644
--- a/Tests/LibWeb/Text/expected/URL/url.txt
+++ b/Tests/LibWeb/Text/expected/URL/url.txt
@@ -88,6 +88,16 @@ port => ''
pathname => '/p'
search => ''
hash => ''
+new URL('http://user%20name:pa%40ss%3Aword@www.ladybird.org', undefined)
+protocol => 'http:'
+username => 'user%20name'
+password => 'pa%40ss%3Aword'
+host => 'www.ladybird.org'
+hostname => 'www.ladybird.org'
+port => ''
+pathname => '/'
+search => ''
+hash => ''
=========================================
URL.parse('ftp://serenityos.org:21', undefined)
protocol => 'ftp:'
@@ -179,3 +189,13 @@ port => ''
pathname => '/p'
search => ''
hash => ''
+URL.parse('http://user%20name:pa%40ss%3Aword@www.ladybird.org', undefined)
+protocol => 'http:'
+username => 'user%20name'
+password => 'pa%40ss%3Aword'
+host => 'www.ladybird.org'
+hostname => 'www.ladybird.org'
+port => ''
+pathname => '/'
+search => ''
+hash => ''
diff --git a/Tests/LibWeb/Text/input/HTML/link-element-username-password-percent-encoded.html b/Tests/LibWeb/Text/input/HTML/link-element-username-password-percent-encoded.html
new file mode 100644
index 0000000000..cc726c853d
--- /dev/null
+++ b/Tests/LibWeb/Text/input/HTML/link-element-username-password-percent-encoded.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/Tests/LibWeb/Text/input/URL/url.html b/Tests/LibWeb/Text/input/URL/url.html
index 1ec4e8970e..dbb6392941 100644
--- a/Tests/LibWeb/Text/input/URL/url.html
+++ b/Tests/LibWeb/Text/input/URL/url.html
@@ -23,6 +23,7 @@
{ input: '/hello', base: 'file://friends/' },
{ input: '//d:/..', base: 'file:///C:/a/b' },
{ input: 'file://a%C2%ADb/p' },
+ { input: 'http://user%20name:pa%40ss%3Aword@www.ladybird.org' },
];
for (url of urls) {
diff --git a/Userland/Libraries/LibHTTP/HttpRequest.cpp b/Userland/Libraries/LibHTTP/HttpRequest.cpp
index 6d08b7f292..51e86f1e5c 100644
--- a/Userland/Libraries/LibHTTP/HttpRequest.cpp
+++ b/Userland/Libraries/LibHTTP/HttpRequest.cpp
@@ -271,12 +271,12 @@ Optional HttpRequest::get_http_basic_authentication_header(URL::URL cons
if (!url.includes_credentials())
return {};
StringBuilder builder;
- builder.append(url.username().release_value_but_fixme_should_propagate_errors());
+ builder.append(URL::percent_decode(url.username()));
builder.append(':');
- builder.append(url.password().release_value_but_fixme_should_propagate_errors());
+ builder.append(URL::percent_decode(url.password()));
// FIXME: change to TRY() and make method fallible
- auto token = MUST(encode_base64(MUST(builder.to_string()).bytes()));
+ auto token = MUST(encode_base64(builder.string_view().bytes()));
builder.clear();
builder.append("Basic "sv);
builder.append(token);
diff --git a/Userland/Libraries/LibURL/URL.cpp b/Userland/Libraries/LibURL/URL.cpp
index d739419764..352abcee80 100644
--- a/Userland/Libraries/LibURL/URL.cpp
+++ b/Userland/Libraries/LibURL/URL.cpp
@@ -36,16 +36,6 @@ URL URL::complete_url(StringView relative_url) const
return Parser::basic_parse(relative_url, *this);
}
-ErrorOr URL::username() const
-{
- return String::from_byte_string(percent_decode(m_data->username));
-}
-
-ErrorOr URL::password() const
-{
- return String::from_byte_string(percent_decode(m_data->password));
-}
-
ByteString URL::path_segment_at_index(size_t index) const
{
VERIFY(index < path_segment_count());
diff --git a/Userland/Libraries/LibURL/URL.h b/Userland/Libraries/LibURL/URL.h
index 1f696bc8f3..4193684ca9 100644
--- a/Userland/Libraries/LibURL/URL.h
+++ b/Userland/Libraries/LibURL/URL.h
@@ -126,8 +126,8 @@ public:
bool is_valid() const { return m_data->valid; }
String const& scheme() const { return m_data->scheme; }
- ErrorOr username() const;
- ErrorOr password() const;
+ String const& username() const { return m_data->username; }
+ String const& password() const { return m_data->password; }
Host const& host() const { return m_data->host; }
ErrorOr serialized_host() const;
ByteString basename() const;
@@ -180,9 +180,6 @@ public:
return equals(other, ExcludeFragment::No);
}
- String const& raw_username() const { return m_data->username; }
- String const& raw_password() const { return m_data->password; }
-
Optional const& blob_url_entry() const { return m_data->blob_url_entry; }
void set_blob_url_entry(Optional entry) { m_data->blob_url_entry = move(entry); }
diff --git a/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp b/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp
index 80bd62f92d..ab2bf80943 100644
--- a/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp
+++ b/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp
@@ -246,12 +246,10 @@ WebIDL::ExceptionOr DOMURL::set_protocol(String const& protocol)
}
// https://url.spec.whatwg.org/#dom-url-username
-WebIDL::ExceptionOr DOMURL::username() const
+String const& DOMURL::username() const
{
- auto& vm = realm().vm();
-
// The username getter steps are to return this’s URL’s username.
- return TRY_OR_THROW_OOM(vm, m_url.username());
+ return m_url.username();
}
// https://url.spec.whatwg.org/#ref-for-dom-url-username%E2%91%A0
@@ -266,12 +264,10 @@ void DOMURL::set_username(String const& username)
}
// https://url.spec.whatwg.org/#dom-url-password
-WebIDL::ExceptionOr DOMURL::password() const
+String const& DOMURL::password() const
{
- auto& vm = realm().vm();
-
// The password getter steps are to return this’s URL’s password.
- return TRY_OR_THROW_OOM(vm, m_url.password());
+ return m_url.password();
}
// https://url.spec.whatwg.org/#ref-for-dom-url-password%E2%91%A0
diff --git a/Userland/Libraries/LibWeb/DOMURL/DOMURL.h b/Userland/Libraries/LibWeb/DOMURL/DOMURL.h
index a122b936c9..e12f47fb64 100644
--- a/Userland/Libraries/LibWeb/DOMURL/DOMURL.h
+++ b/Userland/Libraries/LibWeb/DOMURL/DOMURL.h
@@ -40,10 +40,10 @@ public:
WebIDL::ExceptionOr protocol() const;
WebIDL::ExceptionOr set_protocol(String const&);
- WebIDL::ExceptionOr username() const;
+ String const& username() const;
void set_username(String const&);
- WebIDL::ExceptionOr password() const;
+ String const& password() const;
void set_password(String const&);
WebIDL::ExceptionOr host() const;
diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
index 94139797ef..4c3105d668 100644
--- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
+++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
@@ -1810,7 +1810,7 @@ WebIDL::ExceptionOr> http_network_or_cache_fet
// true, set authorizationValue to httpRequest’s current URL, converted to an `Authorization` value.
else if (http_request->current_url().includes_credentials() && is_authentication_fetch == IsAuthenticationFetch::Yes) {
auto const& url = http_request->current_url();
- auto payload = MUST(String::formatted("{}:{}", MUST(url.username()), MUST(url.password())));
+ auto payload = MUST(String::formatted("{}:{}", URL::percent_decode(url.username()), URL::percent_decode(url.password())));
authorization_value = TRY_OR_THROW_OOM(vm, encode_base64(payload.bytes()));
}
diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp
index 722f6890bd..e834c9b646 100644
--- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp
+++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp
@@ -41,8 +41,8 @@ bool url_matches_about_blank(URL::URL const& url)
// A URL matches about:blank if its scheme is "about", its path contains a single string "blank", its username and password are the empty string, and its host is null.
return url.scheme() == "about"sv
&& url.serialize_path() == "blank"sv
- && url.raw_username().is_empty()
- && url.raw_password().is_empty()
+ && url.username().is_empty()
+ && url.password().is_empty()
&& url.host().has();
}
@@ -53,8 +53,8 @@ bool url_matches_about_srcdoc(URL::URL const& url)
return url.scheme() == "about"sv
&& url.serialize_path() == "srcdoc"sv
&& !url.query().has_value()
- && url.raw_username().is_empty()
- && url.raw_password().is_empty()
+ && url.username().is_empty()
+ && url.password().is_empty()
&& url.host().has();
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp b/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
index 47265b608c..69bc15a1eb 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
@@ -97,7 +97,7 @@ String HTMLHyperlinkElementUtils::username() const
return String {};
// 3. Return this element's url's username.
- return m_url->username().release_value();
+ return m_url->username();
}
// https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-username
@@ -134,7 +134,7 @@ String HTMLHyperlinkElementUtils::password() const
return String {};
// 4. Return url's password.
- return url->password().release_value();
+ return url->password();
}
// https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-password
diff --git a/Userland/Libraries/LibWeb/HTML/History.cpp b/Userland/Libraries/LibWeb/HTML/History.cpp
index f9dcd889ce..b998878766 100644
--- a/Userland/Libraries/LibWeb/HTML/History.cpp
+++ b/Userland/Libraries/LibWeb/HTML/History.cpp
@@ -135,8 +135,8 @@ bool can_have_its_url_rewritten(DOM::Document const& document, URL::URL const& t
// 2. If targetURL and documentURL differ in their scheme, username, password, host, or port components,
// then return false.
if (target_url.scheme() != document_url.scheme()
- || target_url.raw_username() != document_url.raw_username()
- || target_url.raw_password() != document_url.raw_password()
+ || target_url.username() != document_url.username()
+ || target_url.password() != document_url.password()
|| target_url.host() != document_url.host()
|| target_url.port() != document_url.port())
return false;