Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define how to order browser versions. #209

Open
jyasskin opened this issue Mar 12, 2021 · 6 comments
Open

Define how to order browser versions. #209

jyasskin opened this issue Mar 12, 2021 · 6 comments

Comments

@jyasskin
Copy link
Member

Servers and web pages often want to serve different content to "browser A older than version N" vs "browser A at version N or newer". Some do this by comparing strings, which leads version 100 to be treated as older than version 99. The current specification defines version as a string (and propagates that type to the header), which increases the chance of making this mistake.

If we keep the string type, we should define how servers and scripts are expected to order these, so that UAs can assign their own version numbers in a way that servers and scripts get the right results.

If we change the type to a number (probably a decimal), we should probably also grease that by sometimes sending leading 0s.

@miketaylr
Copy link
Collaborator

This feels related to #196 as well.

@amtunlimited
Copy link
Contributor

amtunlimited commented Mar 15, 2021

A couple of possible options:

  • We could, if we felt like being extra, say that the major version be strictly sortable (i.e. integer) and the full version be major-version "." minor-version where minor version can be a string with whatever separator and and "rc"s the implementor desires.
UA-CH-Full-Version = major-version "." minor-version
major-version = integer
minor-version = *chr
  • Alternatively, we could define a new hint that holds a brand list of just minor versions with no major versions, and the minor versions can be whatever they want

  • We could define versions have to be a dot-separated list of integers

UA-CH-Full-Version = integer *version-token
version-token = "." integer

@domenic
Copy link
Collaborator

domenic commented Mar 15, 2021

My personal proposal:

Browser version should keep its current meaning, as an opaque string that incorporates a variety of concerns like marketing and displaying to users and sending diagnostics and so on.

However, for the specific case of working around known bugs or doing polyfill.io-style feature checks, the spec should also define a "comparable significant version" and maybe "comparable full version", and define them as integers. These integers are required to be comparable so that "newer" versions (in an implementation-defined sense) are larger integers than older ones.

I'd envision in practice we'd see comparable significant versions like 88, 89, 90, etc. for Chrome and Firefox, and 121, 122, 130, 134 for Safari. And comparable full versions would have more digits, e.g. 91000044460003 for Chrome full version 91.0.4446.3.

You'd slot this into the current API as comparableVersion in NavigatorUABrandVersion, comparableUAFullVersion in UADataValues, maybe vn= parameters in the header UA brand lists, and maybe a vn= parameter on top of the sh-string that Sec-CH-UA-Full-Version has.

@erik-anderson
Copy link
Contributor

This feels related to #196 as well.

It's a bit different. Windows apps hit this problematic pattern all the time as well of writing version checks that don't fully consider all of the permutations they need to handle correctly between version components (e.g. 6.1 < 7.0 though many developers may do something like "if version.minor >= 1", see it working, and assuming it's right. What Windows eventually moved to was APIs that allow checking if a release is a specific version or higher.

If we think Windows' solution makes sense, I suppose we could extend that model to UA Client Hints, e.g. by defining a response header that could include a brand and full version list as an input (e.g. Accept-CH-UA-Compatible-Input: "Chromium"; v="90.0.100.5", "Awesome Browser"; v="5.1.2.4530") and cause the browser to send a Sec-CH-UA-Compatible: ?1 request header on subsequent requests depending on if it matched any of the list of conditions.

You could also have a dedicated JS API that takes a similar list and also returns a boolean value.

This is somewhat similar to issue #54 where I wanted to explore more significant ways of discouraging sites from "rusting shut" on browser checks, but this doesn't carry the ongoing cost on site devs.

Browser version should keep its current meaning, as an opaque string that incorporates a variety of concerns like marketing and displaying to users and sending diagnostics and so on.

Unfortunately the version info isn't particularly opaque with sites deriving meaning from it in the variety of ways you call out, including things like analytics and marketing checks. Ideally we'd have a more clearly lit path than two similar surfaces that may not be clear to a site developer about which to choose or why, but I understand the desire to easily pump a similar looking version string into existing systems.

A decimal representation as Jeffrey calls out may be a reasonable way (if my more opaque query approach I just outlined doesn't seem promising), though it will carry all of the same challenges I outlined in issue #196.

@miketaylr
Copy link
Collaborator

What's the risk of changing the type from DOMString / sf-string to decimal, instead of adding new version properties? I wonder if adding new stuff just increases the risk of making more mistakes (but I could be wrong).

Existing code (which there shouldn't be much of using UA-CH APIs) should just work*, and not suffer from the problematic string comparison down below... my understanding of https://tc39.es/ecma262/#sec-abstract-relational-comparison is that when comparing a number and a string, the string is converted to a number (or undefined).

Some imaginary code assuming brand is 89:

> brand.version < "9" // here it's a number
false

> brand.version < "9"  // here it's a string
true

(*famous last words)

@domenic
Copy link
Collaborator

domenic commented Mar 30, 2021

On the JavaScript side, changing to a number is relatively safe as you point out. A potential strangeness is that floating-point precision is not the best match for some browser versions, e.g. Chrome full version 91.0.4446.3 might be tranlsated to 91.044463 which will really be represented as 91.0444629999999932579157757572829723358154296875 to JavaScript (so, e.g., fullVersion === 91.04446299999999 will also be true, since 91.04446299999999 === 91.044463).

On the headers side, it likely depends on what server-side processing is doing. E.g. the equivalent of

parse_as_sh_string(headers->get("sec-ch-ua-full-version"));

might fail in some way (e.g. returning a null value or throwing an exception) if the format switches from string to decimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants