Title: [228852] trunk
Revision
228852
Author
[email protected]
Date
2018-02-20 17:08:28 -0800 (Tue, 20 Feb 2018)

Log Message

Provisional load may get committed before receiving the decidePolicyForNavigationResponse response
https://bugs.webkit.org/show_bug.cgi?id=182720
<rdar://problem/37515204>

Reviewed by Alex Christensen.

Source/WebCore:

Wait for the policy response from the client after receiving a resource response,
before sending the NetworkResourceLoader::ContinueDidReceiveResponse IPC back to
the NetworkProcess. Otherwise, the network process may start sending us data and
we may end up committing the provisional load before receiving the policy decision
fron the client.

Change is covered by new API test.

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::responseReceived):
* loader/NetscapePlugInStreamLoader.cpp:
(WebCore::NetscapePlugInStreamLoader::didReceiveResponse):
* loader/NetscapePlugInStreamLoader.h:
* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::deliverResponseAndData):
(WebCore::ResourceLoader::loadDataURL):
(WebCore::ResourceLoader::didReceiveResponse):
(WebCore::ResourceLoader::didReceiveResponseAsync):
* loader/ResourceLoader.h:
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didReceiveResponse):
(WebCore::SubresourceLoader::didReceiveResponsePolicy):
(WebCore::SubresourceLoader::willCancel):
* loader/SubresourceLoader.h:
* loader/ios/PreviewLoader.mm:
(-[WebPreviewLoader _sendDidReceiveResponseIfNecessary]):

Source/WebKit:

* WebProcess/Network/WebResourceLoader.cpp:
(WebKit::WebResourceLoader::didReceiveResponse):
* WebProcess/Storage/ServiceWorkerClientFetch.cpp:
(WebKit::ServiceWorkerClientFetch::didReceiveResponse):
* WebProcess/WebPage/WebURLSchemeTaskProxy.cpp:
(WebKit::WebURLSchemeTaskProxy::didReceiveResponse):

Source/WTF:

Add convenience CompletionHandlerCallingScope class which calls its CompletionHandler
when destroyed, and provides a release() methods to manually call the completionHandler.

* wtf/CompletionHandler.h:
(WTF::CompletionHandlerCallingScope::CompletionHandlerCallingScope):
(WTF::CompletionHandlerCallingScope::~CompletionHandlerCallingScope):
(WTF::CompletionHandlerCallingScope::CompletionHandler<void):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm:
(-[TestAsyncNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (228851 => 228852)


--- trunk/Source/WTF/ChangeLog	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WTF/ChangeLog	2018-02-21 01:08:28 UTC (rev 228852)
@@ -1,3 +1,19 @@
+2018-02-20  Chris Dumez  <[email protected]>
+
+        Provisional load may get committed before receiving the decidePolicyForNavigationResponse response
+        https://bugs.webkit.org/show_bug.cgi?id=182720
+        <rdar://problem/37515204>
+
+        Reviewed by Alex Christensen.
+
+        Add convenience CompletionHandlerCallingScope class which calls its CompletionHandler
+        when destroyed, and provides a release() methods to manually call the completionHandler.
+
+        * wtf/CompletionHandler.h:
+        (WTF::CompletionHandlerCallingScope::CompletionHandlerCallingScope):
+        (WTF::CompletionHandlerCallingScope::~CompletionHandlerCallingScope):
+        (WTF::CompletionHandlerCallingScope::CompletionHandler<void):
+
 2018-02-20  Tim Horton  <[email protected]>
 
         Always inline soft linking functions to work around a clang bug

Modified: trunk/Source/WTF/wtf/CompletionHandler.h (228851 => 228852)


--- trunk/Source/WTF/wtf/CompletionHandler.h	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WTF/wtf/CompletionHandler.h	2018-02-21 01:08:28 UTC (rev 228852)
@@ -64,6 +64,28 @@
     mutable WTF::Function<Out(In...)> m_function;
 };
 
+class CompletionHandlerCallingScope {
+public:
+    CompletionHandlerCallingScope(CompletionHandler<void()>&& completionHandler)
+        : m_completionHandler(WTFMove(completionHandler))
+    { }
+
+    ~CompletionHandlerCallingScope()
+    {
+        if (m_completionHandler)
+            m_completionHandler();
+    }
+
+    CompletionHandlerCallingScope(CompletionHandlerCallingScope&&) = default;
+    CompletionHandlerCallingScope& operator=(CompletionHandlerCallingScope&&) = default;
+
+    CompletionHandler<void()> release() { return WTFMove(m_completionHandler); }
+
+private:
+    CompletionHandler<void()> m_completionHandler;
+};
+
 } // namespace WTF
 
 using WTF::CompletionHandler;
