Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Aug 2017 00:28:25 +0000 (00:28 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Aug 2017 00:28:25 +0000 (00:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175628
<rdar://problem/33919278>

Reviewed by Geoffrey Garen.

LayoutTests/imported/w3c:

Rebaseline a few web-platform-tests due to revert of r220779.

* web-platform-tests/beacon/headers/header-content-type-expected.txt:
* web-platform-tests/fetch/api/basic/request-headers.any-expected.txt:
* web-platform-tests/fetch/api/basic/request-headers.any.worker-expected.txt:

Source/WebCore:

Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight.
To achieve this, the following changes were made:
1. Revert r220779 which caused us to use a non CORS-safelisted Content-Type header for such payload
2. Teach PingLoad how to deal with "simple" cross origin requests (i.e. Don't assume we need a CORS
   preflight merely because the fetch mode is set to "cors").

Test: http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html

* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::extract):
* loader/CrossOriginAccessControl.h:
* loader/LoaderStrategy.h:
* loader/PingLoader.cpp:
(WebCore::PingLoader::loadImage):
(WebCore::PingLoader::sendPing):
(WebCore::PingLoader::sendViolationReport):
(WebCore::PingLoader::startPingLoad):
* loader/PingLoader.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::CachedResource):
(WebCore::CachedResource::load):
* loader/cache/CachedResource.h:
* loader/cache/CachedResourceRequest.cpp:
(WebCore::CachedResourceRequest::CachedResourceRequest):
* loader/cache/CachedResourceRequest.h:
(WebCore::CachedResourceRequest::releaseOriginalRequestHeaders):
* platform/network/HTTPHeaderValues.cpp:
* platform/network/HTTPHeaderValues.h:

Source/WebKit:

Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight.
To achieve this, the following changes were made:
1. Revert r220779 which caused us to use a non CORS-safelisted Content-Type header for such payload
2. Teach PingLoad how to deal with "simple" cross origin requests (i.e. Don't assume we need a CORS
   preflight merely because the fetch mode is set to "cors").

* NetworkProcess/NetworkCORSPreflightChecker.cpp:
(WebKit::NetworkCORSPreflightChecker::startPreflight):
* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const):
(WebKit::NetworkResourceLoadParameters::decode):
* NetworkProcess/NetworkResourceLoadParameters.h:
* NetworkProcess/PingLoad.cpp:
(WebKit::PingLoad::PingLoad):
(WebKit::PingLoad::loadRequest):
(WebKit::PingLoad::originalRequestHeaders const):
(WebKit::PingLoad::willPerformHTTPRedirection):
(WebKit::PingLoad::isAllowedRedirect const):
(WebKit::PingLoad::makeCrossOriginAccessRequest):
(WebKit::PingLoad::makeSimpleCrossOriginAccessRequest):
(WebKit::PingLoad::makeCrossOriginAccessRequestWithPreflight):
(WebKit::PingLoad::preflightSuccess):
* NetworkProcess/PingLoad.h:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::createPingHandle):
* WebProcess/Network/WebLoaderStrategy.h:

Source/WebKitLegacy:

* WebCoreSupport/WebResourceLoadScheduler.cpp:
(WebResourceLoadScheduler::createPingHandle):
* WebCoreSupport/WebResourceLoadScheduler.h:

LayoutTests:

* http/tests/blink/sendbeacon/beacon-same-origin-expected.txt:
* http/wpt/fetch/fetch-request-arraybuffer-content-type-expected.txt:
* http/wpt/fetch/fetch-request-arraybuffer-content-type.html:
Rebaseline test due to revert of r220779.

* http/wpt/beacon/cors/cors-preflight-arraybufferview-failure-expected.txt: Removed.
* http/wpt/beacon/cors/cors-preflight-arraybufferview-failure.html: Removed.
Drop outdated test. CORS preflight failure is still covered by the corresponding Blob payload test.

* http/wpt/beacon/cors/cors-preflight-arraybufferview-success-expected.txt: Removed.
* http/wpt/beacon/cors/cors-preflight-arraybufferview-success.html: Removed.
* http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight-expected.txt: Added.
* http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html: Added.
Rename and update test so that it checks that we no longer do a CORS preflight for cross origin
beacons that have an ArrayBuffer payload.

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

36 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/blink/sendbeacon/beacon-same-origin-expected.txt
LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure-expected.txt [deleted file]
LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure.html [deleted file]
LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-success-expected.txt [deleted file]
LayoutTests/http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html [moved from LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-success.html with 68% similarity]
LayoutTests/http/wpt/fetch/fetch-request-arraybuffer-content-type-expected.txt
LayoutTests/http/wpt/fetch/fetch-request-arraybuffer-content-type.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/beacon/headers/header-content-type-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers.any-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers.any.worker-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/FetchBody.cpp
Source/WebCore/loader/CrossOriginAccessControl.h
Source/WebCore/loader/LoaderStrategy.h
Source/WebCore/loader/PingLoader.cpp
Source/WebCore/loader/PingLoader.h
Source/WebCore/loader/cache/CachedResource.cpp
Source/WebCore/loader/cache/CachedResource.h
Source/WebCore/loader/cache/CachedResourceRequest.cpp
Source/WebCore/loader/cache/CachedResourceRequest.h
Source/WebCore/platform/network/HTTPHeaderValues.cpp
Source/WebCore/platform/network/HTTPHeaderValues.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkCORSPreflightChecker.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h
Source/WebKit/NetworkProcess/PingLoad.cpp
Source/WebKit/NetworkProcess/PingLoad.h
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
Source/WebKit/WebProcess/Network/WebLoaderStrategy.h
Source/WebKitLegacy/ChangeLog
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h

