[Beacon] Add support for quota limitation
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 18 Aug 2017 17:58:41 +0000 (17:58 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 18 Aug 2017 17:58:41 +0000 (17:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175443
<rdar://problem/33729002>

Reviewed by Youenn Fablet.

Source/WebCore:

LoaderStrategy::startPingLoad() now takes a completion handler parameter, allowing CachedResource::load()
to know when a Beacon load is complete. This was needed in order for the fetch in-flight keepalive request
quota limit to work properly for beacon loads as well. We need to know when the beacon load completes in
order to know if the beacon is in-flight or not and only free up its allocated quota once it is no longer
in-flight.

No new tests, updated existing test.

* loader/LoaderStrategy.h:
* loader/PingLoader.cpp:
(WebCore::PingLoader::startPingLoad):
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::load):
* platform/network/PingHandle.h:

Source/WebKit:

WebLoaderStrategy now generates an identifier for ping loads and keep
the completion handler in a local HashMap. Once the ping load is done,
the network process sends an IPC message back to the WebContent process
so that WebLoaderStrategy can look up the completion handler for the
ping load and call it.

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::loadPing):
(WebKit::NetworkConnectionToWebProcess::didFinishPingLoad):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/PingLoad.cpp:
(WebKit::PingLoad::PingLoad):
(WebKit::PingLoad::~PingLoad):
* NetworkProcess/PingLoad.h:
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didFinishPingLoad):
* WebProcess/Network/NetworkProcessConnection.h:
* WebProcess/Network/NetworkProcessConnection.messages.in:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::generatePingLoadIdentifier):
(WebKit::WebLoaderStrategy::startPingLoad):
(WebKit::WebLoaderStrategy::didFinishPingLoad):
* WebProcess/Network/WebLoaderStrategy.h:

Source/WebKitLegacy:

* WebCoreSupport/WebResourceLoadScheduler.cpp:
(WebResourceLoadScheduler::startPingLoad):
* WebCoreSupport/WebResourceLoadScheduler.h:

LayoutTests:

Extend layout test coverage and rebaseline test.

* http/wpt/beacon/beacon-quota-expected.txt:
* http/wpt/beacon/beacon-quota.html:

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/http/wpt/beacon/beacon-quota-expected.txt
LayoutTests/http/wpt/beacon/beacon-quota.html
Source/WebCore/ChangeLog
Source/WebCore/loader/LoaderStrategy.h
Source/WebCore/loader/PingLoader.cpp
Source/WebCore/loader/cache/CachedResource.cpp
Source/WebCore/platform/network/PingHandle.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
Source/WebKit/NetworkProcess/PingLoad.cpp
Source/WebKit/NetworkProcess/PingLoad.h
Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
Source/WebKit/WebProcess/Network/NetworkProcessConnection.h
Source/WebKit/WebProcess/Network/NetworkProcessConnection.messages.in
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
Source/WebKit/WebProcess/Network/WebLoaderStrategy.h
Source/WebKitLegacy/ChangeLog
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h

index 02cfd31b008ef5bc7180d9375ecd685cf166fe08..a0037d0caeb76de4ae538489e2d76646099d87f0 100644 (file)
@@ -1,3 +1,16 @@
+2017-08-18  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Add support for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=175443
+        <rdar://problem/33729002>
+
+        Reviewed by Youenn Fablet.
+
+        Extend layout test coverage and rebaseline test.
+
+        * http/wpt/beacon/beacon-quota-expected.txt:
+        * http/wpt/beacon/beacon-quota.html:
+
 2017-08-18  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed, land TestExpectations for rdar://problem/33850189.
index b78c982473bae413de21cc8eb4509a4402f74327..10b1615390389e9177de6ac5ae46813034588e82 100644 (file)
@@ -1,5 +1,6 @@
-CONSOLE MESSAGE: line 14: Reached maximum amount of queued data of 64Kb for keepalive requests
+CONSOLE MESSAGE: line 44: Reached maximum amount of queued data of 64Kb for keepalive requests
+CONSOLE MESSAGE: line 52: Reached maximum amount of queued data of 64Kb for keepalive requests
 
 PASS Beacon with a body above the Quota Limit should fail. 
-FAIL Multiple Beacons Quota Limit assert_false: Second beacon should not be sent because we reached the quota expected false got true
+PASS Multiple Beacons Quota Limit 
 
