LayoutTests/imported/w3c:
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 May 2017 22:53:13 +0000 (22:53 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 May 2017 22:53:13 +0000 (22:53 +0000)
Implement Subresource Integrity (SRI)
https://bugs.webkit.org/show_bug.cgi?id=148363
<rdar://problem/18945879>

Reviewed by Youenn Fablet.

* web-platform-tests/fetch/api/basic/integrity-expected.txt:
* web-platform-tests/fetch/api/basic/integrity-worker-expected.txt:
Update results now that integrity is implemented.

Source/WebCore:
Implement Subresource Integrity (SRI) [Part 2 - Fetch]
https://bugs.webkit.org/show_bug.cgi?id=148363
<rdar://problem/18945879>

Reviewed by Youenn Fablet.

Tests: http/tests/subresource-integrity/sri-fetch-worker.html
       http/tests/subresource-integrity/sri-fetch.html

* loader/FetchOptions.h:
* loader/ThreadableLoader.cpp:
(WebCore::ThreadableLoaderOptions::isolatedCopy):
* loader/ThreadableLoader.h:
* loader/WorkerThreadableLoader.cpp:
(WebCore::LoaderTaskOptions::LoaderTaskOptions):
Add integrity metadata to the fetch options, and fix the implementation of
ThreadableLoaderOptions::isolatedCopy to work correctly (it was missing isolated
copy derivedCachedDataTypesToRetrieve).

* Modules/fetch/FetchRequest.cpp:
(WebCore::buildOptions):
(WebCore::FetchRequest::initializeOptions):
* Modules/fetch/FetchRequest.h:
Switch to using the integrity metadata on the fetchOptions, removing the need to
store them directly on the internal request.

* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::DocumentThreadableLoader):
(WebCore::DocumentThreadableLoader::didReceiveResponse):
(WebCore::DocumentThreadableLoader::didReceiveData):
(WebCore::DocumentThreadableLoader::didFinishLoading):
(WebCore::DocumentThreadableLoader::loadRequest):
(WebCore::DocumentThreadableLoader::reportIntegrityMetadataError):
* loader/DocumentThreadableLoader.h:
Add a new flag, m_delayCallbacksForIntegrityCheck, which is used when integrity metadata
is present, so we can implement the 'wait' concept from the fetch spec, and delay informing
the clients until we have validated the integrity metadata.

LayoutTests:
Implement Subresource Integrity (SRI)
https://bugs.webkit.org/show_bug.cgi?id=148363
<rdar://problem/18945879>

Reviewed by Youenn Fablet.

Add tests for Subresource Integrity for Fetch based off the ones from Web
Platform Tests. Additional tests for more CORS combinations have been added.

