[WK2][SpeculativeRevalidation] Save to disk cache relationship between resources
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2015 19:29:24 +0000 (19:29 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2015 19:29:24 +0000 (19:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150951
<rdar://problem/23092196>

Reviewed by Darin Adler.

This patch is a first step towards speculative revalidation support in
the WebKit network cache. It maps sub-resources to the main resource
that caused them to be requested. We then write this information to the
network cache, as a list of subresource keys for each main resource,
even if the main resource is not cacheable.

To map sub-resources to main resources, we track the loads happening
in each frame and store the key of the main resource for the frame,
as well as the key of each sub-resource later loaded in the frame. We
use a HysteresisActivity to detect when loads settle down in each frame
(no loads happen for a while) and we then write the information to the
disk. If a new main resource is loaded in a frame where we were already
tracking a load, we save the data to disk before tracking the new load,
instead of waiting for the HysteresisActivity to detect the end of the
load.

The feature is currently behind a compile-time flag that is enabled on
Mac and iOS only. It is also behind a runtime flag (NSUserDefaults)
that is disabled by default.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::start):
Pass frameID in addition to the pageID. We need to globally identify
frames (using <pageID, frameID> pair) to be able to track loads in
each frame.

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::Cache::initialize):
Only initialize the SpeculativeLoader if the
enableNetworkCacheSpeculativeRevalidation run-time flag is set.

(WebKit::NetworkCache::Cache::retrieve):
Register the load with the SpeculativeLoader.

* NetworkProcess/cache/NetworkCacheKey.h:
(WebKit::NetworkCache::Key::Key):
(WebKit::NetworkCache::Key::isHashTableDeletedValue):
(WebKit::NetworkCache::Key::range):
(WTF::NetworkCacheKeyHash::hash):
(WTF::NetworkCacheKeyHash::equal):
(WTF::HashTraits<WebKit::NetworkCache::Key>::isEmptyValue):
Add needed HashTraits for NetworkCache::Key so it can be used as key in
HashMap / HashSet.

* NetworkProcess/cache/NetworkCacheSpeculativeLoader.cpp: Added.
* NetworkProcess/cache/NetworkCacheSpeculativeLoader.h: Added.
Add new NetworkCacheSpeculativeLoader class that takes care of tracking
loads in each frame to map subresources to main resources and then write
this information to the network disk cache. In the future, this class we
also take care of triggering speculative revalidations, thus the naming.

* NetworkProcess/cocoa/NetworkProcessCocoa.mm:
(WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa):
* NetworkProcess/soup/NetworkProcessSoup.cpp:
(WebKit::NetworkProcess::platformInitializeNetworkProcess):
* Shared/Network/NetworkProcessCreationParameters.cpp:
(WebKit::NetworkProcessCreationParameters::encode):
(WebKit::NetworkProcessCreationParameters::decode):
* Shared/Network/NetworkProcessCreationParameters.h:
* UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::registerUserDefaultsIfNeeded):
(WebKit::WebProcessPool::platformInitializeNetworkProcess):
Add new NetworkProcess parameter to control at runtime if speculative loading
should be enabled or not. It is disabled by default.

* WebKit2.xcodeproj/project.pbxproj:
Add new files to XCode project.

* config.h:
Add ENABLE_NETWORK_CACHE_SPECULATIVE_REVALIDATION build flag for the new
feature that is enable by default on COCOA.

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