+using WTF::CompletionHandlerCallingScope;

Modified: trunk/Source/WebCore/ChangeLog (228851 => 228852)


--- trunk/Source/WebCore/ChangeLog	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/ChangeLog	2018-02-21 01:08:28 UTC (rev 228852)
@@ -1,5 +1,40 @@
 2018-02-20  Chris Dumez  <[email protected]>
 
+        Provisional load may get committed before receiving the decidePolicyForNavigationResponse response
+        https://bugs.webkit.org/show_bug.cgi?id=182720
+        <rdar://problem/37515204>
+
+        Reviewed by Alex Christensen.
+
+        Wait for the policy response from the client after receiving a resource response,
+        before sending the NetworkResourceLoader::ContinueDidReceiveResponse IPC back to
+        the NetworkProcess. Otherwise, the network process may start sending us data and
+        we may end up committing the provisional load before receiving the policy decision
+        fron the client.
+
+        Change is covered by new API test.
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::responseReceived):
+        * loader/NetscapePlugInStreamLoader.cpp:
+        (WebCore::NetscapePlugInStreamLoader::didReceiveResponse):
+        * loader/NetscapePlugInStreamLoader.h:
+        * loader/ResourceLoader.cpp:
+        (WebCore::ResourceLoader::deliverResponseAndData):
+        (WebCore::ResourceLoader::loadDataURL):
+        (WebCore::ResourceLoader::didReceiveResponse):
+        (WebCore::ResourceLoader::didReceiveResponseAsync):
+        * loader/ResourceLoader.h:
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::didReceiveResponse):
+        (WebCore::SubresourceLoader::didReceiveResponsePolicy):
+        (WebCore::SubresourceLoader::willCancel):
+        * loader/SubresourceLoader.h:
+        * loader/ios/PreviewLoader.mm:
+        (-[WebPreviewLoader _sendDidReceiveResponseIfNecessary]):
+
+2018-02-20  Chris Dumez  <[email protected]>
+
         Crash under JSC::JSCell::toNumber(JSC::ExecState*)
         https://bugs.webkit.org/show_bug.cgi?id=182984
         <rdar://problem/37694346>

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (228851 => 228852)


--- trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -783,7 +783,12 @@
     }
 #endif
 
+    if (auto* mainResourceLoader = this->mainResourceLoader())
+        mainResourceLoader->markInAsyncResponsePolicyCheck();
     frameLoader()->checkContentPolicy(m_response, [this, protectedThis = makeRef(*this)](PolicyAction policy) {
+        if (auto* mainResourceLoader = this->mainResourceLoader())
+            mainResourceLoader->didReceiveResponsePolicy();
+
         continueAfterContentPolicy(policy);
     });
 }

Modified: trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp (228851 => 228852)


--- trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -97,9 +97,10 @@
     });
 }
 
-void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& response)
+void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& response, CompletionHandler<void()>&& policyCompletionHandler)
 {
     Ref<NetscapePlugInStreamLoader> protectedThis(*this);
+    CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler));
 
     m_client->didReceiveResponse(this, response);
 
@@ -107,21 +108,21 @@
     if (!m_client)
         return;
 
-    ResourceLoader::didReceiveResponse(response);
+    ResourceLoader::didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis), response, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable {
+        // Don't continue if the stream is cancelled
+        if (!m_client)
+            return;
 
-    // Don't continue if the stream is cancelled
-    if (!m_client)
-        return;
+        if (!response.isHTTP())
+            return;
 
-    if (!response.isHTTP())
-        return;
-    
-    if (m_client->wantsAllStreams())
-        return;
+        if (m_client->wantsAllStreams())
+            return;
 
-    // Status code can be null when serving from a Web archive.
-    if (response.httpStatusCode() && (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400))
-        cancel(frameLoader()->client().fileDoesNotExistError(response));
+        // Status code can be null when serving from a Web archive.
+        if (response.httpStatusCode() && (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400))
+            cancel(frameLoader()->client().fileDoesNotExistError(response));
+    });
 }
 
 void NetscapePlugInStreamLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)

Modified: trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.h (228851 => 228852)


--- trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.h	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.h	2018-02-21 01:08:28 UTC (rev 228852)
@@ -60,7 +60,7 @@
     void init(ResourceRequest&&, CompletionHandler<void(bool)>&&) override;
 
     void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& callback) override;
