-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor nested-navigations resource-timing flow
This changes how frames, iframes & objects decide how to report their navigations as resource timing entries to their parent: - Any frame-initiated navigation (e.g. iframe.src change) is reported as an entry. This complies with current spec. - For nested navigations that fail Timing-Allow-Origin, we don't report the normal responseEnd - instead we report the load event time as the responseEnd, to prevent leakage of navigation-related cross-origin information (see w3c/resource-timing#340) This incidentally fixes other existing issues with nested navigations and resource timing, such as flaky tests and inconsistencies regarding restored iframes. Bug: 1404695 Bug: 1348080 Bug: 1290721 Bug: 1380078 Bug: 1378015 Bug: 957181 Spec changes: whatwg/html#8643 whatwg/fetch#1579 Change-Id: I010b026788193cc77a7de3f3d75304602f41fcd5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4145963 Reviewed-by: Yoav Weiss <yoavweiss@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Cr-Commit-Position: refs/heads/main@{#1091970}
- Loading branch information
1 parent
3d997a3
commit 8f8c616
Showing
6 changed files
with
115 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf-8"> | ||
<title>Test ResourceTiming reporting for cross-origin iframe.</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/get-host-info.sub.js"></script> | ||
<script src="resources/observe-entry.js"></script> | ||
</head> | ||
<body> | ||
<body> | ||
<script> | ||
const {REMOTE_ORIGIN} = get_host_info(); | ||
|
||
promise_test(async t => { | ||
const iframe = document.createElement('iframe'); | ||
t.add_cleanup(() => iframe.remove()); | ||
iframe.src = `${REMOTE_ORIGIN}/resource-timing/resources/delay-load.html`; | ||
document.body.appendChild(iframe); | ||
const entry = await observe_entry(iframe.src); | ||
assert_greater_than(entry.duration, 1000); | ||
}, "Cross-origin TAO-fail IFrame entries should report window load time"); | ||
|
||
promise_test(async t => { | ||
const object = document.createElement('object'); | ||
object.type = "text/html"; | ||
t.add_cleanup(() => object.remove()); | ||
object.data = `${REMOTE_ORIGIN}/resource-timing/resources/delay-load.html`; | ||
document.body.appendChild(object); | ||
const entry = await observe_entry(object.data); | ||
assert_greater_than(entry.duration, 1000); | ||
}, "Cross-origin TAO-fail object entries should report window load time"); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<!DOCTYPE html> | ||
<body> | ||
<img src="/images/blue.png?pipe=trickle(d1)"> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,63 @@ | ||
function test_frame_timing_before_load_event(type) { | ||
promise_test(async t => { | ||
const {document, performance} = type === 'frame' ? window.parent : window; | ||
const delay = 500; | ||
const frame = document.createElement(type); | ||
t.add_cleanup(() => frame.remove()); | ||
await new Promise(resolve => { | ||
frame.addEventListener('load', resolve); | ||
frame.src = `resources/iframe-with-delay.sub.html?delay=${delay}`; | ||
(type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); | ||
}); | ||
promise_test(async t => { | ||
const {document, performance} = type === 'frame' ? window.parent : window; | ||
const delay = 500; | ||
const frame = document.createElement(type); | ||
t.add_cleanup(() => frame.remove()); | ||
await new Promise(resolve => { | ||
frame.addEventListener('load', resolve); | ||
frame.src = `/resource-timing/resources/iframe-with-delay.sub.html?delay=${delay}`; | ||
(type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); | ||
}); | ||
|
||
const entries = performance.getEntriesByName(frame.src); | ||
const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; | ||
assert_equals(entries.length, 1); | ||
assert_equals(entries[0].initiatorType, type); | ||
assert_greater_than(performance.now(), entries[0].responseEnd + delay); | ||
const domContentLoadedEventAbsoluteTime = navigationEntry.domContentLoadedEventStart + frame.contentWindow.performance.timeOrigin; | ||
const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; | ||
assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); | ||
}, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); | ||
const entries = performance.getEntriesByName(frame.src); | ||
const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; | ||
assert_equals(entries.length, 1); | ||
assert_equals(entries[0].initiatorType, type); | ||
assert_greater_than(performance.now(), entries[0].responseEnd + delay); | ||
const domContentLoadedEventAbsoluteTime = | ||
navigationEntry.domContentLoadedEventStart + | ||
frame.contentWindow.performance.timeOrigin; | ||
const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; | ||
assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); | ||
}, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); | ||
} | ||
|
||
|
||
function test_frame_timing_change_src(type) { | ||
promise_test(async t => { | ||
const {document, performance} = type === 'frame' ? window.parent : window; | ||
const frame = document.createElement(type); | ||
t.add_cleanup(() => frame.remove()); | ||
await new Promise(resolve => { | ||
const done = () => { | ||
resolve(); | ||
frame.removeEventListener('load', done); | ||
} | ||
frame.addEventListener('load', done); | ||
frame.src = 'resources/green.html?1'; | ||
(type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); | ||
}); | ||
function test_frame_timing_change_src(type, | ||
origin1 = document.origin, | ||
origin2 = document.origin, | ||
tao = false, label = '') { | ||
const uid = token(); | ||
promise_test(async t => { | ||
const {document, performance} = type === 'frame' ? window.parent : window; | ||
const frame = document.createElement(type); | ||
t.add_cleanup(() => frame.remove()); | ||
function createURL(origin) { | ||
const url = new URL(`${origin}/resource-timing/resources/green.html`, location.href); | ||
url.searchParams.set("uid", uid); | ||
if (tao) | ||
url.searchParams.set("pipe", "header(Timing-Allow-Origin, *)"); | ||
return url.toString(); | ||
} | ||
|
||
await new Promise(resolve => { | ||
frame.addEventListener('load', resolve); | ||
frame.src = 'resources/green.html?2'; | ||
}); | ||
await new Promise(resolve => { | ||
const done = () => { | ||
resolve(); | ||
frame.removeEventListener('load', done); | ||
} | ||
frame.addEventListener('load', done); | ||
frame.src = createURL(origin1); | ||
const root = type === 'frame' ? document.querySelector('frameset') : document.body; | ||
root.appendChild(frame); | ||
}); | ||
|
||
const entries = performance.getEntries().filter(e => e.name.includes('green.html')); | ||
assert_equals(entries.length, 2); | ||
}, `A ${type} should report separate RT entries if its src changed from the outside`); | ||
} | ||
await new Promise(resolve => { | ||
frame.addEventListener('load', resolve); | ||
frame.src = createURL(origin2); | ||
}); | ||
|
||
const entries = performance.getEntries().filter(e => e.name.includes(uid)); | ||
assert_equals(entries.length, 2); | ||
}, label || `A ${type} should report separate RT entries if its src changed from the outside`); | ||
} |