-
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
- Loading branch information
1 parent
8c1683d
commit bfe15f6
Showing
6 changed files
with
111 additions
and
46 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,59 @@ | ||
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, iteration) { | ||
const url = new URL(`${origin}/resource-timing/resources/green.html`, location.href); | ||
url.searchParams.set("uid", uid); | ||
url.searchParams.set("iteration", iteration); | ||
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, 1); | ||
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, 1); | ||
}); | ||
|
||
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`); | ||
} |