20 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCache.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.h [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cocoa/NetworkProcessCocoa.mm
Source/WebKit2/NetworkProcess/soup/NetworkProcessSoup.cpp
Source/WebKit2/Platform/Logging.h
Source/WebKit2/Shared/Network/NetworkProcessCreationParameters.cpp
Source/WebKit2/Shared/Network/NetworkProcessCreationParameters.h
Source/WebKit2/UIProcess/Cocoa/WebProcessPoolCocoa.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/config.h

index a219383..2dfd74e 100644 (file)
@@ -1,5 +1,85 @@
 2015-11-06  Chris Dumez  <cdumez@apple.com>
 
+        [WK2][SpeculativeRevalidation] Save to disk cache relationship between resources
+        https://bugs.webkit.org/show_bug.cgi?id=150951
+        <rdar://problem/23092196>
+
+        Reviewed by Darin Adler.
+
+        This patch is a first step towards speculative revalidation support in
+        the WebKit network cache. It maps sub-resources to the main resource
+        that caused them to be requested. We then write this information to the
+        network cache, as a list of subresource keys for each main resource,
+        even if the main resource is not cacheable.
+
+        To map sub-resources to main resources, we track the loads happening
+        in each frame and store the key of the main resource for the frame,
+        as well as the key of each sub-resource later loaded in the frame. We
+        use a HysteresisActivity to detect when loads settle down in each frame
+        (no loads happen for a while) and we then write the information to the
+        disk. If a new main resource is loaded in a frame where we were already
+        tracking a load, we save the data to disk before tracking the new load,
+        instead of waiting for the HysteresisActivity to detect the end of the
+        load.
+
+        The feature is currently behind a compile-time flag that is enabled on
+        Mac and iOS only. It is also behind a runtime flag (NSUserDefaults)
+        that is disabled by default.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::start):
+        Pass frameID in addition to the pageID. We need to globally identify
+        frames (using <pageID, frameID> pair) to be able to track loads in
+        each frame.
+
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::Cache::initialize):
+        Only initialize the SpeculativeLoader if the
+        enableNetworkCacheSpeculativeRevalidation run-time flag is set.
+
+        (WebKit::NetworkCache::Cache::retrieve):
+        Register the load with the SpeculativeLoader.
+
+        * NetworkProcess/cache/NetworkCacheKey.h:
+        (WebKit::NetworkCache::Key::Key):
+        (WebKit::NetworkCache::Key::isHashTableDeletedValue):
+        (WebKit::NetworkCache::Key::range):
+        (WTF::NetworkCacheKeyHash::hash):
+        (WTF::NetworkCacheKeyHash::equal):
+        (WTF::HashTraits<WebKit::NetworkCache::Key>::isEmptyValue):
+        Add needed HashTraits for NetworkCache::Key so it can be used as key in
+        HashMap / HashSet.
+
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoader.cpp: Added.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoader.h: Added.
+        Add new NetworkCacheSpeculativeLoader class that takes care of tracking
+        loads in each frame to map subresources to main resources and then write
+        this information to the network disk cache. In the future, this class we
+        also take care of triggering speculative revalidations, thus the naming.
+
+        * NetworkProcess/cocoa/NetworkProcessCocoa.mm:
+        (WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa):
+        * NetworkProcess/soup/NetworkProcessSoup.cpp:
+        (WebKit::NetworkProcess::platformInitializeNetworkProcess):
+        * Shared/Network/NetworkProcessCreationParameters.cpp:
+        (WebKit::NetworkProcessCreationParameters::encode):
+        (WebKit::NetworkProcessCreationParameters::decode):
+        * Shared/Network/NetworkProcessCreationParameters.h:
+        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
+        (WebKit::registerUserDefaultsIfNeeded):
+        (WebKit::WebProcessPool::platformInitializeNetworkProcess):
+        Add new NetworkProcess parameter to control at runtime if speculative loading
+        should be enabled or not. It is disabled by default.
+
+        * WebKit2.xcodeproj/project.pbxproj:
+        Add new files to XCode project.
+
+        * config.h:
+        Add ENABLE_NETWORK_CACHE_SPECULATIVE_REVALIDATION build flag for the new
+        feature that is enable by default on COCOA.
+
+2015-11-06  Chris Dumez  <cdumez@apple.com>
+
         Unreviewed, remove empty #if block landed by mistake in r192038.
 
         * NetworkProcess/NetworkLoad.cpp:
index 408f8b6..61d2558 100644 (file)
@@ -128,7 +128,7 @@ void NetworkResourceLoader::start()
     }
 
     RefPtr<NetworkResourceLoader> loader(this);