-    void didReceiveResponse(const ResourceResponse&) override;
+    void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler) override;
     void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
     void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override;
     void didFinishLoading(const NetworkLoadMetrics&) override;

Modified: trunk/Source/WebCore/loader/ResourceLoader.cpp (228851 => 228852)


--- trunk/Source/WebCore/loader/ResourceLoader.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/ResourceLoader.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -169,21 +169,20 @@
 
 void ResourceLoader::deliverResponseAndData(const ResourceResponse& response, RefPtr<SharedBuffer>&& buffer)
 {
-    Ref<ResourceLoader> protectedThis(*this);
-
-    didReceiveResponse(response);
-    if (reachedTerminalState())
-        return;
-
-    if (buffer) {
-        unsigned size = buffer->size();
-        didReceiveBuffer(buffer.releaseNonNull(), size, DataPayloadWholeResource);
+    didReceiveResponse(response, [this, protectedThis = makeRef(*this), buffer = WTFMove(buffer)]() mutable {
         if (reachedTerminalState())
             return;
-    }
 
-    NetworkLoadMetrics emptyMetrics;
-    didFinishLoading(emptyMetrics);
+        if (buffer) {
+            unsigned size = buffer->size();
+            didReceiveBuffer(buffer.releaseNonNull(), size, DataPayloadWholeResource);
+            if (reachedTerminalState())
+                return;
+        }
+
+        NetworkLoadMetrics emptyMetrics;
+        didFinishLoading(emptyMetrics);
+    });
 }
 
 void ResourceLoader::start()
@@ -251,14 +250,14 @@
     if (auto* scheduledPairs = m_frame->page()->scheduledRunLoopPairs())
         scheduleContext.scheduledPairs = *scheduledPairs;
 #endif
-    DataURLDecoder::decode(url, scheduleContext, [protectedThis = makeRef(*this), url](auto decodeResult) {
-        if (protectedThis->reachedTerminalState())
+    DataURLDecoder::decode(url, scheduleContext, [this, protectedThis = makeRef(*this), url](auto decodeResult) mutable {
+        if (this->reachedTerminalState())
             return;
         if (!decodeResult) {
             protectedThis->didFail(ResourceError(errorDomainWebKitInternal, 0, url, "Data URL decoding failed"));
             return;
         }
-        if (protectedThis->wasCancelled())
+        if (this->wasCancelled())
             return;
         auto& result = decodeResult.value();
         auto dataSize = result.data ? result.data->size() : 0;
@@ -268,15 +267,15 @@
         dataResponse.setHTTPStatusText(ASCIILiteral("OK"));
         dataResponse.setHTTPHeaderField(HTTPHeaderName::ContentType, result.contentType);
         dataResponse.setSource(ResourceResponse::Source::Network);
-        protectedThis->didReceiveResponse(dataResponse);
+        this->didReceiveResponse(dataResponse, [this, protectedThis = WTFMove(protectedThis), dataSize, data = "" mutable {
+            if (!this->reachedTerminalState() && dataSize)
+                this->didReceiveBuffer(WTFMove(data), dataSize, DataPayloadWholeResource);
 
-        if (!protectedThis->reachedTerminalState() && dataSize)
-            protectedThis->didReceiveBuffer(result.data.releaseNonNull(), dataSize, DataPayloadWholeResource);
-
-        if (!protectedThis->reachedTerminalState()) {
-            NetworkLoadMetrics emptyMetrics;
-            protectedThis->didFinishLoading(emptyMetrics);
-        }
+            if (!this->reachedTerminalState()) {
+                NetworkLoadMetrics emptyMetrics;
+                this->didFinishLoading(emptyMetrics);
+            }
+        });
     });
 }
 
@@ -459,9 +458,10 @@
     FrameLoader::reportAuthenticationChallengeBlocked(m_frame.get(), m_request.url(), ASCIILiteral("it is a cross-origin request"));
 }
 
-void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
+void ResourceLoader::didReceiveResponse(const ResourceResponse& r, CompletionHandler<void()>&& policyCompletionHandler)
 {
     ASSERT(!m_reachedTerminalState);
+    CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler));
 
     // Protect this in this delegate method since the additional processing can do
     // anything including possibly derefing this; one example of this is Radar 3266216.
@@ -660,8 +660,7 @@
         completionHandler();
         return;
     }
-    didReceiveResponse(response);
-    completionHandler();
+    didReceiveResponse(response, WTFMove(completionHandler));
 }
 
 void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int encodedDataLength)

