data:// URL behavior of XHR does not match spec
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Aug 2016 08:06:28 +0000 (08:06 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Aug 2016 08:06:28 +0000 (08:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=109199

Patch by Youenn Fablet <youenn@apple.com> on 2016-08-29
Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/XMLHttpRequest/data-uri-expected.txt:
* web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub-expected.txt:
* web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-defer-scripts-expected.txt:
* web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-scripts-expected.txt:
* web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-not-hang-scriptloader-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-data.js: Adding setStatusText check.
* web-platform-tests/fetch/api/basic/scheme-data-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-data-worker-expected.txt:

Source/WebCore:

Covered by rebased tests.

Making data URLs same origin for XHR and fetch API.
This is the behavior when https://fetch.spec.whatwg.org/#same-origin-data-url-flag is set.
As per the specs, this flag is set for fetch API and XMLHttpRequest.
Introducing this flag in ThreadableLoader options, default value being false.
Setting flag for XHR and fetch API.

Fixing accuracy of data URL loading by setting status code and content-type HTTP header as per fetch specification.

As can be seen from the rebased tests, no constraint is put on the method used as the fetch specification is about to allow all methods for data URLs.

* Modules/fetch/FetchLoader.cpp:
(WebCore::FetchLoader::start): Setting same-origin-data-url-flag to true.
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::DocumentThreadableLoader): Making data URLs same origin if flag is set.
* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::loadDataURL): Setting status code and content-type header according specification.
* loader/ThreadableLoader.cpp:
(WebCore::ThreadableLoaderOptions::ThreadableLoaderOptions): Adding same-origin-data-url-flag option.
* loader/ThreadableLoader.h:
* loader/WorkerThreadableLoader.cpp:
(WebCore::LoaderTaskOptions::LoaderTaskOptions): Ensuring flag is preserved when going to the main thread.
* platform/network/DataURLDecoder.cpp:
(WebCore::DataURLDecoder::parseMediaType): Setting mediaType value, used by ResourceLoader to set the content-type header.
* platform/network/DataURLDecoder.h:
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::createRequest): Setting same-origin-data-url-flag to true.

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

19 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/data-uri-expected.txt
LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub-expected.txt
LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-defer-scripts-expected.txt
LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-scripts-expected.txt
LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-not-hang-scriptloader-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-data-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-data-worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-data.js
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/FetchLoader.cpp
Source/WebCore/loader/DocumentThreadableLoader.cpp
Source/WebCore/loader/ResourceLoader.cpp
Source/WebCore/loader/ThreadableLoader.cpp
Source/WebCore/loader/ThreadableLoader.h
Source/WebCore/loader/WorkerThreadableLoader.cpp
Source/WebCore/platform/network/DataURLDecoder.cpp
Source/WebCore/platform/network/DataURLDecoder.h
Source/WebCore/xml/XMLHttpRequest.cpp

index 0363302..1c5d455 100644 (file)
@@ -1,3 +1,19 @@
+2016-08-29  Youenn Fablet  <youenn@apple.com>
+
+        data:// URL behavior of XHR does not match spec
+        https://bugs.webkit.org/show_bug.cgi?id=109199
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/XMLHttpRequest/data-uri-expected.txt:
+        * web-platform-tests/XMLHttpRequest/send-network-error-sync-events.sub-expected.txt:
+        * web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-defer-scripts-expected.txt:
+        * web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-block-scripts-expected.txt:
+        * web-platform-tests/XMLHttpRequest/xmlhttprequest-sync-not-hang-scriptloader-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-data.js: Adding setStatusText check.
+        * web-platform-tests/fetch/api/basic/scheme-data-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-data-worker-expected.txt:
+
 2016-08-28  Youenn Fablet  <youenn@apple.com>
 
         [Fetch API] Ensure response cloning works when data is loading
index 4889a27..3457532 100644 (file)
@@ -1,22 +1,12 @@
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/plain,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/html,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/html;charset=UTF-8,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:image/png,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/plain,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 40: XMLHttpRequest cannot load data:text/plain,Hello, World!. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: XMLHttpRequest cannot load data:text/plain,Hello, World!. Preflight response is not successful
-CONSOLE MESSAGE: XMLHttpRequest cannot load data:text/plain,Hello, World!. Preflight response is not successful
-CONSOLE MESSAGE: XMLHttpRequest cannot load data:text/plain,Hello, World!. Preflight response is not successful
 