index 6c45c1a7f0013209776370331765348b3c64b5b4..48a5b7166533e8d020bd76ef8acff545d9c3d3fa 100644 (file)
@@ -1,3 +1,27 @@
+2017-08-16  Chris Dumez  <cdumez@apple.com>
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight
+        https://bugs.webkit.org/show_bug.cgi?id=175628
+        <rdar://problem/33919278>
+
+        Reviewed by Geoffrey Garen.
+
+        * http/tests/blink/sendbeacon/beacon-same-origin-expected.txt:
+        * http/wpt/fetch/fetch-request-arraybuffer-content-type-expected.txt:
+        * http/wpt/fetch/fetch-request-arraybuffer-content-type.html:
+        Rebaseline test due to revert of r220779.
+
+        * http/wpt/beacon/cors/cors-preflight-arraybufferview-failure-expected.txt: Removed.
+        * http/wpt/beacon/cors/cors-preflight-arraybufferview-failure.html: Removed.
+        Drop outdated test. CORS preflight failure is still covered by the corresponding Blob payload test.
+
+        * http/wpt/beacon/cors/cors-preflight-arraybufferview-success-expected.txt: Removed.
+        * http/wpt/beacon/cors/cors-preflight-arraybufferview-success.html: Removed.
+        * http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight-expected.txt: Added.
+        * http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html: Added.
+        Rename and update test so that it checks that we no longer do a CORS preflight for cross origin
+        beacons that have an ArrayBuffer payload.
+
 2017-08-16  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: capture async stack trace when workers/main context posts a message
index f07787fa39f5613a18f5cba541c777f4d49d9357..f37bc1a7009bcda63bf5e8373b2eb4e6f0901c7f 100644 (file)
@@ -16,7 +16,7 @@ PASS
 Sending beacon with type: [object Uint32Array]
 PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
 PASS Beacon sent successfully
-PASS Content-Type: application/octet-stream
+PASS Content-Type: application/x-www-form-urlencoded
 PASS Origin: http://127.0.0.1:8000
 PASS Referer: http://127.0.0.1:8000/blink/sendbeacon/beacon-same-origin.html
 PASS Request-Method: POST
diff --git a/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure-expected.txt b/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure-expected.txt
deleted file mode 100644 (file)
index 11932f7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-PASS CORS preflight failure test 
-
diff --git a/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure.html b/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-failure.html
deleted file mode 100644 (file)
index a5aa5bb..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>SendBeacon CORS preflight test</title>
-    <script src=/resources/testharness.js></script>
-    <script src=/resources/testharnessreport.js></script>
-  </head>
-  <body>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script>
-var RESOURCES_DIR = "/WebKit/beacon/resources/";
-
-function pollResult(test, id) {
-  var checkUrl = RESOURCES_DIR + "beacon-preflight.py?cmd=get&id=" + id;
-
-  return new Promise(resolve => {
-    step_timeout(test.step_func(() => {
-      fetch(checkUrl).then(response => {
-        response.json().then(body => {
-          resolve(body);
-        });
-      });
-    }), 1000);
-  });
-}
-
-function testCORSPreflightFailure(what) {
-  var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
-  var id = self.token();
-  var testUrl = testBase + "beacon-preflight.py?allowCors=0&cmd=put&id=" + id;
-
-  promise_test(function(test) {
-    assert_true(navigator.sendBeacon(testUrl, what), "SendBeacon Succeeded");
-    return pollResult(test, id) .then(result => {
-      assert_equals(result['preflight'], 1, "Received preflight")
-      assert_equals(result['preflight_referer'], document.URL, "Preflight referer header")
-      assert_equals(result['preflight_requested_method'], "POST", "Preflight requested method")
-      let requested_headers = result['preflight_requested_headers'].toLowerCase()
-      assert_true(requested_headers.includes("content-type"), "Content-Type header is requested")
-      assert_true(requested_headers.includes("referer"), "Referer header is requested")
-      assert_true(requested_headers.includes("origin"), "Origin header is requested")
-      assert_equals(result['beacon'], 0, "Did not receive beacon")
-    });
-  }, "CORS preflight failure test");
-}
-
-function stringToArrayBufferView(input) {
-  var buffer = new ArrayBuffer(input.length * 2);
-  var view = new Uint16Array(buffer);
-
-  // dumbly copy over the bytes
-  for (var i = 0, len = input.length; i < len; i++) {
-    view[i] = input.charCodeAt(i);
-  }
-  return view;
-}
-
-testCORSPreflightFailure(stringToArrayBufferView("123"));
-    </script>
-  </body>
-</html>
diff --git a/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-success-expected.txt b/LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-success-expected.txt
deleted file mode 100644 (file)
index 1544982..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-PASS CORS preflight success test 
-
diff --git a/LayoutTests/http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight-expected.txt b/LayoutTests/http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight-expected.txt
new file mode 100644 (file)
index 0000000..1895fc6
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Should send beacon with no CORS preflight 
+
similarity index 68%
rename from LayoutTests/http/wpt/beacon/cors/cors-preflight-arraybufferview-success.html
rename to LayoutTests/http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html
index 78b305f2721d2e3d005029ffa63a06d0949d0091..fa4860b634154e48142e2c609238634dc10f018e 100644 (file)
@@ -2,7 +2,7 @@
 <html>
   <head>
     <meta charset="utf-8">
-    <title>SendBeacon CORS preflight test</title>
+    <title>SendBeacon cross origin with an ArrayBuffer / ArrayBufferView payload should not do a CORS preflight</title>
     <script src=/resources/testharness.js></script>
     <script src=/resources/testharnessreport.js></script>
   </head>
@@ -34,16 +34,10 @@ function testCORSPreflightSuccess(what) {
   promise_test(function(test) {
     assert_true(navigator.sendBeacon(testUrl, what), "SendBeacon Succeeded");
     return pollResult(test, id) .then(result => {
-      assert_equals(result['preflight'], 1, "Received preflight")
-      assert_equals(result['preflight_referer'], document.URL, "Preflight referer header")
-      assert_equals(result['preflight_requested_method'], "POST", "Preflight requested method")
-      let requested_headers = result['preflight_requested_headers'].toLowerCase()
-      assert_true(requested_headers.includes("content-type"), "Content-Type header is requested")
-      assert_true(requested_headers.includes("referer"), "Referer header is requested")
-      assert_true(requested_headers.includes("origin"), "Origin header is requested")
+      assert_equals(result['preflight'], 0, "Did not receive CORS preflight")
       assert_equals(result['beacon'], 1, "Received beacon")
     });
-  }, "CORS preflight success test");
+  }, "Should send beacon with no CORS preflight");
 }
 
 function stringToArrayBufferView(input) {
index 8555a1c9fa8a8dd47b0f84fd26bf31889b0894cf..2baa2b886d78a907e8e5c5e657024fef0fb9390f 100644 (file)
@@ -1,3 +1,3 @@
 
-PASS Content-Type header for payload of ArrayBuffer type should be 'application/octet-stream' 
+PASS Content-Type header for payload of ArrayBuffer type should be null 
 
index 5ae18532248e42543a2aaaf090f9bf3947be6e01..04fc662fa31d56cd8ccdcc799f7df5383b97d198 100644 (file)
@@ -6,8 +6,8 @@
 <script>
 test(function(t) {
   let request = new Request("http://localhost", { method: "POST", body: new ArrayBuffer() });
-  assert_equals(request.headers.get('Content-Type'), "application/octet-stream");
-}, "Content-Type header for payload of ArrayBuffer type should be 'application/octet-stream'");
+  assert_equals(request.headers.get('Content-Type'), null);
+}, "Content-Type header for payload of ArrayBuffer type should be null");
 </script>
 </body>
 </html>
