-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Which navigations should add/replace new history entry after initial empty document? #6491
Comments
Not that I've seen
I've been trying to find this for a while too! Looks like it's step 5 https://html.spec.whatwg.org/multipage/browsing-the-web.html#initialise-the-document-object
As a developer, that's the behaviour that would make most sense to me.
I agree, then it isn't down to timing. If you append It feels like the issue discussed in #1191 goes away with the always-replace-initial-nav behaviour. Maybe that means we can all fix the bug where child contexts don't navigate if their parent is also navigated #5767 (comment).
That makes the most sense to me. I was really surprised to hear it starts at 0. Just to confirm: You're saying it should start at 1, and then remain 1 after navigation (since the navigation is "replace"). |
I'm not sure this is what you mean, but historyHandling gets set to "replace" in a few cases:
Right, as Jake pointed out, this is due to https://html.spec.whatwg.org/#initialise-the-document-object step 5/6. In the initial about:blank case, we "do nothing" (step 5). In all other cases, we create a new window. However, actually changing the "associated Document" seems to be broken... at least, I can't find where that happens. It seems like it should happen immediately. I wonder if we broke this recently... /cc @domfarolino
This makes sense to me, but I suspect this was never really considered. This is the case you're triggering via
+1. Also, always doing replace matches the spec better I believe, and seems simpler to understand.
My understanding is that web developers sometimes use
Do you think this issue covers all the issues discussed in those, and we can close them and roll them into here? |
I think it actually happens via history traversal, some steps later. E.g. if you look at the page load processing model for HTML files, it first creates the document, and then "before any script runs", it calls "update the session history with the new page", which will call "traverse the history", which will eventually call "set the active document". I'm going to add a note to make this clearer since it's so easy to miss. |
This should help address some of the questions that came up in #6491.
This seems like a broken test to me. Without knowing anything about how browser history works, I wouldn't expect |
Yes, I apologize for the typo. |
Ah thanks, looking at the setters for "replace" I also found some other cases:
However some callers to navigate does not do the "replace", which sounds bad:
Overall having the caller to "navigate" set the "replace" bit for this case seems error-prone, and we might forget if we add more callers. Do you think it makes sense to actually make the "replace on every navigation when the document is the initial empty document" step part of "navigate"?
Awesome, thanks!
Yeah, it seems like Safari & Firefox doesn't treat about:blank in fragments as about:blank (at least in some cases). I think they should (like Chrome), and I think this aligns with the fetch spec for about:blank (it checks just the path)
Yeah, I'm proposing we always start with 1, and if we do "replace" (which in my proposal is always the case) it will stay at 1. After that if we're not on the initial empty document anymore, we should update it accordingly (increase on append, stay the same on replace/reload).
I think we cover #546 in this issue - "The iframe keeps its content" should be the behavior for case 3 & 4 there if we go with the "always replace" proposal. I'm not sure about #490 - it seems like it's referencing spec text that no longer exists. I think @ArthurSonzogni looked into the synchronous about:blank navigation a while ago (see doc) and found that Firefox doesn't support it while Chrome does. Ideally we'd like to follow Firefox, but looks like there are some dependencies to that behavior in Chrome at least... |
This should help address some of the questions that came up in #6491.
Hmm, I see, good catch. I guess the current spec's philosophy is that the "initial navigation" should be replace, i.e. the navigation to I suspect the latter is more correct, and in that case, indeed a spec change like you suggest would be good. But of course we should double-check with web platform tests, if there aren't any already. BTW, we should try to revive #4691 so we can have a clearer spec idea of what the initial about:blank Document actually is. |
I'm pretty sure you are influencing the results in Firefox by manipulating the contents of the initial |
Yeah I guess so, but the spec is inconsistent currently if it is trying to do that (e.g. "location-object navigate" always replaces). I think having WPT would be good once we have some agreement here. Also it sounds like we need to test various methods of navigation, as @jakearchibald and I found some interesting differences in Safari when navigating with src vs link yesterday :(
Ah thanks. I've updated http://rakina.github.io/aboutblankiframe.html to not modify the document, and also made a version with src not set at all (instead of set to about:blank) at http://rakina.github.io/unsetiframe.html. But they both still behave the same way as the original post. I wonder if I'm doing anything wrong, hmm. I navigate the iframes by setting the src attributes, not sure if that matters. Overall I think not replacing if it's not just a "placeholder initial empty document" sounds good and probably what web devs would want, but I wonder if there's an easy way to actually track that? I saw #546 (comment) in the other thread, which covers document.open(), but not other ways of updating the DOM. If it's not feasible to spec that, maybe checking history entry (instead of checking document) will be good enough? document.open() and other same-document navigations would create new entries (replacing the initial entry), so navigations after those would append instead of replace. |
Thank you @rakina for finding that (and also for writing up this issue). Re-reading that what seems to happen is that if I'm not sure how attached we are to any of this at this point, though changes in this area are always risky. |
Yes. When In the past Chrome used to support many navigations synchronously (about:blank, about:srcdoc, javascript: document commit, MHTML iframe, ...). I just wanted to chime in to tell this |
Are hash change navigations async in Firefox now? |
@rakina I've been doing some work on this area (see e.g. #6566 and #6579) and I'd love to close out this bug with "replace everywhere" behavior. Would you be able to convert the cases you've tested into web platform tests, that expect always-replace and... something appropriate for |
Thanks @domenic for working on clarifying the spec! I think I can help write WPTs in the next week or so (for this and #6213). I've never written a navigation WPT before so I think I'll try to follow web-platform-tests/wpt#28480 and also ask you questions :) FYI the behavior in Chrome for the window.open() case is being fixed a little in https://crrev.com/c/2794069, but I think we have no way to differentiate "initial empty document" and "second initial empty document" right now :/ From briefly reading #6566, I think setting the |
Sounds good! Note that I did get somewhat unexpected results for those tests so it's possible I did them wrong. Feel free to go a different route if you have better ideas.
Looks great!
I'm not quite sure I understand in which case there'd be a second initial empty document (although I appreciate the link ^_^). Is this the case you're referring to below where you navigate to a second (non-"initial")
Yeah, I think that's right, at least for the spec as-is. Since a new Note that (also per the spec today) navigating to |
Yeah I was talking about the case @annevk referred to in #6491 (comment), where setting In Chrome, we treat the document resulting from "src is set to about:blank" and "src is not set" as the same, as we navigate to the second Anyways, I have draft WPTs for the iframe case in web-platform-tests/wpt#28541, will work on the |
Eeek, I see, what a scary mess :). In general, my instinct is to separate the question of window object reuse (#3267) from the question replace vs. push tests (this issue), if we can. It might end up being the case that we only perform window reuse in some cases, but we do replace in more cases. To me it looks like the current spec has the same behavior for Then, if you load a third document (which I suppose must be something besides I like how the current spec treats all those different cases the same.
I'm hopeful that we can test src set to about:blank, and in particular test that it's the same as empty src or missing src. I agree the timing seems quite tricky. It's hard to tell which load events will fire when. Maybe you can poll for when |
OK I've written some more tests in https://crrev.com/c/2831564 / web-platform-tests/wpt#28541. I used a So here's a table of my current understanding of what counts as "initial empty document" vs not. The Chrome's behavior for iframes is probably mostly based on this check, which uses the "has committed real load" concept instead of "initial empty document". I think former stays true as long as the loaded URL in the iframe is
|
These look really great!
You can start up the server (e.g. using the first line in https://chromium.googlesource.com/chromium/src/+/master/docs/testing/web_tests_in_content_shell.md#Running-WPT-Tests-in-Content-Shell) and then launch Firefox. You can also check out the results under "Show all checks" in web-platform-tests/wpt#28541 which gives us the following links:
Oh, you're right, I missed that. That's an annoying special-case. Do you think there's any chance of unifying these cases, perhaps by making all of them perform no navigation on initial insertion? I.e. change the last step of "process the iframe attributes" to
and add a step between the current steps 1 and 2 of "shared attribute processing steps for iframe and frame elements" that says something like
?
That's unfortunate, hmm.
This is intentional as all browsers seem to behave this way; see b31e145 and the linked issues/PRs. |
I guess we would also have to fire a load event, like |
Thanks! I think I've covered enough cases in the WPTs now (Chrome, Firefox, Safari results). No browser passes all the tests, but they're all quite close :) Some things to note:
Should people just review web-platform-tests/wpt#28541 or should I make a new PR? Or maybe it's nicer to review this on Chromium Gerrit's UI? |
Agreed, at least for now.
This is pretty mysterious :(. If we can't make it work, probably we should remove the test.
This test still seems valuable to keep.
Probably we should review web-platform-tests/wpt#28541. Generally folks like @hsivonen and @annevk prefer to use the GitHub UI instead of the Chromium code review tool. It just means you'll commit any changes by going back and modifying Gerrit, which is a bit awkward but probably fine. |
I don't necessarily mind looking at things in Gerrit, but I'm definitely more familiar with GitHub. |
Looking at some of the failures on wpt.fyi (e.g. this one in Chrome) it seems like the wpt test runner is not coping well with window.open() tests of this sort in general. That might be worth raising with the infra team... |
OK, I think I've mostly fixed the tests now (see Chrome, Firefox, Safari results). Some of the window.open() fragment tests still fail mysteriously in Chrome, but they run in Firefox (although they fail because Firefox didn't do replacement) and some runs but fails in Safari. PTAL at web-platform-tests/wpt#28541 :) |
We seem really close now. At a high level, my big questions are:
On specific questions: In web-platform-tests/wpt#28541 (comment) @rakina says
https://html.spec.whatwg.org/#window-open-steps says that the initial about:blank in Also in web-platform-tests/wpt#28541 (comment) @rakina says
Am I correct the scenario is the following one?
and for iframes, both (2) and (3) are a replace, but for window.open(), only (2) is a replace? I think the iframe behavior makes the most sense, if I am understanding the scenario correctly. I hope we can unify them; do you think that'd be possible for Chrome? In spec terms, #6595 proposes to replace if the browsing context is still on its initial about:blank Document, which is defined as
That definition gives the iframe behavior, since a replace fragment navigation does not change the size, and a fragment navigation does not change the document or its "is initial about:blank" boolean value. |
This is a very long thread, so I haven't really caught up. However, I've noticed one thing as I've read through. For browsing context creation case:
The behavior of "Navigation on current document will replace?" is currently noted as:
But this does replace in Firefox, as far as I can tell. I tested with the following snippet in the inspector: const myIframe = document.createElement('iframe');
myIframe.addEventListener(
'load',
() => {
myIframe.contentWindow.somethingRandom = 'Hello world!';
console.log(`Navigating iframe to ${location}`);
myIframe.contentWindow.location = location;
myIframe.addEventListener('load', () => { console.log(myIframe.contentWindow.somethingRandom); }, { once: true });
},
{ once: true });
document.body.appendChild(myIframe); This logs const myIframe = document.createElement('iframe');
document.body.appendChild(myIframe);
myIframe.contentWindow.somethingRandom = 'Hello world!';
console.log(`Navigating iframe to ${location}`);
myIframe.contentWindow.location = location;
myIframe.addEventListener('load', () => { console.log(myIframe.contentWindow.somethingRandom); }, { once: true }); This prints Interestingly enough, the standard does seem to say that the shared attribute processing steps should be skipped in this case (see step 2 of https://html.spec.whatwg.org/#process-the-iframe-attributes). I will admit that when I first read this though, I got it backwards and thought that the steps would unconditionally run on initial insertion... |
@rakina, ping on #6491 (comment) ? |
Sorry for the 2 months delay! I think the spec and WPT PRs are describing what we want:
The above are mostly consistent in all the browsers (Firefox & Chrome passes all tests for iframe-nosrc.html & iframe-src-204.html, while Safari passes 5/7 because it behaves differently on link clicks/form submissions vs other navigation cases). The below cases are where most of the differences lie (although they're already part of the spec....).
Link to Firefox, Chrome, and Safari results for easier comparison. So, if the above points are not controversial, I think the next step is just polishing the spec PR, and the WPTs. I'll spend some more time to try to figure out why the window-open tests are timing out (or someone more proficient in WPTs than me can help here too if they want :D). I'm also currently trying to make Chrome's behavior follow the proposed behavior here (or at least, the ones that are already part of the spec). Answering some questions:
Yep this is the case, and yes the iframe behavior should be possible to implement for the window.open() behavior in Chrome too. Hope this is OK with others too?
Thanks, thats helpful to know. I'll do some more investigations then... |
Awesome, thank you so much for the detailed overview Rakina!
I agree, that would be great to add. But it doesn't need to block resolving this issue and the corresponding PR/WPTs. Maybe you could file a tracking issue so that we don't forget to write such tests? Regarding your comment in the spec PR, can you add tests for history.pushState() as well as fragment navigations? My suspicion is that that should not get converted into a replace, as at least in the spec it never goes through "navigate", but if it does in multiple browsers, then that'd be good new information that we should incorporate here. Regarding the tests failing in Firefox, if it's related to a separate spec non-compliance with load events then you don't necessarily need to change the tests, since it's catching a real interop issue. But probably it'd be good to boil that down to a minimal case which could be written up as a separate isolated WPT and filed as a separate Firefox bug. Once we have a diagnosis on why the tests are failing in Firefox, I think we can loop in Firefox engineers with a clear description of what the delta is between their current behavior and the proposed spec, and then we'll be on track to land everything! |
I've added
OK I've added history.pushState and replaceState tests and looks like these are blocked by security checks, except for the iframe case in Safari somehow? Anyways, I think the tests are in OK enough shape after some reorganization, and I've removed some stuff, including the part that used load event, which I think isn't really needed now. I'll try to re-confirm the cases manually and summarize + tag people in the WPT thread this week! |
Looks great!
Oh, wow, that is bizarre! I see no spec support for such an exception, and the actual exceptions thrown in Chrome and Firefox don't seem like anything I'd expect. So IMO that's a separate set of browser bugs we should track. I'd push for just fixing them but if we find out that this behavior exists for a good reason then we can revisit. It looks like you wrote the tests to expect a replace (not a push), and that passes in one case. Whereas if we made the tests match the current spec and expect a push, then the tests would pass in zero cases. So I guess I'll update #6595 to convert pushState to replaceState in such cases. |
FYI we're implementing the "always replace initial empty document" behavior in Chrome (crrev.com/c/3237493), making us follow the behavior expected in the WPTs. |
Previously, the caller of the navigate algorithm would (usually) check for the browsing context still being on the initial about:blank Document, and if so, switch its history handling to "replace". However, a few call sites missed this: e.g., following hyperlinks or window.open() when they were targeted at an existing browsing context. This change instead centralizes the conversion of "default" navigations into "replace" navigations for the initial about:blank Document. This also fixes a minor bug where the conversion of "default" into "replace" navigations for same-URL fragment navigations was not taking place correctly, due to the check being located after the fragment navigation step. Closes #6491.
Previously, the caller of the navigate algorithm would (usually) check for the browsing context still being on the initial about:blank Document, and if so, switch its history handling to "replace". However, a few call sites missed this: e.g., following hyperlinks or window.open() when they were targeted at an existing browsing context. This change instead centralizes the conversion of "default" navigations into "replace" navigations for the initial about:blank Document. This also fixes a minor bug where the conversion of "default" into "replace" navigations for same-URL fragment navigations was not taking place correctly, due to the check being located after the fragment navigation step. Closes whatwg#6491.
I recently tested out how navigations after initial empty document affect history in various browsers and found some interesting cases on how session history is updated after a navigation from an initial empty document. Interestingly, the behavior also differs depending on whether the initial empty document is on an iframe vs opened window, although they both go through "create a new browsing context" to create the initial empty document..
iframe loaded with unset
src
orabout:blank
Repro at https://rakina.github.io/aboutblankiframe.html, https://rakina.github.io/unsetiframe.html
"replaces" means the
history.length
stays the same and we can't navigate back to the previous URL, while "appends" meanshistory.length
is increased by and 1 and we can navigate back.Chrome seems to always replace the entry for the initial empty document after every navigation (even same-document/fragment navigations).
On Safari, after any navigation that appends (even to "about:blank#foo"), the "replace" behavior is gone. So if you go from initial empty document => about:blank#foo => example.com, you'll end up with 3 history entries.
Additionally, if you navigate to about:blank#foo then to example.com then go back in Firefox, the resulting about:blank#foo page will have a different origin than the main frame.
window.open to unspecified URL or
about:blank
Repro at https://rakina.github.io/windowopenblank.html
The replacement behavior seems to be quite consistent in this case which is nice.
In Chrome & Firefox, the opened window starts with
history.length
of 0, while in Safari it starts withhistory.length
of 1. Chrome & Firefox generally behave the same way with history.length here, and Safari mostly follows too (just starts with a different a value), though there are some weird cases (then again, history.length is generally unreliable so I guess this doesn't really matter?)Again, there's some interesting cases with origin. I have no idea how the origin is calculated, just noting some interesting findings.
My questions:
My suggestions:
Would love to hear people's thoughts. cc @domenic @jakearchibald @csreis @annevk @smaug---- @cdumez
Apologies if this is already discussed somewhere else, I searched for existing related issues and they don't seem to talk about this case specifically and also might be a bit outdated (#546, #490).
The text was updated successfully, but these errors were encountered: