diff --git a/Libraries/LibCore/MimeData.cpp b/Libraries/LibCore/MimeData.cpp index 2db56794280..1e3ac562b80 100644 --- a/Libraries/LibCore/MimeData.cpp +++ b/Libraries/LibCore/MimeData.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Core { @@ -18,7 +19,8 @@ Vector MimeData::urls() const return {}; Vector urls; for (auto& line : StringView(it->value).split_view('\n')) { - urls.append(URL::URL(line)); + if (auto maybe_url = URL::Parser::basic_parse(line); maybe_url.has_value()) + urls.append(maybe_url.release_value()); } return urls; } diff --git a/Libraries/LibURL/URL.cpp b/Libraries/LibURL/URL.cpp index 4debaa956f4..fea438d9a13 100644 --- a/Libraries/LibURL/URL.cpp +++ b/Libraries/LibURL/URL.cpp @@ -193,9 +193,9 @@ URL create_with_file_scheme(ByteString const& path, ByteString const& fragment, URL create_with_url_or_path(ByteString const& url_or_path) { - URL url = url_or_path; - if (url.is_valid()) - return url; + auto url = Parser::basic_parse(url_or_path); + if (url.has_value()) + return url.release_value(); ByteString path = LexicalPath::canonicalized_path(url_or_path); return create_with_file_scheme(path); diff --git a/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Libraries/LibWeb/CSS/CSSStyleSheet.cpp index 25fdb128ce5..663d42bae9f 100644 --- a/Libraries/LibWeb/CSS/CSSStyleSheet.cpp +++ b/Libraries/LibWeb/CSS/CSSStyleSheet.cpp @@ -6,6 +6,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -42,10 +43,10 @@ WebIDL::ExceptionOr> CSSStyleSheet::construct_impl(JS::Re if (options.has_value() && options->base_url.has_value()) { Optional sheet_location_url; if (sheet->location().has_value()) - sheet_location_url = sheet->location().release_value(); + sheet_location_url = URL::Parser::basic_parse(sheet->location().release_value()); // AD-HOC: This isn't explicitly mentioned in the specification, but multiple modern browsers do this. - Optional url = sheet->location().has_value() ? sheet_location_url->complete_url(options->base_url.value()) : options->base_url.value(); + Optional url = sheet->location().has_value() ? sheet_location_url->complete_url(options->base_url.value()) : URL::Parser::basic_parse(options->base_url.value()); if (!url.has_value()) return WebIDL::NotAllowedError::create(realm, "Constructed style sheets must have a valid base URL"_string); diff --git a/Libraries/LibWeb/HTML/Scripting/ImportMap.cpp b/Libraries/LibWeb/HTML/Scripting/ImportMap.cpp index 6347af808df..589846e8015 100644 --- a/Libraries/LibWeb/HTML/Scripting/ImportMap.cpp +++ b/Libraries/LibWeb/HTML/Scripting/ImportMap.cpp @@ -213,10 +213,8 @@ WebIDL::ExceptionOr> sort_and_normalise_sc } // 4. Let normalizedScopePrefix be the serialization of scopePrefixURL. - auto normalised_scope_prefix = scope_prefix_url->serialize(); - // 5. Set normalized[normalizedScopePrefix] to the result of sorting and normalizing a module specifier map given potentialSpecifierMap and baseURL. - normalised.set(normalised_scope_prefix, TRY(sort_and_normalise_module_specifier_map(realm, potential_specifier_map.as_object(), base_url))); + normalised.set(scope_prefix_url.value(), TRY(sort_and_normalise_module_specifier_map(realm, potential_specifier_map.as_object(), base_url))); } // 3. Return the result of sorting in descending order normalized, with an entry a being less than an entry b if a's key is code unit less than b's key. @@ -316,7 +314,7 @@ void merge_existing_and_new_import_maps(Window& global, ImportMap& new_import_ma // 1. For each record of global's resolved module set: for (auto const& record : global.resolved_module_set()) { // 1. If scopePrefix is record's serialized base URL, or if scopePrefix ends with U+002F (/) and scopePrefix is a code unit prefix of record's serialized base URL, then: - if (scope_prefix == record.serialized_base_url || (scope_prefix.to_string().ends_with('/') && record.serialized_base_url.has_value() && Infra::is_code_unit_prefix(scope_prefix.to_string(), *record.serialized_base_url))) { + if (scope_prefix.to_string() == record.serialized_base_url || (scope_prefix.to_string().ends_with('/') && record.serialized_base_url.has_value() && Infra::is_code_unit_prefix(scope_prefix.to_string(), *record.serialized_base_url))) { // 1. For each specifierKey → resolutionResult of scopeImports: scope_imports.remove_all_matching([&](ByteString const& specifier_key, Optional const&) { // 1. If specifierKey is record's specifier, or if all of the following conditions are true: diff --git a/Libraries/LibWeb/Loader/ProxyMappings.cpp b/Libraries/LibWeb/Loader/ProxyMappings.cpp index 945f49d1bda..30270a70be5 100644 --- a/Libraries/LibWeb/Loader/ProxyMappings.cpp +++ b/Libraries/LibWeb/Loader/ProxyMappings.cpp @@ -5,6 +5,7 @@ */ #include "ProxyMappings.h" +#include Web::ProxyMappings& Web::ProxyMappings::the() { @@ -17,7 +18,12 @@ Core::ProxyData Web::ProxyMappings::proxy_for_url(URL::URL const& url) const auto url_string = url.to_byte_string(); for (auto& it : m_mappings) { if (url_string.matches(it.key)) { - auto result = Core::ProxyData::parse_url(m_proxies[it.value]); + auto maybe_url = URL::Parser::basic_parse(m_proxies[it.value]); + if (!maybe_url.has_value()) { + dbgln("Failed to parse proxy URL: {}", m_proxies[it.value]); + continue; + } + auto result = Core::ProxyData::parse_url(maybe_url.value()); if (result.is_error()) { dbgln("Failed to parse proxy URL: {}", m_proxies[it.value]); continue; diff --git a/Libraries/LibWeb/PermissionsPolicy/AutoplayAllowlist.cpp b/Libraries/LibWeb/PermissionsPolicy/AutoplayAllowlist.cpp index d186c0f6d73..06cf43ab5ef 100644 --- a/Libraries/LibWeb/PermissionsPolicy/AutoplayAllowlist.cpp +++ b/Libraries/LibWeb/PermissionsPolicy/AutoplayAllowlist.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -73,16 +74,16 @@ ErrorOr AutoplayAllowlist::enable_for_origins(ReadonlySpan origins TRY(allowlist.try_ensure_capacity(origins.size())); for (auto const& origin : origins) { - URL::URL url { origin }; + auto url = URL::Parser::basic_parse(origin); - if (!url.is_valid()) - url = TRY(String::formatted("https://{}", origin)); - if (!url.is_valid()) { + if (!url.has_value()) + url = URL::Parser::basic_parse(TRY(String::formatted("https://{}", origin))); + if (!url.has_value()) { dbgln("Invalid origin for autoplay allowlist: {}", origin); continue; } - TRY(allowlist.try_append(url.origin())); + TRY(allowlist.try_append(url->origin())); } return {}; diff --git a/Libraries/LibWeb/WebDriver/Proxy.cpp b/Libraries/LibWeb/WebDriver/Proxy.cpp index 9bf1bec6544..6f10bc6da3f 100644 --- a/Libraries/LibWeb/WebDriver/Proxy.cpp +++ b/Libraries/LibWeb/WebDriver/Proxy.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -45,7 +46,7 @@ static ErrorOr validate_proxy_item(StringView key, JsonValue const& if (key == "proxyAutoconfigUrl"sv) { if (!value.is_string()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a string"sv); - if (URL::URL url { value.as_string() }; !url.is_valid()) + if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a valid URL"sv); return {}; } @@ -53,7 +54,7 @@ static ErrorOr validate_proxy_item(StringView key, JsonValue const& if (key == "ftpProxy"sv) { if (!value.is_string()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'ftpProxy' must be a string"sv); - if (URL::URL url { value.as_string() }; !url.is_valid() || url.scheme() != "ftp"sv) + if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "ftp"sv) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'ftpProxy' must be a valid FTP URL"sv); return {}; } @@ -61,7 +62,7 @@ static ErrorOr validate_proxy_item(StringView key, JsonValue const& if (key == "httpProxy"sv) { if (!value.is_string()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'httpProxy' must be a string"sv); - if (URL::URL url { value.as_string() }; !url.is_valid() || url.scheme() != "http"sv) + if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "http"sv) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'httpProxy' must be a valid HTTP URL"sv); return {}; } @@ -82,7 +83,7 @@ static ErrorOr validate_proxy_item(StringView key, JsonValue const& if (key == "sslProxy"sv) { if (!value.is_string()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'sslProxy' must be a string"sv); - if (URL::URL url { value.as_string() }; !url.is_valid() || url.scheme() != "https"sv) + if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "https"sv) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'sslProxy' must be a valid HTTPS URL"sv); return {}; } @@ -90,7 +91,7 @@ static ErrorOr validate_proxy_item(StringView key, JsonValue const& if (key == "socksProxy"sv) { if (!value.is_string()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a string"sv); - if (URL::URL url { value.as_string() }; !url.is_valid()) + if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value()) return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a valid URL"sv); return {}; } diff --git a/Libraries/LibWebView/URL.cpp b/Libraries/LibWebView/URL.cpp index 1128f48d335..34042af4464 100644 --- a/Libraries/LibWebView/URL.cpp +++ b/Libraries/LibWebView/URL.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace WebView { @@ -25,7 +26,7 @@ Optional sanitize_url(StringView url, Optional search_engi if (!search_engine.has_value()) return {}; - return MUST(String::formatted(*search_engine, URL::percent_decode(url))); + return URL::Parser::basic_parse(MUST(String::formatted(*search_engine, URL::percent_decode(url)))); }; ByteString url_with_scheme = url; diff --git a/Services/WebContent/WebDriverConnection.cpp b/Services/WebContent/WebDriverConnection.cpp index 543de6368f1..0c2bfd8d3b3 100644 --- a/Services/WebContent/WebDriverConnection.cpp +++ b/Services/WebContent/WebDriverConnection.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -289,7 +290,7 @@ Messages::WebDriverClient::NavigateToResponse WebDriverConnection::navigate_to(J // 2. Let url be the result of getting the property url from the parameters argument. if (!payload.is_object() || !payload.as_object().has_string("url"sv)) return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload doesn't have a string `url`"sv); - URL::URL url(payload.as_object().get_byte_string("url"sv).value()); + auto url = URL::Parser::basic_parse(payload.as_object().get_byte_string("url"sv).value()); // FIXME: 3. If url is not an absolute URL or is not an absolute URL with fragment or not a local scheme, return error with error code invalid argument. @@ -302,7 +303,7 @@ Messages::WebDriverClient::NavigateToResponse WebDriverConnection::navigate_to(J // FIXME: a. If timer has not been started, start a timer. If this algorithm has not completed before timer reaches the session’s session page load timeout in milliseconds, return an error with error code timeout. // 7. Navigate the current top-level browsing context to url. - current_top_level_browsing_context()->page().load(url); + current_top_level_browsing_context()->page().load(url.value()); auto navigation_complete = GC::create_function(current_top_level_browsing_context()->heap(), [this](Web::WebDriver::Response result) { // 9. Set the current browsing context with the current top-level browsing context. @@ -317,7 +318,7 @@ Messages::WebDriverClient::NavigateToResponse WebDriverConnection::navigate_to(J // AD-HOC: We wait for the navigation to complete regardless of whether the current URL differs from the provided // URL. Even if they're the same, the navigation queues a tasks that we must await, otherwise subsequent // endpoint invocations will attempt to operate on the wrong page. - if (url.is_special() && url.scheme() != "file"sv) { + if (url->is_special() && url->scheme() != "file"sv) { // a. Try to wait for navigation to complete. wait_for_navigation_to_complete(navigation_complete); diff --git a/Tests/LibURL/TestURL.cpp b/Tests/LibURL/TestURL.cpp index ba4f13b7600..5aee815492f 100644 --- a/Tests/LibURL/TestURL.cpp +++ b/Tests/LibURL/TestURL.cpp @@ -18,254 +18,254 @@ TEST_CASE(construct) TEST_CASE(basic) { { - URL::URL url("http://www.serenityos.org"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 80); - EXPECT_EQ(url.serialize_path(), "/"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("http://www.serenityos.org"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 80); + EXPECT_EQ(url->serialize_path(), "/"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } { - URL::URL url("https://www.serenityos.org/index.html"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "https"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 443); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("https://www.serenityos.org/index.html"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "https"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 443); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } { - URL::URL url("https://www.serenityos.org1/index.html"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "https"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org1"); - EXPECT_EQ(url.port_or_default(), 443); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("https://www.serenityos.org1/index.html"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "https"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org1"); + EXPECT_EQ(url->port_or_default(), 443); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } { - URL::URL url("https://localhost:1234/~anon/test/page.html"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "https"); - EXPECT_EQ(url.serialized_host(), "localhost"); - EXPECT_EQ(url.port_or_default(), 1234); - EXPECT_EQ(url.serialize_path(), "/~anon/test/page.html"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("https://localhost:1234/~anon/test/page.html"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "https"); + EXPECT_EQ(url->serialized_host(), "localhost"); + EXPECT_EQ(url->port_or_default(), 1234); + EXPECT_EQ(url->serialize_path(), "/~anon/test/page.html"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } { - URL::URL url("http://www.serenityos.org/index.html?#"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 80); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT_EQ(url.query(), ""); - EXPECT_EQ(url.fragment(), ""); + auto url = URL::Parser::basic_parse("http://www.serenityos.org/index.html?#"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 80); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT_EQ(url->query(), ""); + EXPECT_EQ(url->fragment(), ""); } { - URL::URL url("http://www.serenityos.org/index.html?foo=1&bar=2"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 80); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT_EQ(url.query(), "foo=1&bar=2"); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("http://www.serenityos.org/index.html?foo=1&bar=2"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 80); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT_EQ(url->query(), "foo=1&bar=2"); + EXPECT(!url->fragment().has_value()); } { - URL::URL url("http://www.serenityos.org/index.html#fragment"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 80); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT(!url.query().has_value()); - EXPECT_EQ(url.fragment(), "fragment"); + auto url = URL::Parser::basic_parse("http://www.serenityos.org/index.html#fragment"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 80); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT(!url->query().has_value()); + EXPECT_EQ(url->fragment(), "fragment"); } { - URL::URL url("http://www.serenityos.org/index.html?foo=1&bar=2&baz=/?#frag/ment?test#"sv); - EXPECT_EQ(url.is_valid(), true); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "www.serenityos.org"); - EXPECT_EQ(url.port_or_default(), 80); - EXPECT_EQ(url.serialize_path(), "/index.html"); - EXPECT_EQ(url.query(), "foo=1&bar=2&baz=/?"); - EXPECT_EQ(url.fragment(), "frag/ment?test#"); + auto url = URL::Parser::basic_parse("http://www.serenityos.org/index.html?foo=1&bar=2&baz=/?#frag/ment?test#"sv); + EXPECT_EQ(url.has_value(), true); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "www.serenityos.org"); + EXPECT_EQ(url->port_or_default(), 80); + EXPECT_EQ(url->serialize_path(), "/index.html"); + EXPECT_EQ(url->query(), "foo=1&bar=2&baz=/?"); + EXPECT_EQ(url->fragment(), "frag/ment?test#"); } } TEST_CASE(some_bad_urls) { - EXPECT_EQ(URL::URL("http//serenityos.org"sv).is_valid(), false); - EXPECT_EQ(URL::URL("serenityos.org"sv).is_valid(), false); - EXPECT_EQ(URL::URL("://serenityos.org"sv).is_valid(), false); - EXPECT_EQ(URL::URL("://:80"sv).is_valid(), false); - EXPECT_EQ(URL::URL("http://serenityos.org:80:80/"sv).is_valid(), false); - EXPECT_EQ(URL::URL("http://serenityos.org:80:80"sv).is_valid(), false); - EXPECT_EQ(URL::URL("http://serenityos.org:abc"sv).is_valid(), false); - EXPECT_EQ(URL::URL("http://serenityos.org:abc:80"sv).is_valid(), false); - EXPECT_EQ(URL::URL("http://serenityos.org:abc:80/"sv).is_valid(), false); + EXPECT_EQ(URL::Parser::basic_parse("http//serenityos.org"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("serenityos.org"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("://serenityos.org"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("://:80"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://serenityos.org:80:80/"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://serenityos.org:80:80"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://serenityos.org:abc"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://serenityos.org:abc:80"sv).has_value(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://serenityos.org:abc:80/"sv).has_value(), false); } TEST_CASE(serialization) { - EXPECT_EQ(URL::URL("http://www.serenityos.org/"sv).serialize(), "http://www.serenityos.org/"); - EXPECT_EQ(URL::URL("http://www.serenityos.org:0/"sv).serialize(), "http://www.serenityos.org:0/"); - EXPECT_EQ(URL::URL("http://www.serenityos.org:80/"sv).serialize(), "http://www.serenityos.org/"); - EXPECT_EQ(URL::URL("http://www.serenityos.org:81/"sv).serialize(), "http://www.serenityos.org:81/"); - EXPECT_EQ(URL::URL("https://www.serenityos.org:443/foo/bar.html?query#fragment"sv).serialize(), "https://www.serenityos.org/foo/bar.html?query#fragment"); + EXPECT_EQ(URL::Parser::basic_parse("http://www.serenityos.org/"sv)->serialize(), "http://www.serenityos.org/"); + EXPECT_EQ(URL::Parser::basic_parse("http://www.serenityos.org:0/"sv)->serialize(), "http://www.serenityos.org:0/"); + EXPECT_EQ(URL::Parser::basic_parse("http://www.serenityos.org:80/"sv)->serialize(), "http://www.serenityos.org/"); + EXPECT_EQ(URL::Parser::basic_parse("http://www.serenityos.org:81/"sv)->serialize(), "http://www.serenityos.org:81/"); + EXPECT_EQ(URL::Parser::basic_parse("https://www.serenityos.org:443/foo/bar.html?query#fragment"sv)->serialize(), "https://www.serenityos.org/foo/bar.html?query#fragment"); } TEST_CASE(file_url_with_hostname) { - URL::URL url("file://courage/my/file"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialized_host(), "courage"); - EXPECT_EQ(url.port_or_default(), 0); - EXPECT_EQ(url.serialize_path(), "/my/file"); - EXPECT_EQ(url.serialize(), "file://courage/my/file"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("file://courage/my/file"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialized_host(), "courage"); + EXPECT_EQ(url->port_or_default(), 0); + EXPECT_EQ(url->serialize_path(), "/my/file"); + EXPECT_EQ(url->serialize(), "file://courage/my/file"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } TEST_CASE(file_url_with_localhost) { - URL::URL url("file://localhost/my/file"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialized_host(), ""); - EXPECT_EQ(url.serialize_path(), "/my/file"); - EXPECT_EQ(url.serialize(), "file:///my/file"); + auto url = URL::Parser::basic_parse("file://localhost/my/file"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialized_host(), ""); + EXPECT_EQ(url->serialize_path(), "/my/file"); + EXPECT_EQ(url->serialize(), "file:///my/file"); } TEST_CASE(file_url_without_hostname) { - URL::URL url("file:///my/file"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialized_host(), ""); - EXPECT_EQ(url.serialize_path(), "/my/file"); - EXPECT_EQ(url.serialize(), "file:///my/file"); + auto url = URL::Parser::basic_parse("file:///my/file"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialized_host(), ""); + EXPECT_EQ(url->serialize_path(), "/my/file"); + EXPECT_EQ(url->serialize(), "file:///my/file"); } TEST_CASE(file_url_with_encoded_characters) { - URL::URL url("file:///my/file/test%23file.txt"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialize_path(), "/my/file/test%23file.txt"); - EXPECT_EQ(URL::percent_decode(url.serialize_path()), "/my/file/test#file.txt"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("file:///my/file/test%23file.txt"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialize_path(), "/my/file/test%23file.txt"); + EXPECT_EQ(URL::percent_decode(url->serialize_path()), "/my/file/test#file.txt"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } TEST_CASE(file_url_with_fragment) { - URL::URL url("file:///my/file#fragment"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialize_path(), "/my/file"); - EXPECT(!url.query().has_value()); - EXPECT_EQ(url.fragment(), "fragment"); + auto url = URL::Parser::basic_parse("file:///my/file#fragment"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialize_path(), "/my/file"); + EXPECT(!url->query().has_value()); + EXPECT_EQ(url->fragment(), "fragment"); } TEST_CASE(file_url_with_root_path) { - URL::URL url("file:///"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "file"); - EXPECT_EQ(url.serialize_path(), "/"); + auto url = URL::Parser::basic_parse("file:///"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "file"); + EXPECT_EQ(url->serialize_path(), "/"); } TEST_CASE(file_url_serialization) { - EXPECT_EQ(URL::URL("file://courage/my/file"sv).serialize(), "file://courage/my/file"); - EXPECT_EQ(URL::URL("file://localhost/my/file"sv).serialize(), "file:///my/file"); - EXPECT_EQ(URL::URL("file:///my/file"sv).serialize(), "file:///my/file"); - EXPECT_EQ(URL::URL("file:///my/directory/"sv).serialize(), "file:///my/directory/"); - EXPECT_EQ(URL::URL("file:///my/file%23test"sv).serialize(), "file:///my/file%23test"); - EXPECT_EQ(URL::URL("file:///my/file#fragment"sv).serialize(), "file:///my/file#fragment"); + EXPECT_EQ(URL::Parser::basic_parse("file://courage/my/file"sv)->serialize(), "file://courage/my/file"); + EXPECT_EQ(URL::Parser::basic_parse("file://localhost/my/file"sv)->serialize(), "file:///my/file"); + EXPECT_EQ(URL::Parser::basic_parse("file:///my/file"sv)->serialize(), "file:///my/file"); + EXPECT_EQ(URL::Parser::basic_parse("file:///my/directory/"sv)->serialize(), "file:///my/directory/"); + EXPECT_EQ(URL::Parser::basic_parse("file:///my/file%23test"sv)->serialize(), "file:///my/file%23test"); + EXPECT_EQ(URL::Parser::basic_parse("file:///my/file#fragment"sv)->serialize(), "file:///my/file#fragment"); } TEST_CASE(file_url_relative) { - EXPECT_EQ(URL::URL("https://vkoskiv.com/index.html"sv).complete_url("/static/foo.js"sv)->serialize(), "https://vkoskiv.com/static/foo.js"); - EXPECT_EQ(URL::URL("file:///home/vkoskiv/test/index.html"sv).complete_url("/static/foo.js"sv)->serialize(), "file:///static/foo.js"); - EXPECT_EQ(URL::URL("https://vkoskiv.com/index.html"sv).complete_url("static/foo.js"sv)->serialize(), "https://vkoskiv.com/static/foo.js"); - EXPECT_EQ(URL::URL("file:///home/vkoskiv/test/index.html"sv).complete_url("static/foo.js"sv)->serialize(), "file:///home/vkoskiv/test/static/foo.js"); + EXPECT_EQ(URL::Parser::basic_parse("https://vkoskiv.com/index.html"sv)->complete_url("/static/foo.js"sv)->serialize(), "https://vkoskiv.com/static/foo.js"); + EXPECT_EQ(URL::Parser::basic_parse("file:///home/vkoskiv/test/index.html"sv)->complete_url("/static/foo.js"sv)->serialize(), "file:///static/foo.js"); + EXPECT_EQ(URL::Parser::basic_parse("https://vkoskiv.com/index.html"sv)->complete_url("static/foo.js"sv)->serialize(), "https://vkoskiv.com/static/foo.js"); + EXPECT_EQ(URL::Parser::basic_parse("file:///home/vkoskiv/test/index.html"sv)->complete_url("static/foo.js"sv)->serialize(), "file:///home/vkoskiv/test/static/foo.js"); } TEST_CASE(about_url) { - URL::URL url("about:blank"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "about"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize_path(), "blank"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); - EXPECT_EQ(url.serialize(), "about:blank"); + auto url = URL::Parser::basic_parse("about:blank"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "about"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize_path(), "blank"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); + EXPECT_EQ(url->serialize(), "about:blank"); } TEST_CASE(mailto_url) { - URL::URL url("mailto:mail@example.com"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "mailto"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.port_or_default(), 0); - EXPECT_EQ(url.path_segment_count(), 1u); - EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); - EXPECT_EQ(url.serialize(), "mailto:mail@example.com"); + auto url = URL::Parser::basic_parse("mailto:mail@example.com"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "mailto"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->port_or_default(), 0); + EXPECT_EQ(url->path_segment_count(), 1u); + EXPECT_EQ(url->path_segment_at_index(0), "mail@example.com"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); + EXPECT_EQ(url->serialize(), "mailto:mail@example.com"); } TEST_CASE(mailto_url_with_subject) { - URL::URL url("mailto:mail@example.com?subject=test"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "mailto"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.port_or_default(), 0); - EXPECT_EQ(url.path_segment_count(), 1u); - EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com"); - EXPECT_EQ(url.query(), "subject=test"); - EXPECT(!url.fragment().has_value()); - EXPECT_EQ(url.serialize(), "mailto:mail@example.com?subject=test"); + auto url = URL::Parser::basic_parse("mailto:mail@example.com?subject=test"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "mailto"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->port_or_default(), 0); + EXPECT_EQ(url->path_segment_count(), 1u); + EXPECT_EQ(url->path_segment_at_index(0), "mail@example.com"); + EXPECT_EQ(url->query(), "subject=test"); + EXPECT(!url->fragment().has_value()); + EXPECT_EQ(url->serialize(), "mailto:mail@example.com?subject=test"); } TEST_CASE(trailing_slash_with_complete_url) { - EXPECT_EQ(URL::URL("http://a/b/"sv).complete_url("c/"sv)->serialize(), "http://a/b/c/"); - EXPECT_EQ(URL::URL("http://a/b/"sv).complete_url("c"sv)->serialize(), "http://a/b/c"); - EXPECT_EQ(URL::URL("http://a/b"sv).complete_url("c/"sv)->serialize(), "http://a/c/"); - EXPECT_EQ(URL::URL("http://a/b"sv).complete_url("c"sv)->serialize(), "http://a/c"); + EXPECT_EQ(URL::Parser::basic_parse("http://a/b/"sv)->complete_url("c/"sv)->serialize(), "http://a/b/c/"); + EXPECT_EQ(URL::Parser::basic_parse("http://a/b/"sv)->complete_url("c"sv)->serialize(), "http://a/b/c"); + EXPECT_EQ(URL::Parser::basic_parse("http://a/b"sv)->complete_url("c/"sv)->serialize(), "http://a/c/"); + EXPECT_EQ(URL::Parser::basic_parse("http://a/b"sv)->complete_url("c"sv)->serialize(), "http://a/c"); } TEST_CASE(trailing_port) { - URL::URL url("http://example.com:8086"sv); - EXPECT_EQ(url.port_or_default(), 8086); + auto url = URL::Parser::basic_parse("http://example.com:8086"sv); + EXPECT_EQ(url->port_or_default(), 8086); } TEST_CASE(port_overflow) { - EXPECT_EQ(URL::URL("http://example.com:123456789/"sv).is_valid(), false); + EXPECT_EQ(URL::Parser::basic_parse("http://example.com:123456789/"sv).has_value(), false); } TEST_CASE(equality) { - EXPECT(URL::URL("http://serenityos.org"sv).equals("http://serenityos.org#test"sv, URL::ExcludeFragment::Yes)); - EXPECT_EQ(URL::URL("http://example.com/index.html"sv), URL::URL("http://ex%61mple.com/index.html"sv)); - EXPECT_EQ(URL::URL("file:///my/file"sv), URL::URL("file://localhost/my/file"sv)); - EXPECT_NE(URL::URL("http://serenityos.org/index.html"sv), URL::URL("http://serenityos.org/test.html"sv)); + EXPECT(URL::Parser::basic_parse("http://serenityos.org"sv)->equals(URL::Parser::basic_parse("http://serenityos.org#test"sv).value(), URL::ExcludeFragment::Yes)); + EXPECT_EQ(URL::Parser::basic_parse("http://example.com/index.html"sv), URL::Parser::basic_parse("http://ex%61mple.com/index.html"sv)); + EXPECT_EQ(URL::Parser::basic_parse("file:///my/file"sv), URL::Parser::basic_parse("file://localhost/my/file"sv)); + EXPECT_NE(URL::Parser::basic_parse("http://serenityos.org/index.html"sv), URL::Parser::basic_parse("http://serenityos.org/test.html"sv)); } TEST_CASE(create_with_file_scheme) @@ -290,14 +290,14 @@ TEST_CASE(create_with_file_scheme) EXPECT_EQ(url.path_segment_at_index(2), ""); EXPECT_EQ(url.serialize_path(), "/home/anon/"); - url = URL::URL("file:///home/anon/"sv); + url = URL::Parser::basic_parse("file:///home/anon/"sv).value(); EXPECT_EQ(url.serialize_path(), "/home/anon/"); } TEST_CASE(complete_url) { - URL::URL base_url("http://serenityos.org/index.html#fragment"sv); - auto url = base_url.complete_url("test.html"sv); + auto base_url = URL::Parser::basic_parse("http://serenityos.org/index.html#fragment"sv); + auto url = base_url->complete_url("test.html"sv); EXPECT(url.has_value()); EXPECT_EQ(url->scheme(), "http"); EXPECT_EQ(url->serialized_host(), "serenityos.org"); @@ -305,38 +305,38 @@ TEST_CASE(complete_url) EXPECT(!url->query().has_value()); EXPECT_EQ(url->cannot_be_a_base_url(), false); - EXPECT(base_url.complete_url("../index.html#fragment"sv)->equals(base_url)); + EXPECT(base_url->complete_url("../index.html#fragment"sv)->equals(*base_url)); } TEST_CASE(leading_whitespace) { - URL::URL url { " https://foo.com/"sv }; - EXPECT(url.is_valid()); - EXPECT_EQ(url.to_byte_string(), "https://foo.com/"); + auto url = URL::Parser::basic_parse(" https://foo.com/"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->to_byte_string(), "https://foo.com/"); } TEST_CASE(trailing_whitespace) { - URL::URL url { "https://foo.com/ "sv }; - EXPECT(url.is_valid()); - EXPECT_EQ(url.to_byte_string(), "https://foo.com/"); + auto url = URL::Parser::basic_parse("https://foo.com/ "sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->to_byte_string(), "https://foo.com/"); } TEST_CASE(leading_and_trailing_whitespace) { - URL::URL url { " https://foo.com/ "sv }; - EXPECT(url.is_valid()); - EXPECT_EQ(url.to_byte_string(), "https://foo.com/"); + auto url = URL::Parser::basic_parse(" https://foo.com/ "sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->to_byte_string(), "https://foo.com/"); } TEST_CASE(unicode) { - URL::URL url { "http://example.com/_ünicöde_téxt_©"sv }; - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialize_path(), "/_%C3%BCnic%C3%B6de_t%C3%A9xt_%C2%A9"); - EXPECT_EQ(URL::percent_decode(url.serialize_path()), "/_ünicöde_téxt_©"); - EXPECT(!url.query().has_value()); - EXPECT(!url.fragment().has_value()); + auto url = URL::Parser::basic_parse("http://example.com/_ünicöde_téxt_©"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialize_path(), "/_%C3%BCnic%C3%B6de_t%C3%A9xt_%C2%A9"); + EXPECT_EQ(URL::percent_decode(url->serialize_path()), "/_ünicöde_téxt_©"); + EXPECT(!url->query().has_value()); + EXPECT(!url->fragment().has_value()); } TEST_CASE(query_with_non_ascii) @@ -377,63 +377,63 @@ TEST_CASE(fragment_with_non_ascii) TEST_CASE(complete_file_url_with_base) { - URL::URL url { "file:///home/index.html" }; - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialize_path(), "/home/index.html"); - EXPECT_EQ(url.path_segment_count(), 2u); - EXPECT_EQ(url.path_segment_at_index(0), "home"); - EXPECT_EQ(url.path_segment_at_index(1), "index.html"); + auto url = URL::Parser::basic_parse("file:///home/index.html"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialize_path(), "/home/index.html"); + EXPECT_EQ(url->path_segment_count(), 2u); + EXPECT_EQ(url->path_segment_at_index(0), "home"); + EXPECT_EQ(url->path_segment_at_index(1), "index.html"); - auto sub_url = url.complete_url("js/app.js"sv); + auto sub_url = url->complete_url("js/app.js"sv); EXPECT(sub_url.has_value()); EXPECT_EQ(sub_url->serialize_path(), "/home/js/app.js"); } TEST_CASE(empty_url_with_base_url) { - URL::URL base_url { "https://foo.com/"sv }; + auto base_url = URL::Parser::basic_parse("https://foo.com/"sv); Optional parsed_url = URL::Parser::basic_parse(""sv, base_url); EXPECT_EQ(parsed_url.has_value(), true); - EXPECT(base_url.equals(*parsed_url)); + EXPECT(base_url->equals(*parsed_url)); } TEST_CASE(google_street_view) { - constexpr auto streetview_url = "https://www.google.co.uk/maps/@53.3354159,-1.9573545,3a,75y,121.1h,75.67t/data=!3m7!1e1!3m5!1sSY8xCv17jAX4S7SRdV38hg!2e0!6shttps:%2F%2Fstreetviewpixels-pa.googleapis.com%2Fv1%2Fthumbnail%3Fpanoid%3DSY8xCv17jAX4S7SRdV38hg%26cb_client%3Dmaps_sv.tactile.gps%26w%3D203%26h%3D100%26yaw%3D188.13148%26pitch%3D0%26thumbfov%3D100!7i13312!8i6656"; - URL::URL url(streetview_url); - EXPECT_EQ(url.serialize(), streetview_url); + constexpr auto streetview_url = "https://www.google.co.uk/maps/@53.3354159,-1.9573545,3a,75y,121.1h,75.67t/data=!3m7!1e1!3m5!1sSY8xCv17jAX4S7SRdV38hg!2e0!6shttps:%2F%2Fstreetviewpixels-pa.googleapis.com%2Fv1%2Fthumbnail%3Fpanoid%3DSY8xCv17jAX4S7SRdV38hg%26cb_client%3Dmaps_sv.tactile.gps%26w%3D203%26h%3D100%26yaw%3D188.13148%26pitch%3D0%26thumbfov%3D100!7i13312!8i6656"sv; + auto url = URL::Parser::basic_parse(streetview_url); + EXPECT_EQ(url->serialize(), streetview_url); } TEST_CASE(ipv6_address) { { constexpr auto ipv6_url = "http://[::1]/index.html"sv; - URL::URL url(ipv6_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "[::1]"sv); - EXPECT_EQ(url, ipv6_url); + auto url = URL::Parser::basic_parse(ipv6_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "[::1]"sv); + EXPECT_EQ(url->to_string(), ipv6_url); } { constexpr auto ipv6_url = "http://[0:f:0:0:f:f:0:0]/index.html"sv; - URL::URL url(ipv6_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "[0:f::f:f:0:0]"sv); - EXPECT_EQ(url, ipv6_url); + auto url = URL::Parser::basic_parse(ipv6_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "[0:f::f:f:0:0]"sv); + EXPECT_EQ(url->to_string(), "http://[0:f::f:f:0:0]/index.html"sv); } { constexpr auto ipv6_url = "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html"sv; - URL::URL url(ipv6_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "[2001:db8:85a3::8a2e:370:7334]"sv); - EXPECT_EQ(url, ipv6_url); + auto url = URL::Parser::basic_parse(ipv6_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "[2001:db8:85a3::8a2e:370:7334]"sv); + EXPECT_EQ(url->to_string(), "https://[2001:db8:85a3::8a2e:370:7334]/index.html"sv); } { constexpr auto bad_ipv6_url = "https://[oops]/index.html"sv; - URL::URL url(bad_ipv6_url); - EXPECT_EQ(url.is_valid(), false); + auto url = URL::Parser::basic_parse(bad_ipv6_url); + EXPECT_EQ(url.has_value(), false); } } @@ -441,42 +441,42 @@ TEST_CASE(ipv4_address) { { constexpr auto ipv4_url = "http://127.0.0.1/index.html"sv; - URL::URL url(ipv4_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "127.0.0.1"sv); + auto url = URL::Parser::basic_parse(ipv4_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "127.0.0.1"sv); } { constexpr auto ipv4_url = "http://0x.0x.0"sv; - URL::URL url(ipv4_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "0.0.0.0"sv); + auto url = URL::Parser::basic_parse(ipv4_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "0.0.0.0"sv); } { constexpr auto bad_ipv4_url = "https://127..0.0.1"sv; - URL::URL url(bad_ipv4_url); - EXPECT(!url.is_valid()); + auto url = URL::Parser::basic_parse(bad_ipv4_url); + EXPECT(!url.has_value()); } { constexpr auto ipv4_url = "http://256"sv; - URL::URL url(ipv4_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "0.0.1.0"sv); + auto url = URL::Parser::basic_parse(ipv4_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "0.0.1.0"sv); } { constexpr auto ipv4_url = "http://888888888"sv; - URL::URL url(ipv4_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "52.251.94.56"sv); + auto url = URL::Parser::basic_parse(ipv4_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "52.251.94.56"sv); } { constexpr auto ipv4_url = "http://9111111111"sv; - URL::URL url(ipv4_url); - EXPECT(!url.is_valid()); + auto url = URL::Parser::basic_parse(ipv4_url); + EXPECT(!url.has_value()); } } @@ -484,42 +484,42 @@ TEST_CASE(username_and_password) { { constexpr auto url_with_username_and_password = "http://username:password@test.com/index.html"sv; - URL::URL url(url_with_username_and_password); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "test.com"sv); - EXPECT_EQ(url.username(), "username"sv); - EXPECT_EQ(url.password(), "password"sv); + auto url = URL::Parser::basic_parse(url_with_username_and_password); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "test.com"sv); + EXPECT_EQ(url->username(), "username"sv); + EXPECT_EQ(url->password(), "password"sv); } { constexpr auto url_with_percent_encoded_credentials = "http://username%21%24%25:password%21%24%25@test.com/index.html"sv; - URL::URL url(url_with_percent_encoded_credentials); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "test.com"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); + auto url = URL::Parser::basic_parse(url_with_percent_encoded_credentials); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "test.com"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); } { auto const& username = MUST(String::repeated('a', 50000)); auto const& url_with_long_username = MUST(String::formatted("http://{}:@test.com/index.html", username)); - URL::URL url(url_with_long_username); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "test.com"sv); - EXPECT_EQ(url.username(), username); - EXPECT(url.password().is_empty()); + auto url = URL::Parser::basic_parse(url_with_long_username); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "test.com"sv); + EXPECT_EQ(url->username(), username); + EXPECT(url->password().is_empty()); } { auto const& password = MUST(String::repeated('a', 50000)); auto const& url_with_long_password = MUST(String::formatted("http://:{}@test.com/index.html", password)); - URL::URL url(url_with_long_password); - EXPECT(url.is_valid()); - EXPECT_EQ(url.serialized_host(), "test.com"sv); - EXPECT(url.username().is_empty()); - EXPECT_EQ(url.password(), password); + auto url = URL::Parser::basic_parse(url_with_long_password); + EXPECT(url.has_value()); + EXPECT_EQ(url->serialized_host(), "test.com"sv); + EXPECT(url->username().is_empty()); + EXPECT_EQ(url->password(), password); } } @@ -527,20 +527,20 @@ TEST_CASE(ascii_only_url) { { constexpr auto upper_case_url = "HTTP://EXAMPLE.COM:80/INDEX.HTML#FRAGMENT"sv; - URL::URL url(upper_case_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "example.com"sv); - EXPECT_EQ(url.to_byte_string(), "http://example.com/INDEX.HTML#FRAGMENT"); + auto url = URL::Parser::basic_parse(upper_case_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "example.com"sv); + EXPECT_EQ(url->to_byte_string(), "http://example.com/INDEX.HTML#FRAGMENT"); } { constexpr auto mixed_case_url = "hTtP://eXaMpLe.CoM:80/iNdEx.HtMl#fRaGmEnT"sv; - URL::URL url(mixed_case_url); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "http"); - EXPECT_EQ(url.serialized_host(), "example.com"sv); - EXPECT_EQ(url.to_byte_string(), "http://example.com/iNdEx.HtMl#fRaGmEnT"); + auto url = URL::Parser::basic_parse(mixed_case_url); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "http"); + EXPECT_EQ(url->serialized_host(), "example.com"sv); + EXPECT_EQ(url->to_byte_string(), "http://example.com/iNdEx.HtMl#fRaGmEnT"); } } @@ -548,13 +548,13 @@ TEST_CASE(invalid_domain_code_points) { { constexpr auto upper_case_url = "http://example%25.com"sv; - URL::URL url(upper_case_url); - EXPECT(!url.is_valid()); + auto url = URL::Parser::basic_parse(upper_case_url); + EXPECT(!url.has_value()); } { constexpr auto mixed_case_url = "http://thing\u0007y/'"sv; - URL::URL url(mixed_case_url); - EXPECT(!url.is_valid()); + auto url = URL::Parser::basic_parse(mixed_case_url); + EXPECT(!url.has_value()); } } diff --git a/Tests/LibWeb/TestFetchURL.cpp b/Tests/LibWeb/TestFetchURL.cpp index 265fb889366..4600c8c5110 100644 --- a/Tests/LibWeb/TestFetchURL.cpp +++ b/Tests/LibWeb/TestFetchURL.cpp @@ -6,102 +6,103 @@ #include +#include #include #include TEST_CASE(data_url) { - URL::URL url("data:text/html,test"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data:text/html,test"); + auto url = URL::Parser::basic_parse("data:text/html,test"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data:text/html,test"); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/html"); EXPECT_EQ(StringView(data_url.body.bytes()), "test"sv); } TEST_CASE(data_url_default_mime_type) { - URL::URL url("data:,test"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data:,test"); + auto url = URL::Parser::basic_parse("data:,test"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data:,test"); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/plain;charset=US-ASCII"); EXPECT_EQ(StringView(data_url.body.bytes()), "test"sv); } TEST_CASE(data_url_encoded) { - URL::URL url("data:text/html,Hello%20friends%2C%0X%X0"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data:text/html,Hello%20friends%2C%0X%X0"); + auto url = URL::Parser::basic_parse("data:text/html,Hello%20friends%2C%0X%X0"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data:text/html,Hello%20friends%2C%0X%X0"); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/html"); EXPECT_EQ(StringView(data_url.body.bytes()), "Hello friends,%0X%X0"sv); } TEST_CASE(data_url_base64_encoded) { - URL::URL url("data:text/html;base64,dGVzdA=="sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data:text/html;base64,dGVzdA=="); + auto url = URL::Parser::basic_parse("data:text/html;base64,dGVzdA=="sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data:text/html;base64,dGVzdA=="); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/html"); EXPECT_EQ(StringView(data_url.body.bytes()), "test"sv); } TEST_CASE(data_url_base64_encoded_default_mime_type) { - URL::URL url("data:;base64,dGVzdA=="sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data:;base64,dGVzdA=="); + auto url = URL::Parser::basic_parse("data:;base64,dGVzdA=="sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data:;base64,dGVzdA=="); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/plain;charset=US-ASCII"); EXPECT_EQ(StringView(data_url.body.bytes()), "test"sv); } TEST_CASE(data_url_base64_encoded_with_whitespace) { - URL::URL url("data: text/html ; bAsE64 , dGVz dA== "sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); - EXPECT_EQ(url.serialize(), "data: text/html ; bAsE64 , dGVz dA=="); + auto url = URL::Parser::basic_parse("data: text/html ; bAsE64 , dGVz dA== "sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); + EXPECT_EQ(url->serialize(), "data: text/html ; bAsE64 , dGVz dA=="); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/html"); EXPECT_EQ(StringView(data_url.body.bytes()), "test"); } TEST_CASE(data_url_base64_encoded_with_inline_whitespace) { - URL::URL url("data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"sv); - EXPECT(url.is_valid()); - EXPECT_EQ(url.scheme(), "data"); - EXPECT(!url.host().has_value()); + auto url = URL::Parser::basic_parse("data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"sv); + EXPECT(url.has_value()); + EXPECT_EQ(url->scheme(), "data"); + EXPECT(!url->host().has_value()); - auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url)); + auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(*url)); EXPECT_EQ(data_url.mime_type.serialized(), "text/javascript"); EXPECT_EQ(StringView(data_url.body.bytes()), "d4 = 'four';"sv); } TEST_CASE(data_url_completed_with_fragment) { - auto url = URL::URL("data:text/plain,test"sv).complete_url("#a"sv); + auto url = URL::Parser::basic_parse("data:text/plain,test"sv)->complete_url("#a"sv); EXPECT(url.has_value()); EXPECT_EQ(url->scheme(), "data"); EXPECT_EQ(url->fragment(), "a");