index 41334fabb210e7dcd0d2cdc33cac0b70684d1a69..a74ec325160edc64a2ea8f4b10d74336f228a5b9 100644 (file)
@@ -1,3 +1,17 @@
+2017-08-16  Chris Dumez  <cdumez@apple.com>
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight
+        https://bugs.webkit.org/show_bug.cgi?id=175628
+        <rdar://problem/33919278>
+
+        Reviewed by Geoffrey Garen.
+
+        Rebaseline a few web-platform-tests due to revert of r220779.
+
+        * web-platform-tests/beacon/headers/header-content-type-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-headers.any-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-headers.any.worker-expected.txt:
+
 2017-08-16  Chris Dumez  <cdumez@apple.com>
 
         EventSource: ignore IDs with U+0000
index f558d78f19e53950e385f93516e3626205430d80..0ef518b1aa21e7f1b5232f5bf402faeb1c3b887f 100644 (file)
@@ -1,7 +1,7 @@
 
 PASS Test content-type header for a body string 
-FAIL Test content-type header for a body ArrayBufferView assert_equals: Correct Content-Type header result expected "" but got "application/octet-stream"
-FAIL Test content-type header for a body ArrayBuffer assert_equals: Correct Content-Type header result expected "" but got "application/octet-stream"
+FAIL Test content-type header for a body ArrayBufferView assert_equals: Correct Content-Type header result expected "" but got "application/x-www-form-urlencoded"
+FAIL Test content-type header for a body ArrayBuffer assert_equals: Correct Content-Type header result expected "" but got "application/x-www-form-urlencoded"
 PASS Test content-type header for a body Blob 
 PASS Test content-type header for a body FormData 
 PASS Test content-type header for a body URLSearchParams 
index 5b3e2dde919a2a53eabe557842be54e8c3d572e0..425b86743950696657d34641fa5c5bbe90f61466 100644 (file)
@@ -8,12 +8,12 @@ PASS Fetch with POST with text body
 PASS Fetch with POST with FormData body 
 PASS Fetch with POST with URLSearchParams body 
 FAIL Fetch with POST with Blob body assert_equals: Request should have header content-type: null expected (object) null but got (string) ""
-FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
+FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
 PASS Fetch with POST with Blob body with mime type 
 FAIL Fetch with Chicken assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
 PASS Fetch with Chicken with body 
index 51d9971dfa0df798ff4c252f0ce7164635b362b3..447fe1e70bd6ea63da8ac540c9d70709c0f778c8 100644 (file)
@@ -8,12 +8,12 @@ PASS Fetch with POST with text body
 FAIL Fetch with POST with FormData body Can't find variable: FormData
 PASS Fetch with POST with URLSearchParams body 
 FAIL Fetch with POST with Blob body assert_equals: Request should have header content-type: null expected (object) null but got (string) ""
-FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
-FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/octet-stream"
+FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
 PASS Fetch with POST with Blob body with mime type 
 FAIL Fetch with Chicken assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
 PASS Fetch with Chicken with body 
index 28a3a10bbf30b095e693a3f33356277152ba9e1c..53c226b7b49fbd8e8b387bdad2372812138a3cac 100644 (file)
@@ -1,3 +1,40 @@
+2017-08-16  Chris Dumez  <cdumez@apple.com>
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight
+        https://bugs.webkit.org/show_bug.cgi?id=175628
+        <rdar://problem/33919278>
+
+        Reviewed by Geoffrey Garen.
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight.
+        To achieve this, the following changes were made:
+        1. Revert r220779 which caused us to use a non CORS-safelisted Content-Type header for such payload
+        2. Teach PingLoad how to deal with "simple" cross origin requests (i.e. Don't assume we need a CORS
+           preflight merely because the fetch mode is set to "cors").
+
+        Test: http/wpt/beacon/cors/crossorigin-arraybufferview-no-preflight.html
+
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::extract):
+        * loader/CrossOriginAccessControl.h:
+        * loader/LoaderStrategy.h:
+        * loader/PingLoader.cpp:
+        (WebCore::PingLoader::loadImage):
+        (WebCore::PingLoader::sendPing):
+        (WebCore::PingLoader::sendViolationReport):
+        (WebCore::PingLoader::startPingLoad):
+        * loader/PingLoader.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::CachedResource):
+        (WebCore::CachedResource::load):
+        * loader/cache/CachedResource.h:
+        * loader/cache/CachedResourceRequest.cpp:
+        (WebCore::CachedResourceRequest::CachedResourceRequest):
+        * loader/cache/CachedResourceRequest.h:
+        (WebCore::CachedResourceRequest::releaseOriginalRequestHeaders):
+        * platform/network/HTTPHeaderValues.cpp:
+        * platform/network/HTTPHeaderValues.h:
+
 2017-08-16  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: capture async stack trace when workers/main context posts a message
