[SOUP] Add initial implementation of NetworkProcess disk cache
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Apr 2015 06:17:05 +0000 (06:17 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Apr 2015 06:17:05 +0000 (06:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143872

Reviewed by Martin Robinson.

Source/WebCore:

Allow to create a GRefPtr for SoupBuffer. Even though SoupBuffer
is not a GObject and has copy/free functions instead of ref/unref,
it's internally refcounted, so we could use copy/free as
ref/unref.

* PlatformGTK.cmake:
* platform/network/soup/GRefPtrSoup.cpp: Added.
(WTF::refGPtr):
(WTF::derefGPtr):
* platform/network/soup/GRefPtrSoup.h: Added.

Source/WebKit2:

Implement the platform specific parts of the disk cache
implementation for Soup. It's mainly NetworkCache::Data and
NetworkCache::IOChannel.

* CMakeLists.txt:
* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::dumpFileChanged):
(WebKit::NetworkCache::Cache::initialize):
* NetworkProcess/cache/NetworkCacheBlobStorage.cpp:
* NetworkProcess/cache/NetworkCacheData.h:
(WebKit::NetworkCache::Data::soupBuffer):
* NetworkProcess/cache/NetworkCacheDataSoup.cpp: Added.
(WebKit::NetworkCache::Data::Data):
(WebKit::NetworkCache::Data::empty):
(WebKit::NetworkCache::Data::data):
(WebKit::NetworkCache::Data::isNull):
(WebKit::NetworkCache::Data::apply):
(WebKit::NetworkCache::Data::subrange):
(WebKit::NetworkCache::concatenate):
(WebKit::NetworkCache::MapWrapper::~MapWrapper):
(WebKit::NetworkCache::deleteMapWrapper):
(WebKit::NetworkCache::mapFile):
(WebKit::NetworkCache::Data::adoptMap):
(WebKit::NetworkCache::computeSHA1):
(WebKit::NetworkCache::bytesEqual):
* NetworkProcess/cache/NetworkCacheIOChannel.h:
* NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: Added.
(WebKit::NetworkCache::IOChannel::IOChannel):
(WebKit::NetworkCache::IOChannel::open):
(WebKit::NetworkCache::fillDataFromReadBuffer):
(WebKit::NetworkCache::inputStreamReadReadyCallback):
(WebKit::NetworkCache::IOChannel::read):
(WebKit::NetworkCache::IOChannel::readSync):
(WebKit::NetworkCache::outputStreamWriteReadyCallback):
(WebKit::NetworkCache::IOChannel::write):
* NetworkProcess/cache/NetworkCacheStorageSoup.cpp: Removed.
* NetworkProcess/gtk/NetworkProcessMainGtk.cpp:
* NetworkProcess/soup/NetworkProcessSoup.cpp:
(WebKit::NetworkProcess::platformInitializeNetworkProcess):
(WebKit::NetworkProcess::platformSetCacheModel):
(WebKit::NetworkProcess::clearDiskCache):
* PlatformGTK.cmake:

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

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/PlatformGTK.cmake
Source/WebCore/platform/network/soup/GRefPtrSoup.cpp [new file with mode: 0644]
Source/WebCore/platform/network/soup/GRefPtrSoup.h [new file with mode: 0644]
Source/WebKit2/CMakeLists.txt
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCacheBlobStorage.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCacheData.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp [new file with mode: 0644]
Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageSoup.cpp [deleted file]
Source/WebKit2/NetworkProcess/gtk/NetworkProcessMainGtk.cpp
Source/WebKit2/NetworkProcess/soup/NetworkProcessSoup.cpp
Source/WebKit2/PlatformGTK.cmake

index 3913edd..caf48a7 100644 (file)
@@ -1,3 +1,21 @@
+2015-04-17  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [SOUP] Add initial implementation of NetworkProcess disk cache
+        https://bugs.webkit.org/show_bug.cgi?id=143872
+
+        Reviewed by Martin Robinson.
+
+        Allow to create a GRefPtr for SoupBuffer. Even though SoupBuffer
+        is not a GObject and has copy/free functions instead of ref/unref,
+        it's internally refcounted, so we could use copy/free as
+        ref/unref.
+
+        * PlatformGTK.cmake:
+        * platform/network/soup/GRefPtrSoup.cpp: Added.
+        (WTF::refGPtr):
+        (WTF::derefGPtr):
+        * platform/network/soup/GRefPtrSoup.h: Added.
+
 2015-04-26  Manuel Rego Casasnovas  <rego@igalia.com>
 
         [CSS Grid Layout] LayoutBox::hasDefiniteLogicalHeight() should consider abspos boxes as definite
index d8b6d65..0183011 100644 (file)
@@ -159,6 +159,7 @@ list(APPEND WebCore_SOURCES
     platform/network/soup/CookieStorageSoup.cpp
     platform/network/soup/CredentialStorageSoup.cpp
     platform/network/soup/DNSSoup.cpp
+    platform/network/soup/GRefPtrSoup.cpp
     platform/network/soup/NetworkStorageSessionSoup.cpp
     platform/network/soup/ProxyServerSoup.cpp
     platform/network/soup/ResourceErrorSoup.cpp
diff --git a/Source/WebCore/platform/network/soup/GRefPtrSoup.cpp b/Source/WebCore/platform/network/soup/GRefPtrSoup.cpp
new file mode 100644 (file)
index 0000000..009aec1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 2015 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "GRefPtrSoup.h"
+
+namespace WTF {
+
+template <> SoupBuffer* refGPtr(SoupBuffer* ptr)
+{
+    return ptr ? soup_buffer_copy(ptr) : nullptr;
+}
+
+template <> void derefGPtr(SoupBuffer* ptr)
+{
+    if (ptr)
+        soup_buffer_free(ptr);
+}
+
+} // namespace WTF
diff --git a/Source/WebCore/platform/network/soup/GRefPtrSoup.h b/Source/WebCore/platform/network/soup/GRefPtrSoup.h
new file mode 100644 (file)
index 0000000..69fdb25
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2015 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GRefPtrSoup_h
+#define GRefPtrSoup_h
+
+#if USE(SOUP)
+
+#include <libsoup/soup.h>
+#include <wtf/gobject/GRefPtr.h>
+
+namespace WTF {
+
+template <> SoupBuffer* refGPtr(SoupBuffer*);
+template <> void derefGPtr(SoupBuffer*);
+
+} // namespace WTF
+
+#endif // USE(SOUP)
+
+#endif
index 0b6d687..3cde5eb 100644 (file)
@@ -164,10 +164,14 @@ set(NetworkProcess_SOURCES
     NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
 
     NetworkProcess/cache/NetworkCache.cpp
+    NetworkProcess/cache/NetworkCacheBlobStorage.cpp
     NetworkProcess/cache/NetworkCacheCoders.cpp
-    NetworkProcess/cache/NetworkCacheEncoder.cpp
     NetworkProcess/cache/NetworkCacheDecoder.cpp
+    NetworkProcess/cache/NetworkCacheEncoder.cpp
+    NetworkProcess/cache/NetworkCacheEntry.cpp
     NetworkProcess/cache/NetworkCacheKey.cpp
+    NetworkProcess/cache/NetworkCacheStatistics.cpp
+    NetworkProcess/cache/NetworkCacheStorage.cpp
 )
 
 set(WebKit2_SOURCES
index 64d7ae9..e345043 100644 (file)
@@ -1,3 +1,53 @@
+2015-04-17  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [SOUP] Add initial implementation of NetworkProcess disk cache
+        https://bugs.webkit.org/show_bug.cgi?id=143872
+
+        Reviewed by Martin Robinson.
+
+        Implement the platform specific parts of the disk cache
+        implementation for Soup. It's mainly NetworkCache::Data and
+        NetworkCache::IOChannel.
+
+        * CMakeLists.txt:
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::dumpFileChanged):
+        (WebKit::NetworkCache::Cache::initialize):
+        * NetworkProcess/cache/NetworkCacheBlobStorage.cpp:
+        * NetworkProcess/cache/NetworkCacheData.h:
+        (WebKit::NetworkCache::Data::soupBuffer):
+        * NetworkProcess/cache/NetworkCacheDataSoup.cpp: Added.
+        (WebKit::NetworkCache::Data::Data):
+        (WebKit::NetworkCache::Data::empty):
+        (WebKit::NetworkCache::Data::data):
+        (WebKit::NetworkCache::Data::isNull):
+        (WebKit::NetworkCache::Data::apply):
+        (WebKit::NetworkCache::Data::subrange):
+        (WebKit::NetworkCache::concatenate):
+        (WebKit::NetworkCache::MapWrapper::~MapWrapper):
+        (WebKit::NetworkCache::deleteMapWrapper):
+        (WebKit::NetworkCache::mapFile):
+        (WebKit::NetworkCache::Data::adoptMap):
+        (WebKit::NetworkCache::computeSHA1):
+        (WebKit::NetworkCache::bytesEqual):
+        * NetworkProcess/cache/NetworkCacheIOChannel.h:
+        * NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp: Added.
+        (WebKit::NetworkCache::IOChannel::IOChannel):
+        (WebKit::NetworkCache::IOChannel::open):
+        (WebKit::NetworkCache::fillDataFromReadBuffer):
+        (WebKit::NetworkCache::inputStreamReadReadyCallback):
+        (WebKit::NetworkCache::IOChannel::read):
+        (WebKit::NetworkCache::IOChannel::readSync):
+        (WebKit::NetworkCache::outputStreamWriteReadyCallback):
+        (WebKit::NetworkCache::IOChannel::write):
+        * NetworkProcess/cache/NetworkCacheStorageSoup.cpp: Removed.
+        * NetworkProcess/gtk/NetworkProcessMainGtk.cpp:
+        * NetworkProcess/soup/NetworkProcessSoup.cpp:
+        (WebKit::NetworkProcess::platformInitializeNetworkProcess):
+        (WebKit::NetworkProcess::platformSetCacheModel):
+        (WebKit::NetworkProcess::clearDiskCache):
+        * PlatformGTK.cmake:
+
 2015-04-26  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [ES6] Implement ES6 template literals
index b2928ff..dae4792 100644 (file)
@@ -55,6 +55,13 @@ Cache& singleton()
     return instance;
 }
 
+#if PLATFORM(GTK)
+static void dumpFileChanged(Cache* cache)
+{
+    cache->dumpContentsToFile();
+}
+#endif
+
 bool Cache::initialize(const String& cachePath, bool enableEfficacyLogging)
 {
     m_storage = Storage::open(cachePath);
@@ -71,6 +78,15 @@ bool Cache::initialize(const String& cachePath, bool enableEfficacyLogging)
         });
     }
 #endif