* http/tests/subresource-integrity/resources/crossorigin-anon-resource.txt: Added.
* http/tests/subresource-integrity/resources/crossorigin-creds-resource.txt: Added.
* http/tests/subresource-integrity/resources/crossorigin-ineligible-resource.txt: Added.
* http/tests/subresource-integrity/resources/resource.txt: Added.
* http/tests/subresource-integrity/sri-fetch-expected.txt: Added.
* http/tests/subresource-integrity/sri-fetch-worker-expected.txt: Added.
* http/tests/subresource-integrity/sri-fetch-worker.html: Added.
* http/tests/subresource-integrity/sri-fetch.html: Added.
* http/tests/subresource-integrity/sri-fetch.js: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@216553 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/subresource-integrity/resources/crossorigin-anon-resource.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/resources/crossorigin-creds-resource.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/resources/crossorigin-ineligible-resource.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/resources/resource.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-fetch-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-fetch-worker-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-fetch-worker.html [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-fetch.html [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-fetch.js [new file with mode: 0644]
LayoutTests/http/tests/subresource-integrity/sri-script.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/integrity-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/integrity-worker-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/FetchRequest.cpp
Source/WebCore/Modules/fetch/FetchRequest.h
Source/WebCore/loader/DocumentThreadableLoader.cpp
Source/WebCore/loader/DocumentThreadableLoader.h
Source/WebCore/loader/FetchOptions.h
Source/WebCore/loader/ThreadableLoader.cpp
Source/WebCore/loader/ThreadableLoader.h
Source/WebCore/loader/WorkerThreadableLoader.cpp

index 88302f9..43ec126 100644 (file)
@@ -1,3 +1,24 @@
+2017-05-09  Sam Weinig  <sam@webkit.org>
+
+        Implement Subresource Integrity (SRI)
+        https://bugs.webkit.org/show_bug.cgi?id=148363
+        <rdar://problem/18945879>
+
+        Reviewed by Youenn Fablet.
+
+        Add tests for Subresource Integrity for Fetch based off the ones from Web 
+        Platform Tests. Additional tests for more CORS combinations have been added.
+
+        * http/tests/subresource-integrity/resources/crossorigin-anon-resource.txt: Added.
+        * http/tests/subresource-integrity/resources/crossorigin-creds-resource.txt: Added.
+        * http/tests/subresource-integrity/resources/crossorigin-ineligible-resource.txt: Added.
+        * http/tests/subresource-integrity/resources/resource.txt: Added.
+        * http/tests/subresource-integrity/sri-fetch-expected.txt: Added.
+        * http/tests/subresource-integrity/sri-fetch-worker-expected.txt: Added.
+        * http/tests/subresource-integrity/sri-fetch-worker.html: Added.
+        * http/tests/subresource-integrity/sri-fetch.html: Added.
+        * http/tests/subresource-integrity/sri-fetch.js: Added.
+
 2017-05-09  Matt Lewis  <jlewis3@apple.com>
 
         Marked webrtc/captureCanvas-webrtc.html as flaky.
diff --git a/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-anon-resource.txt b/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-anon-resource.txt
new file mode 100644 (file)
index 0000000..83a3157
--- /dev/null
@@ -0,0 +1 @@
+top
\ No newline at end of file
diff --git a/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-creds-resource.txt b/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-creds-resource.txt
new file mode 100644 (file)
index 0000000..83a3157
--- /dev/null
@@ -0,0 +1 @@
+top
\ No newline at end of file
diff --git a/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-ineligible-resource.txt b/LayoutTests/http/tests/subresource-integrity/resources/crossorigin-ineligible-resource.txt
new file mode 100644 (file)
index 0000000..83a3157
--- /dev/null
@@ -0,0 +1 @@
+top
\ No newline at end of file
diff --git a/LayoutTests/http/tests/subresource-integrity/resources/resource.txt b/LayoutTests/http/tests/subresource-integrity/resources/resource.txt
new file mode 100644 (file)
index 0000000..83a3157
--- /dev/null
@@ -0,0 +1 @@
+top
\ No newline at end of file
diff --git a/LayoutTests/http/tests/subresource-integrity/sri-fetch-expected.txt b/LayoutTests/http/tests/subresource-integrity/sri-fetch-expected.txt
new file mode 100644 (file)
index 0000000..a3eff44
--- /dev/null
@@ -0,0 +1,34 @@
+CONSOLE MESSAGE: Fetch API cannot load http://127.0.0.1:8000/subresource-integrity/resources/resource.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://127.0.0.1:8000/subresource-integrity/resources/resource.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://127.0.0.1:8000/subresource-integrity/resources/resource.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8000/subresource-integrity/resources/crossorigin-anon-resource.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8000/subresource-integrity/resources/crossorigin-creds-resource.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8000/subresource-integrity/resources/crossorigin-ineligible-resource.txt. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8000/subresource-integrity/resources/crossorigin-ineligible-resource.txt. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8000/subresource-integrity/resources/crossorigin-ineligible-resource.txt. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+
+PASS Empty string integrity 
+PASS SHA-256 integrity 
+PASS SHA-384 integrity 
+PASS SHA-512 integrity 
+PASS Invalid integrity 
+PASS Unknown integrity 
+PASS Multiple integrities: valid stronger than invalid 
+PASS Multiple integrities: invalid stronger than valid 
+PASS Multiple integrities: invalid as strong as valid 
+PASS Multiple integrities: both are valid 
+PASS Multiple integrities: both are invalid 
+PASS Anonymous CORS empty integrity 
+PASS Anonymous CORS SHA-512 integrity 
+PASS Anonymous CORS invalid integrity 
+PASS Credential CORS empty integrity 
+PASS Credential CORS SHA-512 integrity 
+PASS Credential CORS invalid integrity 
+PASS Ineligible CORS empty integrity 
+PASS Ineligible CORS SHA-512 integrity 
+PASS Ineligible CORS invalid integrity 
+PASS SHA-256 integrity with 'no-cors' mode 
+
diff --git a/LayoutTests/http/tests/subresource-integrity/sri-fetch-worker-expected.txt b/LayoutTests/http/tests/subresource-integrity/sri-fetch-worker-expected.txt
new file mode 100644 (file)
index 0000000..cf0b0f1
--- /dev/null
@@ -0,0 +1,26 @@
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+
+PASS Empty string integrity 
+PASS SHA-256 integrity 
+PASS SHA-384 integrity 
+PASS SHA-512 integrity 
+PASS Invalid integrity 
+PASS Unknown integrity 
+PASS Multiple integrities: valid stronger than invalid 
+PASS Multiple integrities: invalid stronger than valid 
+PASS Multiple integrities: invalid as strong as valid 
+PASS Multiple integrities: both are valid 
+PASS Multiple integrities: both are invalid 
+PASS Anonymous CORS empty integrity 
+PASS Anonymous CORS SHA-512 integrity 
+PASS Anonymous CORS invalid integrity 
+PASS Credential CORS empty integrity 
+PASS Credential CORS SHA-512 integrity 
+PASS Credential CORS invalid integrity 
+PASS Ineligible CORS empty integrity 
+PASS Ineligible CORS SHA-512 integrity 
+PASS Ineligible CORS invalid integrity 
+PASS SHA-256 integrity with 'no-cors' mode 
+
diff --git a/LayoutTests/http/tests/subresource-integrity/sri-fetch-worker.html b/LayoutTests/http/tests/subresource-integrity/sri-fetch-worker.html
new file mode 100644 (file)
index 0000000..ef93a86
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <script src="/js-test-resources/testharness.js"></script>
+    <script src="/js-test-resources/testharnessreport.js"></script>
+</head>
+<body>
+    <script>
+        fetch_tests_from_worker(new Worker("sri-fetch.js"));
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/subresource-integrity/sri-fetch.html b/LayoutTests/http/tests/subresource-integrity/sri-fetch.html
new file mode 100644 (file)
index 0000000..6fae7da
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <script src="/js-test-resources/testharness.js"></script>
+    <script src="/js-test-resources/testharnessreport.js"></script>
+    <script src="resources/sri-utilities.js"></script>
+</head>
+<body>
+    <script src="sri-fetch.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/subresource-integrity/sri-fetch.js b/LayoutTests/http/tests/subresource-integrity/sri-fetch.js
new file mode 100644 (file)
index 0000000..9bf44b1
--- /dev/null
@@ -0,0 +1,63 @@
+if (this.document === undefined) {
+    importScripts("/js-test-resources/testharness.js");
+    importScripts("resources/sri-utilities.js");
+}
+
+var main_host = '127.0.0.1';
+var remote_host = 'localhost';
+var port_string = "8000";
+var main_host_and_port = main_host + ':' + port_string;
+var remote_host_and_port = remote_host + ':' + port_string;
+
+var resource = "resources/resource.txt";
+var crossorigin_anon_resource = location.protocol + '//' + remote_host_and_port + '/subresource-integrity/resources/crossorigin-anon-resource.txt';
+var crossorigin_creds_resource = location.protocol + '//' + remote_host_and_port + '/subresource-integrity/resources/crossorigin-creds-resource.txt';
+var crossorigin_ineligible_resource = location.protocol + '//' + remote_host_and_port + '/subresource-integrity/resources/crossorigin-ineligible-resource.txt';
+
+function integrity(desc, url, options, expectedError) {
+    if (expectedError === undefined) {
+        promise_test(function(test) {
+            return fetch(url, options).then(function(resp) {
+                assert_equals(resp.status, 200, "Response's status is 200");
+            });
+        }, desc);
+    } else {
+        promise_test(function(test) {
+            return promise_rejects(test, expectedError, fetch(url, options));
+        }, desc);
+    }
+}
+
+var topSha256 = "sha256-KHIDZcXnR2oBHk9DrAA+5fFiR6JjudYjqoXtMR1zvzk=";
+var topSha384 = "sha384-MgZYnnAzPM/MjhqfOIMfQK5qcFvGZsGLzx4Phd7/A8fHTqqLqXqKo8cNzY3xEPTL";
+var topSha512 = "sha512-D6yns0qxG0E7+TwkevZ4Jt5t7Iy3ugmAajG/dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg==";
+var invalidSha256 = "sha256-dKUcPOn/AlUjWIwcHeHNqYXPlvyGiq+2dWOdFcE+24I=";
+var invalidSha512 = "sha512-oUceBRNxPxnY60g/VtPCj2syT4wo4EZh2CgYdWy9veW8+OsReTXoh7dizMGZafvx9+QhMS39L/gIkxnPIn41Zg==";
+var unknownAlgorithm = "foo666-dKUcPOn/AlUjWIwcHeHNqYXPlvyGiq+2dWOdFcE+24I=";
+
+integrity("Empty string integrity", resource, { 'integrity': "" });
+integrity("SHA-256 integrity", resource, { 'integrity': topSha256 });
+integrity("SHA-384 integrity", resource, { 'integrity': topSha384 });
+integrity("SHA-512 integrity", resource, { 'integrity': topSha512 });
+integrity("Invalid integrity", resource, { 'integrity': invalidSha256 }, new TypeError());
+integrity("Unknown integrity", resource, { 'integrity': unknownAlgorithm });
+integrity("Multiple integrities: valid stronger than invalid", resource, { 'integrity': invalidSha256 + " " + topSha384 });
+integrity("Multiple integrities: invalid stronger than valid", resource, { 'integrity': invalidSha512 + " " + topSha384 }, new TypeError());
+integrity("Multiple integrities: invalid as strong as valid", resource, { 'integrity': invalidSha512 + " " + topSha512 });
+integrity("Multiple integrities: both are valid", resource,  { 'integrity': topSha384 + " " + topSha512 });
+integrity("Multiple integrities: both are invalid", resource, { 'integrity': invalidSha256 + " " + invalidSha512 }, new TypeError());
+integrity("Anonymous CORS empty integrity", crossorigin_anon_resource, { 'integrity': "" });
+integrity("Anonymous CORS SHA-512 integrity", crossorigin_anon_resource, { 'integrity': topSha512 });
+integrity("Anonymous CORS invalid integrity", crossorigin_anon_resource, { 'integrity': invalidSha512 }, new TypeError());
+
+// FIXME: Upstream these additional tests to the official web-platform-tests repository.
+
+integrity("Credential CORS empty integrity", crossorigin_creds_resource, { 'integrity': "", 'credentials': 'include' });
+integrity("Credential CORS SHA-512 integrity", crossorigin_creds_resource, { 'integrity': topSha512, 'credentials': 'include' });
+integrity("Credential CORS invalid integrity", crossorigin_creds_resource, { 'integrity': invalidSha512, 'credentials': 'include' }, new TypeError());
+integrity("Ineligible CORS empty integrity", crossorigin_ineligible_resource, { 'integrity': "" }, new TypeError());
+integrity("Ineligible CORS SHA-512 integrity", crossorigin_ineligible_resource, { 'integrity': topSha512 }, new TypeError());
+integrity("Ineligible CORS invalid integrity", crossorigin_ineligible_resource, { 'integrity': invalidSha512 }, new TypeError());
+integrity("SHA-256 integrity with 'no-cors' mode", resource, { 'integrity': topSha256, 'mode': 'no-cors' }, new TypeError());
+
+done();
index 2eaa149..11df18a 100644 (file)
@@ -162,6 +162,7 @@ new SRIScriptTest(
 );
 
 // WebKit additions to the web-platform-tests test cases.
+// FIXME: Upstream these additional tests to the official web-platform-tests repository.
 
 new SRIScriptTest(
     true,
index e15948a..bd801b3 100644 (file)
@@ -1,3 +1,15 @@
+2017-05-09  Sam Weinig  <sam@webkit.org>
+
+        Implement Subresource Integrity (SRI)
+        https://bugs.webkit.org/show_bug.cgi?id=148363
+        <rdar://problem/18945879>
+
+        Reviewed by Youenn Fablet.
+
+        * web-platform-tests/fetch/api/basic/integrity-expected.txt:
+        * web-platform-tests/fetch/api/basic/integrity-worker-expected.txt:
+        Update results now that integrity is implemented.
+
 2017-05-09  Youenn Fablet  <youenn@apple.com>
 
         Refresh webrtc WPT tests
index bd08049..11e1495 100644 (file)
@@ -1,15 +1,19 @@
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8800/fetch/api/resources/top.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8800/fetch/api/resources/top.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8800/fetch/api/resources/top.txt. Failed integrity metadata check.
+CONSOLE MESSAGE: Fetch API cannot load http://localhost:8801/fetch/api/resources/top.txt?pipe=header(Access-Control-Allow-Origin,*). Failed integrity metadata check.
 
 PASS Empty string integrity 
 PASS SHA-256 integrity 
 PASS SHA-384 integrity 
 PASS SHA-512 integrity 
-FAIL Invalid integrity assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Invalid integrity 
 PASS Multiple integrities: valid stronger than invalid 
-FAIL Multiple integrities: invalid stronger than valid assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Multiple integrities: invalid stronger than valid 
 PASS Multiple integrities: invalid as strong as valid 
 PASS Multiple integrities: both are valid 
-FAIL Multiple integrities: both are invalid assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Multiple integrities: both are invalid 
 PASS CORS empty integrity 
 PASS CORS SHA-512 integrity 
-FAIL CORS invalid integrity assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS CORS invalid integrity 
 
index bd08049..4cfaa44 100644 (file)
@@ -3,13 +3,13 @@ PASS Empty string integrity
 PASS SHA-256 integrity 
 PASS SHA-384 integrity 
 PASS SHA-512 integrity 
-FAIL Invalid integrity assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Invalid integrity 
 PASS Multiple integrities: valid stronger than invalid 
-FAIL Multiple integrities: invalid stronger than valid assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Multiple integrities: invalid stronger than valid 
 PASS Multiple integrities: invalid as strong as valid 
 PASS Multiple integrities: both are valid 
-FAIL Multiple integrities: both are invalid assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Multiple integrities: both are invalid 
 PASS CORS empty integrity 
 PASS CORS SHA-512 integrity 
-FAIL CORS invalid integrity assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS CORS invalid integrity 
 
index ab1177c..892cd78 100644 (file)
@@ -1,3 +1,43 @@
+2017-05-09  Sam Weinig  <sam@webkit.org>
+
+        Implement Subresource Integrity (SRI) [Part 2 - Fetch]
+        https://bugs.webkit.org/show_bug.cgi?id=148363
+        <rdar://problem/18945879>
+
+        Reviewed by Youenn Fablet.
+
+        Tests: http/tests/subresource-integrity/sri-fetch-worker.html
+               http/tests/subresource-integrity/sri-fetch.html
+
+        * loader/FetchOptions.h:
+        * loader/ThreadableLoader.cpp:
+        (WebCore::ThreadableLoaderOptions::isolatedCopy):
+        * loader/ThreadableLoader.h:
+        * loader/WorkerThreadableLoader.cpp:
+        (WebCore::LoaderTaskOptions::LoaderTaskOptions):
+        Add integrity metadata to the fetch options, and fix the implementation of
+        ThreadableLoaderOptions::isolatedCopy to work correctly (it was missing isolated
+        copy derivedCachedDataTypesToRetrieve).
+
+        * Modules/fetch/FetchRequest.cpp:
+        (WebCore::buildOptions):
+        (WebCore::FetchRequest::initializeOptions):
+        * Modules/fetch/FetchRequest.h:
+        Switch to using the integrity metadata on the fetchOptions, removing the need to
+        store them directly on the internal request.
+
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::DocumentThreadableLoader):
+        (WebCore::DocumentThreadableLoader::didReceiveResponse):
+        (WebCore::DocumentThreadableLoader::didReceiveData):
+        (WebCore::DocumentThreadableLoader::didFinishLoading):
+        (WebCore::DocumentThreadableLoader::loadRequest):
+        (WebCore::DocumentThreadableLoader::reportIntegrityMetadataError):
+        * loader/DocumentThreadableLoader.h:
+        Add a new flag, m_delayCallbacksForIntegrityCheck, which is used when integrity metadata
+        is present, so we can implement the 'wait' concept from the fetch spec, and delay informing
+        the clients until we have validated the integrity metadata.
+
 2017-05-09  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r216545.
index b879a7b..6b309de 100644 (file)
@@ -105,7 +105,7 @@ static std::optional<Exception> buildOptions(FetchRequest::InternalRequest& requ
         request.options.redirect = init.redirect.value();
 
     if (!init.integrity.isNull())
-        request.integrity = init.integrity;
+        request.options.integrity = init.integrity;
 
     if (!init.method.isNull()) {
         if (auto exception = setMethod(request.request, init.method))
@@ -132,7 +132,7 @@ ExceptionOr<FetchHeaders&> FetchRequest::initializeOptions(const Init& init)
         const String& method = m_internalRequest.request.httpMethod();
         if (method != "GET" && method != "POST" && method != "HEAD")
             return Exception { TypeError, ASCIILiteral("Method must be GET, POST or HEAD in no-cors mode.") };
-        if (!m_internalRequest.integrity.isEmpty())
+        if (!m_internalRequest.options.integrity.isEmpty())
             return Exception { TypeError, ASCIILiteral("There cannot be an integrity in no-cors mode.") };
         m_headers->setGuard(FetchHeaders::Guard::RequestNoCors);
     }
index 47fbf78..62ce08c 100644 (file)
@@ -83,7 +83,7 @@ public:
     Cache cache() const;
     Redirect redirect() const;
 
-    const String& integrity() const { return m_internalRequest.integrity; }
+    const String& integrity() const { return m_internalRequest.options.integrity; }
 
     ExceptionOr<Ref<FetchRequest>> clone(ScriptExecutionContext&);
 
@@ -91,7 +91,6 @@ public:
         ResourceRequest request;
         FetchOptions options;
         String referrer;
-        String integrity;
     };
 
     const FetchOptions& fetchOptions() const { return m_internalRequest.options; }
index 5a0bf41..71c7118 100644 (file)
@@ -52,6 +52,7 @@
 #include "RuntimeEnabledFeatures.h"
 #include "SchemeRegistry.h"
 #include "SecurityOrigin.h"
+#include "SubresourceIntegrity.h"
 #include "SubresourceLoader.h"
 #include "ThreadableLoaderClient.h"
 #include <wtf/Assertions.h>
@@ -95,6 +96,7 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl
     , m_sameOriginRequest(securityOrigin().canRequest(request.url()))
     , m_simpleRequest(true)
     , m_async(blockingBehavior == LoadAsynchronously)
+    , m_delayCallbacksForIntegrityCheck(!m_options.integrity.isEmpty())
     , m_contentSecurityPolicy(WTFMove(contentSecurityPolicy))
     , m_shouldLogError(shouldLogError)
 {
@@ -296,6 +298,9 @@ void DocumentThreadableLoader::didReceiveResponse(unsigned long identifier, cons
 
     InspectorInstrumentation::didReceiveThreadableLoaderResponse(*this, identifier);
 
+    if (m_delayCallbacksForIntegrityCheck)
+        return;
+
     if (options().filteringPolicy == ResponseFilteringPolicy::Disable) {
         m_client->didReceiveResponse(identifier, response);
         return;
@@ -324,6 +329,9 @@ void DocumentThreadableLoader::didReceiveData(unsigned long, const char* data, i
 {
     ASSERT(m_client);
 
+    if (m_delayCallbacksForIntegrityCheck)
+        return;
+
     m_client->didReceiveData(data, dataLength);
 }
 
@@ -361,6 +369,27 @@ void DocumentThreadableLoader::notifyFinished(CachedResource& resource)
 void DocumentThreadableLoader::didFinishLoading(unsigned long identifier)
 {
     ASSERT(m_client);
+
+    if (m_delayCallbacksForIntegrityCheck) {
+        if (!matchIntegrityMetadata(*m_resource, m_options.integrity)) {
+            reportIntegrityMetadataError(m_resource->url());
+            return;
+        }
+
+        auto response = m_resource->response();
+
+        if (options().filteringPolicy == ResponseFilteringPolicy::Disable) {
+            m_client->didReceiveResponse(identifier, response);
+            m_client->didReceiveData(m_resource->resourceBuffer()->data(), m_resource->resourceBuffer()->size());
+        } else {
+            ASSERT(response.type() == ResourceResponse::Type::Default);
+            
+            auto tainting = m_resource->responseTainting();
+            m_client->didReceiveResponse(identifier, ResourceResponse::filterResponse(response, tainting));
+            m_client->didReceiveData(m_resource->resourceBuffer()->data(), m_resource->resourceBuffer()->size());
+        }
+    }
+
     m_client->didFinishLoading(identifier);
 }
 
@@ -407,6 +436,10 @@ void DocumentThreadableLoader::loadRequest(ResourceRequest&& request, SecurityCh
         ResourceLoaderOptions options = m_options;
         options.clientCredentialPolicy = m_sameOriginRequest ? ClientCredentialPolicy::MayAskClientForCredentials : ClientCredentialPolicy::CannotAskClientForCredentials;
         options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+        
+        // If there is integrity metadata to validate, we must buffer.
+        if (!m_options.integrity.isEmpty())
+            options.dataBufferingPolicy = BufferData;
 
         request.setAllowCookies(m_options.allowCredentials == AllowStoredCredentials);
         CachedResourceRequest newRequest(WTFMove(request), options);
@@ -574,6 +607,11 @@ void DocumentThreadableLoader::reportCrossOriginResourceSharingError(const URL&
     logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, url, "Cross-origin redirection denied by Cross-Origin Resource Sharing policy.", ResourceError::Type::AccessControl));
 }
 
+void DocumentThreadableLoader::reportIntegrityMetadataError(const URL& url)
+{
+    logErrorAndFail(ResourceError(errorDomainWebKitInternal, 0, url, "Failed integrity metadata check.", ResourceError::Type::General));
+}
+
 void DocumentThreadableLoader::logErrorAndFail(const ResourceError& error)
 {
     if (m_shouldLogError == ShouldLogError::Yes)
index 2630d57..848e1c2 100644 (file)
@@ -118,6 +118,7 @@ namespace WebCore {
         void reportRedirectionWithBadScheme(const URL&);
         void reportContentSecurityPolicyError(const URL&);
         void reportCrossOriginResourceSharingError(const URL&);
+        void reportIntegrityMetadataError(const URL&);
         void logErrorAndFail(const ResourceError&);
 
         CachedResourceHandle<CachedRawResource> m_resource;
@@ -129,6 +130,7 @@ namespace WebCore {
         bool m_sameOriginRequest;
         bool m_simpleRequest;
         bool m_async;
+        bool m_delayCallbacksForIntegrityCheck;
         std::unique_ptr<ContentSecurityPolicy> m_contentSecurityPolicy;
         std::optional<CrossOriginPreflightChecker> m_preflightChecker;
         std::optional<HTTPHeaderMap> m_originalHeaders;
index b733461..11e17ad 100644 (file)
@@ -28,6 +28,8 @@
 
 #pragma once
 
+#include <wtf/text/WTFString.h>
+
 namespace WebCore {
 
 struct FetchOptions {
@@ -51,6 +53,8 @@ struct FetchOptions {
 
     enum class ReferrerPolicy { EmptyString, NoReferrer, NoReferrerWhenDowngrade, Origin, OriginWhenCrossOrigin, UnsafeUrl };
     ReferrerPolicy referrerPolicy { ReferrerPolicy::EmptyString };
+
+    String integrity;
 };
 
 } // namespace WebCore
index a316da4..9fb7e6e 100644 (file)
@@ -60,6 +60,48 @@ ThreadableLoaderOptions::ThreadableLoaderOptions(const ResourceLoaderOptions& ba
 {
 }
 
+ThreadableLoaderOptions ThreadableLoaderOptions::isolatedCopy() const
+{
+    ThreadableLoaderOptions copy;
+
+    // FetchOptions
+    copy.type = this->type;
+    copy.destination = this->destination;
+    copy.mode = this->mode;
+    copy.credentials = this->credentials;
+    copy.cache = this->cache;
+    copy.redirect = this->redirect;
+    copy.referrerPolicy = this->referrerPolicy;
+    copy.integrity = this->integrity.isolatedCopy();
+
+    // ResourceLoaderOptions
+    copy.sendLoadCallbacks = this->sendLoadCallbacks;
+    copy.sniffContent = this->sniffContent;
+    copy.dataBufferingPolicy = this->dataBufferingPolicy;
+    copy.allowCredentials = this->allowCredentials;
+    copy.securityCheck = this->securityCheck;
+    copy.certificateInfoPolicy = this->certificateInfoPolicy;
+    copy.contentSecurityPolicyImposition = this->contentSecurityPolicyImposition;
+    copy.defersLoadingPolicy = this->defersLoadingPolicy;
+    copy.cachingPolicy = this->cachingPolicy;
+    copy.sameOriginDataURLFlag = this->sameOriginDataURLFlag;
+    copy.initiatorContext = this->initiatorContext;
+    copy.clientCredentialPolicy = this->clientCredentialPolicy;
+    copy.maxRedirectCount = this->maxRedirectCount;
+    copy.derivedCachedDataTypesToRetrieve.reserveInitialCapacity(this->derivedCachedDataTypesToRetrieve.size());
+    for (auto& derivedCachedDataType : this->derivedCachedDataTypesToRetrieve)
+        copy.derivedCachedDataTypesToRetrieve.uncheckedAppend(derivedCachedDataType.isolatedCopy());
+
+    // ThreadableLoaderOptions
+    copy.preflightPolicy = this->preflightPolicy;
+    copy.contentSecurityPolicyEnforcement = this->contentSecurityPolicyEnforcement;
+    copy.initiator = this->initiator.isolatedCopy();
+    copy.filteringPolicy = this->filteringPolicy;
+
+    return copy;
+}
+
+
 RefPtr<ThreadableLoader> ThreadableLoader::create(ScriptExecutionContext& context, ThreadableLoaderClient& client, ResourceRequest&& request, const ThreadableLoaderOptions& options, String&& referrer)
 {
     if (is<WorkerGlobalScope>(context))
index e924b24..630dca0 100644 (file)
@@ -66,6 +66,8 @@ namespace WebCore {
         ThreadableLoaderOptions(const ResourceLoaderOptions&, PreflightPolicy, ContentSecurityPolicyEnforcement, String&& initiator, ResponseFilteringPolicy);
         ~ThreadableLoaderOptions();
 
+        ThreadableLoaderOptions isolatedCopy() const;
+
         PreflightPolicy preflightPolicy { ConsiderPreflight };
         ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement { ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective };
         String initiator; // This cannot be an AtomicString, as isolatedCopy() wouldn't create an object that's safe for passing to another thread.
index 15edb45..142662a 100644 (file)
@@ -94,7 +94,7 @@ struct LoaderTaskOptions {
 };
 
 LoaderTaskOptions::LoaderTaskOptions(const ThreadableLoaderOptions& options, const String& referrer, Ref<SecurityOrigin>&& origin)
-    : options(options, options.preflightPolicy, options.contentSecurityPolicyEnforcement, options.initiator.isolatedCopy(), options.filteringPolicy)
+    : options(options.isolatedCopy())
     , referrer(referrer.isolatedCopy())
     , origin(WTFMove(origin))
 {