index 1609a5f2ac202f3ec72811c9272c6acfd58b39a0..931f0582776d25ef0854cf9964b9d4ce9f21d70b 100644 (file)
@@ -62,16 +62,10 @@ FetchBody FetchBody::extract(ScriptExecutionContext& context, Init&& value, Stri
 
     if (WTF::holds_alternative<RefPtr<ArrayBuffer>>(value)) {
         Ref<const ArrayBuffer> buffer = WTF::get<RefPtr<ArrayBuffer>>(value).releaseNonNull();
-        // FIXME: We should not set a Content-Type here but we need to do this until all network stacks
-        // support sending no Content-Type header (<dar://problem/33906567).
-        contentType = HTTPHeaderValues::octetStreamContentType();
         return FetchBody(WTFMove(buffer));
     }
     if (WTF::holds_alternative<RefPtr<ArrayBufferView>>(value)) {
         Ref<const ArrayBufferView> buffer = WTF::get<RefPtr<ArrayBufferView>>(value).releaseNonNull();
-        // FIXME: We should not set a Content-Type here but we need to do this until all network stacks
-        // support sending no Content-Type header (<dar://problem/33906567).
-        contentType = HTTPHeaderValues::octetStreamContentType();
         return FetchBody(WTFMove(buffer));
     }
 
index 94f223043b4131bb557086b07e6c61f6b73e9e31..d6d2f1a92b5d84c8852f94f4b317b9ed92c0da5e 100644 (file)
@@ -37,7 +37,7 @@ class ResourceResponse;
 class SecurityOrigin;
 class URL;
 
-bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&);
+WEBCORE_EXPORT bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&);
 bool isOnAccessControlSimpleRequestMethodWhitelist(const String&);
 
 WEBCORE_EXPORT void updateRequestForAccessControl(ResourceRequest&, SecurityOrigin&, StoredCredentials);
index c4db7a1bf03a844afa3afacf2142da66e1e5fc5b..57014cb6f045790bafb52424cb43f375f5ef9d54 100644 (file)
@@ -36,6 +36,7 @@ namespace WebCore {
 class CachedResource;
 class ContentSecurityPolicy;
 class Frame;
+class HTTPHeaderMap;
 class NetscapePlugInStreamLoader;
 class NetscapePlugInStreamLoaderClient;
 class NetworkingContext;
@@ -63,7 +64,7 @@ public:
     virtual void suspendPendingRequests() = 0;
     virtual void resumePendingRequests() = 0;
 
-    virtual void createPingHandle(NetworkingContext*, ResourceRequest&, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy*, const FetchOptions&) = 0;
+    virtual void createPingHandle(NetworkingContext*, ResourceRequest&, HTTPHeaderMap&& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy*, const FetchOptions&) = 0;
 
     virtual void storeDerivedDataToCache(const SHA1::Digest& bodyKey, const String& type, const String& partition, WebCore::SharedBuffer&) = 0;
 
index 8e5169b50efb1af11e777703feafb1f965990428..ef64c8f37d2153c913a74b3a01977c782090db7c 100644 (file)
@@ -98,12 +98,15 @@ void PingLoader::loadImage(Frame& frame, const URL& url)
     document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load);
 
     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
+
+    HTTPHeaderMap originalRequestHeader = request.httpHeaderFields();
+
     String referrer = SecurityPolicy::generateReferrerHeader(document.referrerPolicy(), request.url(), frame.loader().outgoingReferrer());
     if (!referrer.isEmpty())
         request.setHTTPReferrer(referrer);
     frame.loader().addExtraFieldsToSubresourceRequest(request);
 
-    startPingLoad(frame, request, document, ShouldFollowRedirects::Yes);
+    startPingLoad(frame, request, WTFMove(originalRequestHeader), document, ShouldFollowRedirects::Yes);
 }
 
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
@@ -125,6 +128,9 @@ void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinati
     request.setHTTPContentType("text/ping");
     request.setHTTPBody(FormData::create("PING"));
     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
+
+    HTTPHeaderMap originalRequestHeader = request.httpHeaderFields();
+
     frame.loader().addExtraFieldsToSubresourceRequest(request);
 
     auto& sourceOrigin = document.securityOrigin();
@@ -139,7 +145,7 @@ void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinati
         }
     }
 
-    startPingLoad(frame, request, document, ShouldFollowRedirects::Yes);
+    startPingLoad(frame, request, WTFMove(originalRequestHeader), document, ShouldFollowRedirects::Yes);
 }
 
 void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, Ref<FormData>&& report, ViolationReportType reportType)
@@ -170,16 +176,18 @@ void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, Ref<For
     if (removeCookies)
         request.setAllowCookies(false);
 
+    HTTPHeaderMap originalRequestHeader = request.httpHeaderFields();
+
     frame.loader().addExtraFieldsToSubresourceRequest(request);
 
     String referrer = SecurityPolicy::generateReferrerHeader(document.referrerPolicy(), reportURL, frame.loader().outgoingReferrer());
     if (!referrer.isEmpty())
         request.setHTTPReferrer(referrer);
 
-    startPingLoad(frame, request, document, ShouldFollowRedirects::No);
+    startPingLoad(frame, request, WTFMove(originalRequestHeader), document, ShouldFollowRedirects::No);
 }
 
-void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, Document& document, ShouldFollowRedirects shouldFollowRedirects)
+void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, HTTPHeaderMap&& originalRequestHeaders, Document& document, ShouldFollowRedirects shouldFollowRedirects)
 {
     unsigned long identifier = frame.page()->progress().createUniqueIdentifier();
     // FIXME: Why activeDocumentLoader? I would have expected documentLoader().
@@ -195,7 +203,7 @@ void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, Document&
     InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame.loader().activeDocumentLoader(), request, ResourceResponse());
 
     auto* contentSecurityPolicy = document.shouldBypassMainWorldContentSecurityPolicy() ? nullptr : document.contentSecurityPolicy();
-    platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, document.securityOrigin(), contentSecurityPolicy, options);
+    platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, WTFMove(originalRequestHeaders), document.securityOrigin(), contentSecurityPolicy, options);
 }
 
 }
index c3a92a287fa53f561df9f3f65aa2726ca33f59cc..05c5497528a4979f974cdfeaa4f9c085ad2326ec 100644 (file)
@@ -40,6 +40,7 @@ namespace WebCore {
 class Document;
 class FormData;
 class Frame;
+class HTTPHeaderMap;
 class URL;
 class ResourceRequest;
 
@@ -56,7 +57,7 @@ public:
 
 private:
     enum class ShouldFollowRedirects { No, Yes };
-    static void startPingLoad(Frame&, ResourceRequest&, Document&, ShouldFollowRedirects);
+    static void startPingLoad(Frame&, ResourceRequest&, HTTPHeaderMap&& originalRequestHeaders, Document&, ShouldFollowRedirects);
 };
 
 } // namespace WebCore
index e5eec25feee4d7b096eed6dc580fb21376af9782..12847d6a99894903cfad0c4339080f029f973394 100644 (file)
@@ -117,6 +117,7 @@ DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Cac
 
 CachedResource::CachedResource(CachedResourceRequest&& request, Type type, SessionID sessionID)
     : m_resourceRequest(request.releaseResourceRequest())