+#if PLATFORM(GTK)
+    // Triggers with "touch $cachePath/dump".
+    if (m_storage) {
+        CString dumpFilePath = WebCore::fileSystemRepresentation(WebCore::pathByAppendingComponent(m_storage->basePath(), "dump"));
+        GRefPtr<GFile> dumpFile = adoptGRef(g_file_new_for_path(dumpFilePath.data()));
+        GFileMonitor* monitor = g_file_monitor_file(dumpFile.get(), G_FILE_MONITOR_NONE, nullptr, nullptr);
+        g_signal_connect_swapped(monitor, "changed", G_CALLBACK(dumpFileChanged), this);
+    }
+#endif
 
     LOG(NetworkCache, "(NetworkProcess) opened cache storage, success %d", !!m_storage);
     return !!m_storage;
index 4ecde7c..7b03be2 100644 (file)
@@ -31,6 +31,7 @@
 #include "Logging.h"
 #include "NetworkCacheFileSystemPosix.h"
 #include <WebCore/FileSystem.h>
+#include <fcntl.h>
 #include <sys/mman.h>
 #include <wtf/RunLoop.h>
 #include <wtf/SHA1.h>
index 10f5d07..84fccc8 100644 (file)
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/text/WTFString.h>
 
+#if USE(SOUP)
+#include <WebCore/GRefPtrSoup.h>
+#endif
+
 namespace WebKit {
 namespace NetworkCache {
 
@@ -106,6 +110,9 @@ public:
 #if PLATFORM(COCOA)
     Data(DispatchPtr<dispatch_data_t>, Backing = Backing::Buffer);
 #endif
+#if USE(SOUP)
+    Data(GRefPtr<SoupBuffer>&&, Backing = Backing::Buffer);
+#endif
     bool isNull() const;
     bool isEmpty() const { return !m_size; }
 
@@ -120,10 +127,17 @@ public:
 #if PLATFORM(COCOA)
     dispatch_data_t dispatchData() const { return m_dispatchData.get(); }
 #endif
+
+#if USE(SOUP)
+    SoupBuffer* soupBuffer() const { return m_buffer.get(); }
+#endif
 private:
 #if PLATFORM(COCOA)
     mutable DispatchPtr<dispatch_data_t> m_dispatchData;
 #endif
+#if USE(SOUP)
+    mutable GRefPtr<SoupBuffer> m_buffer;
+#endif
     mutable const uint8_t* m_data { nullptr };
     size_t m_size { 0 };
     bool m_isMap { false };
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheDataSoup.cpp
new file mode 100644 (file)
index 0000000..b4e5072
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 Igalia S.L
+ *
+ * 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"
+#include "NetworkCacheData.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace WebKit {
+namespace NetworkCache {
+
+Data::Data(const uint8_t* data, size_t size)
+    : m_size(size)
+{
+    uint8_t* copiedData = static_cast<uint8_t*>(fastMalloc(size));
+    memcpy(copiedData, data, size);
+    m_buffer = adoptGRef(soup_buffer_new_with_owner(copiedData, size, copiedData, fastFree));
+}
+
+Data::Data(GRefPtr<SoupBuffer>&& buffer, Backing backing)
+    : m_buffer(buffer)
+    , m_size(buffer ? buffer->length : 0)
+    , m_isMap(m_size && backing == Backing::Map)
+{
+}
+
+Data Data::empty()
+{
+    GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new(SOUP_MEMORY_TAKE, nullptr, 0));
+    return { WTF::move(buffer) };
+}
+
+const uint8_t* Data::data() const
+{
+    return m_buffer ? reinterpret_cast<const uint8_t*>(m_buffer->data) : nullptr;
+}
+
+bool Data::isNull() const
+{
+    return !m_buffer;
+}
+
+bool Data::apply(const std::function<bool (const uint8_t*, size_t)>&& applier) const
+{
+    if (!m_size)
+        return false;
+
+    return applier(reinterpret_cast<const uint8_t*>(m_buffer->data), m_buffer->length);
+}
+
+Data Data::subrange(size_t offset, size_t size) const
+{
+    if (!m_buffer)
+        return { };
+
+    GRefPtr<SoupBuffer> subBuffer = adoptGRef(soup_buffer_new_subbuffer(m_buffer.get(), offset, size));
+    return { WTF::move(subBuffer) };
+}
+
+Data concatenate(const Data& a, const Data& b)
+{
+    if (a.isNull())
+        return b;
+    if (b.isNull())
+        return a;
+
+    size_t size = a.size() + b.size();
+    uint8_t* data = static_cast<uint8_t*>(fastMalloc(size));
+    memcpy(data, a.soupBuffer()->data, a.soupBuffer()->length);
+    memcpy(data + a.soupBuffer()->length, b.soupBuffer()->data, b.soupBuffer()->length);
+    GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(data, size, data, fastFree));
+    return { WTF::move(buffer) };
+}
+
+struct MapWrapper {
+    ~MapWrapper()
+    {
+        munmap(map, size);
+    }
+
+    void* map;
+    size_t size;
+};
+
+static void deleteMapWrapper(MapWrapper* wrapper)
+{
+    delete wrapper;
+}
+
+Data mapFile(int fd, size_t offset, size_t size)
+{
+    if (!size)
+        return Data::empty();
+
+    void* map = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, offset);
+    if (map == MAP_FAILED)
+        return { };
+    return Data::adoptMap(map, size);
+}
+
+Data Data::adoptMap(void* map, size_t size)
+{
+    ASSERT(map);
+    ASSERT(map != MAP_FAILED);
+    MapWrapper* wrapper = new MapWrapper { map, size };
+    GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(map, size, wrapper, reinterpret_cast<GDestroyNotify>(deleteMapWrapper)));
+    return { WTF::move(buffer), Data::Backing::Map };
+}
+
+Data mapFile(const char* path)
+{
+    int fd = open(path, O_RDONLY, 0);
+    if (fd < 0)
+        return { };
+    struct stat stat;
+    if (fstat(fd, &stat) < 0) {
+        close(fd);
+        return { };
+    }
+    size_t size = stat.st_size;
+    auto data = mapFile(fd, 0, size);
+    close(fd);
+
+    return data;
+}
+
+SHA1::Digest computeSHA1(const Data& data)
+{
+    SHA1 sha1;
+    data.apply([&sha1](const uint8_t* data, size_t size) {
+        sha1.addBytes(data, size);
+        return true;
+    });
+    SHA1::Digest digest;
+    sha1.computeHash(digest);
+    return digest;
+}
+
+bool bytesEqual(const Data& a, const Data& b)
+{
+    if (a.isNull() || b.isNull())
+        return false;
+    if (a.size() != b.size())
+        return false;
+    return !memcmp(a.data(), b.data(), a.size());
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif
index c8c6b17..7c04213 100644 (file)
 #include <wtf/WorkQueue.h>
 #include <wtf/text/WTFString.h>
 
+#if USE(SOUP)
+#include <wtf/gobject/GRefPtr.h>
+#endif
+
 namespace WebKit {
 namespace NetworkCache {
 
@@ -63,6 +67,11 @@ private:
 #if PLATFORM(COCOA)
     DispatchPtr<dispatch_io_t> m_dispatchIO;
 #endif
+#if USE(SOUP)
+    GRefPtr<GInputStream> m_inputStream;
+    GRefPtr<GOutputStream> m_outputStream;
+    GRefPtr<GFileIOStream> m_ioStream;
+#endif
 };
 
 }
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp
new file mode 100644 (file)
index 0000000..139b362
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * 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"
+#include "NetworkCacheIOChannel.h"
+
+#if ENABLE(NETWORK_CACHE)
+
+#include "NetworkCacheFileSystemPosix.h"
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const size_t gDefaultReadBufferSize = 4096;
+
+IOChannel::IOChannel(const String& filePath, Type type)
+    : m_path(filePath)
+    , m_type(type)
+{
+    auto path = WebCore::fileSystemRepresentation(filePath);
+    GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(path.data()));
+    switch (m_type) {
+    case Type::Create:
+        g_file_delete(file.get(), nullptr, nullptr);
+        m_outputStream = adoptGRef(G_OUTPUT_STREAM(g_file_create(file.get(), static_cast<GFileCreateFlags>(G_FILE_CREATE_PRIVATE), nullptr, nullptr)));
+        ASSERT(m_outputStream);
+        break;
+    case Type::Write: {
+        m_ioStream = adoptGRef(g_file_open_readwrite(file.get(), nullptr, nullptr));
+        ASSERT(m_ioStream);
+        break;
+    }
+    case Type::Read:
+        m_inputStream = adoptGRef(G_INPUT_STREAM(g_file_read(file.get(), nullptr, nullptr)));
+        ASSERT(m_inputStream);
+        break;
+    }
+}
+
+Ref<IOChannel> IOChannel::open(const String& filePath, IOChannel::Type type)
+{
+    return adoptRef(*new IOChannel(filePath, type));
+}
+
+static void fillDataFromReadBuffer(SoupBuffer* readBuffer, size_t size, Data& data)
+{
+    GRefPtr<SoupBuffer> buffer;
+    if (size != readBuffer->length) {
+        // The subbuffer does not copy the data.
+        buffer = adoptGRef(soup_buffer_new_subbuffer(readBuffer, 0, size));
+    } else
+        buffer = readBuffer;
+
+    if (data.isNull()) {
+        // First chunk, we need to force the data to be copied.
+        data = { reinterpret_cast<const uint8_t*>(buffer->data), size };
+    } else {
+        Data dataRead(WTF::move(buffer));
+        // Concatenate will copy the data.
+        data = concatenate(data, dataRead);
+    }
+}
+
+struct ReadAsyncData {
+    RefPtr<IOChannel> channel;
+    GRefPtr<SoupBuffer> buffer;
+    size_t bytesToRead;
+    std::function<void (Data&, int error)> completionHandler;
+    Data data;
+};
+
+static void inputStreamReadReadyCallback(GInputStream* stream, GAsyncResult* result, gpointer userData)
+{
+    std::unique_ptr<ReadAsyncData> asyncData(static_cast<ReadAsyncData*>(userData));
+    gssize bytesRead = g_input_stream_read_finish(stream, result, nullptr);
+    if (bytesRead == -1) {
+        asyncData->completionHandler(asyncData->data, -1);
+        return;
+    }
+
+    if (!bytesRead) {
+        asyncData->completionHandler(asyncData->data, 0);
+        return;
+    }
+
+    ASSERT(bytesRead > 0);
+    fillDataFromReadBuffer(asyncData->buffer.get(), static_cast<size_t>(bytesRead), asyncData->data);
+
+    size_t pendingBytesToRead = asyncData->bytesToRead - asyncData->data.size();
+    if (!pendingBytesToRead) {
+        asyncData->completionHandler(asyncData->data, 0);
+        return;
+    }
+
+    size_t bytesToRead = std::min(pendingBytesToRead, asyncData->buffer->length);
+    // Use a local variable for the data buffer to pass it to g_input_stream_read_async(), because ReadAsyncData is released.
+    auto data = const_cast<char*>(asyncData->buffer->data);
+    g_input_stream_read_async(stream, data, bytesToRead, G_PRIORITY_DEFAULT, nullptr,
+        reinterpret_cast<GAsyncReadyCallback>(inputStreamReadReadyCallback), asyncData.release());
+}
+
+void IOChannel::read(size_t offset, size_t size, WorkQueue*, std::function<void (Data&, int error)> completionHandler)
+{
+    ASSERT(m_inputStream);
+
+    size_t bufferSize = std::min(size, gDefaultReadBufferSize);
+    uint8_t* bufferData = static_cast<uint8_t*>(fastMalloc(bufferSize));
+    GRefPtr<SoupBuffer> buffer = adoptGRef(soup_buffer_new_with_owner(bufferData, bufferSize, bufferData, fastFree));
+    ReadAsyncData* asyncData = new ReadAsyncData { this, buffer.get(), size, completionHandler, { } };
+
+    // FIXME: implement offset.
+    g_input_stream_read_async(m_inputStream.get(), const_cast<char*>(buffer->data), bufferSize, G_PRIORITY_DEFAULT, nullptr,
+        reinterpret_cast<GAsyncReadyCallback>(inputStreamReadReadyCallback), asyncData);
+}
+
+// FIXME: It would be better to do without this.
+void IOChannel::readSync(size_t offset, size_t size, WorkQueue*, std::function<void (Data&, int error)> completionHandler)
+{
+    ASSERT(m_inputStream);
+    size_t bufferSize = std::min(size, gDefaultReadBufferSize);
+    uint8_t* bufferData = static_cast<uint8_t*>(fastMalloc(bufferSize));
+    GRefPtr<SoupBuffer> readBuffer = adoptGRef(soup_buffer_new_with_owner(bufferData, bufferSize, bufferData, fastFree));
+    Data data;
+    size_t pendingBytesToRead = size;
+    size_t bytesToRead = bufferSize;
+    do {
+        // FIXME: implement offset.
+        gssize bytesRead = g_input_stream_read(m_inputStream.get(), const_cast<char*>(readBuffer->data), bytesToRead, nullptr, nullptr);
+        if (bytesRead == -1) {
+            completionHandler(data, -1);
+            return;
+        }
+
+        if (!bytesRead)
+            break;
+
+        ASSERT(bytesRead > 0);
+        fillDataFromReadBuffer(readBuffer.get(), static_cast<size_t>(bytesRead), data);
+
+        pendingBytesToRead = size - data.size();
+        bytesToRead = std::min(pendingBytesToRead, readBuffer->length);
+    } while (pendingBytesToRead);
+
+    completionHandler(data, 0);
+}
+
+struct WriteAsyncData {
+    RefPtr<IOChannel> channel;
+    GRefPtr<SoupBuffer> buffer;
+    std::function<void (int error)> completionHandler;
+};
+
+static void outputStreamWriteReadyCallback(GOutputStream* stream, GAsyncResult* result, gpointer userData)
+{
+    std::unique_ptr<WriteAsyncData> asyncData(static_cast<WriteAsyncData*>(userData));
+    gssize bytesWritten = g_output_stream_write_finish(stream, result, nullptr);
+    if (bytesWritten == -1) {
+        asyncData->completionHandler(-1);
+        return;
+    }
+
+    gssize pendingBytesToWrite = asyncData->buffer->length - bytesWritten;
+    if (!pendingBytesToWrite) {
+        asyncData->completionHandler(0);
+        return;
+    }
+
+    asyncData->buffer = adoptGRef(soup_buffer_new_subbuffer(asyncData->buffer.get(), bytesWritten, pendingBytesToWrite));
+    // Use a local variable for the data buffer to pass it to g_output_stream_write_async(), because WriteAsyncData is released.
+    auto data = asyncData->buffer->data;
+    g_output_stream_write_async(stream, data, pendingBytesToWrite, G_PRIORITY_DEFAULT, nullptr,
+        reinterpret_cast<GAsyncReadyCallback>(outputStreamWriteReadyCallback), asyncData.release());
+}
+
+void IOChannel::write(size_t offset, const Data& data, WorkQueue*, std::function<void (int error)> completionHandler)
+{
+    ASSERT(m_outputStream || m_ioStream);
+
+    GOutputStream* stream = m_outputStream ? m_outputStream.get() : g_io_stream_get_output_stream(G_IO_STREAM(m_ioStream.get()));
+    WriteAsyncData* asyncData = new WriteAsyncData { this, data.soupBuffer(), completionHandler };
+    // FIXME: implement offset.
+    g_output_stream_write_async(stream, asyncData->buffer->data, data.size(), G_PRIORITY_DEFAULT, nullptr,
+        reinterpret_cast<GAsyncReadyCallback>(outputStreamWriteReadyCallback), asyncData);
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageSoup.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageSoup.cpp
deleted file mode 100644 (file)
index cc837d9..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2014 Igalia S.L.
- *
- * 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"
-#include "NetworkCacheStorage.h"
-
-#if ENABLE(NETWORK_CACHE)
-
-#include "Logging.h"
-#include "NetworkCacheCoders.h"
-#include <WebCore/FileSystem.h>
-#include <WebCore/NotImplemented.h>
-#include <wtf/RunLoop.h>
-
-namespace WebKit {
-
-static const char* networkCacheSubdirectory = "WebKitCache";
-
-NetworkCacheStorage::Data::Data()
-    : m_data(nullptr)
-    , m_size(0)
-{
-    notImplemented();
-}
-
-NetworkCacheStorage::Data::Data(const uint8_t* data, size_t size)
-    : m_data(data)
-    , m_size(size)
-{
-    notImplemented();
-}
-
-const uint8_t* NetworkCacheStorage::Data::data() const
-{
-    notImplemented();
-    return nullptr;
-}
-
-bool NetworkCacheStorage::Data::isNull() const
-{
-    notImplemented();
-    return true;
-}
-
-std::unique_ptr<NetworkCacheStorage> NetworkCacheStorage::open(const String& applicationCachePath)
-{
-    ASSERT(RunLoop::isMain());
-    String networkCachePath = WebCore::pathByAppendingComponent(applicationCachePath, networkCacheSubdirectory);
-    if (!WebCore::makeAllDirectories(networkCachePath))
-        return nullptr;
-    return std::unique_ptr<NetworkCacheStorage>(new NetworkCacheStorage(networkCachePath));
-}
-
-NetworkCacheStorage::NetworkCacheStorage(const String& directoryPath)
-    : m_directoryPath(directoryPath)
-    , m_maximumSize(std::numeric_limits<size_t>::max())
-    , m_activeRetrieveOperationCount(0)
-{
-    initializeKeyFilter();
-}
-
-void NetworkCacheStorage::initializeKeyFilter()
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-}
-
-void NetworkCacheStorage::removeEntry(const NetworkCacheKey&)
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-}
-
-void NetworkCacheStorage::dispatchRetrieveOperation(const RetrieveOperation&)
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-}
-
-void NetworkCacheStorage::dispatchPendingRetrieveOperations()
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-}
-
-void NetworkCacheStorage::retrieve(const NetworkCacheKey&, unsigned /* priority */, std::function<bool (std::unique_ptr<Entry>)> completionHandler)
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-    completionHandler(nullptr);
-}
-
-void NetworkCacheStorage::store(const NetworkCacheKey&, const Entry&, std::function<void (bool success)> completionHandler)
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-    completionHandler(false);
-}
-
-void NetworkCacheStorage::setMaximumSize(size_t size)
-{
-    ASSERT(RunLoop::isMain());
-    notImplemented();
-    m_maximumSize = size;
-}
-
-void NetworkCacheStorage::clear()
-{
-    ASSERT(RunLoop::isMain());
-    LOG(NetworkCacheStorage, "(NetworkProcess) clearing cache");
-    notImplemented();
-    m_keyFilter.clear();
-}
-
-} // namespace WebKit
-
-#endif // ENABLE(NETWORK_CACHE)
index fa0a970..6855e31 100644 (file)
@@ -48,10 +48,12 @@ public:
 
     void platformFinalize() override
     {
+#if !ENABLE(NETWORK_CACHE)
         if (SoupCache* soupCache = SoupNetworkSession::defaultSession().cache()) {
             soup_cache_flush(soupCache);
             soup_cache_dump(soupCache);
         }
+#endif
     }
 };
 
