duonglaiquang · GitHub

Problem in brief

Changes to the "history entry" URL using history.replaceState() are not correctly reflected to location.hash and in certain conditions also not to location.href.

Reproducing

Below code shows behaviors of HtmlUnit and expected (tested in Chrome).

<!DOCTYPE html>
<html>
<head>
<script>
// Comments below assume 'location.href' is "https://www.example.com/some/path"
history.replaceState(null, '', location.origin + '/abc?def=1#foo');
// Expected:
// --> "href=https://www.example.com/abc?def=1#foo, hash=#foo"
// HtmlUnit without "Cache-Control: no-store":
// --> "href="https://www.example.co/abc?def=1#foo, hash=" -- bad 'hash'
// HtmlUnit with "Cache-Control: no-store":
// --> "href="https://www.example.com/some/path, hash=" -- bad 'href' and 'hash'
console.log("href=" + location.href + ", hash=" + location.hash);
</script>
</head>
<body>
</body>
</html>

Some thoughts

  • history.replaceState() updates the original WebRequest.url_
  • location.hash is cached in Location.hash_ which is not updated by history.replaceState()
  • We were looking into how this could be fixed and there's some awkwardness because of the lacks a "history entry" URL concept for history.replaceState() that's separate from the transport layer WebRequest.url_. Possibly adding this new concept to Page or History.HistoryEntry or Location is required.
  • We also noticed there's some differences when encoding is required for the URL set through history.replaceState():
    • e.g. history.replaceState(null, '', location.href + '?foo=Ż') produces "...?foo=%C5%BB" when location.href is viewed through Chrome but "...?foo=Ż" for HtmlUnit.

Read the original on github.com ↗