+    , m_originalRequestHeaders(request.releaseOriginalRequestHeaders())
     , m_options(request.options())
     , m_decodedDataDeletionTimer(*this, &CachedResource::destroyDecodedData, deadDecodedDataDeletionIntervalForResourceType(type))
     , m_sessionID(sessionID)
@@ -272,7 +273,7 @@ void CachedResource::load(CachedResourceLoader& cachedResourceLoader)
             // Beacon is not exposed to workers so it is safe to rely on the document here.
             auto* document = cachedResourceLoader.document();
             auto* contentSecurityPolicy = document && !document->shouldBypassMainWorldContentSecurityPolicy() ? document->contentSecurityPolicy() : nullptr;
-            platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, *m_origin, contentSecurityPolicy, m_options);
+            platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, HTTPHeaderMap(m_originalRequestHeaders), *m_origin, contentSecurityPolicy, m_options);
             // FIXME: We currently do not get notified when ping loads finish so we treat them as finishing right away.
             finishLoading(nullptr);
             return;
index 6996bba27520894818469a01028c0eded0c0047f..a613341a304aa614ecfa0aebf13d104da89ae21d 100644 (file)
@@ -294,6 +294,7 @@ protected:
     // FIXME: Make the rest of these data members private and use functions in derived classes instead.
     HashCountedSet<CachedResourceClient*> m_clients;
     ResourceRequest m_resourceRequest;
+    HTTPHeaderMap m_originalRequestHeaders;
     RefPtr<SubresourceLoader> m_loader;
     ResourceLoaderOptions m_options;
     ResourceResponse m_response;
index 1362c334d0c173d5adef99620b0a9138bc666212..261863a547d3cb149acdc3b62ba0a295788bfcab 100644 (file)
@@ -41,6 +41,7 @@ namespace WebCore {
 
 CachedResourceRequest::CachedResourceRequest(ResourceRequest&& resourceRequest, const ResourceLoaderOptions& options, std::optional<ResourceLoadPriority> priority, String&& charset)
     : m_resourceRequest(WTFMove(resourceRequest))
+    , m_originalRequestHeaders(m_resourceRequest.httpHeaderFields())
     , m_charset(WTFMove(charset))
     , m_options(options)
     , m_priority(priority)
index f507fcc667ef5728683dcb2dab6c8fe1e8978dd5..30405d1879070bb7c3d3ed940d725f55a4449ece 100644 (file)
@@ -51,6 +51,7 @@ public:
     CachedResourceRequest(ResourceRequest&&, const ResourceLoaderOptions&, std::optional<ResourceLoadPriority> = std::nullopt, String&& charset = String());
 
     ResourceRequest&& releaseResourceRequest() { return WTFMove(m_resourceRequest); }
+    HTTPHeaderMap&& releaseOriginalRequestHeaders() { return WTFMove(m_originalRequestHeaders); }
     const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
     const String& charset() const { return m_charset; }
     void setCharset(const String& charset) { m_charset = charset; }
@@ -94,6 +95,7 @@ public:
 
 private:
     ResourceRequest m_resourceRequest;
+    HTTPHeaderMap m_originalRequestHeaders;
     String m_charset;
     ResourceLoaderOptions m_options;
     std::optional<ResourceLoadPriority> m_priority;
index 2c6e40ff3aef865394031cfe587e45d123d0323b..5595eb3a1818d8e4222ac5a5823fbe0a3b654154 100644 (file)
@@ -44,12 +44,6 @@ const String& formURLEncodedContentType()
     return contentType;
 }
 
-const String& octetStreamContentType()
-{
-    static NeverDestroyed<const String> contentType(MAKE_STATIC_STRING_IMPL("application/octet-stream"));
-    return contentType;
-}
-
 const String& noCache()
 {
     static NeverDestroyed<const String> value(MAKE_STATIC_STRING_IMPL("no-cache"));
index 52f2907cd8f34b5e4edb78f639c43773b82e822d..9d85f961ba4e8429f847460fa041a51078f4eea9 100644 (file)
@@ -32,7 +32,6 @@ namespace HTTPHeaderValues {
 
 const String& textPlainContentType();
 const String& formURLEncodedContentType();
-const String& octetStreamContentType();
 const String& noCache();
 const String& maxAge0();
 }
index 837dbf1e5691c9de989fa2f2000ef0012f3067cb..dcd1bc97c26473eee4aaa3f00596422553635a83 100644 (file)
@@ -1,3 +1,38 @@
+2017-08-16  Chris Dumez  <cdumez@apple.com>
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight
+        https://bugs.webkit.org/show_bug.cgi?id=175628
+        <rdar://problem/33919278>
+
+        Reviewed by Geoffrey Garen.
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight.
+        To achieve this, the following changes were made:
+        1. Revert r220779 which caused us to use a non CORS-safelisted Content-Type header for such payload
+        2. Teach PingLoad how to deal with "simple" cross origin requests (i.e. Don't assume we need a CORS
+           preflight merely because the fetch mode is set to "cors").
+
+        * NetworkProcess/NetworkCORSPreflightChecker.cpp:
+        (WebKit::NetworkCORSPreflightChecker::startPreflight):
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const):
+        (WebKit::NetworkResourceLoadParameters::decode):
+        * NetworkProcess/NetworkResourceLoadParameters.h:
+        * NetworkProcess/PingLoad.cpp:
+        (WebKit::PingLoad::PingLoad):
+        (WebKit::PingLoad::loadRequest):
+        (WebKit::PingLoad::originalRequestHeaders const):
+        (WebKit::PingLoad::willPerformHTTPRedirection):
+        (WebKit::PingLoad::isAllowedRedirect const):
+        (WebKit::PingLoad::makeCrossOriginAccessRequest):
+        (WebKit::PingLoad::makeSimpleCrossOriginAccessRequest):
+        (WebKit::PingLoad::makeCrossOriginAccessRequestWithPreflight):
+        (WebKit::PingLoad::preflightSuccess):
+        * NetworkProcess/PingLoad.h:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::createPingHandle):
+        * WebProcess/Network/WebLoaderStrategy.h:
+
 2017-08-16  Yoshiaki Jitsukawa  <Yoshiaki.Jitsukawa@sony.com>
 
         [PAL] Move spi/ios and spi/win directories into PAL
