diff --git a/third_party/WebKit/LayoutTests/http/tests/security/resources/cors-script.php b/third_party/WebKit/LayoutTests/http/tests/security/resources/cors-script.php index 80293ebbd8ec1..29721a66b08c4 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/resources/cors-script.php +++ b/third_party/WebKit/LayoutTests/http/tests/security/resources/cors-script.php @@ -10,6 +10,10 @@ if (strtolower($_GET["credentials"]) == "true") { header("Access-Control-Allow-Credentials: true"); } +$custom_header_arg = strtolower($_GET["custom"]); +if (!(empty($custom_header_arg))) { + header("Access-Control-Allow-Headers: " . $custom_header_arg); +} if ($_SERVER["HTTP_SUBORIGIN"] == "foobar") { header("Access-Control-Allow-Suborigin: foobar"); diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt index 89d54c99a52ea..0872ab0ab7503 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt @@ -1,4 +1,6 @@ CONSOLE MESSAGE: line 9: If a Suborigin makes a request, a response without an Access-Control-Allow-Suborigin header should fail and should output a reasonable error message. CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://foobar_127.0.0.1:8000' is therefore not allowed access. ALERT: PASS: XHR correctly failed +CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://foobar_127.0.0.1:8000' is therefore not allowed access. +ALERT: PASS: XHR correctly failed diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php index f0b594b455e8c..8535c8af4b116 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php +++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php @@ -13,21 +13,43 @@ function success() { alert("PASS: XHR correctly failed"); - if (window.testRunner) - testRunner.notifyDone(); + next(); } function failure() { alert("FAIL: XHR incorrectly succeeded"); - if (window.testRunner) + next(); +} + +// First one should fail with preflight failure. Second one should +// fail with access control header failure. +var tests = [ + function() { + var xhr = new XMLHttpRequest(); + xhr.onerror = success; + xhr.onload = failure; + xhr.open("GET", "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false"); + xhr.setRequestHeader("x-custom-header", "foobar"); + xhr.send(); + }, + function() { + var xhr = new XMLHttpRequest(); + xhr.onerror = success; + xhr.onload = failure; + xhr.open("GET", "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false"); + xhr.send(); + } +]; + +function next() { + if (tests.length !== 0) { + tests.shift()(); + } else if (window.testRunner) { testRunner.notifyDone(); + } } -var xhr = new XMLHttpRequest(); -xhr.onerror = success; -xhr.onload = failure; -xhr.open("GET", "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false"); -xhr.send(); +next(); diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php index ee75787847a4c..31ddf78d45511 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php +++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php @@ -42,6 +42,10 @@ } xhr.open("GET", this.src); + // Set a custom header to force a preflight. Even though the + // scheme/host/port of the source and destination origins are the same, the + // Suborigin should cause the request to be treated as cross-origin. + xhr.setRequestHeader("x-custom-header", "foobar"); xhr.send(); }; @@ -49,28 +53,52 @@ // XHR preflight tests new SuboriginXHRTest( - true, - "Basic anonymous XHR preflight", + false, + "Complex anonymous XHR preflight, no AC for custom header", xorigin_preflight_script + "?cors=http://foobar_127.0.0.1:8000", "anonymous").execute(); new SuboriginXHRTest( true, - "Basic anonymous XHR preflight with '*' ACAO", + "Complex anonymous XHR preflight, has AC for custom header", + xorigin_preflight_script + "?cors=http://foobar_127.0.0.1:8000&custom=x-custom-header", + "anonymous").execute(); + +new SuboriginXHRTest( + false, + "Complex anonymous XHR preflight with '*' ACAO, no AC for custom header", xorigin_preflight_script + "?cors=*", "anonymous").execute(); new SuboriginXHRTest( true, - "Basic XHR with credentials preflight", + "Complex anonymous XHR preflight with '*' ACAO, has AC for custom header", + xorigin_preflight_script + "?cors=*&custom=x-custom-header", + "anonymous").execute(); + +new SuboriginXHRTest( + false, + "Complex XHR with credentials preflight, no AC for custom header", xorigin_preflight_script + "?cors=http://foobar_127.0.0.1:8000&credentials=true", "use-credentials").execute(); +new SuboriginXHRTest( + true, + "Complex XHR with credentials preflight, has AC for custom header", + xorigin_preflight_script + "?cors=http://foobar_127.0.0.1:8000&credentials=true&custom=x-custom-header", + "use-credentials").execute(); + new SuboriginXHRTest( false, - "Basic XHR with credentials preflight with '*' ACAO", + "Complex XHR with credentials preflight with '*' ACAO, no AC for custom header", xorigin_preflight_script + "?cors=*&credentials=true", "use-credentials").execute(); + +new SuboriginXHRTest( + false, + "Complex XHR with credentials preflight with '*' ACAO, has AC for custom header", + xorigin_preflight_script + "?cors=*&credentials=true&custom=x-custom-header", + "use-credentials").execute(); diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index 43a9adb7ecf07..0da900e6d01bd 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp @@ -894,7 +894,7 @@ void XMLHttpRequest::createRequest(PassRefPtr httpBody, Excepti request.addHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; - options.preflightPolicy = (uploadEvents || securityOrigin()->hasSuborigin()) ? ForcePreflight : ConsiderPreflight; + options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.crossOriginRequestPolicy = UseAccessControl; options.initiator = FetchInitiatorTypeNames::xmlhttprequest; options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h index 7a286dad26da9..8d8828c066abb 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h @@ -98,6 +98,11 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted { // familiar with Suborigins, you probably want canAccess() for now. // Suborigins is a spec in progress, and where it should be enforced is // still in flux. See https://crbug.com/336894 for more details. + // + // TODO(jww): Once the Suborigin spec has become more settled, and we are + // confident in the correctness of our implementation, canAccess should be + // made to check the suborigin and this should be turned into + // canAccessBypassSuborigin check, which should be the exceptional case. bool canAccessCheckSuborigins(const SecurityOrigin*) const; // Returns true if this SecurityOrigin can read content retrieved from @@ -111,6 +116,11 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted { // Suborigins, you probably want canRequest() for now. Suborigins is a spec // in progress, and where it should be enforced is still in flux. See // https://crbug.com/336894 for more details. + // + // TODO(jww): Once the Suborigin spec has become more settled, and we are + // confident in the correctness of our implementation, canRequest should be + // made to check the suborigin and this should be turned into + // canRequestBypassSuborigin check, which should be the exceptional case. bool canRequestNoSuborigin(const KURL&) const; // Returns true if drawing an image from this URL taints a canvas from