Modified: trunk/Source/WebCore/loader/ResourceLoader.h (228851 => 228852)


--- trunk/Source/WebCore/loader/ResourceLoader.h	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/ResourceLoader.h	2018-02-21 01:08:28 UTC (rev 228852)
@@ -101,7 +101,7 @@
 
     virtual void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& callback);
     virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
-    virtual void didReceiveResponse(const ResourceResponse&);
+    virtual void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler);
     virtual void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType);
     virtual void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
     virtual void didFinishLoading(const NetworkLoadMetrics&);

Modified: trunk/Source/WebCore/loader/SubresourceLoader.cpp (228851 => 228852)


--- trunk/Source/WebCore/loader/SubresourceLoader.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/SubresourceLoader.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -288,11 +288,13 @@
 
 #endif
 
-void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
+void SubresourceLoader::didReceiveResponse(const ResourceResponse& response, CompletionHandler<void()>&& policyCompletionHandler)
 {
     ASSERT(!response.isNull());
     ASSERT(m_state == Initialized);
 
+    CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler));
+
 #if USE(QUICK_LOOK)
     if (shouldCreatePreviewLoaderForResponse(response)) {
         m_previewLoader = PreviewLoader::create(*this, response);
@@ -335,7 +337,7 @@
             if (m_frame && m_frame->page())
                 m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes);
             if (!reachedTerminalState())
-                ResourceLoader::didReceiveResponse(revalidationResponse);
+                ResourceLoader::didReceiveResponse(revalidationResponse, [completionHandlerCaller = WTFMove(completionHandlerCaller)] { });
             return;
         }
         // Did not get 304 response, continue as a regular resource load.
@@ -356,38 +358,51 @@
     if (reachedTerminalState())
         return;
 
-    ResourceLoader::didReceiveResponse(response);
-    if (reachedTerminalState())
-        return;
+    bool isResponseMultipart = response.isMultipart();
+    ResourceLoader::didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis), isResponseMultipart, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable {
+        if (reachedTerminalState())
+            return;
 
-    // FIXME: Main resources have a different set of rules for multipart than images do.
-    // Hopefully we can merge those 2 paths.
-    if (response.isMultipart() && m_resource->type() != CachedResource::MainResource) {
-        m_loadingMultipartContent = true;
+        // FIXME: Main resources have a different set of rules for multipart than images do.
+        // Hopefully we can merge those 2 paths.
+        if (isResponseMultipart && m_resource->type() != CachedResource::MainResource) {
+            m_loadingMultipartContent = true;
 
-        // We don't count multiParts in a CachedResourceLoader's request count
-        m_requestCountTracker = std::nullopt;
-        if (!m_resource->isImage()) {
-            cancel();
-            return;
+            // We don't count multiParts in a CachedResourceLoader's request count
+            m_requestCountTracker = std::nullopt;
+            if (!m_resource->isImage()) {
+                cancel();
+                return;
+            }
         }
-    }
 
-    auto* buffer = resourceData();
-    if (m_loadingMultipartContent && buffer && buffer->size()) {
-        // The resource data will change as the next part is loaded, so we need to make a copy.
-        m_resource->finishLoading(buffer->copy().ptr());
-        clearResourceData();
-        // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
-        // After the first multipart section is complete, signal to delegates that this load is "finished"
-        NetworkLoadMetrics emptyMetrics;
-        m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
-        didFinishLoadingOnePart(emptyMetrics);
-    }
+        auto* buffer = resourceData();
+        if (m_loadingMultipartContent && buffer && buffer->size()) {
+            // The resource data will change as the next part is loaded, so we need to make a copy.
+            m_resource->finishLoading(buffer->copy().ptr());
+            clearResourceData();
+            // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
+            // After the first multipart section is complete, signal to delegates that this load is "finished"
+            NetworkLoadMetrics emptyMetrics;
+            m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
+            didFinishLoadingOnePart(emptyMetrics);
+        }
 
-    checkForHTTPStatusCodeError();
+        checkForHTTPStatusCodeError();
+
+        if (m_inAsyncResponsePolicyCheck)
+            m_policyForResponseCompletionHandler = completionHandlerCaller.release();
+    });
 }
 
+void SubresourceLoader::didReceiveResponsePolicy()
+{
+    ASSERT(m_inAsyncResponsePolicyCheck);
+    m_inAsyncResponsePolicyCheck = false;
+    if (auto completionHandler = WTFMove(m_policyForResponseCompletionHandler))
+        completionHandler();
+}
+
 void SubresourceLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)
 {
 #if USE(QUICK_LOOK)
@@ -659,6 +674,9 @@
     ASSERT(!reachedTerminalState());
     LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().string().latin1().data());
 