index c21012ec7f9e8cc08d2213d435c78f041054afca..f58ff6f73d8671565f3a3fc68520d7c1e39e1266 100644 (file)
@@ -33,7 +33,6 @@
 #include "NetworkLoadParameters.h"
 #include "SessionTracker.h"
 #include <WebCore/CrossOriginAccessControl.h>
-#include <WebCore/CrossOriginPreflightResultCache.h>
 #include <WebCore/SecurityOrigin.h>
 
 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_parameters.sessionID.isAlwaysOnLoggingAllowed(), Network, "%p - NetworkCORSPreflightChecker::" fmt, this, ##__VA_ARGS__)
@@ -60,11 +59,6 @@ NetworkCORSPreflightChecker::~NetworkCORSPreflightChecker()
 void NetworkCORSPreflightChecker::startPreflight()
 {
     RELEASE_LOG_IF_ALLOWED("startPreflight");
-    if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(m_parameters.sourceOrigin->toString(), m_parameters.originalRequest.url(), m_parameters.allowStoredCredentials, m_parameters.originalRequest.httpMethod(), m_parameters.originalRequest.httpHeaderFields())) {
-        RELEASE_LOG_IF_ALLOWED("startPreflight - preflight can be skipped thanks to cached result");
-        m_completionCallback(Result::Success);
-        return;
-    }
 
     NetworkLoadParameters loadParameters;
     loadParameters.sessionID = m_parameters.sessionID;
index 982f679aae7f6b363555f404fa859d8bdc715a8f..099ed2900e2a7b8159c7abdc5a1602f3ede1a321 100644 (file)
@@ -88,6 +88,7 @@ void NetworkResourceLoadParameters::encode(IPC::Encoder& encoder) const
         encoder << SecurityOriginData::fromSecurityOrigin(*sourceOrigin);
     encoder.encodeEnum(mode);
     encoder << cspResponseHeaders;
+    encoder << originalRequestHeaders;
 }
 
 bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourceLoadParameters& result)
@@ -166,6 +167,8 @@ bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourc
         return false;
     if (!decoder.decode(result.cspResponseHeaders))
         return false;
+    if (!decoder.decode(result.originalRequestHeaders))
+        return false;
 
     return true;
 }
index 1cfe7a8be3f8486cffa56f8d79d0cf7dbf7bbf69..cfe986e9899a170b4f0d7468dcd8e8e11bdf2a4d 100644 (file)
@@ -30,6 +30,7 @@
 #include "SandboxExtension.h"
 #include <WebCore/ContentSecurityPolicyResponseHeaders.h>
 #include <WebCore/FetchOptions.h>
+#include <WebCore/HTTPHeaderMap.h>
 #include <WebCore/ResourceHandle.h>
 #include <WebCore/ResourceLoaderOptions.h>
 #include <WebCore/ResourceRequest.h>
@@ -59,6 +60,7 @@ public:
     RefPtr<WebCore::SecurityOrigin> sourceOrigin;
     WebCore::FetchOptions::Mode mode;
     std::optional<WebCore::ContentSecurityPolicyResponseHeaders> cspResponseHeaders;
+    std::optional<WebCore::HTTPHeaderMap> originalRequestHeaders;
 };
 
 } // namespace WebKit
index 588568e89b331b8f867be2826f157416db1dc61a..0d9cb86dd792c6df0047cb4ed0ce198e3a381226 100644 (file)
@@ -34,6 +34,7 @@
 #include "SessionTracker.h"
 #include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/CrossOriginAccessControl.h>
+#include <WebCore/CrossOriginPreflightResultCache.h>
 
 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_parameters.sessionID.isAlwaysOnLoggingAllowed(), Network, "%p - PingLoad::" fmt, this, ##__VA_ARGS__)
 
@@ -46,14 +47,19 @@ PingLoad::PingLoad(NetworkResourceLoadParameters&& parameters)
     , m_timeoutTimer(*this, &PingLoad::timeoutTimerFired)
     , m_isSameOriginRequest(securityOrigin().canRequest(m_parameters.request.url()))
 {
+    ASSERT(m_parameters.sourceOrigin);
+    ASSERT(m_parameters.originalRequestHeaders);
+
     // If the server never responds, this object will hang around forever.
     // Set a very generous timeout, just in case.
     m_timeoutTimer.startOneShot(60000_s);
 
-    if (needsCORSPreflight(m_parameters.request))
-        doCORSPreflight(m_parameters.request);
-    else
-        loadRequest(m_parameters.request);
+    if (m_isSameOriginRequest || m_parameters.mode == FetchOptions::Mode::NoCors) {
+        loadRequest(ResourceRequest { m_parameters.request });
+        return;
+    }
+
+    makeCrossOriginAccessRequest(ResourceRequest { m_parameters.request });
 }
 
 PingLoad::~PingLoad()
@@ -68,12 +74,12 @@ PingLoad::~PingLoad()
     }
 }
 
-void PingLoad::loadRequest(const ResourceRequest& request)
+void PingLoad::loadRequest(ResourceRequest&& request)
 {
     RELEASE_LOG_IF_ALLOWED("startNetworkLoad");
     if (auto* networkSession = SessionTracker::networkSession(m_parameters.sessionID)) {
         auto loadParameters = m_parameters;
-        loadParameters.request = request;
+        loadParameters.request = WTFMove(request);
         m_task = NetworkDataTask::create(*networkSession, *this, WTFMove(loadParameters));
         m_task->resume();
     } else
@@ -85,6 +91,11 @@ SecurityOrigin& PingLoad::securityOrigin() const
     return m_origin ? *m_origin : *m_parameters.sourceOrigin;
 }
 
