Title: [279881] trunk
Revision
279881
Author
[email protected]
Date
2021-07-13 12:18:51 -0700 (Tue, 13 Jul 2021)

Log Message

Revoking Blob URL after calling XMLHttpRequest::open() causes the XHR to fail
https://bugs.webkit.org/show_bug.cgi?id=227821

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

Rebaseline WPT tests now that more checks are passing.

* web-platform-tests/FileAPI/url/url-with-xhr.any-expected.txt:
* web-platform-tests/FileAPI/url/url-with-xhr.any.worker-expected.txt:

Source/WebCore:

Revoking Blob URL after calling XMLHttpRequest::open() causes the XHR to fail. This doesn't match the behavior of
other browsers and is causing WebKit to fail one of the subtests on:
- http://wpt.live/FileAPI/url/url-with-xhr.any.html

XMLHttpRequest::open() now extends the lifetime of the Blob URL as necessary in order to complete the load.

No new tests, rebaselined existing tests.

* fileapi/BlobURL.cpp:
(WebCore::URLWithBlobURLLifetimeExtension::URLWithBlobURLLifetimeExtension):
(WebCore::URLWithBlobURLLifetimeExtension::~URLWithBlobURLLifetimeExtension):
* fileapi/BlobURL.h:
(WebCore::BlobURLLifeTimeExtender::url const):
* loader/PolicyChecker.cpp:
(WebCore::FrameLoader::PolicyChecker::extendBlobURLLifetimeIfNecessary const):
(WebCore::FrameLoader::PolicyChecker::checkNavigationPolicy):
* loader/PolicyChecker.h:
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::XMLHttpRequest):
(WebCore::XMLHttpRequest::setResponseType):
(WebCore::XMLHttpRequest::open):
(WebCore::XMLHttpRequest::prepareToSend):
(WebCore::XMLHttpRequest::send):
(WebCore::XMLHttpRequest::createRequest):
* xml/XMLHttpRequest.h:

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (279880 => 279881)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-07-13 19:18:51 UTC (rev 279881)
@@ -1,3 +1,15 @@
+2021-07-13  Chris Dumez  <[email protected]>
+
+        Revoking Blob URL after calling XMLHttpRequest::open() causes the XHR to fail
+        https://bugs.webkit.org/show_bug.cgi?id=227821
+
+        Reviewed by Alex Christensen.
+
+        Rebaseline WPT tests now that more checks are passing.
+
+        * web-platform-tests/FileAPI/url/url-with-xhr.any-expected.txt:
+        * web-platform-tests/FileAPI/url/url-with-xhr.any.worker-expected.txt:
+
 2021-07-13  Martin Robinson  <[email protected]>
 
         RenderLayerScrollableArea::updateScrollPosition assumes that it can scroll to the targeted scroll position

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any-expected.txt (279880 => 279881)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any-expected.txt	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any-expected.txt	2021-07-13 19:18:51 UTC (rev 279881)
@@ -12,5 +12,5 @@
 PASS XHR with method "PUT" should fail
 PASS XHR with method "CUSTOM" should fail
 PASS XHR should return Content-Type from Blob
-FAIL Revoke blob URL after open(), will fetch assert_unreached: Got unexpected error event Reached unreachable code
+PASS Revoke blob URL after open(), will fetch
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any.worker-expected.txt (279880 => 279881)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any.worker-expected.txt	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/url-with-xhr.any.worker-expected.txt	2021-07-13 19:18:51 UTC (rev 279881)
@@ -12,5 +12,5 @@
 PASS XHR with method "PUT" should fail
 PASS XHR with method "CUSTOM" should fail
 PASS XHR should return Content-Type from Blob
-FAIL Revoke blob URL after open(), will fetch assert_unreached: Got unexpected error event Reached unreachable code
+PASS Revoke blob URL after open(), will fetch
 

Modified: trunk/Source/WebCore/ChangeLog (279880 => 279881)