-FAIL XHR method GET with charset text/plain assert_equals: expected "Hello, World!" but got ""
-FAIL XHR method GET with charset text/plain (base64) assert_equals: expected "Hello, World!" but got ""
-FAIL XHR method GET with charset text/html assert_equals: expected "Hello, World!" but got ""
-FAIL XHR method GET with charset text/html;charset=UTF-8 assert_equals: expected "Hello, World!" but got ""
-FAIL XHR method GET with charset image/png assert_equals: expected "Hello, World!" but got ""
-PASS XHR method POST with charset text/plain 
-PASS XHR method PUT with charset text/plain 
-PASS XHR method DELETE with charset text/plain 
-PASS XHR method HEAD with charset text/plain 
-PASS XHR method UNICORN with charset text/plain 
+PASS XHR method GET with charset text/plain 
+PASS XHR method GET with charset text/plain (base64) 
+PASS XHR method GET with charset text/html 
+PASS XHR method GET with charset text/html;charset=UTF-8 
+PASS XHR method GET with charset image/png 
+FAIL XHR method POST with charset text/plain assert_equals: expected 0 but got 200
+FAIL XHR method PUT with charset text/plain assert_equals: expected 0 but got 200
+FAIL XHR method DELETE with charset text/plain assert_equals: expected 0 but got 200
+FAIL XHR method HEAD with charset text/plain assert_equals: expected 0 but got 200
+FAIL XHR method UNICORN with charset text/plain assert_equals: expected 0 but got 200
 
index b5635ca..091e011 100644 (file)
@@ -1,5 +1,4 @@
 CONSOLE MESSAGE: line 24: XMLHttpRequest cannot load http://nonexistent-origin.localhost}:8800. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 32: XMLHttpRequest cannot load data:text/html;charset=utf-8;base64,PT0NUWVBFIGh0bWw%2BDQo8. Cross origin requests are only supported for HTTP.
 
 PASS XmlHttpRequest: The send() method: Throw a "throw an "NetworkError" exception when Network error happens (synchronous flag is set) 
 
index 0be3fa4..34b1e52 100644 (file)
@@ -1,6 +1,4 @@
-CONSOLE MESSAGE: line 1: XMLHttpRequest cannot load data:text/plain,aaa. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 1: NetworkError (DOM Exception 19):  A network error occurred.
 
 
-FAIL Check that a sync XHR in a defer script blocks later defer scripts from running assert_equals: expected 1 but got 0
+PASS Check that a sync XHR in a defer script blocks later defer scripts from running 
 
index 00cce24..b06d112 100644 (file)
@@ -1,4 +1,3 @@
-CONSOLE MESSAGE: line 17: XMLHttpRequest cannot load data:,. Cross origin requests are only supported for HTTP.
 
-FAIL Check that while a sync XHR is in flight async script loads don't complete and run script  A network error occurred.
+PASS Check that while a sync XHR is in flight async script loads don't complete and run script 
 
index 96c5b71..5ac9ab2 100644 (file)
@@ -1,5 +1,3 @@
-CONSOLE MESSAGE: line 14: XMLHttpRequest cannot load data:,. Cross origin requests are only supported for HTTP.
-CONSOLE MESSAGE: line 14: NetworkError (DOM Exception 19):  A network error occurred.
 
 
 PASS Ensure that an async script added during a defer script that then does a
index 9b1e8b8..719f70a 100644 (file)
@@ -1,8 +1,8 @@
 
-FAIL Fetching data:,response%27s%20body is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-FAIL Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-FAIL Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-PASS Fetching [GET] data:notAdataUrl.com is KO 
-PASS Fetching [POST] data:,response%27s%20body is KO 
-PASS Fetching [HEAD] data:,response%27s%20body is KO 
+PASS Fetching data:,response%27s%20body is OK 
+PASS Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK 
+PASS Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK 
+FAIL Fetching [GET] data:notAdataUrl.com is KO assert_unreached: Should have rejected. Reached unreachable code
+FAIL Fetching [POST] data:,response%27s%20body is KO assert_unreached: Should have rejected. Reached unreachable code
+FAIL Fetching [HEAD] data:,response%27s%20body is KO assert_unreached: Should have rejected. Reached unreachable code
 
index 9b1e8b8..719f70a 100644 (file)
@@ -1,8 +1,8 @@
 
-FAIL Fetching data:,response%27s%20body is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-FAIL Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-FAIL Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
-PASS Fetching [GET] data:notAdataUrl.com is KO 
-PASS Fetching [POST] data:,response%27s%20body is KO 
-PASS Fetching [HEAD] data:,response%27s%20body is KO 
+PASS Fetching data:,response%27s%20body is OK 
+PASS Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK 
+PASS Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK 
+FAIL Fetching [GET] data:notAdataUrl.com is KO assert_unreached: Should have rejected. Reached unreachable code
+FAIL Fetching [POST] data:,response%27s%20body is KO assert_unreached: Should have rejected. Reached unreachable code
+FAIL Fetching [HEAD] data:,response%27s%20body is KO assert_unreached: Should have rejected. Reached unreachable code
 