index 18e58f83549832d238366fe37123e4335cc62a55..a6c37a3b424d11e7f4da39122c3244aefd9aac78 100644 (file)
@@ -1,10 +1,40 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
 <script>
+    const RESOURCES_DIR = "/WebKit/beacon/resources/";
+
     // We should expect 64KiB of rolling quota for any type of keep-alive request sent.
     var expectedQuota = 65536;
 
+    function checkBeaconReceived(id)
+    {
+        return new Promise(function(resolve, reject) {
+            var checkUrl = RESOURCES_DIR + "beacon-preflight.py?cmd=get&id=" + id;
+            fetch(checkUrl).then(response => {
+                response.json().then(result => {
+                    resolve(result['beacon'] == 1);
+                });
+            }, reject);
+        });
+    }
+
+    function waitForBeacon(id)
+    {
+        return new Promise(function(resolve, reject) {
+            checkBeaconReceived(id).then(wasReceived => {
+                if (wasReceived) {
+                    resolve();
+                    return;
+                }
+                setTimeout(function() {
+                    waitForBeacon(id).then(resolve, reject);
+                }, 10);
+            });
+        });
+    }
+
     function createPayload(payloadSize)
     {
         return new Blob(["*".repeat(payloadSize)]);
         assert_false(navigator.sendBeacon("/", createPayload(expectedQuota + 1)));
     }, "Beacon with a body above the Quota Limit should fail.");
 
-    test(function() {
-        assert_true(navigator.sendBeacon("/", createPayload(expectedQuota)), "Beacon with a body at the Quota Limit should succeed.");
-        assert_false(navigator.sendBeacon("/", createPayload(1)), "Second beacon should not be sent because we reached the quota");
+    promise_test(function() {
+        var id = self.token();
+        var target = RESOURCES_DIR + "beacon-preflight.py?allowCors=1&cmd=put&id=" + id;
+
+        assert_true(navigator.sendBeacon(target, createPayload(expectedQuota)), "Beacon with a body at the Quota Limit should succeed.");
+        assert_false(navigator.sendBeacon(target, createPayload(1)), "Second beacon should not be sent because we reached the quota");
+        return waitForBeacon(id).then(function() {
+            assert_true(navigator.sendBeacon(target, createPayload(1)), "Allocated quota should be returned once the beacon is no longer in flight");
+        });
     }, "Multiple Beacons Quota Limit");
 </script>
index f8a08f06f043ad906d55a53f9adc00286ebecb86..ff6a6b4d08259547c090c85fc5f75e89dda24472 100644 (file)
@@ -1,3 +1,26 @@
+2017-08-18  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Add support for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=175443
+        <rdar://problem/33729002>
+
+        Reviewed by Youenn Fablet.
+
+        LoaderStrategy::startPingLoad() now takes a completion handler parameter, allowing CachedResource::load()
+        to know when a Beacon load is complete. This was needed in order for the fetch in-flight keepalive request
+        quota limit to work properly for beacon loads as well. We need to know when the beacon load completes in
+        order to know if the beacon is in-flight or not and only free up its allocated quota once it is no longer
+        in-flight.
+
+        No new tests, updated existing test.
+
+        * loader/LoaderStrategy.h:
+        * loader/PingLoader.cpp:
+        (WebCore::PingLoader::startPingLoad):
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::load):
+        * platform/network/PingHandle.h:
+
 2017-08-18  Youenn Fablet  <youenn@apple.com>
 
         [Cache API] Add a WK2 implementation of CacheStorageConnection
index c30476e731e94eeff243866dca06315a46d5393f..b64293475cdec54664c4fe8055de683630cf96c6 100644 (file)
@@ -64,7 +64,7 @@ public:
     virtual void suspendPendingRequests() = 0;
     virtual void resumePendingRequests() = 0;
 
-    virtual void createPingHandle(NetworkingContext*, ResourceRequest&, const HTTPHeaderMap& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy*, const FetchOptions&) = 0;
+    virtual void startPingLoad(NetworkingContext*, ResourceRequest&, const HTTPHeaderMap& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy*, const FetchOptions&, WTF::Function<void()>&& completionHandler = { }) = 0;
 
     virtual void storeDerivedDataToCache(const SHA1::Digest& bodyKey, const String& type, const String& partition, WebCore::SharedBuffer&) = 0;
 
index ef64c8f37d2153c913a74b3a01977c782090db7c..a2eb98de3cef1e6c267dc1d6dbc12e2beb034dcf 100644 (file)
@@ -203,7 +203,7 @@ void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, HTTPHeade
     InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame.loader().activeDocumentLoader(), request, ResourceResponse());
 
     auto* contentSecurityPolicy = document.shouldBypassMainWorldContentSecurityPolicy() ? nullptr : document.contentSecurityPolicy();