index dff7616..e271ddd 100644 (file)
@@ -28,6 +28,7 @@
 #if ENABLE(NETWORK_PROCESS)
 #include "NetworkProcess.h"
 
+#include "NetworkCache.h"
 #include "NetworkProcessCreationParameters.h"
 #include "ResourceCachesToClear.h"
 #include "WebCookieManager.h"
@@ -44,6 +45,7 @@ using namespace WebCore;
 
 namespace WebKit {
 
+#if !ENABLE(NETWORK_CACHE)
 static uint64_t getCacheDiskFreeSize(SoupCache* cache)
 {
     ASSERT(cache);
@@ -55,6 +57,7 @@ static uint64_t getCacheDiskFreeSize(SoupCache* cache)
 
     return WebCore::getVolumeFreeSizeForPath(cacheDir.get());
 }
+#endif
 
 static uint64_t getMemorySize()
 {
@@ -83,7 +86,14 @@ void NetworkProcess::userPreferredLanguagesChanged(const Vector<String>& languag
 void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreationParameters& parameters)
 {
     ASSERT(!parameters.diskCacheDirectory.isEmpty());
+    m_diskCacheDirectory = parameters.diskCacheDirectory;
+
+#if ENABLE(NETWORK_CACHE)
+    // Clear the old soup cache if it exists.
+    SoupNetworkSession::defaultSession().clearCache(m_diskCacheDirectory);
 
+    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.
     SoupNetworkSession::defaultSession().clearCache(parameters.diskCacheDirectory);
@@ -97,6 +107,7 @@ void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreati
     soup_cache_set_max_size(soupCache.get(), G_MAXUINT);
     soup_cache_load(soupCache.get());
     soup_cache_set_max_size(soupCache.get(), initialMaxSize);
+#endif
 
     if (!parameters.cookiePersistentStoragePath.isEmpty()) {
         supplement<WebCookieManager>()->setCookiePersistentStorage(parameters.cookiePersistentStoragePath,
@@ -121,16 +132,26 @@ void NetworkProcess::platformSetCacheModel(CacheModel cacheModel)
     unsigned long urlCacheMemoryCapacity = 0;
     unsigned long urlCacheDiskCapacity = 0;
 
+#if ENABLE(NETWORK_CACHE)
+    uint64_t diskFreeSize = WebCore::getVolumeFreeSizeForPath(m_diskCacheDirectory.utf8().data()) / 1024 / 1024;
+#else
     SoupCache* cache = SoupNetworkSession::defaultSession().cache();
     uint64_t diskFreeSize = getCacheDiskFreeSize(cache) / 1024 / 1024;
+#endif
 
     uint64_t memSize = getMemorySize();
     calculateCacheSizes(cacheModel, memSize, diskFreeSize,
         cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval,
         pageCacheCapacity, urlCacheMemoryCapacity, urlCacheDiskCapacity);
 
+#if ENABLE(NETWORK_CACHE)
+    auto& networkCache = NetworkCache::singleton();
+    if (networkCache.isEnabled())
+        networkCache.setCapacity(urlCacheDiskCapacity);
+#else
     if (urlCacheDiskCapacity > soup_cache_get_max_size(cache))
         soup_cache_set_max_size(cache, urlCacheDiskCapacity);
+#endif
 }
 
 void NetworkProcess::setIgnoreTLSErrors(bool ignoreTLSErrors)
@@ -154,7 +175,11 @@ void NetworkProcess::clearCacheForAllOrigins(uint32_t cachesToClear)
 void NetworkProcess::clearDiskCache(std::chrono::system_clock::time_point /* modifiedSince */, std::function<void ()> /* completionHandler */)
 {
     // FIXME: Find a way to only clear a part of the cache based on the date.
+#if ENABLE(NETWORK_CACHE)
+    NetworkCache::singleton().clear();
+#else
     soup_cache_clear(SoupNetworkSession::defaultSession().cache());
+#endif
 }
 
 void NetworkProcess::platformTerminate()
index b02e947..485a9dd 100644 (file)
@@ -18,7 +18,8 @@ set(WebKit2_USE_PREFIX_HEADER ON)
 list(APPEND WebKit2_SOURCES
     DatabaseProcess/gtk/DatabaseProcessMainGtk.cpp
 
-    NetworkProcess/cache/NetworkCacheStorageSoup.cpp
+    NetworkProcess/cache/NetworkCacheDataSoup.cpp
+    NetworkProcess/cache/NetworkCacheIOChannelSoup.cpp
 
     NetworkProcess/gtk/NetworkProcessMainGtk.cpp