--- trunk/Source/WebCore/ChangeLog	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/ChangeLog	2021-07-13 19:18:51 UTC (rev 279881)
@@ -1,3 +1,36 @@
+2021-07-13  Chris Dumez  <[email protected]>
+
+        Revoking Blob URL after calling XMLHttpRequest::open() causes the XHR to fail
+        https://bugs.webkit.org/show_bug.cgi?id=227821
+
+        Reviewed by Alex Christensen.
+
+        Revoking Blob URL after calling XMLHttpRequest::open() causes the XHR to fail. This doesn't match the behavior of
+        other browsers and is causing WebKit to fail one of the subtests on:
+        - http://wpt.live/FileAPI/url/url-with-xhr.any.html
+
+        XMLHttpRequest::open() now extends the lifetime of the Blob URL as necessary in order to complete the load.
+
+        No new tests, rebaselined existing tests.
+
+        * fileapi/BlobURL.cpp:
+        (WebCore::URLWithBlobURLLifetimeExtension::URLWithBlobURLLifetimeExtension):
+        (WebCore::URLWithBlobURLLifetimeExtension::~URLWithBlobURLLifetimeExtension):
+        * fileapi/BlobURL.h:
+        (WebCore::BlobURLLifeTimeExtender::url const):
+        * loader/PolicyChecker.cpp:
+        (WebCore::FrameLoader::PolicyChecker::extendBlobURLLifetimeIfNecessary const):
+        (WebCore::FrameLoader::PolicyChecker::checkNavigationPolicy):
+        * loader/PolicyChecker.h:
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::XMLHttpRequest):
+        (WebCore::XMLHttpRequest::setResponseType):
+        (WebCore::XMLHttpRequest::open):
+        (WebCore::XMLHttpRequest::prepareToSend):
+        (WebCore::XMLHttpRequest::send):
+        (WebCore::XMLHttpRequest::createRequest):
+        * xml/XMLHttpRequest.h:
+
 2021-07-13  Philippe Normand  <[email protected]>
 
         [GStreamer] Allow runtime opt-out of GL rendering

Modified: trunk/Source/WebCore/fileapi/BlobURL.cpp (279880 => 279881)


--- trunk/Source/WebCore/fileapi/BlobURL.cpp	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/fileapi/BlobURL.cpp	2021-07-13 19:18:51 UTC (rev 279881)
@@ -96,4 +96,46 @@
     return URL({ }, urlString);
 }
 
+URLWithBlobURLLifetimeExtension::URLWithBlobURLLifetimeExtension(const URL& url)
+    : m_url(url)
+{
+    extendBlobURLLifetimeIfNecessary();
+}
+
+URLWithBlobURLLifetimeExtension::~URLWithBlobURLLifetimeExtension()
+{
+    unregisterCurrentURLIfNecessary();
+}
+
+void URLWithBlobURLLifetimeExtension::extendBlobURLLifetimeIfNecessary()
+{
+    if (m_url.protocolIsBlob()) {
+        auto origin = SecurityOrigin::create(BlobURL::getOriginURL(m_url));
+        URL temporaryBlobURL = BlobURL::createPublicURL(origin.ptr());
+        ThreadableBlobRegistry::registerBlobURL(origin.ptr(), temporaryBlobURL, m_url);
+        m_url = WTFMove(temporaryBlobURL);
+    }
+}
+
+void URLWithBlobURLLifetimeExtension::unregisterCurrentURLIfNecessary()
+{
+    if (m_url.protocolIsBlob())
+        ThreadableBlobRegistry::unregisterBlobURL(m_url);
+}
+
+URLWithBlobURLLifetimeExtension& URLWithBlobURLLifetimeExtension::operator=(URLWithBlobURLLifetimeExtension&& other)
+{
+    unregisterCurrentURLIfNecessary();
+    m_url = std::exchange(other.m_url, { });
+    return *this;
+}
+
+URLWithBlobURLLifetimeExtension& URLWithBlobURLLifetimeExtension::operator=(URL&& url)
+{
+    unregisterCurrentURLIfNecessary();
+    m_url = WTFMove(url);
+    extendBlobURLLifetimeIfNecessary();
+    return *this;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/fileapi/BlobURL.h (279880 => 279881)


--- trunk/Source/WebCore/fileapi/BlobURL.h	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/fileapi/BlobURL.h	2021-07-13 19:18:51 UTC (rev 279881)
@@ -58,4 +58,29 @@
     BlobURL() { }
 };
 
