From 1128375dff8a2b8183f33e6cee59adf6b2c84210 Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Tue, 2 Jul 2024 01:04:40 +0100 Subject: [PATCH] LibWeb: Support Gecko and WebKit navigator compatibility modes This will log a debug message when calls are made to the NavigatorIDMixin that make decisions based on the compatibility mode. --- .../Libraries/LibWeb/HTML/NavigatorID.cpp | 95 +++++++++++++++++-- Userland/Libraries/LibWeb/HTML/NavigatorID.h | 6 +- .../LibWeb/Loader/ResourceLoader.cpp | 2 +- .../Libraries/LibWeb/Loader/ResourceLoader.h | 5 + Userland/Libraries/LibWeb/Loader/UserAgent.h | 8 ++ 5 files changed, 105 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/NavigatorID.cpp b/Userland/Libraries/LibWeb/HTML/NavigatorID.cpp index 0a67784628f..919abc9ab12 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigatorID.cpp +++ b/Userland/Libraries/LibWeb/HTML/NavigatorID.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Andrew Kaster + * Copyright (c) 2024, Jamie Mansfield * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,29 +8,49 @@ #include #include #include +#include namespace Web::HTML { // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-appversion String NavigatorIDMixin::app_version() const { + auto navigator_compatibility_mode = ResourceLoader::the().navigator_compatibility_mode(); + // Must return the appropriate string that starts with "5.0 (", as follows: // Let trail be the substring of default `User-Agent` value that follows the "Mozilla/" prefix. auto user_agent_string = ResourceLoader::the().user_agent(); - auto trail = MUST(user_agent_string.substring_from_byte_offset(strlen("Mozilla/"), user_agent_string.bytes().size() - strlen("Mozilla/"))); // If the navigator compatibility mode is Chrome or WebKit - // NOTE: We are using Chrome for now. Make sure to update all APIs if you add a toggle for this. + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Chrome || navigator_compatibility_mode == NavigatorCompatibilityMode::WebKit) { + dbgln("Call to NavigatorIDMixin::app_version, using Chrome or WebKit compatibility mode"); - // Return trail. - return trail; + // Return trail. + return trail; + } // If the navigator compatibility mode is Gecko - // If trail starts with "5.0 (Windows", then return "5.0 (Windows)". - // Otherwise, return the prefix of trail up to but not including the first U+003B (;), concatenated with the - // character U+0029 RIGHT PARENTHESIS. For example, "5.0 (Macintosh)", "5.0 (Android 10)", or "5.0 (X11)". + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Gecko) { + dbgln("Call to NavigatorIDMixin::app_version, using Gecko compatibility mode"); + + // If trail starts with "5.0 (Windows", then return "5.0 (Windows)". + if (trail.starts_with_bytes("5.0 (Windows"sv, CaseSensitivity::CaseSensitive)) + return "5.0 (Windows)"_string; + + // Otherwise, return the prefix of trail up to but not including the first U+003B (;), concatenated with the + // character U+0029 RIGHT PARENTHESIS. For example, "5.0 (Macintosh)", "5.0 (Android 10)", or "5.0 (X11)". + if (auto index = trail.find_byte_offset(';'); index.has_value()) { + StringBuilder output; + output.append(MUST(trail.substring_from_byte_offset(0, *index))); + output.append(')'); + return MUST(output.to_string()); + } + return trail; + } + + VERIFY_NOT_REACHED(); } // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-platform @@ -43,6 +64,32 @@ String NavigatorIDMixin::platform() const return ResourceLoader::the().platform(); } +// https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-productsub +String NavigatorIDMixin::product_sub() const +{ + auto navigator_compatibility_mode = ResourceLoader::the().navigator_compatibility_mode(); + + // Must return the appropriate string from the following list: + + // If the navigator compatibility mode is Chrome or WebKit + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Chrome || navigator_compatibility_mode == NavigatorCompatibilityMode::WebKit) { + dbgln("Call to NavigatorIDMixin::product_sub, using Chrome or WebKit compatibility mode"); + + // The string "20030107". + return "20030107"_string; + } + + // If the navigator compatibility mode is Gecko + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Gecko) { + dbgln("Call to NavigatorIDMixin::product_sub, using Gecko compatibility mode"); + + // The string "20100101". + return "20100101"_string; + } + + VERIFY_NOT_REACHED(); +} + // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-useragent String NavigatorIDMixin::user_agent() const { @@ -50,4 +97,38 @@ String NavigatorIDMixin::user_agent() const return ResourceLoader::the().user_agent(); } +// https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-vendor +String NavigatorIDMixin::vendor() const +{ + auto navigator_compatibility_mode = ResourceLoader::the().navigator_compatibility_mode(); + + // Must return the appropriate string from the following list: + + // If the navigator compatibility mode is Chrome + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Chrome) { + dbgln("Call to NavigatorIDMixin::vendor, using Chrome compatibility mode"); + + // The string "Google Inc.". + return "Google Inc."_string; + } + + // If the navigator compatibility mode is Gecko + if (navigator_compatibility_mode == NavigatorCompatibilityMode::Gecko) { + dbgln("Call to NavigatorIDMixin::vendor, using Gecko compatibility mode"); + + // The empty string. + return ""_string; + } + + // If the navigator compatibility mode is WebKit + if (navigator_compatibility_mode == NavigatorCompatibilityMode::WebKit) { + dbgln("Call to NavigatorIDMixin::vendor, using WebKit compatibility mode"); + + // The string "Apple Computer, Inc.". + return "Apple Computer, Inc."_string; + } + + VERIFY_NOT_REACHED(); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/NavigatorID.h b/Userland/Libraries/LibWeb/HTML/NavigatorID.h index e1c23fd5b9e..5e68b704bef 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigatorID.h +++ b/Userland/Libraries/LibWeb/HTML/NavigatorID.h @@ -32,18 +32,18 @@ public: String product() const { return "Gecko"_string; } // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-productsub - String product_sub() const { return "20030107"_string; } // Compatibility mode "Chrome" + String product_sub() const; // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-useragent String user_agent() const; // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-vendor - String vendor() const { return "Google Inc."_string; } // Compatibility mode "Chrome" + String vendor() const; // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-vendorsub String vendor_sub() const { return String {}; } - // NOTE: If the navigator compatibility mode is Gecko, then the user agent must also support the following partial interface: + // FIXME: If the navigator compatibility mode is Gecko, then the user agent must also support the following partial interface: // bool taint_enabled() // ByteString oscpu() }; diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index 7c16f36f117..0e902f516eb 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -60,6 +59,7 @@ ResourceLoader::ResourceLoader(NonnullRefPtr connector) : m_connector(move(connector)) , m_user_agent(MUST(String::from_utf8(default_user_agent))) , m_platform(MUST(String::from_utf8(default_platform))) + , m_navigator_compatibility_mode(default_navigator_compatibility_mode) { } diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h index 2cda8c86ea1..43c23116a67 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace Web { @@ -99,6 +100,9 @@ public: String const& platform() const { return m_platform; } void set_platform(String platform) { m_platform = move(platform); } + NavigatorCompatibilityMode navigator_compatibility_mode() { return m_navigator_compatibility_mode; } + void set_navigator_compatibility_mode(NavigatorCompatibilityMode mode) { m_navigator_compatibility_mode = mode; } + bool enable_do_not_track() const { return m_enable_do_not_track; } void set_enable_do_not_track(bool enable) { m_enable_do_not_track = enable; } @@ -119,6 +123,7 @@ private: NonnullRefPtr m_connector; String m_user_agent; String m_platform; + NavigatorCompatibilityMode m_navigator_compatibility_mode; bool m_enable_do_not_track { false }; Optional> m_page {}; }; diff --git a/Userland/Libraries/LibWeb/Loader/UserAgent.h b/Userland/Libraries/LibWeb/Loader/UserAgent.h index ad75fd8928f..0d9fb896163 100644 --- a/Userland/Libraries/LibWeb/Loader/UserAgent.h +++ b/Userland/Libraries/LibWeb/Loader/UserAgent.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024, Jamie Mansfield * * SPDX-License-Identifier: BSD-2-Clause */ @@ -53,10 +54,17 @@ namespace Web { # error Unknown OS #endif +enum class NavigatorCompatibilityMode { + Chrome, + Gecko, + WebKit +}; + #define BROWSER_NAME "Ladybird" #define BROWSER_VERSION "1.0" constexpr auto default_user_agent = "Mozilla/5.0 (" OS_STRING "; " CPU_STRING ") " BROWSER_NAME "/" BROWSER_VERSION ""sv; constexpr auto default_platform = OS_STRING " " CPU_STRING ""sv; +constexpr auto default_navigator_compatibility_mode = NavigatorCompatibilityMode::Chrome; }