Bug 263619 - WebKit User Agent Overrides file
Summary: WebKit User Agent Overrides file
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit Misc. (show other bugs)
Version: Safari 17
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
: 270513 (view as bug list)
Depends on:
Blocks:
 
Reported: 2023-10-24 15:30 PDT by Karl Dubost
Modified: 2024-03-05 06:49 PST (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Karl Dubost 2023-10-24 15:30:03 PDT
Time to time for resolving Web Compatibility issues it is necessary to be able to override the User Agent String both in the HTTP header `User-Agent:` and the `navigator.userAgent`.

WebKit GTK has already a mechanism for UserAgent Quirks
https://searchfox.org/wubkat/source/Source/WebCore/platform/glib/UserAgentQuirks.cpp

Firefox on iOS is also using User Agent Quirks, called customUAFor in 
https://github.com/mozilla-mobile/firefox-ios/blob/main/Shared/UserAgent.swift

* Minimum Viable Product: User Agent String for a specific domain

Some features that might be needed to think about:
* UA changes depending on the platform (Desktop, Phone, iPad, All)
* Specific Set of URLs (Regex? Targeting specific URL such as JS)
* Easy to adjust the list of User Agent Quirks, if possible out of release schedule
Comment 1 Karl Dubost 2023-10-24 15:32:03 PDT
<rdar://59289090>
Comment 2 Karl Dubost 2023-11-14 23:48:57 PST
Mozilla Firefox has an extensive mechanism for doing UA override with some patterns that are interesting to analyze. 
The UA overrides are defined in a JS file containing a variable which is an object.

Each UA override is described with 
* comment (about the issue)
* id (bugzilla id) which is used as a unique_id
* platform (one of "desktop", "android, "all")
* domain (domain related to the UA override)
* config (containing two parameters for the UA override)
  * matches (Array of patterns with a regex syntax)
  * uaTransformer (Actual transformation to apply)

The uaTransformer is using a series of function to convert the original UA into a new string. Some are very specific to Mozilla needs. 
https://github.com/mozilla-extensions/webcompat-addon/blob/main/src/lib/ua_helpers.js
* capRvTo109(originalUA)
* capVersionTo99(originalUA)
* capVersionToNumber(originalUA, cap = 120)
* getDeviceAppropriateChromeUA(config = {})
* getPrefix(originalUA)
* getWindowsUA(originalUA)
* overrideWithDeviceAppropriateChromeUA(config)

The types of modifications done on the UA are in general:
https://github.com/mozilla-extensions/webcompat-addon/blob/main/src/data/ua_overrides.js

1. Replace by a different UA
2. Change the version number of the UA
3. Add a suffix to the original UA, aka "originalUA + string"
4. Drop or replace a part of the original UA with a originalUA.replace(/pattern1/, new_string)


matches have often the form of an array of one or multiple strings
matches: [
  "*://*.example.com/*", 
  "*://*.example.com/specific/path*"
]

Some arrays have comments with specific bug numbers when the same fix applies to multiple different domains.
Comment 3 Karl Dubost 2023-11-15 00:03:17 PST
platform in the context of WebKit will be probably:

* iOS (mobile), macOS (desktop), iPadOS (aka iPad mini)
* iPad has the desktop UA, which is also the case for VisionPro.
* webapps is an interesting case by itself, aka fixing a website added as a web app, because it covers different form factors.

This to address the possibility to have UA override depending on the target.
Comment 4 Karl Dubost 2023-11-15 00:04:36 PST
@@TODO@@ Document WebKit GTK current UA Overrides. 
https://searchfox.org/wubkat/source/Source/WebCore/platform/glib/UserAgentQuirks.cpp
@@TODO@@ Document Firefox iOS current UA Overrides. 
https://github.com/mozilla-mobile/firefox-ios/blob/main/Shared/UserAgent.swift
Comment 5 Michael Catanzaro 2023-11-15 06:32:42 PST
(In reply to Karl Dubost from comment #4)
> @@TODO@@ Document WebKit GTK current UA Overrides. 
> https://searchfox.org/wubkat/source/Source/WebCore/platform/glib/
> UserAgentQuirks.cpp

It's safe to delete these once they can be expressed in whatever new configuration you plan on developing. Something like what Mozilla does would be fine (although wow! that is both more complex and more powerful than I had expected). Something like whatever Safari does is probably also fine. The current quirks are just not very smart, so basically whatever you come up with will be better than what we have now.

It will be especially nice to be able to configure the quirks at runtime.
Comment 6 Karl Dubost 2023-11-27 19:08:37 PST
This is only for discussion.

A possible structure as a series of JSON one-liner for the UA override could be

{
  "site": [ "example.org"],
  "platform": ["mac"],
  "bugId": 263619,
  "uaTransformer": { "suffix": "string" },
  "comment": "Possible comment to be used in Web Inspector console.",
  "webapp": true
}

This could be in a file where each individual line is a JSON structure in a text or binary file (to be determined). 

{ "site": …}
{ "site": …}
{ "site": …}
{ "site": …}

That makes it easy to parse quickly and act upon it. 

Pseudo schema:

* "site" is an array of matching domain name/path as string and/or regex
    "example.org"

* "platform" is an array designating which platforms the UA override applies.
  "mac", "ios", "ipados", etc.
  The list of keywords should be extensible so other platforms can add their matching requirements. The value "all" could be a magic keyword, which basically means all cases.

* "bugId" is an integer on bugs.webkit.org referring to the bug where the UA override was decided.
  (ISSUE: what about other bug trackers)

* "uaTransformer" is an object which design the type of action to do on the UA string on the argument of the function. if there is a need for more addition in the future this could be added. 
   * "suffix"  would add a space and a "string" suffix to the original UA string.
   * "replace" would replace the full original UA string by the one designated in "string"
     (ISSUE: To decide if "string is a codename referring to another object of the list of possible replacement strings or just the plain string.")
   * "regex" could be way to replace part of a string. For example:
     "uaTransformer": { "regex": "/Version\/\d+\.\d/Version/16.0"}

* "comment" is a string that could give context in the Web Inspector about the UA override, and so Web developers of a site might understand why the site behaves differently. That should associate the bugID, so they have an opportunity to comment about it. 

* "webapp: true is an additional keyword to make sure that this UA override applies only when the site has been transformed as a webapp.
Comment 7 Karl Dubost 2023-11-27 19:15:48 PST
I haven't documented yet what WebKit GTK is doing
https://searchfox.org/wubkat/source/Source/WebCore/platform/glib/UserAgentQuirks.cpp


* urlRequiresChromeBrowser
* urlRequiresFirefoxBrowser
* urlRequiresMacintoshPlatform
* urlRequiresUnbrandedUserAgent

All of these are matching on domain names, not paths.

There is a notion of "chassisType() != WTF::ChassisType::Mobile" for targeting mobile.
Comment 8 Karl Dubost 2023-11-27 19:20:37 PST
Firefox iOS has also User Agent overrides 
https://github.com/mozilla-mobile/firefox-ios/blob/main/Shared/UserAgent.swift

the rules are slightly more complex than WebKit GTK but pretty similar. 

the current matching rules are matching on domain names only.
I'm not sure all the code is used on the other hand.
Comment 9 Michael Catanzaro 2023-11-28 11:17:03 PST
(In reply to Karl Dubost from comment #6)
> This could be in a file where each individual line is a JSON structure in a
> text or binary file (to be determined). 

Text please. :) JSON is a good format, and it's text. Keep it simple. The other popular format that might work well is YAML, which is a bit easier for humans to work with than JSON. Either is fine.

For WPE/GTK, we'll probably compress the default rules and compile them into the ELF binary using GResource, so access will be fast and not require I/O by default, but also allow users to override using a file on disk if desired, say ~/.config/epiphany/ua-overrides.json. If the format is binary, then users can't easily do that.
 
> * "uaTransformer" is an object which design the type of action to do on the
> UA string on the argument of the function. if there is a need for more
> addition in the future this could be added. 
>    * "suffix"  would add a space and a "string" suffix to the original UA
> string.
>    * "replace" would replace the full original UA string by the one
> designated in "string"
>      (ISSUE: To decide if "string is a codename referring to another object
> of the list of possible replacement strings or just the plain string.")
>    * "regex" could be way to replace part of a string. For example:
>      "uaTransformer": { "regex": "/Version\/\d+\.\d/Version/16.0"}

The uaTransformer is the hard part. I suspect a suffix rule would only rarely be useful. We'll probably wind up using replace a lot, and possibly also regex. It would work best if we have predefined replacement UAs that we can somehow reference instead of copying them, e.g.:

{
  "site": [ "example.org"],
  "platform": ["mac"],
  "bugId": 263619,
  "uaTransformer": { "replace": "urlRequiresChromeBrowser" },
  "comment": "Possible comment to be used in Web Inspector console.",
  "webapp": true
}

Writing "urlRequiresChromeBrowser" or similar is surely easier than copy/pasting the same Chrome user agent again and again throughout the file. We'll likely only need a few such quirks.
Comment 10 Karl Dubost 2023-11-28 18:34:17 PST
Thanks Michael for the comments. 

I just also found out that the code for WebKit GTK has a bit of history of moving in between GTK and a more generic location then back to glib. :) 

Sep 2012: Move user agent helpers to WebCore
https://github.com/WebKit/WebKit/commit/4dd3225d58b20744b0582a2c3aec5eb72b7fb5f0
 
Jun 2014: Creation of UserAgentQuirks in UserAgentGTK (!!!)
https://github.com/WebKit/WebKit/commit/fd495e8dce1c8246b2c29b7877eb39f674eca6d3

Nov 2015: creating a specific code for UA outside of WebPageProxy for EFL ports
https://github.com/WebKit/Webkit/commit/fd285cae62e8ae22026e18dbb8a55ebe493fe0d5

Oct 2016: Move user agent quirks to cross-platform location
https://github.com/WebKit/Webkit/commit/6ede1ea5992c2108b9f4205d9fb3d131e2259cbf

Mar 2023: [GLib] Move UA quirks file to platform/glib
https://github.com/WebKit/WebKit/commit/bc8aee2a7776dc029caa77dea926181cd68d39c8
Comment 11 Michael Catanzaro 2023-11-29 09:13:00 PST
Yeah, it was designed to be cross-platform code, but after EFL was removed it was only used by WPE and GTK. Somebody complained that it was confusing for it to be in a cross-platform location.

I think we won't need that code anymore once your new solution is in place.
Comment 12 Michael Catanzaro 2024-03-05 06:48:26 PST
*** Bug 270513 has been marked as a duplicate of this bug. ***