| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>Resource Timing - ResourceTiming for revalidation requests</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/rt-utilities.sub.js"></script> |
| </head> |
| <body> |
| <h1>Resource Timing: ResourceTiming for revalidation requests</h1> |
| <div id="log"></div> |
| <script> |
| const IncludeTimingOriginAllowHeaders = { Yes: true, No: false }; |
| function createRevalidationURL({tao, crossOrigin}) { |
| let token = Math.random(); |
| let content = encodeURIComponent("var revalidationTest = 1;"); |
| let mimeType = encodeURIComponent("text/javascript"); |
| let date = encodeURIComponent(new Date(2000, 1, 1).toGMTString()); |
| let params = `content=${content}&mimeType=${mimeType}&date=${date}&tao=${tao ? true : false}`; |
| |
| const path = "WebKit/resource-timing/resources/rt-revalidation-response.py"; |
| if (crossOrigin) |
| return crossOriginURL(`${token}&${params}`, path); |
| return location.origin + `/${path}?${token}&${params}`; |
| } |
| |
| function makeRequest(url, revalidation = false) { |
| let xhr = new XMLHttpRequest; |
| xhr.open("GET", url, true); |
| if (revalidation) |
| xhr.setRequestHeader("If-Modified-Since", new Date().toGMTString()); |
| xhr.send(); |
| } |
| |
| function assertAlways(entry) { |
| assert_equals(entry.workerStart, 0, "entry should not have a workerStart time"); |
| assert_equals(entry.secureConnectionStart, 0, "entry should not have a secureConnectionStart time"); |
| |
| assert_not_equals(entry.startTime, 0, "entry should have a non-0 fetchStart time"); |
| assert_not_equals(entry.fetchStart, 0, "entry should have a non-0 startTime time"); |
| assert_not_equals(entry.responseEnd, 0, "entry should have a non-0 responseEnd time"); |
| |
| assert_greater_than_equal(entry.fetchStart, entry.startTime, "fetchStart after startTime"); |
| assert_greater_than_equal(entry.responseEnd, entry.fetchStart, "responseEnd after fetchStart"); |
| } |
| |
| function assertAllowedTimingData(entry) { |
| assert_greater_than_equal(entry.domainLookupStart || entry.fetchStart, entry.fetchStart, "domainLookupStart after fetchStart"); |
| assert_greater_than_equal(entry.domainLookupEnd || entry.fetchStart, entry.domainLookupStart, "domainLookupEnd after domainLookupStart"); |
| assert_greater_than_equal(entry.connectStart || entry.fetchStart, entry.domainLookupEnd, "connectStart after domainLookupEnd"); |
| assert_greater_than_equal(entry.connectEnd || entry.fetchStart, entry.connectStart, "connectEnd after connectStart"); |
| assert_greater_than_equal(entry.requestStart || entry.fetchStart, entry.connectEnd, "requestStart after connectEnd"); |
| assert_greater_than_equal(entry.responseStart || entry.fetchStart, entry.requestStart, "responseStart after requestStart"); |
| assert_greater_than_equal(entry.responseEnd || entry.fetchStart, entry.responseStart, "responseEnd after responseStart"); |
| } |
| |
| function assertDisallowedTimingData(entry) { |
| // These attributes must be zero: |
| // https://w3c.github.io/resource-timing/#cross-origin-resources |
| const keys = [ |
| "redirectStart", |
| "redirectEnd", |
| "domainLookupStart", |
| "domainLookupEnd", |
| "connectStart", |
| "connectEnd", |
| "requestStart", |
| "responseStart", |
| "secureConnectionStart", |
| ]; |
| for (let key of keys) |
| assert_equals(entry[key], 0, `entry ${key} must be zero for Cross Origin resource without passing Timing-Allow-Origin check`); |
| } |
| |
| // Same Origin (revalidation request). |
| |
| let sameOriginURL = createRevalidationURL({tao: true, crossOrigin: false}); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertAllowedTimingData(entry); |
| }); |
| makeRequest(sameOriginURL); |
| return promise; |
| }, "Same Origin network load"); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertAllowedTimingData(entry); |
| }); |
| makeRequest(sameOriginURL, true); |
| return promise; |
| }, "Same Origin revalidation load"); |
| |
| // Cross Origin (revalidation request) without Timing Allow. |
| |
| let crossOriginURLNoTao = createRevalidationURL({tao: false, crossOrigin: true}); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertDisallowedTimingData(entry); |
| }); |
| makeRequest(crossOriginURLNoTao); |
| return promise; |
| }, "Cross Origin network load (no TimingAllow)"); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertDisallowedTimingData(entry); |
| }); |
| makeRequest(crossOriginURLNoTao, true); |
| return promise; |
| }, "Cross Origin revalidation load (no TimingAllow)"); |
| |
| // Cross Origin (revalidation request) with Timing Allow. |
| |
| let crossOriginURLWithTao = createRevalidationURL({tao: true, crossOrigin: true}); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertAllowedTimingData(entry); |
| }); |
| makeRequest(crossOriginURLWithTao); |
| return promise; |
| }, "Cross Origin network load (with TimingAllow)"); |
| |
| promise_test(function(t) { |
| let promise = observeResources(1).then(([entry]) => { |
| assertAlways(entry); |
| assertAllowedTimingData(entry); |
| }); |
| makeRequest(crossOriginURLWithTao, true); |
| return promise; |
| }, "Cross Origin revalidation load (with TimingAllow)"); |
| </script> |
| </body> |
| </html> |