Changeset 203899 in webkit


Ignore:
Timestamp:
Jul 29, 2016 4:08:04 AM (8 years ago)
Author:
commit-queue@webkit.org
Message:

CrossOrigin preflight checker should compute the right Access-Control-Request-Headers value
https://bugs.webkit.org/show_bug.cgi?id=160028

Patch by Youenn Fablet <youenn@apple.com> on 2016-07-29
Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

  • web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt:
  • web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt:
  • web-platform-tests/fetch/api/cors/cors-no-preflight.js:

(corsNoPreflight): fixing bugs in that test and adding new test to cover mime type checking that should ignore case.

  • web-platform-tests/fetch/api/cors/cors-preflight-worker.html:
  • web-platform-tests/fetch/api/cors/cors-preflight.html:
  • web-platform-tests/fetch/api/cors/cors-preflight.js:

(corsPreflight): Adding safe headers to the request and checking more precisely sent Access-Control-Request-Headers header value.

Source/WebCore:

Covered by updated test.

Computing Access-Control-Request-Headers value according https://fetch.spec.whatwg.org/#cors-preflight-fetch:

  • Remove safe headers
  • lowercase header names
  • sort lexicographically header names

The only difference is that we keep separating headers with ', ' instead of ',' as per the spec.
Also, some headers that might be safe are still marked as unsafe (DPR, Downlink...).

Moved setting of Origin header after preflighting, consistently with fetch spec.

  • loader/CrossOriginAccessControl.cpp:

(WebCore::createAccessControlPreflightRequest): Implementing new computation of Access-Control-Request-Headers.

  • loader/DocumentThreadableLoader.cpp:

(WebCore::DocumentThreadableLoader::makeCrossOriginAccessRequest): Removing call to updateRequestForAccessControl (which sets Origin header value).
(WebCore::DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest): Adding call to updateRequestForAccessControl.
(WebCore::DocumentThreadableLoader::preflightSuccess): Ditto.

  • platform/network/HTTPParsers.cpp:

(WebCore::isCrossOriginSafeRequestHeader): Helper routine to implement https://fetch.spec.whatwg.org/#cors-safelisted-request-header.

  • platform/network/HTTPParsers.h:

LayoutTests:

Rebasing regular tests. Also updating skipped worker tests.

  • platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt: Added.
  • platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt: Added.
  • platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-redirect-worker-expected.txt: Added.
  • platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt: Added.
  • platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt: Added.
  • platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-redirect-worker-expected.txt: Added.
  • platform/mac/TestExpectations:
