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 6c45c1a..48a5b71 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 f07787f..f37bc1a 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 
+
@@ -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 8555a1c..2baa2b8 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 5ae1853..04fc662 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 41334fa..a74ec32 100644 (file)
@@ -1,5 +1,19 @@
 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
         https://bugs.webkit.org/show_bug.cgi?id=175178
 
index f558d78..0ef518b 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 5b3e2dd..425b867 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 51d9971..447fe1e 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 28a3a10..53c226b 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 1609a5f..931f058 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 94f2230..d6d2f1a 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 c4db7a1..57014cb 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 8e5169b..ef64c8f 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 c3a92a2..05c5497 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 e5eec25..12847d6 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 6996bba..a613341 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 1362c33..261863a 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 f507fcc..30405d1 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 2c6e40f..5595eb3 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 52f2907..9d85f96 100644 (file)
@@ -32,7 +32,6 @@ namespace HTTPHeaderValues {
 
 const String& textPlainContentType();
 const String& formURLEncodedContentType();
-const String& octetStreamContentType();
 const String& noCache();
 const String& maxAge0();
 }
index 837dbf1..dcd1bc9 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 c21012e..f58ff6f 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 982f679..099ed29 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 1cfe7a8..cfe986e 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 588568e..0d9cb86 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 3600a4b..ad35464 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 9d9775b..298a3bf 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 4d35114..49421fd 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 0b69b44..36a9f55 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 71d01e1..bbe79e9 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 34cb676..0bb291b 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 { }