+class URLWithBlobURLLifetimeExtension {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(URLWithBlobURLLifetimeExtension);
+public:
+    URLWithBlobURLLifetimeExtension() = default;
+    explicit URLWithBlobURLLifetimeExtension(const URL&);
+    ~URLWithBlobURLLifetimeExtension();
+
+    URLWithBlobURLLifetimeExtension(URLWithBlobURLLifetimeExtension&& other)
+        : m_url(std::exchange(other.m_url, { }))
+    { }
+
+    URLWithBlobURLLifetimeExtension& operator=(URLWithBlobURLLifetimeExtension&&);
+    URLWithBlobURLLifetimeExtension& operator=(URL&&);
+
+    operator const URL&() const { return m_url; }
+    const URL& url() const { return m_url; }
+
+private:
+    void unregisterCurrentURLIfNecessary();
+    void extendBlobURLLifetimeIfNecessary();
+
+    URL m_url;
+};
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/PolicyChecker.cpp (279880 => 279881)


--- trunk/Source/WebCore/loader/PolicyChecker.cpp	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/loader/PolicyChecker.cpp	2021-07-13 19:18:51 UTC (rev 279881)
@@ -104,21 +104,17 @@
     checkNavigationPolicy(WTFMove(newRequest), redirectResponse, m_frame.loader().activeDocumentLoader(), { }, WTFMove(function));
 }
 
-CompletionHandlerCallingScope FrameLoader::PolicyChecker::extendBlobURLLifetimeIfNecessary(ResourceRequest& request, DocumentLoader* loader) const
+URLWithBlobURLLifetimeExtension FrameLoader::PolicyChecker::extendBlobURLLifetimeIfNecessary(ResourceRequest& request, DocumentLoader* loader, PolicyDecisionMode mode) const
 {
-    if (!request.url().protocolIsBlob())
+    if (mode != PolicyDecisionMode::Asynchronous || !request.url().protocolIsBlob())
         return { };
 
-    // Create a new temporary blobURL in case this one gets revoked during the asynchronous navigation policy decision.
-    auto origin = SecurityOrigin::create(BlobURL::getOriginURL(request.url()));
-    URL temporaryBlobURL = BlobURL::createPublicURL(origin.ptr());
-    ThreadableBlobRegistry::registerBlobURL(origin.ptr(), temporaryBlobURL, request.url());
-    request.setURL(temporaryBlobURL);
+    URLWithBlobURLLifetimeExtension urlWithLifetimeExtension(request.url());
+    request.setURL(urlWithLifetimeExtension);
     if (loader)
-        loader->request().setURL(temporaryBlobURL);
-    return CompletionHandler<void()>([temporaryBlobURL = WTFMove(temporaryBlobURL)] {
-        ThreadableBlobRegistry::unregisterBlobURL(temporaryBlobURL);
-    });
+        loader->request().setURL(urlWithLifetimeExtension);
+
+    return urlWithLifetimeExtension;
 }
 
 void FrameLoader::PolicyChecker::checkNavigationPolicy(ResourceRequest&& request, const ResourceResponse& redirectResponse, DocumentLoader* loader, RefPtr<FormState>&& formState, NavigationPolicyDecisionFunction&& function, PolicyDecisionMode policyDecisionMode)
@@ -201,7 +197,7 @@
 
     m_frame.loader().clearProvisionalLoadForPolicyCheck();
 
-    auto blobURLLifetimeExtension = policyDecisionMode == PolicyDecisionMode::Asynchronous ? extendBlobURLLifetimeIfNecessary(request, loader) : CompletionHandlerCallingScope { };
+    auto blobURLLifetimeExtension = extendBlobURLLifetimeIfNecessary(request, loader, policyDecisionMode);
 
     bool isInitialEmptyDocumentLoad = !m_frame.loader().stateMachine().committedFirstRealDocumentLoad() && request.url().protocolIsAbout() && !substituteData.isValid();
     auto requestIdentifier = PolicyCheckIdentifier::create();

Modified: trunk/Source/WebCore/loader/PolicyChecker.h (279880 => 279881)


--- trunk/Source/WebCore/loader/PolicyChecker.h	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/loader/PolicyChecker.h	2021-07-13 19:18:51 UTC (rev 279881)
@@ -51,6 +51,7 @@
 class NavigationAction;
 class ResourceError;
 class ResourceResponse;