+    if (auto policyForResponseCompletionHandler = WTFMove(m_policyForResponseCompletionHandler))
+        policyForResponseCompletionHandler();
+
     Ref<SubresourceLoader> protectedThis(*this);
 #if PLATFORM(IOS)
     m_state = m_state == Uninitialized ? CancelledWhileInitializing : Finishing;

Modified: trunk/Source/WebCore/loader/SubresourceLoader.h (228851 => 228852)


--- trunk/Source/WebCore/loader/SubresourceLoader.h	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/SubresourceLoader.h	2018-02-21 01:08:28 UTC (rev 228852)
@@ -30,6 +30,7 @@
 
 #include "FrameLoaderTypes.h"
 #include "ResourceLoader.h"
+#include <wtf/CompletionHandler.h>
 #include <wtf/text/WTFString.h>
  
 namespace WebCore {
@@ -60,6 +61,9 @@
 
     unsigned redirectCount() const { return m_redirectCount; }
 
+    void markInAsyncResponsePolicyCheck() { m_inAsyncResponsePolicyCheck = true; }
+    void didReceiveResponsePolicy();
+
 private:
     SubresourceLoader(Frame&, CachedResource&, const ResourceLoaderOptions&);
 
@@ -67,7 +71,7 @@
 
     void willSendRequestInternal(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&&) override;
     void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override;
-    void didReceiveResponse(const ResourceResponse&) override;
+    void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler) override;
     void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override;
     void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override;
     void didFinishLoading(const NetworkLoadMetrics&) override;
@@ -124,8 +128,10 @@
     SubresourceLoaderState m_state;
     std::optional<RequestCountTracker> m_requestCountTracker;
     RefPtr<SecurityOrigin> m_origin;
+    CompletionHandler<void()> m_policyForResponseCompletionHandler;
     unsigned m_redirectCount { 0 };
     bool m_loadingMultipartContent { false };
+    bool m_inAsyncResponsePolicyCheck { false };
 };
 
 }

Modified: trunk/Source/WebCore/loader/ios/PreviewLoader.mm (228851 => 228852)


--- trunk/Source/WebCore/loader/ios/PreviewLoader.mm	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebCore/loader/ios/PreviewLoader.mm	2018-02-21 01:08:28 UTC (rev 228852)
@@ -130,7 +130,7 @@
     _resourceLoader->documentLoader()->setPreviewConverter(WTFMove(_converter));
 
     _hasSentDidReceiveResponse = YES;
-    _resourceLoader->didReceiveResponse(response);
+    _resourceLoader->didReceiveResponse(response, nullptr);
 }
 
 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived

Modified: trunk/Source/WebKit/ChangeLog (228851 => 228852)


--- trunk/Source/WebKit/ChangeLog	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebKit/ChangeLog	2018-02-21 01:08:28 UTC (rev 228852)
@@ -1,3 +1,18 @@
+2018-02-20  Chris Dumez  <[email protected]>
+
+        Provisional load may get committed before receiving the decidePolicyForNavigationResponse response
+        https://bugs.webkit.org/show_bug.cgi?id=182720
+        <rdar://problem/37515204>
+
+        Reviewed by Alex Christensen.
+
+        * WebProcess/Network/WebResourceLoader.cpp:
+        (WebKit::WebResourceLoader::didReceiveResponse):
+        * WebProcess/Storage/ServiceWorkerClientFetch.cpp:
+        (WebKit::ServiceWorkerClientFetch::didReceiveResponse):
+        * WebProcess/WebPage/WebURLSchemeTaskProxy.cpp:
+        (WebKit::WebURLSchemeTaskProxy::didReceiveResponse):
+
 2018-02-20  Matt Lewis  <[email protected]>
 
         Unreviewed, rolling out r228829.

Modified: trunk/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp (228851 => 228852)


--- trunk/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -107,19 +107,21 @@
     LOG(Network, "(WebProcess) WebResourceLoader::didReceiveResponse for '%s'. Status %d.", m_coreLoader->url().string().latin1().data(), response.httpStatusCode());
     RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", status = %d)", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID, response.httpStatusCode());
 
-    Ref<WebResourceLoader> protect(*this);
+    Ref<WebResourceLoader> protectedThis(*this);
 
     if (m_coreLoader->documentLoader()->applicationCacheHost().maybeLoadFallbackForResponse(m_coreLoader.get(), response))
         return;
 
