-
Notifications
You must be signed in to change notification settings - Fork 3k
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
HTML: navigate cancels iframe lazy-load #45650
base: master
Are you sure you want to change the base?
Conversation
would be interesting to test also what happens when the iframe receives lazy steps after a navigation is started but before it's committed. e.g. you have an about:blank with lazy and without a src, you navigate it with a link, then set a src, and the new document is ready to commit before the lazy steps are run |
@noamr per spec, when the |
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
setup({single_test: true}); | ||
onload = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work (reliably) because of https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:current-navigation-was-lazy-loaded-5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify? To say onload
overall "doesn't work" indicates that the lazyloaded support/blank.html
iframe ends up loading ASAP (before this onload
handler is set), causing the outer document's load event to fire before our handler is assigned to catch the load event.
But I can't imagine that's the case, right? Certainly the main document's load event does not fire before this script runs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the load
event might fire before the iframe is loaded, since a lazy-loading iframe doesn't block the load
event. Therefore it's racy. But the step_timeout
should address this sufficiently.
These are unstable in Chrome:
The first one I think should be stable per spec, since the lazy navigation happens after The |
setup({single_test: true}); | ||
onload = () => { | ||
step_timeout(() => { | ||
assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?src", location.href).href); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we assert above this, that location.href
equals support/blank.htm?foo
(at least I think it will at this time?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right after calling pushState
yes. When this script runs, it's racy whether the lazy load has happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pushState
and replaceState
tests were incorrect since the iframe's doc's URL is about:blank
, and so the URL components (except fragment) need to match about:blank
. Fixed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this script runs, it's racy whether the lazy load has happened.
What do you mean by "happened"? Do you mean https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:current-navigation-was-lazy-loaded-4 just being set to true? Or do you mean that plus the resumption steps executed, and the support/blank.htm?src
navigation has completed?
In any case, I'm not sure I follow. By this point in the script, we've done nothing asynchronous, right? I think what has happened up to this point is:
- https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:current-navigation-was-lazy-loaded-4 gets set to true, for the lazyload navigation to
support/blank.html?src
. But the iframe's document is stillabout:blank
, since the lazy load resumption steps were not run immediately - Synchronously after,
pushState()
comes along and changes theabout:blank
Document's URL toabout:blank#foo
, which is allowed per https://html.spec.whatwg.org/C#can-have-its-url-rewritten
So is there any room in there for the lazy loaded navigation to have already completed by then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The navigation might have completed. The event loop is allowed to spin between each script, and the pushState()
happens in the first script element.
html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-pushState.html
Outdated
Show resolved
Hide resolved
.../semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-replaceState.html
Outdated
Show resolved
Hide resolved
html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-form-submit.html
Outdated
Show resolved
Hide resolved
// Should have no effect on lazy-loading | ||
iframe.contentWindow.history.pushState(null, "", iframe.dataset.src); | ||
</script> | ||
<!-- Loading testharness.js here is intentional. --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WebKit passes the tests if testharness.js is loaded in head
, but fails these tests (or a simple demo without external scripts).
html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-form-submit.html
Show resolved
Hide resolved
Sorry for the delay, I took some time off last week and early this week. Getting through my backlog so I will take a look at this as soon as I can |
let pushStateSuccess = true; | ||
try { | ||
// Should have no effect on lazy-loading. | ||
// Per https://html.spec.whatwg.org/#can-have-its-url-rewritten |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Per https://html.spec.whatwg.org/#can-have-its-url-rewritten | |
// Per https://html.spec.whatwg.org/C#can-have-its-url-rewritten |
nit: Just so the average reader has an easier time with this link.
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
setup({single_test: true}); | ||
assert_true(pushStateSuccess); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can just avoid this check altogether since pushState()
will throw an exception in the error case and we don't have to handle that explicitly? That is, I assume the error thrown to the harness in the error case is enough to fail the test reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The harness isn't loaded yet when that exception is thrown, hence this assertion.
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
setup({single_test: true}); | ||
onload = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify? To say onload
overall "doesn't work" indicates that the lazyloaded support/blank.html
iframe ends up loading ASAP (before this onload
handler is set), causing the outer document's load event to fire before our handler is assigned to catch the load event.
But I can't imagine that's the case, right? Certainly the main document's load event does not fire before this script runs?
@@ -0,0 +1,33 @@ | |||
<!DOCTYPE html> | |||
<title>History state change for iframe loading='lazy' before it is loaded: history.pushState</title> | |||
<iframe data-src="about:blank#foo" src="support/blank.htm?src" loading="lazy"></iframe> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<iframe data-src="about:blank#foo" src="support/blank.htm?src" loading="lazy"></iframe> | |
<iframe data-src="about:blank#push" src="support/blank.htm?src" loading="lazy"></iframe> |
nit: more descriptive
setup({single_test: true}); | ||
onload = () => { | ||
step_timeout(() => { | ||
assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?src", location.href).href); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this script runs, it's racy whether the lazy load has happened.
What do you mean by "happened"? Do you mean https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:current-navigation-was-lazy-loaded-4 just being set to true? Or do you mean that plus the resumption steps executed, and the support/blank.htm?src
navigation has completed?
In any case, I'm not sure I follow. By this point in the script, we've done nothing asynchronous, right? I think what has happened up to this point is:
- https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:current-navigation-was-lazy-loaded-4 gets set to true, for the lazyload navigation to
support/blank.html?src
. But the iframe's document is stillabout:blank
, since the lazy load resumption steps were not run immediately - Synchronously after,
pushState()
comes along and changes theabout:blank
Document's URL toabout:blank#foo
, which is allowed per https://html.spec.whatwg.org/C#can-have-its-url-rewritten
So is there any room in there for the lazy loaded navigation to have already completed by then?
step_timeout(() => { | ||
assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?src", location.href).href); | ||
done(); | ||
}, 1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have to be done on a timeout? Or can it be done on the lazyloaded iframe's load event, since it will be fired asynchronously (with respect to this code currently running) once support/blank.html
loads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since some tests do potentially two navigations, a timeout is still needed. But maybe I can use the iframe load event instead of the window load event...
// only the fragment can be changed for about: URLs. | ||
iframe.contentWindow.history.pushState(null, "", iframe.dataset.src); | ||
} catch(ex) { | ||
replaceStateSuccess = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be pushStateSuccess
, oops
See whatwg/html#10226