+class URLWithBlobURLLifetimeExtension;
 
 enum class NavigationPolicyDecision : uint8_t {
     ContinueLoad,
@@ -89,7 +90,7 @@
 
 private:
     void handleUnimplementablePolicy(const ResourceError&);
-    WTF::CompletionHandlerCallingScope extendBlobURLLifetimeIfNecessary(ResourceRequest&, DocumentLoader*) const;
+    URLWithBlobURLLifetimeExtension extendBlobURLLifetimeIfNecessary(ResourceRequest&, DocumentLoader*, PolicyDecisionMode = PolicyDecisionMode::Asynchronous) const;
 
     Frame& m_frame;
 

Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (279880 => 279881)


--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp	2021-07-13 19:18:51 UTC (rev 279881)
@@ -251,7 +251,7 @@
     // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
     // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
     // such as file: and data: still make sense to allow.
-    if (!m_async && scriptExecutionContext()->isDocument() && m_url.protocolIsInHTTPFamily()) {
+    if (!m_async && scriptExecutionContext()->isDocument() && m_url.url().protocolIsInHTTPFamily()) {
         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.responseType cannot be changed for synchronous HTTP(S) requests made from the window context.");
         return Exception { InvalidAccessError };
     }
@@ -382,8 +382,9 @@
     clearResponse();
     clearRequest();
 
-    m_url = url;
-    context->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(m_url, ContentSecurityPolicy::InsecureRequestType::Load);
+    auto upgradedURL = url;
+    context->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(upgradedURL, ContentSecurityPolicy::InsecureRequestType::Load);
+    m_url = WTFMove(upgradedURL);
 
     m_async = async;
 
@@ -416,7 +417,7 @@
     auto& context = *scriptExecutionContext();
 
     if (is<Document>(context) && downcast<Document>(context).shouldIgnoreSyncXHRs()) {
-        logConsoleError(scriptExecutionContext(), makeString("Ignoring XMLHttpRequest.send() call for '", m_url.string(), "' because the maximum number of synchronous failures was reached."));
+        logConsoleError(scriptExecutionContext(), makeString("Ignoring XMLHttpRequest.send() call for '", m_url.url().string(), "' because the maximum number of synchronous failures was reached."));
         return ExceptionOr<void> { };
     }
 
@@ -515,7 +516,7 @@
         return WTFMove(result.value());
 
     if (m_method != "GET" && m_method != "HEAD") {
-        if (!m_url.protocolIsInHTTPFamily()) {
+        if (!m_url.url().protocolIsInHTTPFamily()) {
             // FIXME: We would like to support posting Blobs to non-http URLs (e.g. custom URL schemes)
             // but because of the architecture of blob-handling that will require a fair amount of work.
             
@@ -588,7 +589,7 @@
 ExceptionOr<void> XMLHttpRequest::createRequest()
 {
     // Only GET request is supported for blob URL.
-    if (!m_async && m_url.protocolIsBlob() && m_method != "GET")
+    if (!m_async && m_url.url().protocolIsBlob() && m_method != "GET")
         return Exception { NetworkError };
 
     if (m_async && m_upload && m_upload->hasEventListeners())
@@ -740,6 +741,7 @@
 {
     m_requestHeaders.clear();
     m_requestEntityBody = nullptr;
+    m_url = URL { };
 }
 
 void XMLHttpRequest::genericError()
@@ -931,6 +933,7 @@
     m_responseBuilder.shrinkToFit();
 
     m_loadingActivity = std::nullopt;
+    m_url = URL { };
 
     m_sendFlag = false;
     changeState(DONE);

Modified: trunk/Source/WebCore/xml/XMLHttpRequest.h (279880 => 279881)


--- trunk/Source/WebCore/xml/XMLHttpRequest.h	2021-07-13 18:50:07 UTC (rev 279880)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.h	2021-07-13 19:18:51 UTC (rev 279881)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "ActiveDOMObject.h"
+#include "BlobURL.h"
 #include "ExceptionOr.h"
 #include "FormData.h"
 #include "ResourceResponse.h"
@@ -215,7 +216,7 @@
 
     std::unique_ptr<XMLHttpRequestUpload> m_upload;
 
-    URL m_url;
+    URLWithBlobURLLifetimeExtension m_url;
     String m_method;
     HTTPHeaderMap m_requestHeaders;
     RefPtr<FormData> m_requestEntityBody;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to