-    platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, WTFMove(originalRequestHeaders), document.securityOrigin(), contentSecurityPolicy, options);
+    platformStrategies()->loaderStrategy()->startPingLoad(frame.loader().networkingContext(), request, WTFMove(originalRequestHeaders), document.securityOrigin(), contentSecurityPolicy, options);
 }
 
 }
index 6684ec78c67ae7ead0a96a100f29d78efa2f3dc1..829cd9be561863090a381264a475a1979d97324c 100644 (file)
@@ -268,14 +268,15 @@ void CachedResource::load(CachedResourceLoader& cachedResourceLoader)
         }
         // FIXME: We should not special-case Beacon here.
         if (shouldUsePingLoad(type())) {
-        ASSERT(m_origin);
+            ASSERT(m_origin);
             // Beacon is not exposed to workers so it is safe to rely on the document here.
             auto* document = cachedResourceLoader.document();
             auto* contentSecurityPolicy = document && !document->shouldBypassMainWorldContentSecurityPolicy() ? document->contentSecurityPolicy() : nullptr;
             ASSERT(m_originalRequestHeaders);
-            platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, *m_originalRequestHeaders, *m_origin, contentSecurityPolicy, m_options);
-            // FIXME: We currently do not get notified when ping loads finish so we treat them as finishing right away.
-            finishLoading(nullptr);
+            CachedResourceHandle<CachedResource> protectedThis(this);
+            platformStrategies()->loaderStrategy()->startPingLoad(frame.loader().networkingContext(), request, *m_originalRequestHeaders, *m_origin, contentSecurityPolicy, m_options, [this, protectedThis = WTFMove(protectedThis)] {
+                finishLoading(nullptr);
+            });
             return;
         }
     }
index cbafc093569fee1378d833d367f3464a9c458b62..fb210a4b0753c5d74e004354dc3426e515ce4847 100644 (file)
@@ -43,11 +43,12 @@ public:
         No,
     };
     
-    PingHandle(NetworkingContext* networkingContext, const ResourceRequest& request, bool shouldUseCredentialStorage, UsesAsyncCallbacks useAsyncCallbacks, bool shouldFollowRedirects)
+    PingHandle(NetworkingContext* networkingContext, const ResourceRequest& request, bool shouldUseCredentialStorage, UsesAsyncCallbacks useAsyncCallbacks, bool shouldFollowRedirects, WTF::Function<void()>&& completionHandler)
         : m_timeoutTimer(*this, &PingHandle::timeoutTimerFired)
         , m_shouldUseCredentialStorage(shouldUseCredentialStorage)
         , m_shouldFollowRedirects(shouldFollowRedirects)
         , m_usesAsyncCallbacks(useAsyncCallbacks)
+        , m_completionHandler(WTFMove(completionHandler))
     {
         m_handle = ResourceHandle::create(networkingContext, request, this, false, false);
 
@@ -79,6 +80,9 @@ private:
 
     virtual ~PingHandle()
     {
+        if (m_completionHandler)
+            m_completionHandler();
+
         if (m_handle) {
             ASSERT(m_handle->client() == this);
             m_handle->clearClient();
@@ -91,6 +95,7 @@ private:
     bool m_shouldUseCredentialStorage;
     bool m_shouldFollowRedirects;
     UsesAsyncCallbacks m_usesAsyncCallbacks;
+    WTF::Function<void()> m_completionHandler;
 };
 
 } // namespace WebCore
index e38d72dd7954b1f42af6e38c5e244895962ab2f1..d45c507b62dfe452ec5feb046e3edb64d3c89155 100644 (file)
@@ -1,3 +1,35 @@
+2017-08-18  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Add support for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=175443
+        <rdar://problem/33729002>
+
+        Reviewed by Youenn Fablet.
+
+        WebLoaderStrategy now generates an identifier for ping loads and keep
+        the completion handler in a local HashMap. Once the ping load is done,
+        the network process sends an IPC message back to the WebContent process
+        so that WebLoaderStrategy can look up the completion handler for the
+        ping load and call it.
+
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::loadPing):
+        (WebKit::NetworkConnectionToWebProcess::didFinishPingLoad):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/PingLoad.cpp:
+        (WebKit::PingLoad::PingLoad):
+        (WebKit::PingLoad::~PingLoad):
+        * NetworkProcess/PingLoad.h:
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didFinishPingLoad):
+        * WebProcess/Network/NetworkProcessConnection.h:
+        * WebProcess/Network/NetworkProcessConnection.messages.in:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::generatePingLoadIdentifier):
+        (WebKit::WebLoaderStrategy::startPingLoad):
+        (WebKit::WebLoaderStrategy::didFinishPingLoad):
+        * WebProcess/Network/WebLoaderStrategy.h:
+
 2017-08-18  Youenn Fablet  <youenn@apple.com>
 
         [Cache API] Add a WK2 implementation of CacheStorageConnection