-    NetworkCache::singleton().retrieve(originalRequest(), m_parameters.webPageID, [loader](std::unique_ptr<NetworkCache::Entry> entry) {
+    NetworkCache::singleton().retrieve(originalRequest(), m_parameters.webPageID, m_parameters.webFrameID, [loader](std::unique_ptr<NetworkCache::Entry> entry) {
         if (loader->hasOneRef()) {
             // The loader has been aborted and is only held alive by this lambda.
             return;
index 404317b..a11be2e 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(NETWORK_CACHE)
 
 #include "Logging.h"
+#include "NetworkCacheSpeculativeLoader.h"
 #include "NetworkCacheStatistics.h"
 #include "NetworkCacheStorage.h"
 #include <WebCore/CacheValidation.h>
@@ -71,11 +72,16 @@ static void dumpFileChanged(Cache* cache)
 }
 #endif
 
-bool Cache::initialize(const String& cachePath, bool enableEfficacyLogging)
+bool Cache::initialize(const String& cachePath, const Parameters& parameters)
 {
     m_storage = Storage::open(cachePath);
 
-    if (enableEfficacyLogging)
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    if (parameters.enableNetworkCacheSpeculativeRevalidation)
+        m_speculativeLoader = std::make_unique<SpeculativeLoader>(*m_storage);
+#endif
+
+    if (parameters.enableEfficacyLogging)
         m_statistics = Statistics::open(cachePath);
 
 #if PLATFORM(COCOA)
@@ -337,7 +343,7 @@ static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalR
     return StoreDecision::Yes;
 }
 
-void Cache::retrieve(const WebCore::ResourceRequest& originalRequest, uint64_t webPageID, std::function<void (std::unique_ptr<Entry>)> completionHandler)
+void Cache::retrieve(const WebCore::ResourceRequest& originalRequest, uint64_t webPageID, uint64_t webFrameID, std::function<void (std::unique_ptr<Entry>)> completionHandler)
 {
     ASSERT(isEnabled());
     ASSERT(originalRequest.url().protocolIsInHTTPFamily());
@@ -348,6 +354,14 @@ void Cache::retrieve(const WebCore::ResourceRequest& originalRequest, uint64_t w
         m_statistics->recordRetrievalRequest(webPageID);
 
     Key storageKey = makeCacheKey(originalRequest);
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    if (m_speculativeLoader)
+        m_speculativeLoader->registerLoad(webPageID, webFrameID, originalRequest, storageKey);
+#else
+    UNUSED_PARAM(webFrameID);
+#endif
+
     auto retrieveDecision = makeRetrieveDecision(originalRequest);
     if (retrieveDecision != RetrieveDecision::Yes) {
         if (m_statistics)
index fb4f326..78389e0 100644 (file)
@@ -44,6 +44,7 @@ namespace WebKit {
 namespace NetworkCache {
 
 class Cache;
+class SpeculativeLoader;
 class Statistics;
 
 Cache& singleton();
@@ -87,13 +88,19 @@ class Cache {
     WTF_MAKE_NONCOPYABLE(Cache);
     friend class WTF::NeverDestroyed<Cache>;
 public:
-    bool initialize(const String& cachePath, bool enableEfficacyLogging);
+    struct Parameters {
+        bool enableEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+        bool enableNetworkCacheSpeculativeRevalidation;
+#endif
+    };
+    bool initialize(const String& cachePath, const Parameters&);
     void setCapacity(size_t);
 
     bool isEnabled() const { return !!m_storage; }
 
     // Completion handler may get called back synchronously on failure.
-    void retrieve(const WebCore::ResourceRequest&, uint64_t webPageID, std::function<void (std::unique_ptr<Entry>)>);
+    void retrieve(const WebCore::ResourceRequest&, uint64_t webPageID, uint64_t webFrameID, std::function<void (std::unique_ptr<Entry>)>);
     void store(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, std::function<void (MappedBody&)>);
     void update(const WebCore::ResourceRequest&, uint64_t webPageID, const Entry&, const WebCore::ResourceResponse& validatingResponse);
 
@@ -116,6 +123,9 @@ private:
     void deleteDumpFile();
 
     std::unique_ptr<Storage> m_storage;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    std::unique_ptr<SpeculativeLoader> m_speculativeLoader;
+#endif
     std::unique_ptr<Statistics> m_statistics;
 };
 
index e6d8fc9..e71777b 100644 (file)
@@ -79,7 +79,7 @@ Storage::Record Entry::encodeAsStorageRecord() const
 
 std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storageEntry)
 {
-    std::unique_ptr<Entry> entry(new Entry(storageEntry));
+    auto entry = std::make_unique<Entry>(storageEntry);
 
     Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
     if (!decoder.decode(entry->m_response))
index efa5e68..8de393f 100644 (file)
@@ -46,6 +46,7 @@ class Entry {
     WTF_MAKE_NONCOPYABLE(Entry); WTF_MAKE_FAST_ALLOCATED;
 public:
     Entry(const Key&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, const Vector<std::pair<String, String>>& varyingRequestHeaders);
+    explicit Entry(const Storage::Record&);
 
     Storage::Record encodeAsStorageRecord() const;
     static std::unique_ptr<Entry> decodeStorageRecord(const Storage::Record&);
@@ -68,7 +69,6 @@ public:
     void asJSON(StringBuilder&, const Storage::RecordInfo&) const;
 
 private:
-    Entry(const Storage::Record&);
     void initializeBufferFromStorageRecord() const;
 #if ENABLE(SHAREABLE_RESOURCE)
     void initializeShareableResourceHandleFromStorageRecord() const;
index b828d49..1f06a65 100644 (file)
@@ -54,6 +54,11 @@ Key::Key(const String& partition, const String& type, const String& range, const
 {
 }
 
+Key::Key(WTF::HashTableDeletedValueType)
+    : m_identifier(WTF::HashTableDeletedValue)
+{
+}
+
 Key& Key::operator=(const Key& other)
 {
     m_partition = other.m_partition.isolatedCopy();
index e633b65..12a7007 100644 (file)
@@ -49,11 +49,15 @@ public:
     Key& operator=(const Key&);
     Key& operator=(Key&&) = default;
 
+    Key(WTF::HashTableDeletedValueType);
+    bool isHashTableDeletedValue() const { return m_identifier.isHashTableDeletedValue(); }
+
     bool isNull() const { return m_identifier.isNull(); }
 
     const String& partition() const { return m_partition; }
     const String& identifier() const { return m_identifier; }
     const String& type() const { return m_type; }
+    const String& range() const { return m_range; }
 
     HashType hash() const { return m_hash; }
 
@@ -81,5 +85,36 @@ private:
 }
 }
 
+namespace WTF {
+
+struct NetworkCacheKeyHash {
+    static unsigned hash(const WebKit::NetworkCache::Key& key)
+    {
+        static_assert(SHA1::hashSize >= sizeof(unsigned), "Hash size must be greater than sizeof(unsigned)");
+        return *reinterpret_cast<const unsigned*>(key.hash().data());
+    }
+
+    static bool equal(const WebKit::NetworkCache::Key& a, const WebKit::NetworkCache::Key& b)
+    {
+        return a == b;
+    }
+
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<WebKit::NetworkCache::Key> {
+    typedef NetworkCacheKeyHash Hash;
+};
+
+template<> struct HashTraits<WebKit::NetworkCache::Key> : SimpleClassHashTraits<WebKit::NetworkCache::Key> {
+    static const bool emptyValueIsZero = false;
+
+    static const bool hasIsEmptyValueFunction = true;
+    static bool isEmptyValue(const WebKit::NetworkCache::Key& key) { return key.isNull(); }
+};
+
+} // namespace WTF
+
 #endif
 #endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.cpp
new file mode 100644 (file)
index 0000000..43f5c95
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include "NetworkCacheSpeculativeLoader.h"
+
+#include "Logging.h"
+#include "NetworkCacheSubresourcesEntry.h"
+#include <WebCore/HysteresisActivity.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+namespace NetworkCache {
+
+using namespace WebCore;
+
+static const AtomicString& subresourcesType()
+{
+    ASSERT(RunLoop::isMain());
+    static NeverDestroyed<const AtomicString> resource("subresources", AtomicString::ConstructFromLiteral);
+    return resource;
+}
+
+static inline Key makeSubresourcesKey(const Key& resourceKey)
+{
+    return Key(resourceKey.partition(), subresourcesType(), resourceKey.range(), resourceKey.identifier());
+}
+
+class SpeculativeLoader::PendingFrameLoad {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    PendingFrameLoad(const Key& mainResourceKey, std::function<void()> completionHandler)
+        : m_mainResourceKey(mainResourceKey)
+        , m_completionHandler(completionHandler)
+        , m_loadHysteresisActivity([this](HysteresisState state) { if (state == HysteresisState::Stopped) m_completionHandler(); })
+    { }
+
+    void registerSubresource(const Key& subresourceKey)
+    {
+        ASSERT(RunLoop::isMain());
+        m_subresourceKeys.add(subresourceKey);
+        m_loadHysteresisActivity.impulse();
+    }
+
+    Optional<Storage::Record> encodeAsSubresourcesRecord()
+    {
+        ASSERT(RunLoop::isMain());
+        if (m_subresourceKeys.isEmpty())
+            return { };
+
+        auto subresourcesStorageKey = makeSubresourcesKey(m_mainResourceKey);
+        Vector<Key> subresourceKeys;
+        copyToVector(m_subresourceKeys, subresourceKeys);
+
+#if !LOG_DISABLED
+        LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Saving to disk list of subresources for '%s':", m_mainResourceKey.identifier().utf8().data());
+        for (auto& subresourceKey : subresourceKeys)
+            LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) * Subresource: '%s'.", subresourceKey.identifier().utf8().data());
+#endif
+
+        return SubresourcesEntry(subresourcesStorageKey, WTF::move(subresourceKeys)).encodeAsStorageRecord();
+    }
+
+    void markAsCompleted()
+    {
+        ASSERT(RunLoop::isMain());
+        m_completionHandler();
+    }
+
+private:
+    Key m_mainResourceKey;
+    HashSet<Key> m_subresourceKeys;
+    std::function<void()> m_completionHandler;
+    HysteresisActivity m_loadHysteresisActivity;
+};
+
+SpeculativeLoader::SpeculativeLoader(Storage& storage)
+    : m_storage(storage)
+{
+}
+
+SpeculativeLoader::~SpeculativeLoader()
+{
+}
+
+void SpeculativeLoader::registerLoad(uint64_t webPageID, uint64_t webFrameID, const ResourceRequest& request, const Key& resourceKey)
+{
+    ASSERT(RunLoop::isMain());
+
+    if (!request.url().protocolIsInHTTPFamily() || request.httpMethod() != "GET")
+        return;
+
+    auto frameKey = std::make_pair(webPageID, webFrameID);
+    auto isMainResource = request.requester() == ResourceRequest::Requester::Main;
+    if (isMainResource) {
+        // Mark previous load in this frame as completed if necessary.
+        if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameKey))
+            pendingFrameLoad->markAsCompleted();
+
+        // Start tracking loads in this frame.
+        m_pendingFrameLoads.add(frameKey, std::make_unique<PendingFrameLoad>(resourceKey, [this, frameKey]() {
+            auto frameLoad = m_pendingFrameLoads.take(frameKey);
+            auto optionalRecord = frameLoad->encodeAsSubresourcesRecord();
+            if (!optionalRecord)
+                return;
+            m_storage.store(optionalRecord.value(), [](const Data&) { });
+        }));
+        return;
+    }
+
+    if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameKey))
+        pendingFrameLoad->registerSubresource(resourceKey);
+}
+
+} // namespace NetworkCache
+
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoader.h
new file mode 100644 (file)
index 0000000..2bde337
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NetworkCacheSpeculativeLoader_h
+#define NetworkCacheSpeculativeLoader_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include "NetworkCacheStorage.h"
+#include <WebCore/ResourceRequest.h>
+#include <wtf/HashMap.h>
+
+namespace WebKit {
+
+namespace NetworkCache {
+
+class SpeculativeLoader {
+public:
+    explicit SpeculativeLoader(Storage&);
+    ~SpeculativeLoader();
+
+    void registerLoad(uint64_t webPageID, uint64_t webFrameID, const WebCore::ResourceRequest&, const Key& resourceKey);
+
+private:
+    Storage& m_storage;
+
+    class PendingFrameLoad;
+    using GlobalFrameID = std::pair<uint64_t /*webPageID*/, uint64_t /*webFrameID*/>;
+    HashMap<GlobalFrameID, std::unique_ptr<PendingFrameLoad>> m_pendingFrameLoads;
+};
+
+} // namespace NetworkCache
+
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#endif // NetworkCacheSpeculativeLoader_h
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp
new file mode 100644 (file)
index 0000000..77dd000
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include "NetworkCacheSubresourcesEntry.h"
+
+#include "Logging.h"
+#include "NetworkCacheCoders.h"
+#include "NetworkCacheDecoder.h"
+#include "NetworkCacheEncoder.h"
+
+namespace WebKit {
+namespace NetworkCache {
+
+Storage::Record SubresourcesEntry::encodeAsStorageRecord() const
+{
+    Encoder encoder;
+    encoder << m_subresourceKeys;
+
+    encoder.encodeChecksum();
+
+    return { m_key, m_timeStamp, { encoder.buffer(), encoder.bufferSize() } , { } };
+}
+
+std::unique_ptr<SubresourcesEntry> SubresourcesEntry::decodeStorageRecord(const Storage::Record& storageEntry)
+{
+    auto entry = std::make_unique<SubresourcesEntry>(storageEntry);
+
+    Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
+    if (!decoder.decode(entry->m_subresourceKeys))
+        return nullptr;
+
+    if (!decoder.verifyChecksum()) {
+        LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
+        return nullptr;
+    }
+
+    return entry;
+}
+
+SubresourcesEntry::SubresourcesEntry(const Storage::Record& storageEntry)
+    : m_key(storageEntry.key)
+    , m_timeStamp(storageEntry.timeStamp)
+{
+    ASSERT(m_key.type() == "subresources");
+}
+
+SubresourcesEntry::SubresourcesEntry(const Key& key, Vector<Key>&& subresourceKeys)
+    : m_key(key)
+    , m_timeStamp(std::chrono::system_clock::now())
+    , m_subresourceKeys(WTF::move(subresourceKeys))
+{
+    ASSERT(m_key.type() == "subresources");
+}
+
+} // namespace WebKit
+} // namespace NetworkCache
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h b/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h
new file mode 100644 (file)
index 0000000..beadbd2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NetworkCacheSubresourcesEntry_h
+#define NetworkCacheSubresourcesEntry_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include "NetworkCacheStorage.h"
+
+namespace WebKit {
+namespace NetworkCache {
+
+class SubresourcesEntry {
+    WTF_MAKE_NONCOPYABLE(SubresourcesEntry); WTF_MAKE_FAST_ALLOCATED;
+public:
+    SubresourcesEntry(const Key&, Vector<Key>&& subresourceKeys);
+    explicit SubresourcesEntry(const Storage::Record&);
+
+    Storage::Record encodeAsStorageRecord() const;
+    static std::unique_ptr<SubresourcesEntry> decodeStorageRecord(const Storage::Record&);
+
+    const Key& key() const { return m_key; }
+    std::chrono::system_clock::time_point timeStamp() const { return m_timeStamp; }
+    const Vector<Key>& subresourceKeys() const { return m_subresourceKeys; }
+
+private:
+    Key m_key;
+    std::chrono::system_clock::time_point m_timeStamp;
+    Storage::Record m_sourceStorageRecord;
+    Vector<Key> m_subresourceKeys;
+};
+
+} // namespace WebKit
+} // namespace NetworkCache
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#endif // NetworkCacheSubresourcesEntry_h
index cd22084..5d55cea 100644 (file)
@@ -95,10 +95,18 @@ void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessC
     if (!m_diskCacheDirectory.isNull()) {
         SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
 #if ENABLE(NETWORK_CACHE)
-        if (parameters.shouldEnableNetworkCache && NetworkCache::singleton().initialize(m_diskCacheDirectory, parameters.shouldEnableNetworkCacheEfficacyLogging)) {
-            RetainPtr<NSURLCache> urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
-            [NSURLCache setSharedURLCache:urlCache.get()];
-            return;
+        if (parameters.shouldEnableNetworkCache) {
+            NetworkCache::Cache::Parameters cacheParameters = {
+                parameters.shouldEnableNetworkCacheEfficacyLogging
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+                , parameters.shouldEnableNetworkCacheSpeculativeRevalidation
+#endif
+            };
+            if (NetworkCache::singleton().initialize(m_diskCacheDirectory, cacheParameters)) {
+                auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
+                [NSURLCache setSharedURLCache:urlCache.get()];
+                return;
+            }
         }
 #endif
         String nsURLCacheDirectory = m_diskCacheDirectory;
index 910e619..f9a0ff8 100644 (file)
@@ -74,7 +74,7 @@ void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreati
     // Clear the old soup cache if it exists.
     SoupNetworkSession::defaultSession().clearCache(WebCore::directoryName(m_diskCacheDirectory));
 
-    NetworkCache::singleton().initialize(m_diskCacheDirectory, parameters.shouldEnableNetworkCacheEfficacyLogging);
+    NetworkCache::singleton().initialize(m_diskCacheDirectory, { parameters.shouldEnableNetworkCacheEfficacyLogging });
 #else
     // We used to use the given cache directory for the soup cache, but now we use a subdirectory to avoid
     // conflicts with other cache files in the same directory. Remove the old cache files if they still exist.
index 199597e..9bb8345 100644 (file)
@@ -46,6 +46,7 @@ namespace WebKit {
     M(Network) \
     M(NetworkCache) \
     M(NetworkCacheStorage) \
+    M(NetworkCacheSpeculativePreloading) \
     M(NetworkScheduling) \
     M(Plugins) \
     M(Printing) \
index 5aaa820..a37bbe3 100644 (file)
@@ -51,6 +51,9 @@ void NetworkProcessCreationParameters::encode(IPC::ArgumentEncoder& encoder) con
 #if ENABLE(NETWORK_CACHE)
     encoder << shouldEnableNetworkCache;
     encoder << shouldEnableNetworkCacheEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    encoder << shouldEnableNetworkCacheSpeculativeRevalidation;
+#endif
 #endif
 #if ENABLE(SECCOMP_FILTERS)
     encoder << cookieStorageDirectory;
@@ -104,6 +107,10 @@ bool NetworkProcessCreationParameters::decode(IPC::ArgumentDecoder& decoder, Net
         return false;
     if (!decoder.decode(result.shouldEnableNetworkCacheEfficacyLogging))
         return false;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    if (!decoder.decode(result.shouldEnableNetworkCacheSpeculativeRevalidation))
+        return false;
+#endif
 #endif
 #if ENABLE(SECCOMP_FILTERS)
     if (!decoder.decode(result.cookieStorageDirectory))
index 80b61ca..90869c1 100644 (file)
@@ -60,6 +60,9 @@ struct NetworkProcessCreationParameters {
 #if ENABLE(NETWORK_CACHE)
     bool shouldEnableNetworkCache;
     bool shouldEnableNetworkCacheEfficacyLogging;
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    bool shouldEnableNetworkCacheSpeculativeRevalidation;
+#endif
 #endif
 #if ENABLE(SECCOMP_FILTERS)
     String cookieStorageDirectory;
index 424b997..fd1083f 100644 (file)
@@ -84,6 +84,9 @@ static NSString * const WebKit2HTTPSProxyDefaultsKey = @"WebKit2HTTPSProxy";
 #if ENABLE(NETWORK_CACHE)
 static NSString * const WebKitNetworkCacheEnabledDefaultsKey = @"WebKitNetworkCacheEnabled";
 static NSString * const WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey = @"WebKitNetworkCacheEfficacyLoggingEnabled";
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+static NSString * const WebKitNetworkCacheSpeculativeRevalidationEnabledDefaultsKey = @"WebKitNetworkCacheResourceRevalidationEnabled";
+#endif
 #endif
 
 namespace WebKit {
@@ -106,6 +109,9 @@ static void registerUserDefaultsIfNeeded()
 #if ENABLE(NETWORK_CACHE)
     [registrationDictionary setObject:[NSNumber numberWithBool:YES] forKey:WebKitNetworkCacheEnabledDefaultsKey];
     [registrationDictionary setObject:[NSNumber numberWithBool:NO] forKey:WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey];
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    [registrationDictionary setObject:[NSNumber numberWithBool:NO] forKey:WebKitNetworkCacheSpeculativeRevalidationEnabledDefaultsKey];
+#endif
 #endif
 
     [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary];
@@ -254,6 +260,9 @@ void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationPara
 #if ENABLE(NETWORK_CACHE)
     parameters.shouldEnableNetworkCache = isNetworkCacheEnabled();
     parameters.shouldEnableNetworkCacheEfficacyLogging = [defaults boolForKey:WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey];
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    parameters.shouldEnableNetworkCacheSpeculativeRevalidation = [defaults boolForKey:WebKitNetworkCacheSpeculativeRevalidationEnabledDefaultsKey];
+#endif
 #endif
 
 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
index 35d974f..ff2698f 100644 (file)
                7CF47FFF17276AE3008ACB91 /* WKBundlePageBannerMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CF47FFD17276AE3008ACB91 /* WKBundlePageBannerMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7EC4F0FB18E4ACBB008056AF /* NetworkProcessCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7EC4F0F918E4A945008056AF /* NetworkProcessCocoa.mm */; };
                83048AE61ACA45DC0082C832 /* ProcessThrottlerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */; };
+               8310428B1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 831042891BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h */; };
+               8310428C1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8310428A1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp */; };
+               832AE2521BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.h */; };
+               832AE2531BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.cpp */; };
                834B250F1A831A8D00CFB150 /* NetworkCacheFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B250E1A831A8D00CFB150 /* NetworkCacheFileSystem.h */; };
                834B25121A842C8700CFB150 /* NetworkCacheStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */; };
                8360349F1ACB34D600626549 /* WebSQLiteDatabaseTracker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8360349D1ACB34D600626549 /* WebSQLiteDatabaseTracker.cpp */; };
                7CF47FFD17276AE3008ACB91 /* WKBundlePageBannerMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBundlePageBannerMac.h; sourceTree = "<group>"; };
                7EC4F0F918E4A945008056AF /* NetworkProcessCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkProcessCocoa.mm; path = NetworkProcess/cocoa/NetworkProcessCocoa.mm; sourceTree = "<group>"; };
                83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessThrottlerClient.h; sourceTree = "<group>"; };
+               831042891BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheSubresourcesEntry.h; sourceTree = "<group>"; };
+               8310428A1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSubresourcesEntry.cpp; sourceTree = "<group>"; };
+               832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheSpeculativeLoader.h; sourceTree = "<group>"; };
+               832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSpeculativeLoader.cpp; sourceTree = "<group>"; };
                834B250E1A831A8D00CFB150 /* NetworkCacheFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheFileSystem.h; sourceTree = "<group>"; };
                834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheStatistics.h; sourceTree = "<group>"; };
                8360349D1ACB34D600626549 /* WebSQLiteDatabaseTracker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSQLiteDatabaseTracker.cpp; sourceTree = "<group>"; };
                                E42E060D1AA750E500B11699 /* NetworkCacheIOChannelCocoa.mm */,
                                E4436EC01A0CFDB200EAD204 /* NetworkCacheKey.cpp */,
                                E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */,
+                               832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.cpp */,
+                               832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.h */,
                                83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */,
                                834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */,
                                E4436EC31A0CFDB200EAD204 /* NetworkCacheStorage.cpp */,
                                E4436EC21A0CFDB200EAD204 /* NetworkCacheStorage.h */,
+                               8310428A1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp */,
+                               831042891BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h */,
                        );
                        name = cache;
                        path = NetworkProcess/cache;
                                75A8D2E1187DEC1A00C39C9E /* APISession.h in Headers */,
                                1AFDE6621954E9B100C48FFA /* APISessionState.h in Headers */,
                                1A4D664818A2D91A00D82E21 /* APIUIClient.h in Headers */,
+                               832AE2521BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.h in Headers */,
                                BCDB86C11200FB97007254BE /* APIURL.h in Headers */,
                                BCE2315D122C30CA00D5C35A /* APIURLRequest.h in Headers */,
                                BC90A1D2122DD55E00CC8C50 /* APIURLResponse.h in Headers */,
                                293EBEAB1627D9C9005F89F1 /* WKDOMText.h in Headers */,
                                BC017D2116263308007054F5 /* WKDOMTextIterator.h in Headers */,
                                1AB7D78D1288CD9A00CFD08C /* WKDownload.h in Headers */,
+                               8310428B1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h in Headers */,
                                1AF4592F19464B2000F9D4A2 /* WKError.h in Headers */,
                                BCFD548C132D82680055D816 /* WKErrorCF.h in Headers */,
                                37B5045219EEF31300CE2CF8 /* WKErrorPrivate.h in Headers */,
                                7C89D2971A6753B2003A5FDE /* APIPageConfiguration.cpp in Sources */,
                                1A3A73CF1A48C7F1007231B3 /* APIPageGroupHandle.cpp in Sources */,
                                1AC1336E18565D2B00F3EC05 /* APIPageHandle.cpp in Sources */,
+                               832AE2531BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoader.cpp in Sources */,
                                7CE4D21F1A4914CA00C7F152 /* APIProcessPoolConfiguration.cpp in Sources */,
                                FED3C1DC1B447EAC00E0EB7F /* APISerializedScriptValueCocoa.mm in Sources */,
                                A182D5B41BE6BD250087A7CC /* AccessibilityIOS.mm in Sources */,
                                1A8EF4CC1252403700F7067F /* PluginControllerProxy.cpp in Sources */,
                                1A2D91A61281D739001EB962 /* PluginControllerProxyMac.mm in Sources */,
                                1A8EF96E1252AF6B00F7067F /* PluginControllerProxyMessageReceiver.cpp in Sources */,
+                               8310428C1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp in Sources */,
                                1A17977F137EE82C00F97D45 /* PluginCreationParameters.cpp in Sources */,
                                7C3F8C90173AF52D007B7F39 /* PluginInformation.cpp in Sources */,
                                7C135AAC173B0CFF00586AE2 /* PluginInformationMac.mm in Sources */,
index 68e7e4d..0d640c8 100644 (file)
 #endif
 #endif
 
+#ifndef ENABLE_NETWORK_CACHE_SPECULATIVE_REVALIDATION
+#if ENABLE(NETWORK_CACHE) && PLATFORM(COCOA)
+#define ENABLE_NETWORK_CACHE_SPECULATIVE_REVALIDATION 1
+#else
+#define ENABLE_NETWORK_CACHE_SPECULATIVE_REVALIDATION 0
+#endif
+#endif
+
 #ifndef HAVE_SAFARI_SERVICES_FRAMEWORK
 #if PLATFORM(IOS) && (!defined TARGET_OS_IOS || TARGET_OS_IOS)
 #define HAVE_SAFARI_SERVICES_FRAMEWORK 1