From f1f7f68f361a5d77f3e7b8877f72c16c91e42539 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 5 Apr 2025 14:47:08 -0400 Subject: [PATCH] LibWebView: Highlight about: and data: URL schemes --- Libraries/LibWebView/URL.cpp | 25 +++++++++++++++++++------ Tests/LibWebView/TestWebViewURL.cpp | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Libraries/LibWebView/URL.cpp b/Libraries/LibWebView/URL.cpp index d4c110c4410..a7e135c6847 100644 --- a/Libraries/LibWebView/URL.cpp +++ b/Libraries/LibWebView/URL.cpp @@ -89,6 +89,14 @@ Vector sanitize_urls(ReadonlySpan raw_urls, URL::URL const return sanitized_urls; } +static URLParts break_internal_url_into_parts(URL::URL const& url, StringView url_string) +{ + auto scheme = url_string.substring_view(0, url.scheme().bytes_as_string_view().length() + ":"sv.length()); + auto path = url_string.substring_view(scheme.length()); + + return URLParts { scheme, path, {} }; +} + static URLParts break_file_url_into_parts(URL::URL const& url, StringView url_string) { auto scheme = url_string.substring_view(0, url.scheme().bytes_as_string_view().length() + "://"sv.length()); @@ -141,13 +149,18 @@ Optional break_url_into_parts(StringView url_string) if (!url_string.starts_with(scheme)) return {}; - if (!url_string.substring_view(scheme_length).starts_with("://"sv)) - return {}; - if (url.scheme() == "file"sv) - return break_file_url_into_parts(url, url_string); - if (url.scheme().is_one_of("http"sv, "https"sv)) - return break_web_url_into_parts(url, url_string); + auto schemeless_url = url_string.substring_view(scheme_length); + + if (schemeless_url.starts_with("://"sv)) { + if (url.scheme() == "file"sv) + return break_file_url_into_parts(url, url_string); + if (url.scheme().is_one_of("http"sv, "https"sv)) + return break_web_url_into_parts(url, url_string); + } else if (schemeless_url.starts_with(':')) { + if (url.scheme().is_one_of("about"sv, "data"sv)) + return break_internal_url_into_parts(url, url_string); + } return {}; } diff --git a/Tests/LibWebView/TestWebViewURL.cpp b/Tests/LibWebView/TestWebViewURL.cpp index c2924d5c472..0e331a8d67c 100644 --- a/Tests/LibWebView/TestWebViewURL.cpp +++ b/Tests/LibWebView/TestWebViewURL.cpp @@ -77,6 +77,17 @@ TEST_CASE(invalid_url) EXPECT(!WebView::break_url_into_parts("https:"sv).has_value()); EXPECT(!WebView::break_url_into_parts("https:/"sv).has_value()); EXPECT(!WebView::break_url_into_parts("https://"sv).has_value()); + + EXPECT(!WebView::break_url_into_parts("a"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("ab"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("abo"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("abou"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("about"sv).has_value()); + + EXPECT(!WebView::break_url_into_parts("d"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("da"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("dat"sv).has_value()); + EXPECT(!WebView::break_url_into_parts("data"sv).has_value()); } TEST_CASE(file_url) @@ -112,6 +123,12 @@ TEST_CASE(http_url) TEST_CASE(about_url) { + compare_url_parts("about:"sv, { "about:"sv, {}, {} }); + compare_url_parts("about:a"sv, { "about:"sv, "a"sv, {} }); + compare_url_parts("about:ab"sv, { "about:"sv, "ab"sv, {} }); + compare_url_parts("about:abc"sv, { "about:"sv, "abc"sv, {} }); + compare_url_parts("about:abc/def"sv, { "about:"sv, "abc/def"sv, {} }); + EXPECT(!is_sanitized_url_the_same("about"sv)); EXPECT(!is_sanitized_url_the_same("about blabla:"sv)); EXPECT(!is_sanitized_url_the_same("blabla about:"sv)); @@ -122,6 +139,12 @@ TEST_CASE(about_url) TEST_CASE(data_url) { + compare_url_parts("data:"sv, { "data:"sv, {}, {} }); + compare_url_parts("data:a"sv, { "data:"sv, "a"sv, {} }); + compare_url_parts("data:ab"sv, { "data:"sv, "ab"sv, {} }); + compare_url_parts("data:abc"sv, { "data:"sv, "abc"sv, {} }); + compare_url_parts("data:abc/def"sv, { "data:"sv, "abc/def"sv, {} }); + EXPECT(is_sanitized_url_the_same("data:text/html"sv)); EXPECT(!is_sanitized_url_the_same("data text/html"sv));