The `blink::CanChangeToUrlForHistoryApi()` helper takes in a target URL
and a document's current URL, and evaluates whether we can set the
latter to the former for same-document navigations. The spec equivalent
is HTML's "can have its URL rewritten" [1] algorithm.
Before this CL, that function deviated from the spec in a number of
ways:
1. It created a SecurityOrigin out of the target URL and used it for
same-origin checks with the document's actual origin. This is
fraught for `about:blank/srcdoc` KURLs which don't carry their
actual origin with them. So they're always seen as opaque, and
`history.pushState()/replaceState()` was rejected for them. Per
spec however, those APIs should work in those documents. This was
discovered in https://crrev.com/c/4690242 and is fixed here.
2. It has non-standard code that allows opaque origins to change their
fragment. This isn't actually much of an issue, and it's documented
that the behavior exists for compatibility reasons, but the issue
is that at the same time, we *disallow* path mutations for URLs
in opaque origins, even though HTML allows these modifications for
all HTTP(S) URLs, per step (2) of the spec algorithm [1].
This CL implements this step correctly and changes the
corresponding security web test expectations to expect a
path-mutating `history.pushState()` to succeed on an HTTP(S) site
running in an opaque origin.
3. It deferred to `EqualIgnoringPathQueryAndFragment()` for all other
URLs, while the HTML Standard explicitly disallows path mutations
per step (4) in the spec algorithm [1].
a. This had the positive side-effect of allowing path mutations
for "standard" URLs — like `chrome://`, `chrome-extension://`,
and `chrome-error://` — that are registered specially with
`url::AddStandardScheme()`. Chrome WebUI and extensions seem
to rely on this behavior, and that's fine since it's a
non-standard allowance.
b. The negative side-effect of (a) above is that we allowed path
mutations for even non-specially-registered URLs, like `blob:`
URLs. For example, before this CL, Blink allowed changing
`blob:https://example.com/{UUID-HERE}` to
`blob:https://spoof.com@example.com/abcd`, which is
same-origin, so the code permitted it, but it was a path
change, which is illegal per spec. What's more is that this is
considered a UI URL spoof, and if you did this the browser
would change the URL bar to `about:blank#blocked` but the
document's URL would still be updated to the spoofed URL in
Blink; this led to really weird test expectations [2]. This
CL fixes the behavior and those test expectations
After this CL and the fixes mentioned above, there are still two
outstanding non-standard conditions that this algorithm maintains:
1. Allowing non-HTTP(s) opaque documents to mutate their query and
fragment, for historical compatibility concerns that are documented
in the code.
2. Allowing "standard"-scheme URLs — which includes `filesystem:` and
ones registered specially by //content embedders, like
`chrome:`, `chrome-extension`, etc. — to change their path, query,
and fragment, which is a much looser policy than we apply to other
URLs.
Additionally, before this CL, because we didn't even allow `pushState()`
to be called on `about:blank` documents at all, we never had to
implement step 4 of
https://html.spec.whatwg.org/C/#url-and-history-update-steps, which
ensures that `pushState()` on `about:blank` documents are done with the
"replace" navigation mode. Now that this CL enables this to be hit, we
must implement that step to be spec compliant. Without it, tests like
`iframe-src-204-pushState-replaceState.html` would fail.
[1]: https://html.spec.whatwg.org/#can-have-its-url-rewritten
[2]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/blob_storage/blob_url_browsertest.cc;l=173-177;drc=cb17f93f3a17a6831cf90d616e23840f2ca726a5
Bug: 1239052,1465972
Change-Id: Id23d894d33c955894757d970d39a68076f2a8d5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4701743
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Dominic Farolino <dom@chromium.org>
Reviewed-by: Charlie Reis <creis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1177746}