index 20c8e972fae14c1d46ca0749f30832a08ee23aa1..acdcc438f694881a215d66afded9711427fbd873 100644 (file)
@@ -239,16 +239,26 @@ void NetworkConnectionToWebProcess::loadPing(NetworkResourceLoadParameters&& loa
 {
 #if USE(NETWORK_SESSION)
     // PingLoad manages its own lifetime, deleting itself when its purpose has been fulfilled.
-    new PingLoad(WTFMove(loadParameters), WTFMove(originalRequestHeaders));
+    new PingLoad(WTFMove(loadParameters), WTFMove(originalRequestHeaders), *this);
 #else
     UNUSED_PARAM(originalRequestHeaders);
     RefPtr<NetworkingContext> context = RemoteNetworkingContext::create(loadParameters.sessionID, loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
 
     // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
-    new PingHandle(context.get(), loadParameters.request, loadParameters.allowStoredCredentials == AllowStoredCredentials, PingHandle::UsesAsyncCallbacks::Yes, loadParameters.shouldFollowRedirects);
+    new PingHandle(context.get(), loadParameters.request, loadParameters.allowStoredCredentials == AllowStoredCredentials, PingHandle::UsesAsyncCallbacks::Yes, loadParameters.shouldFollowRedirects, [this, protectedThis = makeRef(*this), identifier = loadParameters.identifier] {
+        didFinishPingLoad(identifier);
+    });
 #endif
 }
 
+void NetworkConnectionToWebProcess::didFinishPingLoad(uint64_t pingLoadIdentifier)
+{
+    if (!m_connection->isValid())
+        return;
+
+    m_connection->send(Messages::NetworkProcessConnection::DidFinishPingLoad(pingLoadIdentifier), 0);
+}
+
 void NetworkConnectionToWebProcess::removeLoadIdentifier(ResourceLoadIdentifier identifier)
 {
     RefPtr<NetworkResourceLoader> loader = m_networkResourceLoaders.get(identifier);
index c66c7cf982b68d4fe77b212ae42853d98073c92f..524cd8d895eeeb987d78cd8050e9ee8dfa3401db 100644 (file)
@@ -61,6 +61,7 @@ public:
     IPC::Connection& connection() { return m_connection.get(); }
 
     void didCleanupResourceLoader(NetworkResourceLoader&);
+    void didFinishPingLoad(uint64_t pingLoadIdentifier);
 
     bool captureExtraNetworkLoadMetricsEnabled() const { return m_captureExtraNetworkLoadMetricsEnabled; }
 
index 177cea158527366d08e6f35c7061d1a85a5e168d..829b2797fc53704fe04a232aaa2e880c2d522b5a 100644 (file)
@@ -31,6 +31,7 @@
 #include "AuthenticationManager.h"
 #include "Logging.h"
 #include "NetworkCORSPreflightChecker.h"
+#include "NetworkConnectionToWebProcess.h"
 #include "SessionTracker.h"
 #include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/CrossOriginAccessControl.h>
@@ -42,9 +43,10 @@ namespace WebKit {
 
 using namespace WebCore;
 
-PingLoad::PingLoad(NetworkResourceLoadParameters&& parameters, HTTPHeaderMap&& originalRequestHeaders)
+PingLoad::PingLoad(NetworkResourceLoadParameters&& parameters, HTTPHeaderMap&& originalRequestHeaders, Ref<NetworkConnectionToWebProcess>&& connection)
     : m_parameters(WTFMove(parameters))
     , m_originalRequestHeaders(WTFMove(originalRequestHeaders))
+    , m_connection(WTFMove(connection))
     , m_timeoutTimer(*this, &PingLoad::timeoutTimerFired)
     , m_isSameOriginRequest(securityOrigin().canRequest(m_parameters.request.url()))
 {
@@ -64,6 +66,8 @@ PingLoad::PingLoad(NetworkResourceLoadParameters&& parameters, HTTPHeaderMap&& o
 
 PingLoad::~PingLoad()
 {
+    m_connection->didFinishPingLoad(m_parameters.identifier);
+
     if (m_redirectHandler)
         m_redirectHandler({ });
 
index 2ff723e484b5456850536aa9bebc20a3c1599e1c..457ef6ce4fc82b51e80fcb0aa7cf23cdad4b1015 100644 (file)
@@ -39,10 +39,11 @@ class URL;
 namespace WebKit {
 
 class NetworkCORSPreflightChecker;
+class NetworkConnectionToWebProcess;
 
 class PingLoad final : private NetworkDataTaskClient {
 public:
-    PingLoad(NetworkResourceLoadParameters&&, WebCore::HTTPHeaderMap&& originalRequestHeaders);
+    PingLoad(NetworkResourceLoadParameters&&, WebCore::HTTPHeaderMap&& originalRequestHeaders, Ref<NetworkConnectionToWebProcess>&&);
     
 private:
     ~PingLoad();
@@ -70,6 +71,7 @@ private:
     
     NetworkResourceLoadParameters m_parameters;
     WebCore::HTTPHeaderMap m_originalRequestHeaders; // Needed for CORS checks.
+    Ref<NetworkConnectionToWebProcess> m_connection;
     RefPtr<NetworkDataTask> m_task;
     WebCore::Timer m_timeoutTimer;
     std::unique_ptr<NetworkCORSPreflightChecker> m_corsPreflightChecker;
index 5a5f97c11951e344982410ba07b0267f87a6686d..42a2db20e555f8cc910729de7da5435b5479904d 100644 (file)
@@ -135,6 +135,11 @@ void NetworkProcessConnection::didWriteBlobsToTemporaryFiles(uint64_t requestIde
         handler(filenames);
 }
 
+void NetworkProcessConnection::didFinishPingLoad(uint64_t pingLoadIdentifier)
+{
+    WebProcess::singleton().webLoaderStrategy().didFinishPingLoad(pingLoadIdentifier);
+}
+
 #if ENABLE(SHAREABLE_RESOURCE)
 void NetworkProcessConnection::didCacheResource(const ResourceRequest& request, const ShareableResource::Handle& handle, PAL::SessionID sessionID)
 {
index 56aca8bf4c1ca6be6b3d859d2b4191639b3268fb..09cd05b9ce9a877a6cd7966c219b0c53dc9c4a89 100644 (file)
@@ -73,6 +73,7 @@ private:
     void didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference messageReceiverName, IPC::StringReference messageName) override;
 
     void didWriteBlobsToTemporaryFiles(uint64_t requestIdentifier, const Vector<String>& filenames);
+    void didFinishPingLoad(uint64_t pingLoadIdentifier);
 
 #if ENABLE(SHAREABLE_RESOURCE)
     // Message handlers.
index 23a2eca019fec9dc0a38f60ed993a2ac258debad..b674f7eb4919685ebb432aaa869a7e2a9094155c 100644 (file)
@@ -27,4 +27,5 @@ messages -> NetworkProcessConnection LegacyReceiver {
 #endif
 
     DidWriteBlobsToTemporaryFiles(uint64_t requestIdentifier, Vector<String> filenames)
+    DidFinishPingLoad(uint64_t pingLoadIdentifier)
 }
index 919e2f8ca4d8f353b4fccc5556ea23dfd55c5f1f..69fb91c82b8ae607d10f6f128b92b396c196355c 100644 (file)
@@ -350,6 +350,10 @@ void WebLoaderStrategy::networkProcessCrashed()
         scheduleInternallyFailedLoad(*loader.value->resourceLoader());
 
     m_webResourceLoaders.clear();
+
+    auto pingLoadCompletionHandlers = WTFMove(m_pingLoadCompletionHandlers);
+    for (auto& pingLoadCompletionHandler : pingLoadCompletionHandlers.values())
+        pingLoadCompletionHandler();
 }
 
 void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, unsigned long resourceLoadIdentifier, const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
@@ -386,12 +390,21 @@ void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, un
     }
 }
 
-void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, const HTTPHeaderMap& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy* contentSecurityPolicy, const FetchOptions& options)
+static uint64_t generatePingLoadIdentifier()
+{
+    static uint64_t identifier = 0;
+    return ++identifier;
+}
+
+void WebLoaderStrategy::startPingLoad(NetworkingContext* networkingContext, ResourceRequest& request, const HTTPHeaderMap& originalRequestHeaders, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy* contentSecurityPolicy, const FetchOptions& options, WTF::Function<void()>&& completionHandler)
 {
     // It's possible that call to createPingHandle might be made during initial empty Document creation before a NetworkingContext exists.
     // It is not clear that we should send ping loads during that process anyways.
-    if (!networkingContext)
+    if (!networkingContext) {
+        if (completionHandler)
+            completionHandler();
         return;
+    }
 
     WebFrameNetworkingContext* webContext = static_cast<WebFrameNetworkingContext*>(networkingContext);
     WebFrameLoaderClient* webFrameLoaderClient = webContext->webFrameLoaderClient();
@@ -399,6 +412,7 @@ void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, R
     WebPage* webPage = webFrame ? webFrame->page() : nullptr;
     
     NetworkResourceLoadParameters loadParameters;
+    loadParameters.identifier = generatePingLoadIdentifier();
     loadParameters.request = request;
     loadParameters.sourceOrigin = WTFMove(sourceOrigin);
     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
@@ -409,9 +423,18 @@ void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, R
     if (contentSecurityPolicy)
         loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
 
+    if (completionHandler)
+        m_pingLoadCompletionHandlers.add(loadParameters.identifier, WTFMove(completionHandler));
+
     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::LoadPing(WTFMove(loadParameters), originalRequestHeaders), 0);
 }
 
+void WebLoaderStrategy::didFinishPingLoad(uint64_t pingLoadIdentifier)
+{
+    if (auto completionHandler = m_pingLoadCompletionHandlers.take(pingLoadIdentifier))
+        completionHandler();
+}
+
 void WebLoaderStrategy::storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer& data)
 {
     NetworkCache::DataKey key { partition, type, bodyHash };
index 7b7cde78facfb08ea2388a604ac7b7aef5e6928f..27fea04f3b475b8863634a05f48ed90b1815035f 100644 (file)
@@ -59,7 +59,8 @@ public:
     void suspendPendingRequests() final;
     void resumePendingRequests() final;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap& originalRequestHeaders, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) final;
+    void startPingLoad(WebCore::NetworkingContext*, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap& originalRequestHeaders, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&, WTF::Function<void()>&& completionHandler) final;
+    void didFinishPingLoad(uint64_t pingLoadIdentifier);
 
     void storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer&) final;
 
@@ -84,6 +85,7 @@ private:
     
     HashMap<unsigned long, RefPtr<WebResourceLoader>> m_webResourceLoaders;
     HashMap<unsigned long, WebURLSchemeTaskProxy*> m_urlSchemeTasks;
+    HashMap<unsigned long, WTF::Function<void()>> m_pingLoadCompletionHandlers;
 };
 
 } // namespace WebKit