-    m_coreLoader->didReceiveResponse(response);
+    CompletionHandler<void()> policyDecisionCompletionHandler;
+    if (needsContinueDidReceiveResponseMessage) {
+        policyDecisionCompletionHandler = [this, protectedThis = WTFMove(protectedThis)] {
+            // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function().
+            if (m_coreLoader)
+                send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse());
+        };
+    }
 
-    // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function(). 
-    if (!m_coreLoader)
-        return;
-
-    if (needsContinueDidReceiveResponseMessage)
-        send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse());
+    m_coreLoader->didReceiveResponse(response, WTFMove(policyDecisionCompletionHandler));
 }
 
 void WebResourceLoader::didReceiveData(const IPC::DataReference& data, int64_t encodedDataLength)

Modified: trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp (228851 => 228852)


--- trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -141,9 +141,10 @@
         if (response.url().isNull())
             response.setURL(m_loader->request().url());
 
-        m_loader->didReceiveResponse(response);
-        if (auto callback = WTFMove(m_callback))
-            callback(Result::Succeeded);
+        m_loader->didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis)] {
+            if (auto callback = WTFMove(m_callback))
+                callback(Result::Succeeded);
+        });
     });
 }
 

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebURLSchemeTaskProxy.cpp (228851 => 228852)


--- trunk/Source/WebKit/WebProcess/WebPage/WebURLSchemeTaskProxy.cpp	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebURLSchemeTaskProxy.cpp	2018-02-21 01:08:28 UTC (rev 228852)
@@ -93,7 +93,7 @@
     if (!hasLoader())
         return;
 
-    m_coreLoader->didReceiveResponse(response);
+    m_coreLoader->didReceiveResponse(response, nullptr);
 }
 
 void WebURLSchemeTaskProxy::didReceiveData(size_t size, const uint8_t* data)

Modified: trunk/Tools/ChangeLog (228851 => 228852)


--- trunk/Tools/ChangeLog	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Tools/ChangeLog	2018-02-21 01:08:28 UTC (rev 228852)
@@ -1,3 +1,17 @@
+2018-02-20  Chris Dumez  <[email protected]>
+
+        Provisional load may get committed before receiving the decidePolicyForNavigationResponse response
+        https://bugs.webkit.org/show_bug.cgi?id=182720
+        <rdar://problem/37515204>
+
+        Reviewed by Alex Christensen.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm:
+        (-[TestAsyncNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
+        (TestWebKitAPI::TEST):
+
 2018-02-20  Nan Wang  <[email protected]>
 
         AX: AOM: Dispatch accessibleclick event

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm (228851 => 228852)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm	2018-02-21 00:51:06 UTC (rev 228851)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm	2018-02-21 01:08:28 UTC (rev 228852)
@@ -31,6 +31,7 @@
 #import <wtf/RetainPtr.h>
 
 #if WK_API_ENABLED
+static bool shouldAccept = true;
 static bool navigationComplete = false;
 static bool navigationFailed = false;
 
@@ -66,7 +67,7 @@
     int64_t deferredWaitTime = 100 * NSEC_PER_MSEC;
     dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime);
     dispatch_after(when, dispatch_get_main_queue(), ^{
-        decisionHandler(WKNavigationResponsePolicyAllow);
+        decisionHandler(shouldAccept ? WKNavigationResponsePolicyAllow : WKNavigationResponsePolicyCancel);
     });
 }
 @end
@@ -82,6 +83,9 @@
     [webView setNavigationDelegate:delegate.get()];
     [webView setUIDelegate:delegate.get()];
 
+    shouldAccept = true;
+    navigationFailed = false;
+    navigationComplete = false;
     [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
     TestWebKitAPI::Util::run(&navigationComplete);
 
@@ -88,6 +92,24 @@
     EXPECT_FALSE(navigationFailed);
 }
 
+TEST(WebKit, PolicyForNavigationResponseCancelAsynchronously)
+{
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto webView = adoptNS([[WKWebView alloc] init]);
+    auto delegate = adoptNS([[TestAsyncNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+    [webView setUIDelegate:delegate.get()];
+
+    shouldAccept = false;
+    navigationFailed = false;
+    navigationComplete = false;
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    TestWebKitAPI::Util::run(&navigationComplete);
+
+    EXPECT_TRUE(navigationFailed);
+}
+
 } // namespace TestWebKitAPI
 
 #endif // WK_API_ENABLED
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to