Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (215980 => 215981)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2017-04-30 03:32:58 UTC (rev 215981)
@@ -1,3 +1,23 @@
+2017-04-29 Joseph Pecoraro <pecor...@apple.com>
+
+ Zero out PerformanceResourceTiming properties for cached cross-origin responses without Timing-Allow-Origin
+ https://bugs.webkit.org/show_bug.cgi?id=171394
+
+ Reviewed by Youenn Fablet.
+
+ WebKit doesn't create multiple PerformanceResourceTiming entries for
+ loads that use the same CachedResource. However for revalidation
+ requests, which may happen for cached entries, we will send new
+ network requests. These tests cover whether revalidation requests
+ include timing data or not.
+
+ * web-platform-tests/resource-timing/resources/rt-revalidation-response.py: Added.
+ * web-platform-tests/resource-timing/rt-cors-expected.txt:
+ * web-platform-tests/resource-timing/rt-cors.js:
+ * web-platform-tests/resource-timing/rt-cors.worker-expected.txt:
+ * web-platform-tests/resource-timing/rt-revalidate-requests-expected.txt: Added.
+ * web-platform-tests/resource-timing/rt-revalidate-requests.html: Added.
+
2017-04-28 Chris Dumez <cdu...@apple.com>
Tweak window.open features argument tokenizer to match HTML standard and Edge
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/resources/rt-revalidation-response.py (0 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/resources/rt-revalidation-response.py (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/resources/rt-revalidation-response.py 2017-04-30 03:32:58 UTC (rev 215981)
@@ -0,0 +1,22 @@
+def main(request, response):
+ response.headers.set("Access-Control-Allow-Origin", "*")
+ response.headers.set("Access-Control-Allow-Headers", "If-Modified-Since")
+
+ # Just return 304 for any request with If-Modified-Since.
+ modifiedSince = request.headers.get("If-Modified-Since", None)
+ if modifiedSince is not None:
+ response.status = (304, "Not Modified")
+ return ""
+
+ # Otherwise return content from parameters.
+ content = request.GET.first("content", None)
+ mime = request.GET.first("mime", "text/plain")
+ date = request.GET.first("date", None)
+ tao = request.GET.first("tao", None)
+
+ if tao == "true":
+ response.headers.set("Timing-Allow-Origin", "*")
+ response.headers.set("Last-Modified", date)
+ response.status = (200, "OK")
+ response.headers.set("Content-Type", mime)
+ return content
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors-expected.txt (215980 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors-expected.txt 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors-expected.txt 2017-04-30 03:32:58 UTC (rev 215981)
@@ -10,7 +10,7 @@
PASS Cross Origin resource with origin in Timing-Allow-Origin list must have timing data (middle entry, multiple headers)
PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, comma separated)
PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, multiple headers)
-PASS Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)
+PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)
PASS Redirect to Same Origin request must have timing data
PASS Redirect to Cross Origin resource without Timing-Allow-Origin must have filtered timing data
PASS Redirect to Cross Origin resource with Timing-Allow-Origin null value must have filtered timing data
@@ -20,7 +20,7 @@
PASS Redirect to Cross Origin resource with origin in Timing-Allow-Origin list must have timing data (middle entry, multiple headers)
PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, comma separated)
PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, multiple headers)
-PASS Redirect to Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)
+PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)
PASS Multiple level redirect to Same Origin resource must have timing data
PASS Multiple level redirect to Cross Origin resource without Timing-Allow-Origin must have must have filtered timing data
PASS Multiple level redirect to Cross Origin resource with Timing-Allow-Origin must have must have timing data
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.js (215980 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.js 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.js 2017-04-30 03:32:58 UTC (rev 215981)
@@ -152,7 +152,8 @@
promise_test(function(t) {
let promise = observeResources(1).then(([entry]) => {
assertNonRedirectTimingData(entry);
- assertDisallowedTimingData(entry); });
+ assertDisallowedTimingData(entry);
+ });
let url = "" "cross-origin");
url = "" [location.origin + ".test", "x" + location.origin]);
fetch(url);
@@ -162,12 +163,13 @@
promise_test(function(t) {
let promise = observeResources(1).then(([entry]) => {
assertNonRedirectTimingData(entry);
- assertDisallowedTimingData(entry); });
+ assertDisallowedTimingData(entry);
+ });
let url = "" "cross-origin");
url = "" location.origin.toUpperCase());
fetch(url);
return promise;
-}, "Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)");
+}, "Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)");
// Redirects
@@ -278,7 +280,7 @@
url = "" location.origin.toUpperCase());
fetch(urlWithRedirectTo(url));
return promise;
-}, "Redirect to Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)");
+}, "Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)");
// Multiple redirects
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.worker-expected.txt (215980 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.worker-expected.txt 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-cors.worker-expected.txt 2017-04-30 03:32:58 UTC (rev 215981)
@@ -9,7 +9,7 @@
PASS Cross Origin resource with origin in Timing-Allow-Origin list must have timing data (middle entry, multiple headers)
PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, comma separated)
PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, multiple headers)
-PASS Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)
+PASS Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)
PASS Redirect to Same Origin request must have timing data
PASS Redirect to Cross Origin resource without Timing-Allow-Origin must have filtered timing data
PASS Redirect to Cross Origin resource with Timing-Allow-Origin null value must have filtered timing data
@@ -19,7 +19,7 @@
PASS Redirect to Cross Origin resource with origin in Timing-Allow-Origin list must have timing data (middle entry, multiple headers)
PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, comma separated)
PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (other origins, multiple headers)
-PASS Redirect to Cross Origin resource with origin not Timing-Allow-Origin list must have filtered timing data (case-sensitive)
+PASS Redirect to Cross Origin resource with origin not in Timing-Allow-Origin list must have filtered timing data (case-sensitive)
PASS Multiple level redirect to Same Origin resource must have timing data
PASS Multiple level redirect to Cross Origin resource without Timing-Allow-Origin must have must have filtered timing data
PASS Multiple level redirect to Cross Origin resource with Timing-Allow-Origin must have must have timing data
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-resources-per-worker.html (215980 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-resources-per-worker.html 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-resources-per-worker.html 2017-04-30 03:32:58 UTC (rev 215981)
@@ -49,7 +49,10 @@
Promise.all(promises).then(function() {
let supported = worker1Entries !== "error" && worker2Entries !== "error";
+
+ // Exclude the Worker script if it was in the list since it may have been added in the meantime.
let windowEntries = window.performance.getEntriesByType("resource");
+ windowEntries = windowEntries.filter((entry) => !/rt-worker-resources\.js$/.test(entry.name));
test(function() {
assert_true(supported);
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests-expected.txt (0 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests-expected.txt 2017-04-30 03:32:58 UTC (rev 215981)
@@ -0,0 +1,10 @@
+Resource Timing: ResourceTiming for revalidation requests
+
+
+PASS Same Origin network load
+PASS Same Origin revalidation load
+PASS Cross Origin network load (no TimingAllow)
+PASS Cross Origin revalidation load (no TimingAllow)
+PASS Cross Origin network load (with TimingAllow)
+PASS Cross Origin revalidation load (with TimingAllow)
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests.html (0 => 215981)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/resource-timing/rt-revalidate-requests.html 2017-04-30 03:32:58 UTC (rev 215981)
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Resource Timing - ResourceTiming for revalidation requests</title>
+<meta name="author" title="JosephPecoraro" href=""
+<script src=""
+<script src=""
+<script src=""
+</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 = "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>
Modified: trunk/Source/WebCore/ChangeLog (215980 => 215981)
--- trunk/Source/WebCore/ChangeLog 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/Source/WebCore/ChangeLog 2017-04-30 03:32:58 UTC (rev 215981)
@@ -1,3 +1,20 @@
+2017-04-29 Joseph Pecoraro <pecor...@apple.com>
+
+ Zero out PerformanceResourceTiming properties for cached cross-origin responses without Timing-Allow-Origin
+ https://bugs.webkit.org/show_bug.cgi?id=171394
+
+ Reviewed by Youenn Fablet.
+
+ * loader/ResourceTiming.cpp:
+ (WebCore::ResourceTiming::fromCache):
+ (WebCore::ResourceTiming::ResourceTiming):
+ * loader/ResourceTiming.h:
+ * loader/cache/CachedResourceLoader.cpp:
+ (WebCore::CachedResourceLoader::requestResource):
+ Include the timing-allow-origin check for cached responses.
+ Also, avoid including an extra entry for an ongoing cached resource
+ load, since when that load completes it should be reported.
+
2017-04-29 Youenn Fablet <you...@apple.com>
Readd assertion removed accidentally in r215955
Modified: trunk/Source/WebCore/loader/ResourceTiming.cpp (215980 => 215981)
--- trunk/Source/WebCore/loader/ResourceTiming.cpp 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/Source/WebCore/loader/ResourceTiming.cpp 2017-04-30 03:32:58 UTC (rev 215981)
@@ -55,9 +55,9 @@
return false;
}
-ResourceTiming ResourceTiming::fromCache(const URL& url, const String& initiator, const LoadTiming& loadTiming)
+ResourceTiming ResourceTiming::fromCache(const URL& url, const String& initiator, const LoadTiming& loadTiming, const ResourceResponse& response, const SecurityOrigin& securityOrigin)
{
- return ResourceTiming(url, initiator, loadTiming);
+ return ResourceTiming(url, initiator, loadTiming, response, securityOrigin);
}
ResourceTiming ResourceTiming::fromLoad(CachedResource& resource, const String& initiator, const LoadTiming& loadTiming, const NetworkLoadMetrics& networkLoadMetrics, const SecurityOrigin& securityOrigin)
@@ -70,11 +70,11 @@
return ResourceTiming(url, initiator, loadTiming, networkLoadMetrics, response, securityOrigin);
}
-ResourceTiming::ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming)
+ResourceTiming::ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming, const ResourceResponse& response, const SecurityOrigin& securityOrigin)
: m_url(url)
, m_initiator(initiator)
, m_loadTiming(loadTiming)
- , m_allowTimingDetails(true)
+ , m_allowTimingDetails(passesTimingAllowCheck(response, securityOrigin))
{
}
Modified: trunk/Source/WebCore/loader/ResourceTiming.h (215980 => 215981)
--- trunk/Source/WebCore/loader/ResourceTiming.h 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/Source/WebCore/loader/ResourceTiming.h 2017-04-30 03:32:58 UTC (rev 215981)
@@ -38,7 +38,7 @@
class ResourceTiming {
WTF_MAKE_FAST_ALLOCATED;
public:
- static ResourceTiming fromCache(const URL&, const String& initiator, const LoadTiming&);
+ static ResourceTiming fromCache(const URL&, const String& initiator, const LoadTiming&, const ResourceResponse&, const SecurityOrigin&);
static ResourceTiming fromLoad(CachedResource&, const String& initiator, const LoadTiming&, const NetworkLoadMetrics&, const SecurityOrigin&);
static ResourceTiming fromSynchronousLoad(const URL&, const String& initiator, const LoadTiming&, const NetworkLoadMetrics&, const ResourceResponse&, const SecurityOrigin&);
@@ -55,7 +55,7 @@
private:
ResourceTiming(CachedResource&, const String& initiator, const LoadTiming&, const NetworkLoadMetrics&, const SecurityOrigin&);
ResourceTiming(const URL&, const String& initiator, const LoadTiming&, const NetworkLoadMetrics&, const ResourceResponse&, const SecurityOrigin&);
- ResourceTiming(const URL&, const String& initiator, const LoadTiming&);
+ ResourceTiming(const URL&, const String& initiator, const LoadTiming&, const ResourceResponse&, const SecurityOrigin&);
ResourceTiming(const URL& url, const String& initiator, const LoadTiming& loadTiming, const NetworkLoadMetrics& networkLoadMetrics, bool allowTimingDetails)
: m_url(url)
, m_initiator(initiator)
Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp (215980 => 215981)
--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp 2017-04-30 03:30:32 UTC (rev 215980)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp 2017-04-30 03:32:58 UTC (rev 215981)
@@ -776,12 +776,14 @@
#if ENABLE(WEB_TIMING)
loadTiming.setResponseEnd(MonotonicTime::now());
- if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) {
- ResourceTiming resourceTiming = ResourceTiming::fromCache(url, request.initiatorName(), loadTiming);
+ if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled() && document() && !resource->isLoading()) {
+ const SecurityOrigin& origin = request.origin() ? *request.origin() : document()->securityOrigin();
+ ResourceTiming resourceTiming = ResourceTiming::fromCache(url, request.initiatorName(), loadTiming, resource->response(), origin);
if (initiatorContext == InitiatorContext::Worker) {
+ ASSERT(request.origin());
ASSERT(is<CachedRawResource>(resource.get()));
downcast<CachedRawResource>(resource.get())->finishedTimingForWorkerLoad(WTFMove(resourceTiming));
- } else if (document()) {
+ } else {
ASSERT(initiatorContext == InitiatorContext::Document);
m_resourceTimingInfo.storeResourceTimingInitiatorInformation(resource, request.initiatorName(), frame());
m_resourceTimingInfo.addResourceTiming(*resource.get(), *document(), WTFMove(resourceTiming));