index dd3cde06f7372a88d6989c354d6ec9afeba34fba..d973aabff039852ffa17c5c970e1bc4e50aac2ea 100644 (file)
@@ -1,3 +1,15 @@
+2017-08-18  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Add support for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=175443
+        <rdar://problem/33729002>
+
+        Reviewed by Youenn Fablet.
+
+        * WebCoreSupport/WebResourceLoadScheduler.cpp:
+        (WebResourceLoadScheduler::startPingLoad):
+        * WebCoreSupport/WebResourceLoadScheduler.h:
+
 2017-08-17  Chris Dumez  <cdumez@apple.com>
 
         Regression(r220817): We should only copy the original request headers for Ping loads
index 82a81b7ea68d367ed8ce78eaee0344987e53e7fe..3a752f58c4671778128e7319b558fc66183a4ee3 100644 (file)
@@ -363,9 +363,9 @@ bool WebResourceLoadScheduler::HostInformation::limitRequests(ResourceLoadPriori
     return m_requestsLoading.size() >= (webResourceLoadScheduler().isSerialLoadingEnabled() ? 1 : m_maxRequestsInFlight);
 }
 
-void WebResourceLoadScheduler::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, const HTTPHeaderMap&, Ref<SecurityOrigin>&&, WebCore::ContentSecurityPolicy*, const FetchOptions& options)
+void WebResourceLoadScheduler::startPingLoad(NetworkingContext* networkingContext, ResourceRequest& request, const HTTPHeaderMap&, Ref<SecurityOrigin>&&, WebCore::ContentSecurityPolicy*, const FetchOptions& options, WTF::Function<void()>&& completionHandler)
 {
     // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
-    new PingHandle(networkingContext, request, options.credentials != FetchOptions::Credentials::Omit, PingHandle::UsesAsyncCallbacks::No, options.redirect == FetchOptions::Redirect::Follow);
+    new PingHandle(networkingContext, request, options.credentials != FetchOptions::Credentials::Omit, PingHandle::UsesAsyncCallbacks::No, options.redirect == FetchOptions::Redirect::Follow, WTFMove(completionHandler));
 }
 