+const HTTPHeaderMap& PingLoad::originalRequestHeaders() const
+{
+    return *m_parameters.originalRequestHeaders;
+}
+
 void PingLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, ResourceRequest&& request, RedirectCompletionHandler&& completionHandler)
 {
     RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - shouldFollowRedirects? %d", m_parameters.shouldFollowRedirects);
@@ -103,12 +114,15 @@ void PingLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, R
 
     // FIXME: We should ensure the number of redirects does not exceed 20.
 
-    if (!needsCORSPreflight(request)) {
-        completionHandler(request);
+    if (isAllowedRedirect(request.url())) {
+        completionHandler(WTFMove(request));
         return;
     }
     RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect requires a CORS preflight");
 
+    // Force any subsequent request to use these checks.
+    m_isSameOriginRequest = false;
+
     // Use a unique origin for subsequent loads if needed.
     // https://fetch.spec.whatwg.org/#concept-http-redirect-fetch (Step 10).
     ASSERT(m_parameters.mode == FetchOptions::Mode::Cors);
@@ -117,13 +131,19 @@ void PingLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, R
             m_origin = SecurityOrigin::createUnique();
     }
 
-    m_isSameOriginRequest = false;
+    // Except in case where preflight is needed, loading should be able to continue on its own.
+    if (m_isSimpleRequest && isSimpleCrossOriginAccessRequest(request.httpMethod(), originalRequestHeaders())) {
+        completionHandler(WTFMove(request));
+        return;
+    }
+
+    m_parameters.allowStoredCredentials = DoNotAllowStoredCredentials;
     m_redirectHandler = WTFMove(completionHandler);
 
     // Let's fetch the request with the original headers (equivalent to request cloning specified by fetch algorithm).
     request.setHTTPHeaderFields(m_parameters.request.httpHeaderFields());
 
-    doCORSPreflight(request);
+    makeCrossOriginAccessRequest(WTFMove(request));
 }
 
 void PingLoad::didReceiveChallenge(const AuthenticationChallenge&, ChallengeCompletionHandler&& completionHandler)
@@ -177,12 +197,12 @@ void PingLoad::timeoutTimerFired()
     delete this;
 }
 
-bool PingLoad::needsCORSPreflight(const ResourceRequest& request) const
+bool PingLoad::isAllowedRedirect(const URL& url) const
 {
     if (m_parameters.mode == FetchOptions::Mode::NoCors)
-        return false;
+        return true;
 
-    return !m_isSameOriginRequest || !securityOrigin().canRequest(request.url());
+    return m_isSameOriginRequest && securityOrigin().canRequest(url);
 }
 
 ContentSecurityPolicy* PingLoad::contentSecurityPolicy() const
@@ -194,33 +214,73 @@ ContentSecurityPolicy* PingLoad::contentSecurityPolicy() const
     return m_contentSecurityPolicy.get();
 }
 
-void PingLoad::doCORSPreflight(const ResourceRequest& request)
+void PingLoad::makeCrossOriginAccessRequest(ResourceRequest&& request)
+{
+    ASSERT(m_parameters.mode == FetchOptions::Mode::Cors);
+    RELEASE_LOG_IF_ALLOWED("makeCrossOriginAccessRequest");
+
+    if (isSimpleCrossOriginAccessRequest(request.httpMethod(), originalRequestHeaders())) {
+        makeSimpleCrossOriginAccessRequest(WTFMove(request));
+        return;
+    }
+
+    m_isSimpleRequest = false;
+    if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(securityOrigin().toString(), request.url(), m_parameters.allowStoredCredentials, request.httpMethod(), originalRequestHeaders())) {
+        RELEASE_LOG_IF_ALLOWED("makeCrossOriginAccessRequest - preflight can be skipped thanks to cached result");
+        preflightSuccess(WTFMove(request));
+    } else
+        makeCrossOriginAccessRequestWithPreflight(WTFMove(request));
+}
+
+void PingLoad::makeSimpleCrossOriginAccessRequest(ResourceRequest&& request)
+{
+    ASSERT(isSimpleCrossOriginAccessRequest(request.httpMethod(), originalRequestHeaders()));
+    RELEASE_LOG_IF_ALLOWED("makeSimpleCrossOriginAccessRequest");
+
+    if (!request.url().protocolIsInHTTPFamily()) {
+        RELEASE_LOG_IF_ALLOWED("makeSimpleCrossOriginAccessRequest: Cross origin requests are only supported for HTTP.");
+        return;
+    }
+
+    updateRequestForAccessControl(request, securityOrigin(), m_parameters.allowStoredCredentials);
+    loadRequest(WTFMove(request));
+}
+
+void PingLoad::makeCrossOriginAccessRequestWithPreflight(ResourceRequest&& request)
 {
-    RELEASE_LOG_IF_ALLOWED("doCORSPreflight");
+    RELEASE_LOG_IF_ALLOWED("makeCrossOriginAccessRequestWithPreflight");
     ASSERT(!m_corsPreflightChecker);
 
     NetworkCORSPreflightChecker::Parameters parameters = {
-        request,
+        WTFMove(request),
         securityOrigin(),
         m_parameters.sessionID,
         m_parameters.allowStoredCredentials
     };
     m_corsPreflightChecker = std::make_unique<NetworkCORSPreflightChecker>(WTFMove(parameters), [this](NetworkCORSPreflightChecker::Result result) {
-        RELEASE_LOG_IF_ALLOWED("doCORSPreflight complete, success: %d forRedirect? %d", result == NetworkCORSPreflightChecker::Result::Success, !!m_redirectHandler);
+        RELEASE_LOG_IF_ALLOWED("makeCrossOriginAccessRequestWithPreflight preflight complete, success: %d forRedirect? %d", result == NetworkCORSPreflightChecker::Result::Success, !!m_redirectHandler);
         auto corsPreflightChecker = WTFMove(m_corsPreflightChecker);
-        if (result == NetworkCORSPreflightChecker::Result::Success) {
-            ResourceRequest actualRequest = corsPreflightChecker->originalRequest();
-            updateRequestForAccessControl(actualRequest, securityOrigin(), m_parameters.allowStoredCredentials);
-            if (auto redirectHandler = std::exchange(m_redirectHandler, nullptr))
-                redirectHandler(actualRequest);
-            else
-                loadRequest(actualRequest);
-        } else
+        if (result == NetworkCORSPreflightChecker::Result::Success)
+            preflightSuccess(ResourceRequest { corsPreflightChecker->originalRequest() });
+        else
             delete this;
     });
     m_corsPreflightChecker->startPreflight();
 }
 
+void PingLoad::preflightSuccess(ResourceRequest&& request)
+{
+    RELEASE_LOG_IF_ALLOWED("preflightSuccess");
+
+    ResourceRequest actualRequest = WTFMove(request);
+    updateRequestForAccessControl(actualRequest, securityOrigin(), m_parameters.allowStoredCredentials);
+
+    if (auto redirectHandler = std::exchange(m_redirectHandler, nullptr))
+        redirectHandler(WTFMove(actualRequest));
+    else
+        loadRequest(WTFMove(actualRequest));
+}
+
 } // namespace WebKit
 
 #endif // USE(NETWORK_SESSION)