index 7754667..f4ac2c5 100644 (file)
@@ -9,6 +9,7 @@ function checkFetchResponse(url, data, mime) {
   promise_test(function(test) {
     return fetch(url).then(function(resp) {
       assert_equals(resp.status, 200, "HTTP status is 200");
+      assert_equals(resp.statusText, "OK", "HTTP statusText is OK");
       assert_equals(resp.type, "basic", "response type is basic");
       assert_equals(resp.headers.get("Content-Type"), mime, "Content-Type is " + resp.headers.get("Content-Type"));
      return resp.text();
index 5ed9724..4f3f18e 100644 (file)
@@ -1,3 +1,39 @@
+2016-08-29  Youenn Fablet  <youenn@apple.com>
+
+        data:// URL behavior of XHR does not match spec
+        https://bugs.webkit.org/show_bug.cgi?id=109199
+
+        Reviewed by Darin Adler.
+
+        Covered by rebased tests.
+
+        Making data URLs same origin for XHR and fetch API.
+        This is the behavior when https://fetch.spec.whatwg.org/#same-origin-data-url-flag is set.
+        As per the specs, this flag is set for fetch API and XMLHttpRequest.
+        Introducing this flag in ThreadableLoader options, default value being false.
+        Setting flag for XHR and fetch API.
+
+        Fixing accuracy of data URL loading by setting status code and content-type HTTP header as per fetch specification.
+
+        As can be seen from the rebased tests, no constraint is put on the method used as the fetch specification is about to allow all methods for data URLs.
+
+        * Modules/fetch/FetchLoader.cpp:
+        (WebCore::FetchLoader::start): Setting same-origin-data-url-flag to true.
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::DocumentThreadableLoader): Making data URLs same origin if flag is set.
+        * loader/ResourceLoader.cpp:
+        (WebCore::ResourceLoader::loadDataURL): Setting status code and content-type header according specification.
+        * loader/ThreadableLoader.cpp:
+        (WebCore::ThreadableLoaderOptions::ThreadableLoaderOptions): Adding same-origin-data-url-flag option.
+        * loader/ThreadableLoader.h:
+        * loader/WorkerThreadableLoader.cpp:
+        (WebCore::LoaderTaskOptions::LoaderTaskOptions): Ensuring flag is preserved when going to the main thread.
+        * platform/network/DataURLDecoder.cpp:
+        (WebCore::DataURLDecoder::parseMediaType): Setting mediaType value, used by ResourceLoader to set the content-type header.
+        * platform/network/DataURLDecoder.h:
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::createRequest): Setting same-origin-data-url-flag to true.
+
 2016-08-25  Frederic Wang  <fwang@igalia.com>
 
         Add support for non-BMP operators U+1EEF0 and U+1EEF1
index d97ec92..67a8b4a 100644 (file)
@@ -77,7 +77,8 @@ void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& req
     ThreadableLoaderOptions options(request.fetchOptions(), ConsiderPreflight,
         context.shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective,
         String(cachedResourceRequestInitiators().fetch),
-        OpaqueResponseBodyPolicy::DoNotReceive);
+        OpaqueResponseBodyPolicy::DoNotReceive,
+        SameOriginDataURLFlag::Set);
     options.sendLoadCallbacks = SendCallbacks;
     options.dataBufferingPolicy = DoNotBufferData;
 
index 7b22886..48ce574 100644 (file)
@@ -105,6 +105,10 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl
     if (m_async && m_options.mode == FetchOptions::Mode::Cors)
         m_originalHeaders = request.httpHeaderFields();
 
+    // As per step 11 of https://fetch.spec.whatwg.org/#main-fetch, data scheme (if same-origin data-URL flag is set) and about scheme are considered same-origin.
+    if (request.url().protocolIsData())
+        m_sameOriginRequest = options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set;
+
     if (m_sameOriginRequest || m_options.mode == FetchOptions::Mode::NoCors) {
         loadRequest(WTFMove(request), DoSecurityCheck);
         return;
index e892649..5d83dff 100644 (file)
@@ -259,6 +259,9 @@ void ResourceLoader::loadDataURL()
         auto dataSize = result.data ? result.data->size() : 0;
 
         ResourceResponse dataResponse { url, result.mimeType, dataSize, result.charset };
+        dataResponse.setHTTPStatusCode(200);
+        dataResponse.setHTTPStatusText(ASCIILiteral("OK"));
+        dataResponse.setHTTPHeaderField(HTTPHeaderName::ContentType, result.contentType);
         protectedThis->didReceiveResponse(dataResponse);
 
         if (!protectedThis->reachedTerminalState() && dataSize)
index 5a26dea..21ff37a 100644 (file)
@@ -50,12 +50,13 @@ ThreadableLoaderOptions::~ThreadableLoaderOptions()
 {
 }
 
-ThreadableLoaderOptions::ThreadableLoaderOptions(const ResourceLoaderOptions& baseOptions, PreflightPolicy preflightPolicy, ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement, String&& initiator, OpaqueResponseBodyPolicy opaqueResponse)
+ThreadableLoaderOptions::ThreadableLoaderOptions(const ResourceLoaderOptions& baseOptions, PreflightPolicy preflightPolicy, ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement, String&& initiator, OpaqueResponseBodyPolicy opaqueResponse, SameOriginDataURLFlag sameOriginDataURLFlag)
     : ResourceLoaderOptions(baseOptions)
     , preflightPolicy(preflightPolicy)
     , contentSecurityPolicyEnforcement(contentSecurityPolicyEnforcement)
     , initiator(WTFMove(initiator))
     , opaqueResponse(opaqueResponse)
+    , sameOriginDataURLFlag(sameOriginDataURLFlag)
 {
 }
 
index 3a5246e..702ff34 100644 (file)
@@ -63,15 +63,21 @@ namespace WebCore {
         DoNotReceive
     };
 
+    enum class SameOriginDataURLFlag {
+        Set,
+        Unset
+    };
+
     struct ThreadableLoaderOptions : ResourceLoaderOptions {
         ThreadableLoaderOptions();
-        ThreadableLoaderOptions(const ResourceLoaderOptions&, PreflightPolicy, ContentSecurityPolicyEnforcement, String&& initiator, OpaqueResponseBodyPolicy);
+        ThreadableLoaderOptions(const ResourceLoaderOptions&, PreflightPolicy, ContentSecurityPolicyEnforcement, String&& initiator, OpaqueResponseBodyPolicy, SameOriginDataURLFlag);
         ~ThreadableLoaderOptions();
 
         PreflightPolicy preflightPolicy { ConsiderPreflight };
         ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement { ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective };
         String initiator; // This cannot be an AtomicString, as isolatedCopy() wouldn't create an object that's safe for passing to another thread.
         OpaqueResponseBodyPolicy opaqueResponse { OpaqueResponseBodyPolicy::Receive };
+        SameOriginDataURLFlag sameOriginDataURLFlag { SameOriginDataURLFlag::Unset };
     };
 
     // Useful for doing loader operations from any thread (not threadsafe,
index 0319770..d80d7c5 100644 (file)
@@ -92,7 +92,7 @@ struct LoaderTaskOptions {
 };
 
 LoaderTaskOptions::LoaderTaskOptions(const ThreadableLoaderOptions& options, const String& referrer, const SecurityOrigin& origin)
-    : options(options, options.preflightPolicy, options.contentSecurityPolicyEnforcement, options.initiator.isolatedCopy(), options.opaqueResponse)
+    : options(options, options.preflightPolicy, options.contentSecurityPolicyEnforcement, options.initiator.isolatedCopy(), options.opaqueResponse, options.sameOriginDataURLFlag)
     , referrer(referrer.isolatedCopy())
     , origin(origin.isolatedCopy())
 {
index 3ecda2a..abfb46c 100644 (file)
@@ -115,10 +115,10 @@ static Result parseMediaType(const String& mediaType)
         if (charset.isEmpty())
             charset = ASCIILiteral("US-ASCII");
     }
-    return { mimeType, charset, nullptr };
+    return { mimeType, charset, !mediaType.isEmpty() ? mediaType : "text/plain;charset=US-ASCII", nullptr };
 }
 
-static std::unique_ptr<DecodeTask> createDecodeTask(const URL& url, const ScheduleContext& scheduleContext, DecodeCompletionHandler completionHandler)
+static std::unique_ptr<DecodeTask> createDecodeTask(const URL& url, const ScheduleContext& scheduleContext, DecodeCompletionHandler&& completionHandler)
 {
     const char dataString[] = "data:";
     const char base64String[] = ";base64";
index 4c01121..8901c73 100644 (file)
@@ -45,6 +45,7 @@ namespace DataURLDecoder {
 struct Result {
     String mimeType;
     String charset;
+    String contentType;
     RefPtr<SharedBuffer> data;
 };
 
index c83ab8c..270404a 100644 (file)
@@ -693,6 +693,7 @@ void XMLHttpRequest::createRequest(ExceptionCode& ec)
     options.mode = FetchOptions::Mode::Cors;
     options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective;
     options.initiator = cachedResourceRequestInitiators().xmlhttprequest;
+    options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
 
     if (m_timeoutMilliseconds) {
         if (!m_async)