index 20a8d56e215768c6556082ea1559812d57a262dd..3701bc33b70a8ee9e7b77aae2f24d6d03ee4fa0e 100644 (file)
@@ -44,26 +44,26 @@ class SecurityOrigin;
 
 WebResourceLoadScheduler& webResourceLoadScheduler();
 
-class WebResourceLoadScheduler : public WebCore::LoaderStrategy {
+class WebResourceLoadScheduler final : public WebCore::LoaderStrategy {
     WTF_MAKE_NONCOPYABLE(WebResourceLoadScheduler); WTF_MAKE_FAST_ALLOCATED;
 public:
     WebResourceLoadScheduler();
 
-    RefPtr<WebCore::SubresourceLoader> loadResource(WebCore::Frame&, WebCore::CachedResource&, const WebCore::ResourceRequest&, const WebCore::ResourceLoaderOptions&) override;
-    void loadResourceSynchronously(WebCore::NetworkingContext*, unsigned long, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ClientCredentialPolicy, WebCore::ResourceError&, WebCore::ResourceResponse&, Vector<char>&) override;
-    void remove(WebCore::ResourceLoader*) override;
-    void setDefersLoading(WebCore::ResourceLoader*, bool) override;
-    void crossOriginRedirectReceived(WebCore::ResourceLoader*, const WebCore::URL& redirectURL) override;
+    RefPtr<WebCore::SubresourceLoader> loadResource(WebCore::Frame&, WebCore::CachedResource&, const WebCore::ResourceRequest&, const WebCore::ResourceLoaderOptions&) final;
+    void loadResourceSynchronously(WebCore::NetworkingContext*, unsigned long, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ClientCredentialPolicy, WebCore::ResourceError&, WebCore::ResourceResponse&, Vector<char>&) final;
+    void remove(WebCore::ResourceLoader*) final;
+    void setDefersLoading(WebCore::ResourceLoader*, bool) final;
+    void crossOriginRedirectReceived(WebCore::ResourceLoader*, const WebCore::URL& redirectURL) final;
     
-    void servePendingRequests(WebCore::ResourceLoadPriority minimumPriority = WebCore::ResourceLoadPriority::VeryLow) override;
-    void suspendPendingRequests() override;
-    void resumePendingRequests() override;
+    void servePendingRequests(WebCore::ResourceLoadPriority minimumPriority = WebCore::ResourceLoadPriority::VeryLow) final;
+    void suspendPendingRequests() final;
+    void resumePendingRequests() final;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) override;
+    void startPingLoad(WebCore::NetworkingContext*, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&, WTF::Function<void()>&& completionHandler) final;
 
-    void storeDerivedDataToCache(const SHA1::Digest&, const String&, const String&, WebCore::SharedBuffer&) override { }
+    void storeDerivedDataToCache(const SHA1::Digest&, const String&, const String&, WebCore::SharedBuffer&) final { }
 
-    void setCaptureExtraNetworkLoadMetricsEnabled(bool) override { }
+    void setCaptureExtraNetworkLoadMetricsEnabled(bool) final { }
 
     bool isSerialLoadingEnabled() const { return m_isSerialLoadingEnabled; }
     void setSerialLoadingEnabled(bool b) { m_isSerialLoadingEnabled = b; }