index 3600a4b449737832fe6dfc163db48cc3c21c2069..ad35464e5133f188089402be1ee978313a87c7ae 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace WebCore {
 class ContentSecurityPolicy;
+class URL;
 }
 
 namespace WebKit {
@@ -57,11 +58,15 @@ private:
     void cannotShowURL() final;
     void timeoutTimerFired();
 
-    void loadRequest(const WebCore::ResourceRequest&);
-    bool needsCORSPreflight(const WebCore::ResourceRequest&) const;
-    void doCORSPreflight(const WebCore::ResourceRequest&);
+    void loadRequest(WebCore::ResourceRequest&&);
+    bool isAllowedRedirect(const WebCore::URL&) const;
+    void makeCrossOriginAccessRequest(WebCore::ResourceRequest&&);
+    void makeSimpleCrossOriginAccessRequest(WebCore::ResourceRequest&&);
+    void makeCrossOriginAccessRequestWithPreflight(WebCore::ResourceRequest&&);
+    void preflightSuccess(WebCore::ResourceRequest&&);
 
     WebCore::SecurityOrigin& securityOrigin() const;
+    const WebCore::HTTPHeaderMap& originalRequestHeaders() const; // Needed for CORS checks.
     
     NetworkResourceLoadParameters m_parameters;
     RefPtr<NetworkDataTask> m_task;
@@ -69,6 +74,7 @@ private:
     std::unique_ptr<NetworkCORSPreflightChecker> m_corsPreflightChecker;
     RefPtr<WebCore::SecurityOrigin> m_origin;
     bool m_isSameOriginRequest;
+    bool m_isSimpleRequest { true };
     RedirectCompletionHandler m_redirectHandler;
     mutable std::unique_ptr<WebCore::ContentSecurityPolicy> m_contentSecurityPolicy;
 };
index 9d9775b048f61a909358077796e37b561c7cdbfc..298a3bf25c7ab1bf92d595ca4c326858ce75ad4a 100644 (file)
@@ -386,7 +386,7 @@ void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, un
     }
 }
 
-void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy* contentSecurityPolicy, const FetchOptions& options)
+void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, HTTPHeaderMap&& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy* contentSecurityPolicy, const FetchOptions& options)
 {
     // It's possible that call to createPingHandle might be made during initial empty Document creation before a NetworkingContext exists.
     // It is not clear that we should send ping loads during that process anyways.
@@ -400,6 +400,7 @@ void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, R
     
     NetworkResourceLoadParameters loadParameters;
     loadParameters.request = request;
+    loadParameters.originalRequestHeaders = WTFMove(originalRequestHeaders);
     loadParameters.sourceOrigin = WTFMove(sourceOrigin);
     loadParameters.sessionID = webPage ? webPage->sessionID() : SessionID::defaultSessionID();
     loadParameters.allowStoredCredentials = options.credentials == FetchOptions::Credentials::Omit ? DoNotAllowStoredCredentials : AllowStoredCredentials;
@@ -409,7 +410,7 @@ void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, R
     if (contentSecurityPolicy)
         loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
 
-    WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::LoadPing(loadParameters), 0);
+    WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::LoadPing(WTFMove(loadParameters)), 0);
 }
 
 void WebLoaderStrategy::storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer& data)
index 4d3511467cc1468d268a210d6013cd3ac3bff9f0..49421fd042f4711f83c4762b2ee38e5a4696b1d8 100644 (file)
@@ -59,7 +59,7 @@ public:
     void suspendPendingRequests() final;
     void resumePendingRequests() final;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) final;
+    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, WebCore::HTTPHeaderMap&& originalRequestHeaders, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) final;
 
     void storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer&) final;
 
index 0b69b4418032b606fad51e581655c01c6676e3bd..36a9f554cb8fc9ac23f6b3e51e524185c2f39096 100644 (file)
@@ -1,3 +1,15 @@
+2017-08-16  Chris Dumez  <cdumez@apple.com>
+
+        Cross origin Beacon requests with a ArrayBuffer / ArrayBufferView payload should not do a CORS preflight
+        https://bugs.webkit.org/show_bug.cgi?id=175628
+        <rdar://problem/33919278>
+
+        Reviewed by Geoffrey Garen.
+
+        * WebCoreSupport/WebResourceLoadScheduler.cpp:
+        (WebResourceLoadScheduler::createPingHandle):
+        * WebCoreSupport/WebResourceLoadScheduler.h:
+
 2017-08-16  Yoshiaki Jitsukawa  <Yoshiaki.Jitsukawa@sony.com>
 
         [PAL] Move spi/ios and spi/win directories into PAL
index 71d01e127869d5a1f41829f2697af6084f1b70ec..bbe79e93eefb787ef9195b55d0976a34e1fd04e8 100644 (file)
@@ -363,7 +363,7 @@ bool WebResourceLoadScheduler::HostInformation::limitRequests(ResourceLoadPriori
     return m_requestsLoading.size() >= (webResourceLoadScheduler().isSerialLoadingEnabled() ? 1 : m_maxRequestsInFlight);
 }
 
-void WebResourceLoadScheduler::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&&, WebCore::ContentSecurityPolicy*, const FetchOptions& options)
+void WebResourceLoadScheduler::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, HTTPHeaderMap&&, Ref<SecurityOrigin>&&, WebCore::ContentSecurityPolicy*, const FetchOptions& options)
 {
     // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
     new PingHandle(networkingContext, request, options.credentials != FetchOptions::Credentials::Omit, PingHandle::UsesAsyncCallbacks::No, options.redirect == FetchOptions::Redirect::Follow);
index 34cb6767a91244e5f558a58a27bcbcb4a9513b4a..0bb291b9c6ac921371ef95a08633945fa0187ca9 100644 (file)
@@ -59,7 +59,7 @@ public:
     void suspendPendingRequests() override;
     void resumePendingRequests() override;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) override;
+    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, WebCore::HTTPHeaderMap&&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) override;
 
     void storeDerivedDataToCache(const SHA1::Digest&, const String&, const String&, WebCore::SharedBuffer&) override { }