Location:
trunk
Files:
1 deleted
18 edited
4 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r203858 r203899  
     12016-07-29  Youenn Fablet  <youenn@apple.com>
     2
     3        CrossOrigin preflight checker should compute the right Access-Control-Request-Headers value
     4        https://bugs.webkit.org/show_bug.cgi?id=160028
     5
     6        Reviewed by Alex Christensen.
     7
     8        Rebasing regular tests. Also updating skipped worker tests.
     9
     10        * platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt: Added.
     11        * platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt: Added.
     12        * platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-redirect-worker-expected.txt: Added.
     13        * platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt: Added.
     14        * platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt: Added.
     15        * platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-redirect-worker-expected.txt: Added.
     16        * platform/mac/TestExpectations:
     17
    1182016-07-28  Youenn Fablet  <youennf@gmail.com>
    219
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r203852 r203899  
     12016-07-29  Youenn Fablet  <youenn@apple.com>
     2
     3        CrossOrigin preflight checker should compute the right Access-Control-Request-Headers value
     4        https://bugs.webkit.org/show_bug.cgi?id=160028
     5
     6        Reviewed by Alex Christensen.
     7
     8        * web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt:
     9        * web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt:
     10        * web-platform-tests/fetch/api/cors/cors-no-preflight.js:
     11        (corsNoPreflight): fixing bugs in that test and adding new test to cover mime type checking that should ignore case.
     12        * web-platform-tests/fetch/api/cors/cors-preflight-worker.html:
     13        * web-platform-tests/fetch/api/cors/cors-preflight.html:
     14        * web-platform-tests/fetch/api/cors/cors-preflight.js:
     15        (corsPreflight): Adding safe headers to the request and checking more precisely sent Access-Control-Request-Headers header value.
     16
    1172016-07-28  Chris Dumez  <cdumez@apple.com>
    218
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-basic-worker-expected.txt

    r203732 r203899  
    11
    2 FAIL Same domain different port [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     2PASS Same domain different port [no-cors mode]
    33PASS Same domain different port [server forbid CORS]
    4 FAIL Same domain different port [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
    5 FAIL Same domain different protocol different port [no-cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     4PASS Same domain different port [cors mode]
     5PASS Same domain different protocol different port [no-cors mode]
    66PASS Same domain different protocol different port [server forbid CORS]
    7 FAIL Same domain different protocol different port [cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    8 FAIL Cross domain basic usage [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     7PASS Same domain different protocol different port [cors mode]
     8PASS Cross domain basic usage [no-cors mode]
    99PASS Cross domain basic usage [server forbid CORS]
    10 FAIL Cross domain basic usage [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
    11 FAIL Cross domain different port [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     10PASS Cross domain basic usage [cors mode]
     11PASS Cross domain different port [no-cors mode]
    1212PASS Cross domain different port [server forbid CORS]
    13 FAIL Cross domain different port [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
    14 FAIL Cross domain different protocol [no-cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     13PASS Cross domain different port [cors mode]
     14PASS Cross domain different protocol [no-cors mode]
    1515PASS Cross domain different protocol [server forbid CORS]
    16 FAIL Cross domain different protocol [cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     16PASS Cross domain different protocol [cors mode]
    1717
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-filtering-worker-expected.txt

    r203732 r203899  
    11
    2 FAIL CORS filter on Cache-Control header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    3 FAIL CORS filter on Content-Language header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    4 FAIL CORS filter on Content-Type header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    5 FAIL CORS filter on Expires header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    6 FAIL CORS filter on Last-Modified header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    7 FAIL CORS filter on Pragma header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    8 FAIL CORS filter on Age header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    9 FAIL CORS filter on Server header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    10 FAIL CORS filter on Warning header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    11 FAIL CORS filter on Content-Length header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    12 FAIL CORS filter on Set-Cookie header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    13 FAIL CORS filter on Set-Cookie2 header assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    14 FAIL CORS filter on Age header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    15 FAIL CORS filter on Server header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    16 FAIL CORS filter on Warning header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    17 FAIL CORS filter on Content-Length header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    18 FAIL CORS filter on Set-Cookie header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
    19 FAIL CORS filter on Set-Cookie2 header, header is exposed assert_equals: CORS fetch's response has cors type expected "cors" but got "basic"
     2PASS CORS filter on Cache-Control header
     3PASS CORS filter on Content-Language header
     4PASS CORS filter on Content-Type header
     5PASS CORS filter on Expires header
     6PASS CORS filter on Last-Modified header
     7PASS CORS filter on Pragma header
     8PASS CORS filter on Age header
     9PASS CORS filter on Server header
     10PASS CORS filter on Warning header
     11PASS CORS filter on Content-Length header
     12PASS CORS filter on Set-Cookie header
     13PASS CORS filter on Set-Cookie2 header
     14PASS CORS filter on Age header, header is exposed
     15PASS CORS filter on Server header, header is exposed
     16PASS CORS filter on Warning header, header is exposed
     17PASS CORS filter on Content-Length header, header is exposed
     18PASS CORS filter on Set-Cookie header, header is exposed
     19PASS CORS filter on Set-Cookie2 header, header is exposed
    2020
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt

    r200195 r203899  
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt

    r200195 r203899  
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight.js

    r203408 r203899  
    1616
    1717  promise_test(function(test) {
    18     fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) {
     18    return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) {
    1919      assert_equals(resp.status, 200, "Clean stash response's status is 200");
    2020      return fetch(url + urlParameters, requestInit).then(function(resp) {
     
    2929
    3030corsNoPreflight("Cross domain basic usage [GET]", host_info.HTTP_REMOTE_ORIGIN, "GET");
    31 corsNoPreflight("Same domain different port [GET]", host_info.HTTP_ORIGIN_WITH_DIFFERENT_ORIGIN, "GET");
    32 corsNoPreflight("Cross domain different port [GET]", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_ORIGIN, "GET");
     31corsNoPreflight("Same domain different port [GET]", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT, "GET");
     32corsNoPreflight("Cross domain different port [GET]", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, "GET");
    3333corsNoPreflight("Cross domain different protocol [GET]", host_info.HTTPS_REMOTE_ORIGIN, "GET");
    3434corsNoPreflight("Same domain different protocol different port [GET]", host_info.HTTPS_ORIGIN, "GET");
     
    4242corsNoPreflight("Cross domain [GET] [Content-Type: text/plain]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "text/plain");
    4343corsNoPreflight("Cross domain [GET] [Content-Type: text/plain;charset=utf-8]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "text/plain;charset=utf-8");
     44corsNoPreflight("Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "Text/Plain;charset=utf-8");
    4445
    4546done();
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-worker-expected.txt

    r203732 r203899  
    88PASS CORS [NEW], server allows
    99PASS CORS [NEW], server refuses
    10 PASS CORS [GET] [x-test-header: allowed], server allows
     10FAIL CORS [GET] [x-test-header: allowed], server allows assert_equals: Access-Control-Allow-Headers value expected "x-test-header1" but got "referer,x-test-header1"
    1111PASS CORS [GET] [x-test-header: refused], server refuses
    12 PASS CORS [GET] [several headers], server allows
     12FAIL CORS [GET] [several headers], server allows assert_equals: Access-Control-Allow-Headers value expected "content-type,x-test-header-a,x-test-header-b,x-test-header-c,x-test-header-d,x-test-header1,x-test-header2,x-test-header3" but got "content-type,referer,x-test-header-a,x-test-header-b,x-test-header-c,x-test-header-d,x-test-header1,x-test-header2,x-test-header3"
    1313PASS CORS [GET] [several headers], server refuses
    14 PASS CORS [PUT] [several headers], server allows
     14FAIL CORS [PUT] [several headers], server allows assert_equals: Access-Control-Allow-Headers value expected "content-type,x-test-header-a,x-test-header-b,x-test-header-c,x-test-header-d,x-test-header1,x-test-header2,x-test-header3" but got "content-type,referer,x-test-header-a,x-test-header-b,x-test-header-c,x-test-header-d,x-test-header1,x-test-header2,x-test-header3"
    1515PASS CORS [PUT] [several headers], server refuses
    1616
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-worker.html

    r200195 r203899  
    1515  <body>
    1616    <script>
    17       fetch_tests_from_worker(new Worker("cors-preflight.js?pipe=sub"));
     17      fetch_tests_from_worker(new Worker("cors-preflight.js"));
    1818    </script>
    1919  </body>
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight.html

    r200195 r203899  
    1515  <body>
    1616    <script src="../resources/utils.js"></script>
     17    <script src="../resources/get-host-info.sub.js"></script>
    1718    <script src="/common/utils.js"></script>
    18     <script src="cors-preflight.js?pipe=sub"></script>
     19    <script src="cors-preflight.js"></script>
    1920  </body>
    2021</html>
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight.js

    r203164 r203899  
    11if (this.document === undefined) {
    22  importScripts("/resources/testharness.js");
     3  importScripts("/common/utils.js");
    34  importScripts("../resources/utils.js");
    4   importScripts("/common/utils.js");
     5  importScripts("../resources/get-host-info.sub.js");
     6}
     7
     8function headerNames(headers)
     9{
     10    let names = [];
     11    for (let header of headers)
     12        names.push(header[0].toLowerCase());
     13    return names
    514}
    615
     
    1019  Check control access headers added by UA (for method and headers)
    1120*/
    12 function corsPreflight(desc, corsUrl, method, allowed, headers) {
     21function corsPreflight(desc, corsUrl, method, allowed, headers, safeHeaders) {
    1322  return promise_test(function(test) {
    1423    var uuid_token = token();
     
    1726      var urlParameters = "?token=" + uuid_token + "&max_age=0";
    1827      var requestInit = {"mode": "cors", "method": method};
     28      var requestHeaders = [];
    1929      if (headers)
    20         requestInit["headers"] = headers;
     30        requestHeaders.push.apply(requestHeaders, headers);
     31      if (safeHeaders)
     32        requestHeaders.push.apply(requestHeaders, safeHeaders);
     33      requestInit["headers"] = requestHeaders;
    2134
    2235      if (allowed) {
     
    2740          urlParameters += "&control_request_headers"
    2841          //Make the server allow the headers
    29           urlParameters += "&allow_headers="
    30           urlParameters += headers.map(function (x) { return x[0]; }).join("%2C%20");
     42          urlParameters += "&allow_headers=" + headerNames(headers).join("%20%2C");
    3143        }
    3244        return fetch(url + urlParameters, requestInit).then(function(resp) {
     
    3446          assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made");
    3547          if (headers) {
    36             var actualHeaders = resp.headers.get("x-control-request-headers").split(",");
     48            var actualHeaders = resp.headers.get("x-control-request-headers").toLowerCase().split(",");
    3749            for (var i in actualHeaders)
    3850              actualHeaders[i] = actualHeaders[i].trim();
    3951            for (var header of headers)
    40               assert_in_array(header[0], actualHeaders, "Preflight asked permission for header: " + header);
     52              assert_in_array(header[0].toLowerCase(), actualHeaders, "Preflight asked permission for header: " + header);
     53
     54            let accessControlAllowHeaders = headerNames(headers).sort().join(",");
     55            assert_equals(resp.headers.get("x-control-request-headers").replace(new RegExp(" ", "g"), ""), accessControlAllowHeaders, "Access-Control-Allow-Headers value");
     56            return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
    4157          }
    42           return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
    4358        });
    4459      } else {
     
    5166}
    5267
    53 var corsUrl = "http://{{host}}:{{ports[http][1]}}" + dirname(location.pathname) + RESOURCES_DIR + "preflight.py";
     68var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py";
    5469
    5570corsPreflight("CORS [DELETE], server allows", corsUrl, "DELETE", true);
     
    6580corsPreflight("CORS [GET] [x-test-header: refused], server refuses", corsUrl, "GET", false, [["x-test-header1", "refused"]]);
    6681
    67 var headers = [["x-test-header1", "allowedOrRefused"],
    68                ["x-test-header2", "allowedOrRefused"],
    69                ["x-test-header3", "allowedOrRefused"]];
    70 corsPreflight("CORS [GET] [several headers], server allows", corsUrl, "GET", true, headers);
    71 corsPreflight("CORS [GET] [several headers], server refuses", corsUrl, "GET", false, headers);
    72 corsPreflight("CORS [PUT] [several headers], server allows", corsUrl, "PUT", true, headers);
    73 corsPreflight("CORS [PUT] [several headers], server refuses", corsUrl, "PUT", false, headers);
     82var headers = [
     83    ["x-test-header1", "allowedOrRefused"],
     84    ["x-test-header2", "allowedOrRefused"],
     85    ["X-test-header3", "allowedOrRefused"],
     86    ["x-test-header-b", "allowedOrRefused"],
     87    ["x-test-header-D", "allowedOrRefused"],
     88    ["x-test-header-C", "allowedOrRefused"],
     89    ["x-test-header-a", "allowedOrRefused"],
     90    ["Content-Type", "allowedOrRefused"],
     91];
     92var safeHeaders= [
     93    ["Accept", "*"],
     94    ["Accept-Language", "bzh"],
     95    ["Content-Language", "eu"],
     96];
     97
     98corsPreflight("CORS [GET] [several headers], server allows", corsUrl, "GET", true, headers, safeHeaders);
     99corsPreflight("CORS [GET] [several headers], server refuses", corsUrl, "GET", false, headers, safeHeaders);
     100corsPreflight("CORS [PUT] [several headers], server allows", corsUrl, "PUT", true, headers, safeHeaders);
     101corsPreflight("CORS [PUT] [several headers], server refuses", corsUrl, "PUT", false, headers, safeHeaders);
    74102
    75103done();
  • trunk/LayoutTests/platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt

    r203898 r203899  
    33PASS Same domain different port [GET]
    44PASS Cross domain different port [GET]
    5 PASS Cross domain different protocol [GET]
    6 PASS Same domain different protocol different port [GET]
     5FAIL Cross domain different protocol [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     6FAIL Same domain different protocol different port [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    77PASS Cross domain [POST]
    88PASS Cross domain [HEAD]
     
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/platform/ios-simulator-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt

    r203898 r203899  
    33PASS Same domain different port [GET]
    44PASS Cross domain different port [GET]
    5 PASS Cross domain different protocol [GET]
    6 PASS Same domain different protocol different port [GET]
     5FAIL Cross domain different protocol [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     6FAIL Same domain different protocol different port [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    77PASS Cross domain [POST]
    88PASS Cross domain [HEAD]
     
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-basic-worker-expected.txt

    r203732 r203899  
    11
    2 FAIL Same domain different port [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     2PASS Same domain different port [no-cors mode]
    33PASS Same domain different port [server forbid CORS]
    4 FAIL Same domain different port [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
     4PASS Same domain different port [cors mode]
    55FAIL Same domain different protocol different port [no-cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    66PASS Same domain different protocol different port [server forbid CORS]
    77FAIL Same domain different protocol different port [cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    8 FAIL Cross domain basic usage [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     8PASS Cross domain basic usage [no-cors mode]
    99PASS Cross domain basic usage [server forbid CORS]
    10 FAIL Cross domain basic usage [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
    11 FAIL Cross domain different port [no-cors mode] assert_equals: Opaque filter: status is 0 expected 0 but got 200
     10PASS Cross domain basic usage [cors mode]
     11PASS Cross domain different port [no-cors mode]
    1212PASS Cross domain different port [server forbid CORS]
    13 FAIL Cross domain different port [cors mode] assert_equals: CORS response's type is cors expected "cors" but got "basic"
     13PASS Cross domain different port [cors mode]
    1414FAIL Cross domain different protocol [no-cors mode] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    1515PASS Cross domain different protocol [server forbid CORS]
  • trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-expected.txt

    r203898 r203899  
    33PASS Same domain different port [GET]
    44PASS Cross domain different port [GET]
    5 PASS Cross domain different protocol [GET]
    6 PASS Same domain different protocol different port [GET]
     5FAIL Cross domain different protocol [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     6FAIL Same domain different protocol different port [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    77PASS Cross domain [POST]
    88PASS Cross domain [HEAD]
     
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/fetch/api/cors/cors-no-preflight-worker-expected.txt

    r203898 r203899  
    33PASS Same domain different port [GET]
    44PASS Cross domain different port [GET]
    5 PASS Cross domain different protocol [GET]
    6 PASS Same domain different protocol different port [GET]
     5FAIL Cross domain different protocol [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
     6FAIL Same domain different protocol different port [GET] promise_test: Unhandled rejection with value: object "TypeError: Type error"
    77PASS Cross domain [POST]
    88PASS Cross domain [HEAD]
     
    1414PASS Cross domain [GET] [Content-Type: text/plain]
    1515PASS Cross domain [GET] [Content-Type: text/plain;charset=utf-8]
     16PASS Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]
    1617
  • trunk/LayoutTests/platform/mac/TestExpectations

    r203837 r203899  
    14261426# rdar://problem/27475162
    14271427[ Sierra+ ] compositing/video/poster.html [ Pass ImageOnlyFailure ]
    1428 
    1429 webkit.org/b/160056 imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight.html [ Pass Failure ]
  • trunk/Source/WebCore/ChangeLog

    r203896 r203899  
     12016-07-29  Youenn Fablet  <youenn@apple.com>
     2
     3        CrossOrigin preflight checker should compute the right Access-Control-Request-Headers value
     4        https://bugs.webkit.org/show_bug.cgi?id=160028
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by updated test.
     9
     10        Computing Access-Control-Request-Headers value according https://fetch.spec.whatwg.org/#cors-preflight-fetch:
     11        - Remove safe headers
     12        - lowercase header names
     13        - sort lexicographically header names
     14        The only difference is that we keep separating headers with ', ' instead of ',' as per the spec.
     15        Also, some headers that might be safe are still marked as unsafe (DPR, Downlink...).
     16
     17        Moved setting of Origin header after preflighting, consistently with fetch spec.
     18
     19        * loader/CrossOriginAccessControl.cpp:
     20        (WebCore::createAccessControlPreflightRequest): Implementing new computation of Access-Control-Request-Headers.
     21        * loader/DocumentThreadableLoader.cpp:
     22        (WebCore::DocumentThreadableLoader::makeCrossOriginAccessRequest): Removing call to updateRequestForAccessControl (which sets Origin header value).
     23        (WebCore::DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest): Adding call to updateRequestForAccessControl.
     24        (WebCore::DocumentThreadableLoader::preflightSuccess): Ditto.
     25        * platform/network/HTTPParsers.cpp:
     26        (WebCore::isCrossOriginSafeRequestHeader): Helper routine to implement https://fetch.spec.whatwg.org/#cors-safelisted-request-header.
     27        * platform/network/HTTPParsers.h:
     28
    1292016-07-29  Frederic Wang  <fwang@igalia.com>
    230
  • trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp

    r203815 r203899  
    117117
    118118    if (!requestHeaderFields.isEmpty()) {
     119        Vector<String> unsafeHeaders;
     120        for (const auto& headerField : requestHeaderFields.commonHeaders()) {
     121            if (!isCrossOriginSafeRequestHeader(headerField.key, headerField.value))
     122                unsafeHeaders.append(httpHeaderNameString(headerField.key).toStringWithoutCopying().convertToASCIILowercase());
     123        }
     124        for (const auto& headerField : requestHeaderFields.uncommonHeaders())
     125            unsafeHeaders.append(headerField.key.convertToASCIILowercase());
     126
     127        std::sort(unsafeHeaders.begin(), unsafeHeaders.end(), WTF::codePointCompareLessThan);
     128
    119129        StringBuilder headerBuffer;
    120        
     130
    121131        bool appendComma = false;
    122         for (const auto& headerField : requestHeaderFields) {
     132        for (const auto& headerField : unsafeHeaders) {
     133            // FIXME: header names should be separated by 0x2C, without space.
    123134            if (appendComma)
    124135                headerBuffer.appendLiteral(", ");
    125136            else
    126137                appendComma = true;
    127            
    128             headerBuffer.append(headerField.key);
     138
     139            headerBuffer.append(headerField);
    129140        }
    130 
    131         preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestHeaders, headerBuffer.toString().convertToASCIILowercase());
     141        preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestHeaders, headerBuffer.toString());
    132142    }
    133143
  • trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp

    r203815 r203899  
    114114    ASSERT(m_options.mode == FetchOptions::Mode::Cors);
    115115
    116     auto crossOriginRequest = request;
    117     updateRequestForAccessControl(crossOriginRequest, securityOrigin(), m_options.allowCredentials());
    118 
    119     if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest.httpMethod(), crossOriginRequest.httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight)
    120         makeSimpleCrossOriginAccessRequest(crossOriginRequest);
     116    if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight)
     117        makeSimpleCrossOriginAccessRequest(request);
    121118    else {
    122119        m_simpleRequest = false;
    123         if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(securityOrigin().toString(), crossOriginRequest.url(), m_options.allowCredentials(), crossOriginRequest.httpMethod(), crossOriginRequest.httpHeaderFields()))
    124             preflightSuccess(WTFMove(crossOriginRequest));
     120        if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(securityOrigin().toString(), request.url(), m_options.allowCredentials(), request.httpMethod(), request.httpHeaderFields()))
     121            preflightSuccess(ResourceRequest(request));
    125122        else
    126             makeCrossOriginAccessRequestWithPreflight(WTFMove(crossOriginRequest));
     123            makeCrossOriginAccessRequestWithPreflight(ResourceRequest(request));
    127124    }
    128125}
     
    139136    }
    140137
    141     loadRequest(request, DoSecurityCheck);
     138    auto crossOriginRequest = request;
     139    updateRequestForAccessControl(crossOriginRequest, securityOrigin(), m_options.allowCredentials());
     140    loadRequest(crossOriginRequest, DoSecurityCheck);
    142141}
    143142
     
    335334{
    336335    ResourceRequest actualRequest(WTFMove(request));
    337     actualRequest.setHTTPOrigin(securityOrigin().toString());
     336    updateRequestForAccessControl(actualRequest, securityOrigin(), m_options.allowCredentials());
    338337
    339338    m_preflightChecker = Nullopt;
  • trunk/Source/WebCore/platform/network/HTTPParsers.cpp

    r203815 r203899  
    855855}
    856856
    857 }
     857// Implements https://fetch.spec.whatwg.org/#cors-safelisted-request-header
     858bool isCrossOriginSafeRequestHeader(HTTPHeaderName name, const String& value)
     859{
     860    switch (name) {
     861    case HTTPHeaderName::Accept:
     862    case HTTPHeaderName::AcceptLanguage:
     863    case HTTPHeaderName::ContentLanguage:
     864        return true;
     865    case HTTPHeaderName::ContentType: {
     866        String mimeType = extractMIMETypeFromMediaType(value);
     867        return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain");
     868    }
     869    default:
     870        // FIXME: Should we also make safe other headers (DPR, Downlink, Save-Data...)? That would require validating their values.
     871        return false;
     872    }
     873}
     874
     875}
  • trunk/Source/WebCore/platform/network/HTTPParsers.h

    r203815 r203899  
    110110bool isCrossOriginSafeHeader(HTTPHeaderName, const HTTPHeaderSet&);
    111111bool isCrossOriginSafeHeader(const String&, const HTTPHeaderSet&);
     112bool isCrossOriginSafeRequestHeader(HTTPHeaderName, const String&);
    112113
    113114inline bool isHTTPSpace(UChar character)
Note: See TracChangeset for help on using the changeset viewer.