Diff
Modified: trunk/LayoutTests/ChangeLog (223072 => 223073)
--- trunk/LayoutTests/ChangeLog 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/LayoutTests/ChangeLog 2017-10-09 22:17:05 UTC (rev 223073)
@@ -1,3 +1,14 @@
+2017-10-09 Youenn Fablet <[email protected]>
+
+ Add quota to cache API
+ https://bugs.webkit.org/show_bug.cgi?id=177552
+
+ Reviewed by Alex Christensen.
+
+ * http/wpt/cache-storage/cache-quota.https.any-expected.txt: Added.
+ * http/wpt/cache-storage/cache-quota.https.any.html: Added.
+ * http/wpt/cache-storage/cache-quota.https.any.js: Added.
+
2017-10-09 Matt Lewis <[email protected]>
Unskipped http/tests/cache/disk-cache/disk-cache-validation-no-body.html
Added: trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any-expected.txt (0 => 223073)
--- trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any-expected.txt 2017-10-09 22:17:05 UTC (rev 223073)
@@ -0,0 +1,7 @@
+
+PASS Testing synthetic response body size padding
+PASS Testing non opaque response body size padding
+PASS Testing opaque response body size padding
+PASS Hitting cache quota for non opaque responses
+PASS Hitting cache quota for padded responses
+
Added: trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.html (0 => 223073)
--- trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.html (rev 0)
+++ trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.html 2017-10-09 22:17:05 UTC (rev 223073)
@@ -0,0 +1 @@
+<!-- This file is required for WebKit test infrastructure to run the templated test -->
\ No newline at end of file
Added: trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.js (0 => 223073)
--- trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.js (rev 0)
+++ trunk/LayoutTests/http/wpt/cache-storage/cache-quota.any.js 2017-10-09 22:17:05 UTC (rev 223073)
@@ -0,0 +1,169 @@
+// META: script=/service-workers/cache-storage/resources/test-helpers.js
+// META: script=/common/get-host-info.sub.js
+
+var test_url = 'https://example.com/foo';
+var test_body = 'Hello world!';
+
+function getResponseBodySizeWithPadding(response)
+{
+ var cache;
+ var request = new Request("temp");
+ var clone = response.clone();
+ return self.caches.open("test").then((c) => {
+ cache = c;
+ return cache.put(request, clone);
+ }).then(() => {
+ return self.caches.delete("temp");
+ }).then(() => {
+ return window.internals.responseSizeWithPadding(clone);
+ });
+}
+
+promise_test(() => {
+ if (!window.internals)
+ return Promise.reject("Test requires internals");
+
+ var response = new Response("");
+ return getResponseBodySizeWithPadding(response).then(size => {
+ assert_equals(size, 0, "zero size synthetic response");
+ return getResponseBodySizeWithPadding(response.clone());
+ }).then((size) => {
+ assert_equals(size, 0, "zero size synthetic cloned response");
+
+ response = new Response("a");
+ return getResponseBodySizeWithPadding(response);
+ }).then((size) => {
+ assert_equals(size, 1, "non zero size synthetic response");
+ return getResponseBodySizeWithPadding(response.clone());
+ }).then((size) => {
+ assert_equals(size, 1, "non zero size synthetic cloned response");
+ })
+}, "Testing synthetic response body size padding");
+
+promise_test(() => {
+ if (!window.internals)
+ return Promise.reject("Test requires internals");
+
+ var paddedSize;
+ var response, responseClone;
+ return fetch("").then(r => {
+ response = r;
+ responseClone = response.clone();
+ return getResponseBodySizeWithPadding(response);
+ }).then((size) => {
+ paddedSize = size;
+ return response.arrayBuffer();
+ }).then((buffer) => {
+ assert_equals(buffer.byteLength, paddedSize, "non opaque network response");
+ return getResponseBodySizeWithPadding(responseClone);
+ }).then((size) => {
+ assert_equals(size, paddedSize, "non opaque network cloned response");
+ });
+}, "Testing non opaque response body size padding");
+
+promise_test(() => {
+ if (!window.internals)
+ return Promise.reject("Test requires internals");
+
+ var actualSize, paddedSize;
+ var response, responseClone1;
+ return fetch(get_host_info().HTTP_REMOTE_ORIGIN, {mode: "no-cors"}).then(r => {
+ response = r;
+ }).then(() => {
+ return fetch(get_host_info().HTTP_ORIGIN);
+ }).then(r => {
+ return r.arrayBuffer();
+ }).then((buffer) => {
+ actualSize = buffer.byteLength;
+ }).then(() => {
+ responseClone1 = response.clone();
+ return getResponseBodySizeWithPadding(response);
+ }).then((size) => {
+ paddedSize = size;
+ return getResponseBodySizeWithPadding(responseClone1);
+ }).then((size) => {
+ assert_not_equals(size, actualSize, "padded size should be different from actual size");
+ assert_equals(size, paddedSize, "opaque network cloned response");
+ });
+}, "Testing opaque response body size padding");
+
+async function doCleanup()
+{
+ var cachesKeys = await self.caches.keys();
+ for (let name of cachesKeys) {
+ let cache = await self.caches.open(name);
+ let keys = await cache.keys();
+ for (let key of keys)
+ await cache.delete(key);
+ }
+}
+
+promise_test((test) => {
+ var cache;
+ var response1ko = new Response(new ArrayBuffer(1 * 1024));
+ var response399ko = new Response(new ArrayBuffer(399 * 1024));
+
+ return doCleanup().then(() => {
+ return self.caches.open("temp1");
+ }).then((c) => {
+ cache = c;
+ return cache.put("399ko", response399ko.clone());
+ }).then(() => {
+ return cache.put("1ko-v1", response1ko.clone());
+ }).then(() => {
+ return cache.put("1ko-v2", response1ko.clone()).then(assert_unreached, (e) => {
+ assert_equals(e.name, "QuotaExceededError");
+ });
+ }).then(() => {
+ return cache.delete("1ko-v1");
+ }).then(() => {
+ return cache.put("1ko-v2", response1ko.clone());
+ }).then(() => {
+ return cache.delete("399ko");
+ }).then(() => {
+ return cache.delete("1ko-v1");
+ }).then(() => {
+ return cache.delete("1ko-v2");
+ });
+}, 'Hitting cache quota for non opaque responses');
+
+promise_test((test) => {
+ if (!window.internals)
+ return Promise.reject("Test requires internals");
+
+ var cache;
+ var response1ko = new Response(new ArrayBuffer(1 * 1024));
+ var responsePadded = new Response(new ArrayBuffer(1 * 1024));
+ var response200ko = new Response(new ArrayBuffer(200 * 1024));
+
+ return doCleanup().then(() => {
+ return self.caches.open("temp2");
+ }).then((c) => {
+ cache = c;
+ return fetch(get_host_info().HTTP_REMOTE_ORIGIN, {mode: "no-cors"});
+ }).then((r) => {
+ responsePadded = r;
+ internals.setResponseSizeWithPadding(responsePadded, 200 * 1024);
+ return cache.put("200ko", response200ko.clone());
+ }).then(() => {
+ return cache.put("1ko-padded-to-200ko", responsePadded.clone());
+ }).then(() => {
+ return cache.put("1ko", response1ko.clone()).then(assert_unreached, (e) => {
+ assert_equals(e.name, "QuotaExceededError");
+ });
+ }).then(() => {
+ return cache.delete("1ko-padded-to-200ko");
+ }).then(() => {
+ return cache.put("1ko-v2", response1ko.clone());
+ }).then(() => {
+ return cache.put("1ko-v3", response1ko.clone());
+ }).then(() => {
+ return cache.delete("200ko");
+ }).then(() => {
+ return cache.delete("1ko-v2");
+ }).then(() => {
+ return cache.delete("1ko-v3");
+ });
+}, 'Hitting cache quota for padded responses');
+
+done();
Modified: trunk/Source/WebCore/ChangeLog (223072 => 223073)
--- trunk/Source/WebCore/ChangeLog 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/ChangeLog 2017-10-09 22:17:05 UTC (rev 223073)
@@ -1,3 +1,47 @@
+2017-10-09 Youenn Fablet <[email protected]>
+
+ Add quota to cache API
+ https://bugs.webkit.org/show_bug.cgi?id=177552
+
+ Reviewed by Alex Christensen.
+
+ Tests: http/wpt/cache-storage/cache-quota.any.html
+
+ Storing padded opaque response body sizes within FetchResponse and CacheStorageConnection.
+ See https://github.com/whatwg/storage/issues/31 for the rationale about this padding.
+ Storing in CacheStorageConnection is needed for handling cloned network fetched created responses.
+ Storing in FetchResponse is needed for handling cloned cache-storage created opaque responses.
+
+ Adding internals to query and set the fuzzed size of a response.
+
+ * Modules/cache/CacheStorageConnection.cpp:
+ (WebCore::computeRealBodySize):
+ (WebCore::CacheStorageConnection::computeRecordBodySize):
+ (WebCore::CacheStorageConnection::setResponseBodySizeWithPadding):
+ (WebCore::CacheStorageConnection::responseBodySizeWithPadding const):
+ * Modules/cache/CacheStorageConnection.h:
+ * Modules/cache/DOMCache.cpp:
+ (WebCore::DOMCache::toConnectionRecord):
+ (WebCore::DOMCache::updateRecords):
+ * Modules/cache/DOMCache.h:
+ * Modules/cache/DOMCacheEngine.cpp:
+ (WebCore::DOMCacheEngine::errorToException):
+ (WebCore::DOMCacheEngine::Record::copy const):
+ * Modules/cache/DOMCacheEngine.h:
+ * Modules/cache/WorkerCacheStorageConnection.cpp:
+ (WebCore::toCrossThreadRecordData):
+ (WebCore::fromCrossThreadRecordData):
+ * Modules/fetch/FetchResponse.cpp:
+ (WebCore::FetchResponse::clone):
+ (WebCore::FetchResponse::BodyLoader::didReceiveResponse):
+ * Modules/fetch/FetchResponse.h:
+ * Modules/fetch/FetchResponse.idl:
+ * testing/Internals.cpp:
+ (WebCore::Internals::setResponseSizeWithPadding):
+ (WebCore::Internals::responseSizeWithPadding const):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2017-10-09 Zalan Bujtas <[email protected]>
Remove redundant RenderObject::virtualContinuation
Modified: trunk/Source/WebCore/Modules/cache/CacheStorageConnection.cpp (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/CacheStorageConnection.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/CacheStorageConnection.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -27,6 +27,9 @@
#include "config.h"
#include "CacheStorageConnection.h"
+#include "FetchResponse.h"
+#include <wtf/RandomNumber.h>
+
using namespace WebCore::DOMCacheEngine;
namespace WebCore {
@@ -71,6 +74,37 @@
doBatchDeleteOperation(requestIdentifier, cacheIdentifier, request, WTFMove(options));
}
+static inline uint64_t computeRealBodySize(const DOMCacheEngine::ResponseBody& body)
+{
+ uint64_t result = 0;
+ WTF::switchOn(body, [&] (const Ref<WebCore::FormData>& formData) {
+ result = formData->lengthInBytes();
+ }, [&] (const Ref<WebCore::SharedBuffer>& buffer) {
+ result = buffer->size();
+ }, [] (const std::nullptr_t&) {
+ });
+ return result;
+}
+
+uint64_t CacheStorageConnection::computeRecordBodySize(const FetchResponse& response, const DOMCacheEngine::ResponseBody& body, ResourceResponse::Tainting tainting)
+{
+ if (!response.opaqueLoadIdentifier()) {
+ ASSERT_UNUSED(tainting, tainting != ResourceResponse::Tainting::Opaque);
+ return computeRealBodySize(body);
+ }
+
+ return m_opaqueResponseToSizeWithPaddingMap.ensure(response.opaqueLoadIdentifier(), [&] () {
+ uint64_t realSize = computeRealBodySize(body);
+
+ // Padding the size as per https://github.com/whatwg/storage/issues/31.
+ uint64_t sizeWithPadding = realSize + static_cast<uint64_t>(randomNumber() * 128000);
+ sizeWithPadding = ((sizeWithPadding / 32000) + 1) * 32000;
+
+ m_opaqueResponseToSizeWithPaddingMap.set(response.opaqueLoadIdentifier(), sizeWithPadding);
+ return sizeWithPadding;
+ }).iterator->value;
+}
+
void CacheStorageConnection::batchPutOperation(uint64_t cacheIdentifier, Vector<Record>&& records, RecordIdentifiersCallback&& callback)
{
uint64_t requestIdentifier = ++m_lastRequestIdentifier;
Modified: trunk/Source/WebCore/Modules/cache/CacheStorageConnection.h (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/CacheStorageConnection.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/CacheStorageConnection.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -32,6 +32,8 @@
namespace WebCore {
+class FetchResponse;
+
class CacheStorageConnection : public ThreadSafeRefCounted<CacheStorageConnection> {
public:
static Ref<CacheStorageConnection> create() { return adoptRef(*new CacheStorageConnection()); }
@@ -44,6 +46,7 @@
void retrieveRecords(uint64_t cacheIdentifier, const URL&, DOMCacheEngine::RecordsCallback&&);
void batchDeleteOperation(uint64_t cacheIdentifier, const ResourceRequest&, CacheQueryOptions&&, DOMCacheEngine::RecordIdentifiersCallback&&);
void batchPutOperation(uint64_t cacheIdentifier, Vector<DOMCacheEngine::Record>&&, DOMCacheEngine::RecordIdentifiersCallback&&);
+ uint64_t computeRecordBodySize(const FetchResponse&, const DOMCacheEngine::ResponseBody&, ResourceResponse::Tainting);
virtual void reference(uint64_t /* cacheIdentifier */) { }
virtual void dereference(uint64_t /* cacheIdentifier */) { }
@@ -78,6 +81,7 @@
HashMap<uint64_t, DOMCacheEngine::CacheInfosCallback> m_retrieveCachesPendingRequests;
HashMap<uint64_t, DOMCacheEngine::RecordsCallback> m_retrieveRecordsPendingRequests;
HashMap<uint64_t, DOMCacheEngine::RecordIdentifiersCallback> m_batchDeleteAndPutPendingRequests;
+ HashMap<uint64_t, uint64_t> m_opaqueResponseToSizeWithPaddingMap;
uint64_t m_lastRequestIdentifier { 0 };
};
Modified: trunk/Source/WebCore/Modules/cache/DOMCache.cpp (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/DOMCache.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/DOMCache.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -38,8 +38,6 @@
namespace WebCore {
-static Record toConnectionRecord(const FetchRequest&, FetchResponse&, ResponseBody&&);
-
DOMCache::DOMCache(ScriptExecutionContext& context, String&& name, uint64_t identifier, Ref<CacheStorageConnection>&& connection)
: ActiveDOMObject(&context)
, m_name(WTFMove(name))
@@ -480,7 +478,7 @@
});
}
-Record toConnectionRecord(const FetchRequest& request, FetchResponse& response, DOMCacheEngine::ResponseBody&& responseBody)
+Record DOMCache::toConnectionRecord(const FetchRequest& request, FetchResponse& response, DOMCacheEngine::ResponseBody&& responseBody)
{
// FIXME: Add a setHTTPHeaderFields on ResourceResponseBase.
ResourceResponse cachedResponse = response.resourceResponse();
@@ -493,9 +491,15 @@
ASSERT(!cachedRequest.isNull());
ASSERT(!cachedResponse.isNull());
+ auto sizeWithPadding = response.bodySizeWithPadding();
+ if (!sizeWithPadding) {
+ sizeWithPadding = m_connection->computeRecordBodySize(response, responseBody, cachedResponse.tainting());
+ response.setBodySizeWithPadding(sizeWithPadding);
+ }
+
return { 0, 0,
request.headers().guard(), WTFMove(cachedRequest), request.fetchOptions(), request.internalRequestReferrer(),
- response.headers().guard(), WTFMove(cachedResponse), WTFMove(responseBody)
+ response.headers().guard(), WTFMove(cachedResponse), WTFMove(responseBody), sizeWithPadding
};
}
@@ -533,7 +537,7 @@
if (current.updateResponseCounter != record.updateResponseCounter) {
auto responseHeaders = FetchHeaders::create(record.responseHeadersGuard, HTTPHeaderMap { record.response.httpHeaderFields() });
auto response = FetchResponse::create(*scriptExecutionContext(), std::nullopt, WTFMove(responseHeaders), WTFMove(record.response));
- response->setBodyData(WTFMove(record.responseBody));
+ response->setBodyData(WTFMove(record.responseBody), record.responseBodySize);
current.response = WTFMove(response);
current.updateResponseCounter = record.updateResponseCounter;
@@ -545,7 +549,7 @@
auto responseHeaders = FetchHeaders::create(record.responseHeadersGuard, HTTPHeaderMap { record.response.httpHeaderFields() });
auto response = FetchResponse::create(*scriptExecutionContext(), std::nullopt, WTFMove(responseHeaders), WTFMove(record.response));
- response->setBodyData(WTFMove(record.responseBody));
+ response->setBodyData(WTFMove(record.responseBody), record.responseBodySize);
newRecords.append(CacheStorageRecord { record.identifier, record.updateResponseCounter, WTFMove(request), WTFMove(response) });
}
Modified: trunk/Source/WebCore/Modules/cache/DOMCache.h (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/DOMCache.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/DOMCache.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -80,6 +80,7 @@
void updateRecords(Vector<DOMCacheEngine::Record>&&);
Vector<Ref<FetchResponse>> cloneResponses(const Vector<CacheStorageRecord>&);
+ DOMCacheEngine::Record toConnectionRecord(const FetchRequest&, FetchResponse&, DOMCacheEngine::ResponseBody&&);
String m_name;
uint64_t m_identifier;
Modified: trunk/Source/WebCore/Modules/cache/DOMCacheEngine.cpp (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/DOMCacheEngine.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/DOMCacheEngine.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -44,6 +44,8 @@
return Exception { TypeError, ASCIILiteral("Failed reading data from the file system") };
case Error::WriteDisk:
return Exception { TypeError, ASCIILiteral("Failed writing data to the file system") };
+ case Error::QuotaExceeded:
+ return Exception { QuotaExceededError, ASCIILiteral("Quota exceeded") };
default:
return Exception { TypeError, ASCIILiteral("Internal error") };
}
@@ -135,7 +137,7 @@
Record Record::copy() const
{
- return Record { identifier, updateResponseCounter, requestHeadersGuard, request, options, referrer, responseHeadersGuard, response, copyResponseBody(responseBody) };
+ return Record { identifier, updateResponseCounter, requestHeadersGuard, request, options, referrer, responseHeadersGuard, response, copyResponseBody(responseBody), responseBodySize };
}
static inline CacheInfo isolateCacheInfo(const CacheInfo& info)
Modified: trunk/Source/WebCore/Modules/cache/DOMCacheEngine.h (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/DOMCacheEngine.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/DOMCacheEngine.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -42,6 +42,7 @@
NotImplemented,
ReadDisk,
WriteDisk,
+ QuotaExceeded,
Internal
};
@@ -68,6 +69,7 @@
FetchHeaders::Guard responseHeadersGuard;
ResourceResponse response;
ResponseBody responseBody;
+ uint64_t responseBodySize;
};
struct CacheInfo {
@@ -121,12 +123,12 @@
decoder >> infos;
if (!infos)
return std::nullopt;
-
+
std::optional<uint64_t> updateCounter;
decoder >> updateCounter;
if (!updateCounter)
return std::nullopt;
-
+
return {{ WTFMove(*infos), WTFMove(*updateCounter) }};
}
@@ -142,7 +144,7 @@
decoder >> identifier;
if (!identifier)
return std::nullopt;
-
+
std::optional<bool> hadStorageError;
decoder >> hadStorageError;
if (!hadStorageError)
@@ -161,6 +163,7 @@
WebCore::DOMCacheEngine::Error::NotImplemented,
WebCore::DOMCacheEngine::Error::ReadDisk,
WebCore::DOMCacheEngine::Error::WriteDisk,
+ WebCore::DOMCacheEngine::Error::QuotaExceeded,
WebCore::DOMCacheEngine::Error::Internal
>;
};
Modified: trunk/Source/WebCore/Modules/cache/WorkerCacheStorageConnection.cpp (223072 => 223073)
--- trunk/Source/WebCore/Modules/cache/WorkerCacheStorageConnection.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/cache/WorkerCacheStorageConnection.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -53,6 +53,7 @@
FetchHeaders::Guard responseHeadersGuard;
ResourceResponse::CrossThreadData response;
ResponseBody responseBody;
+ uint64_t responseBodySize;
};
static CrossThreadRecordData toCrossThreadRecordData(const Record& record)
@@ -66,7 +67,8 @@
record.referrer.isolatedCopy(),
record.responseHeadersGuard,
record.response.crossThreadData(),
- isolatedResponseBody(record.responseBody)
+ isolatedResponseBody(record.responseBody),
+ record.responseBodySize
};
}
@@ -81,7 +83,8 @@
WTFMove(data.referrer),
data.responseHeadersGuard,
ResourceResponse::fromCrossThreadData(WTFMove(data.response)),
- WTFMove(data.responseBody)
+ WTFMove(data.responseBody),
+ data.responseBodySize
};
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (223072 => 223073)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -159,6 +159,8 @@
clone->cloneBody(*this);
if (isBodyOpaque())
clone->setBodyAsOpaque();
+ clone->m_opaqueLoadIdentifier = m_opaqueLoadIdentifier;
+ clone->m_bodySizeWithPadding = m_bodySizeWithPadding;
return WTFMove(clone);
}
@@ -239,11 +241,14 @@
m_response.unsetPendingActivity(&m_response);
}
+static uint64_t nextOpaqueLoadIdentifier { 0 };
void FetchResponse::BodyLoader::didReceiveResponse(const ResourceResponse& resourceResponse)
{
m_response.m_response = ResourceResponseBase::filter(resourceResponse);
- if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque)
+ if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque) {
+ m_response.m_opaqueLoadIdentifier = ++nextOpaqueLoadIdentifier;
m_response.setBodyAsOpaque();
+ }
m_response.m_headers->filterAndFill(m_response.m_response.httpHeaderFields(), FetchHeaders::Guard::Response);
m_response.updateContentType();
@@ -326,8 +331,9 @@
m_bodyLoader->setConsumeDataCallback(WTFMove(callback));
}
-void FetchResponse::setBodyData(ResponseData&& data)
+void FetchResponse::setBodyData(ResponseData&& data, uint64_t bodySizeWithPadding)
{
+ m_bodySizeWithPadding = bodySizeWithPadding;
WTF::switchOn(data,
[this](Ref<FormData>& formData) {
if (isBodyNull())
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (223072 => 223073)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -87,7 +87,7 @@
using ResponseData = Variant<std::nullptr_t, Ref<FormData>, Ref<SharedBuffer>>;
ResponseData consumeBody();
- void setBodyData(ResponseData&&);
+ void setBodyData(ResponseData&&, uint64_t bodySizeWithPadding);
bool isLoading() const { return !!m_bodyLoader; }
@@ -97,6 +97,10 @@
const ResourceResponse& resourceResponse() const { return m_response; }
+ uint64_t bodySizeWithPadding() const { return m_bodySizeWithPadding; }
+ void setBodySizeWithPadding(uint64_t size) { m_bodySizeWithPadding = size; }
+ uint64_t opaqueLoadIdentifier() const { return m_opaqueLoadIdentifier; }
+
private:
FetchResponse(ScriptExecutionContext&, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
@@ -138,6 +142,9 @@
ResourceResponse m_response;
std::optional<BodyLoader> m_bodyLoader;
mutable String m_responseURL;
+ // Opaque responses will padd their body size when used with Cache API.
+ uint64_t m_bodySizeWithPadding { 0 };
+ uint64_t m_opaqueLoadIdentifier { 0 };
};
inline Ref<FetchResponse> FetchResponse::create(ScriptExecutionContext& context, std::optional<FetchBody>&& body, Ref<FetchHeaders>&& headers, ResourceResponse&& response)
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.idl (223072 => 223073)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.idl 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.idl 2017-10-09 22:17:05 UTC (rev 223073)
@@ -43,6 +43,7 @@
ConstructorCallWith=ScriptExecutionContext,
ConstructorMayThrowException,
EnabledAtRuntime=FetchAPI,
+ ExportToWrappedFunction,
Exposed=(Window,Worker),
InterfaceName=Response,
] interface FetchResponse {
Modified: trunk/Source/WebCore/testing/Internals.cpp (223072 => 223073)
--- trunk/Source/WebCore/testing/Internals.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/testing/Internals.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -58,6 +58,7 @@
#include "Element.h"
#include "EventHandler.h"
#include "ExtensionStyleSheets.h"
+#include "FetchResponse.h"
#include "File.h"
#include "FontCache.h"
#include "FormController.h"
@@ -4174,4 +4175,14 @@
contextDocument()->setConsoleMessageListener(WTFMove(listener));
}
+void Internals::setResponseSizeWithPadding(FetchResponse& response, uint64_t size)
+{
+ response.setBodySizeWithPadding(size);
+}
+
+uint64_t Internals::responseSizeWithPadding(FetchResponse& response) const
+{
+ return response.bodySizeWithPadding();
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/testing/Internals.h (223072 => 223073)
--- trunk/Source/WebCore/testing/Internals.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/testing/Internals.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -50,6 +50,7 @@
class DOMWindow;
class Document;
class Element;
+class FetchResponse;
class File;
class Frame;
class GCObservation;
@@ -600,6 +601,8 @@
void clearCacheStorageMemoryRepresentation(DOMPromiseDeferred<void>&&);
void cacheStorageEngineRepresentation(DOMPromiseDeferred<IDLDOMString>&&);
+ void setResponseSizeWithPadding(FetchResponse&, uint64_t size);
+ uint64_t responseSizeWithPadding(FetchResponse&) const;
void setConsoleMessageListener(RefPtr<StringCallback>&&);
Modified: trunk/Source/WebCore/testing/Internals.idl (223072 => 223073)
--- trunk/Source/WebCore/testing/Internals.idl 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebCore/testing/Internals.idl 2017-10-09 22:17:05 UTC (rev 223073)
@@ -547,6 +547,8 @@
Promise<void> clearCacheStorageMemoryRepresentation();
Promise<DOMString> cacheStorageEngineRepresentation();
+ void setResponseSizeWithPadding(FetchResponse response, unsigned long long size);
+ unsigned long long responseSizeWithPadding(FetchResponse response);
void setConsoleMessageListener(StringCallback callback);
Modified: trunk/Source/WebKit/ChangeLog (223072 => 223073)
--- trunk/Source/WebKit/ChangeLog 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/ChangeLog 2017-10-09 22:17:05 UTC (rev 223073)
@@ -1,3 +1,73 @@
+2017-10-09 Youenn Fablet <[email protected]>
+
+ Add quota to cache API
+ https://bugs.webkit.org/show_bug.cgi?id=177552
+
+ Reviewed by Alex Christensen.
+
+ Adding support for quota checking in CacheStorage::Caches.
+ It is passed to NetworkProcess at creation time.
+ Default quota size is configured to 400Ko by origin per default.
+ This value is suitable for testing.
+ Future patch should raise this default value and allows configuring it.
+
+ Quota is computed based on the response body size.
+ This size is padded at WebCore for opaque responses.
+ Size is stored persistently as opaque response padded size should remain stable.
+ See https://github.com/whatwg/storage/issues/31 for the rationale about this padding.
+
+ In case of putting several records at the same time, the size of all records
+ is computed so that all records will be written or rejected together.
+
+ Sending QuotaExceeded error when quota is exceeded.
+ Future effort should allow asking UIProcess for quota extension.
+
+ * NetworkProcess/NetworkProcess.cpp:
+ (WebKit::NetworkProcess::cacheStoragePerOriginQuota const):
+ * NetworkProcess/NetworkProcess.h:
+ * NetworkProcess/NetworkProcessCreationParameters.cpp:
+ (WebKit::NetworkProcessCreationParameters::encode const):
+ (WebKit::NetworkProcessCreationParameters::decode):
+ * NetworkProcess/NetworkProcessCreationParameters.h:
+ * NetworkProcess/cache/CacheStorageEngine.cpp:
+ (WebKit::CacheStorage::Engine::readCachesFromDisk):
+ * NetworkProcess/cache/CacheStorageEngineCache.cpp:
+ (WebKit::CacheStorage::Cache::toRecordInformation):
+ (WebKit::CacheStorage::isolatedCopy):
+ (WebKit::CacheStorage::Cache::open):
+ (WebKit::CacheStorage::Cache::storeRecords):
+ (WebKit::CacheStorage::Cache::put):
+ (WebKit::CacheStorage::Cache::writeRecordToDisk):
+ (WebKit::CacheStorage::Cache::updateRecordToDisk):
+ (WebKit::CacheStorage::Cache::removeRecordFromDisk):
+ (WebKit::CacheStorage::Cache::encode):
+ (WebKit::CacheStorage::Cache::decodeRecordHeader):
+ (WebKit::CacheStorage::Cache::decode):
+ * NetworkProcess/cache/CacheStorageEngineCache.h:
+ * NetworkProcess/cache/CacheStorageEngineCaches.cpp:
+ (WebKit::CacheStorage::Caches::Caches):
+ (WebKit::CacheStorage::Caches::initialize):
+ (WebKit::CacheStorage::Caches::initializeSize):
+ (WebKit::CacheStorage::Caches::requestSpace):
+ (WebKit::CacheStorage::Caches::writeRecord):
+ (WebKit::CacheStorage::Caches::removeRecord):
+ (WebKit::CacheStorage::Caches::removeCacheEntry):
+ * NetworkProcess/cache/CacheStorageEngineCaches.h:
+ (WebKit::CacheStorage::Caches::create):
+ (WebKit::CacheStorage::Caches::hasEnoughSpace const):
+ * NetworkProcess/cache/NetworkCacheStorage.cpp:
+ (WebKit::NetworkCache::Storage::traverse):
+ * NetworkProcess/cocoa/NetworkProcessCocoa.mm:
+ (WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa):
+ * Shared/WebCoreArgumentCoders.cpp:
+ (IPC::ArgumentCoder<DOMCacheEngine::Record>::encode):
+ (IPC::ArgumentCoder<DOMCacheEngine::Record>::decode):
+ * UIProcess/API/APIProcessPoolConfiguration.cpp:
+ (API::ProcessPoolConfiguration::copy):
+ * UIProcess/API/APIProcessPoolConfiguration.h:
+ * UIProcess/WebProcessPool.cpp:
+ (WebKit::WebProcessPool::ensureNetworkProcess):
+
2017-10-09 Sam Weinig <[email protected]>
Make HashMap::keys() and HashMap::values() work with WTF::map/WTF::copyToVector
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -766,6 +766,11 @@
#endif
}
+uint64_t NetworkProcess::cacheStoragePerOriginQuota() const
+{
+ return m_cacheStoragePerOriginQuota;
+}
+
#if !PLATFORM(COCOA)
void NetworkProcess::initializeProcess(const ChildProcessInitializationParameters&)
{
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -145,6 +145,7 @@
Seconds loadThrottleLatency() const { return m_loadThrottleLatency; }
String cacheStorageDirectory(PAL::SessionID) const;
+ uint64_t cacheStoragePerOriginQuota() const;
void preconnectTo(const WebCore::URL&, WebCore::StoredCredentialsPolicy);
@@ -237,6 +238,7 @@
Vector<RefPtr<NetworkConnectionToWebProcess>> m_webProcessConnections;
String m_cacheStorageDirectory;
+ uint64_t m_cacheStoragePerOriginQuota { 0 };
String m_diskCacheDirectory;
bool m_hasSetCacheModel;
CacheModel m_cacheModel;
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -46,6 +46,7 @@
encoder << diskCacheSizeOverride;
encoder << canHandleHTTPSServerTrustEvaluation;
encoder << cacheStorageDirectory;
+ encoder << cacheStoragePerOriginQuota;
encoder << cacheStorageDirectoryExtensionHandle;
encoder << diskCacheDirectory;
encoder << diskCacheDirectoryExtensionHandle;
@@ -116,6 +117,8 @@
return false;
if (!decoder.decode(result.cacheStorageDirectory))
return false;
+ if (!decoder.decode(result.cacheStoragePerOriginQuota))
+ return false;
if (!decoder.decode(result.cacheStorageDirectoryExtensionHandle))
return false;
if (!decoder.decode(result.diskCacheDirectory))
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -56,6 +56,7 @@
bool canHandleHTTPSServerTrustEvaluation { true };
String cacheStorageDirectory;
+ uint64_t cacheStoragePerOriginQuota;
SandboxExtension::Handle cacheStorageDirectoryExtensionHandle;
String diskCacheDirectory;
SandboxExtension::Handle diskCacheDirectoryExtensionHandle;
Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -190,7 +190,7 @@
{
initialize([this, origin, callback = WTFMove(callback)](std::optional<Error>&& error) mutable {
auto& caches = m_caches.ensure(origin, [&origin, this] {
- return Caches::create(*this, String { origin });
+ return Caches::create(*this, String { origin }, NetworkProcess::singleton().cacheStoragePerOriginQuota());
}).iterator->value;
if (caches->isInitialized()) {
Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -52,8 +52,6 @@
namespace CacheStorage {
-static std::optional<std::pair<Record, double>> decodeRecordHeader(const Storage::Record&);
-
static inline String computeKeyURL(const URL& url)
{
URL keyURL { url };
@@ -100,7 +98,7 @@
RecordInformation Cache::toRecordInformation(const Record& record)
{
Key key { ASCIILiteral("record"), m_uniqueName, { }, createCanonicalUUIDString(), m_caches.salt() };
- RecordInformation recordInformation { WTFMove(key), monotonicallyIncreasingTimeMS(), record.identifier, 0 , record.request.url(), false, { } };
+ RecordInformation recordInformation { WTFMove(key), monotonicallyIncreasingTimeMS(), record.identifier, 0 , record.responseBodySize, record.request.url(), false, { } };
updateVaryInformation(recordInformation, record.request, record.response);
@@ -123,6 +121,11 @@
void Cache::clearMemoryRepresentation()
{
+ for (auto& records : m_records.values()) {
+ for (auto& record : records)
+ removeRecordFromDisk(record);
+ }
+
m_records = { };
m_nextRecordIdentifier = 0;
m_state = State::Uninitialized;
@@ -130,7 +133,7 @@
static RecordInformation isolatedCopy(const RecordInformation& information)
{
- auto result = RecordInformation { information.key, information.insertionTime, information.identifier, information.updateResponseCounter, information.url.isolatedCopy(), information.hasVaryStar, { } };
+ auto result = RecordInformation { information.key, information.insertionTime, information.identifier, information.updateResponseCounter, information.size, information.url.isolatedCopy(), information.hasVaryStar, { } };
HashMap<String, String> varyHeaders;
for (const auto& keyValue : information.varyHeaders)
varyHeaders.set(keyValue.key.isolatedCopy(), keyValue.value.isolatedCopy());
@@ -175,7 +178,7 @@
if (!storageRecord) {
RunLoop::main().dispatch([caches = WTFMove(caches), callback = WTFMove(callback), traversalResult = isolatedCopy(WTFMove(traversalResult)) ]() mutable {
for (auto& key : traversalResult.failedRecords)
- caches->removeRecord(key);
+ caches->removeCacheEntry(key);
auto* cache = caches->find(traversalResult.cacheIdentifier);
if (!cache) {
@@ -194,10 +197,10 @@
return;
}
- auto& record = decoded->first;
- auto insertionTime = decoded->second;
+ auto& record = decoded->record;
+ auto insertionTime = decoded->insertionTime;
- RecordInformation recordInformation { storageRecord->key, insertionTime, 0, 0, record.request.url(), false, { } };
+ RecordInformation recordInformation { storageRecord->key, insertionTime, 0, 0, record.responseBodySize, record.request.url(), false, { } };
updateVaryInformation(recordInformation, record.request, record.response);
auto& sameURLRecords = traversalResult.records.ensure(computeKeyURL(recordInformation.url), [] { return Vector<RecordInformation> { }; }).iterator->value;
@@ -377,36 +380,67 @@
Vector<uint64_t> m_recordIdentifiers;
};
-void Cache::put(Vector<Record>&& records, RecordIdentifiersCallback&& callback)
+void Cache::storeRecords(Vector<Record>&& records, RecordIdentifiersCallback&& callback)
{
- ASSERT(m_state == State::Open);
-
auto taskCounter = AsynchronousPutTaskCounter::create(WTFMove(callback));
WebCore::CacheQueryOptions options;
for (auto& record : records) {
auto* sameURLRecords = recordsFromURL(record.request.url());
+ auto matchingRecords = queryCache(sameURLRecords, record.request, options);
- auto matchingRecords = queryCache(sameURLRecords, record.request, options);
- if (matchingRecords.isEmpty()) {
+ auto position = !matchingRecords.isEmpty() ? sameURLRecords->findMatching([&](const auto& item) { return item.identifier == matchingRecords[0]; }) : notFound;
+
+ if (position == notFound) {
record.identifier = ++m_nextRecordIdentifier;
taskCounter->addRecordIdentifier(record.identifier);
auto& recordToWrite = addRecord(sameURLRecords, record);
- writeRecordToDisk(recordToWrite, WTFMove(record), taskCounter.copyRef());
+ writeRecordToDisk(recordToWrite, WTFMove(record), taskCounter.copyRef(), 0);
} else {
- auto identifier = matchingRecords[0];
- auto position = sameURLRecords->findMatching([&](const auto& item) { return item.identifier == identifier; });
- ASSERT(position != notFound);
- if (position != notFound) {
- auto& existingRecord = sameURLRecords->at(position);
- taskCounter->addRecordIdentifier(identifier);
- updateRecordToDisk(existingRecord, WTFMove(record), taskCounter.copyRef());
- }
+ auto& existingRecord = sameURLRecords->at(position);
+ taskCounter->addRecordIdentifier(existingRecord.identifier);
+ updateRecordToDisk(existingRecord, WTFMove(record), taskCounter.copyRef());
}
}
}
+void Cache::put(Vector<Record>&& records, RecordIdentifiersCallback&& callback)
+{
+ ASSERT(m_state == State::Open);
+
+ WebCore::CacheQueryOptions options;
+ uint64_t spaceRequired = 0;
+
+ for (auto& record : records) {
+ auto* sameURLRecords = recordsFromURL(record.request.url());
+ auto matchingRecords = queryCache(sameURLRecords, record.request, options);
+
+ auto position = (sameURLRecords && !matchingRecords.isEmpty()) ? sameURLRecords->findMatching([&](const auto& item) { return item.identifier == matchingRecords[0]; }) : notFound;
+
+ spaceRequired += record.responseBodySize;
+ if (position != notFound)
+ spaceRequired -= sameURLRecords->at(position).size;
+ }
+
+ if (m_caches.hasEnoughSpace(spaceRequired)) {
+ storeRecords(WTFMove(records), WTFMove(callback));
+ return;
+ }
+
+ m_caches.requestSpace(spaceRequired, [caches = makeRef(m_caches), identifier = m_identifier, records = WTFMove(records), callback = WTFMove(callback)](std::optional<DOMCacheEngine::Error>&& error) mutable {
+ if (error) {
+ callback(makeUnexpected(error.value()));
+ return;
+ }
+ auto* cache = caches->find(identifier);
+ if (!cache)
+ return;
+
+ cache->storeRecords(WTFMove(records), WTFMove(callback));
+ });
+}
+
void Cache::remove(WebCore::ResourceRequest&& request, WebCore::CacheQueryOptions&& options, RecordIdentifiersCallback&& callback)
{
ASSERT(m_state == State::Open);
@@ -446,9 +480,9 @@
}
}
-void Cache::writeRecordToDisk(const RecordInformation& recordInformation, Record&& record, Ref<AsynchronousPutTaskCounter>&& taskCounter)
+void Cache::writeRecordToDisk(const RecordInformation& recordInformation, Record&& record, Ref<AsynchronousPutTaskCounter>&& taskCounter, uint64_t previousRecordSize)
{
- m_caches.writeRecord(*this, recordInformation, WTFMove(record), [taskCounter = WTFMove(taskCounter)](std::optional<Error>&& error) {
+ m_caches.writeRecord(*this, recordInformation, WTFMove(record), previousRecordSize, [taskCounter = WTFMove(taskCounter)](std::optional<Error>&& error) {
if (error)
taskCounter->setError(error.value());
});
@@ -473,6 +507,8 @@
if (position == notFound)
return;
auto& recordInfo = sameURLRecords->at(position);
+ auto previousSize = recordInfo.size;
+ recordInfo.size = record.responseBodySize;
auto& recordFromDisk = result.value();
record.requestHeadersGuard = recordFromDisk.requestHeadersGuard;
@@ -482,7 +518,7 @@
updateVaryInformation(recordInfo, record.request, record.response);
- cache->writeRecordToDisk(recordInfo, WTFMove(record), WTFMove(taskCounter));
+ cache->writeRecordToDisk(recordInfo, WTFMove(record), WTFMove(taskCounter), previousSize);
});
}
@@ -493,7 +529,7 @@
void Cache::removeRecordFromDisk(const RecordInformation& record)
{
- m_caches.removeRecord(record.key);
+ m_caches.removeRecord(record);
}
Storage::Record Cache::encode(const RecordInformation& recordInformation, const Record& record)
@@ -500,6 +536,7 @@
{
WTF::Persistence::Encoder encoder;
encoder << recordInformation.insertionTime;
+ encoder << recordInformation.size;
encoder << record.requestHeadersGuard;
record.request.encodeWithoutPlatformData(encoder);
encoder << record.options;
@@ -507,6 +544,7 @@
encoder << record.responseHeadersGuard;
encoder << record.response;
+ encoder << record.responseBodySize;
encoder.encodeChecksum();
@@ -522,7 +560,7 @@
return { recordInformation.key, { }, header, body, { } };
}
-static inline std::optional<std::pair<Record, double>> decodeRecordHeader(const Storage::Record& storage)
+std::optional<Cache::DecodedRecord> Cache::decodeRecordHeader(const Storage::Record& storage)
{
WTF::Persistence::Decoder decoder(storage.header.data(), storage.header.size());
@@ -532,6 +570,10 @@
if (!decoder.decode(insertionTime))
return std::nullopt;
+ uint64_t size;
+ if (!decoder.decode(size))
+ return std::nullopt;
+
if (!decoder.decode(record.requestHeadersGuard))
return std::nullopt;
@@ -550,10 +592,13 @@
if (!decoder.decode(record.response))
return std::nullopt;
+ if (!decoder.decode(record.responseBodySize))
+ return std::nullopt;
+
if (!decoder.verifyChecksum())
return std::nullopt;
- return std::make_pair(WTFMove(record), insertionTime);
+ return DecodedRecord { insertionTime, size, WTFMove(record) };
}
std::optional<Record> Cache::decode(const Storage::Record& storage)
@@ -563,7 +608,7 @@
if (!result)
return std::nullopt;
- auto record = WTFMove(result->first);
+ auto record = WTFMove(result->record);
record.responseBody = WebCore::SharedBuffer::create(storage.body.data(), storage.body.size());
return WTFMove(record);
Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -43,6 +43,8 @@
uint64_t identifier { 0 };
uint64_t updateResponseCounter { 0 };
+ uint64_t size { 0 };
+
WebCore::URL url;
bool hasVaryStar { false };
HashMap<String, String> varyHeaders;
@@ -78,11 +80,26 @@
static std::optional<WebCore::DOMCacheEngine::Record> decode(const NetworkCache::Storage::Record&);
static NetworkCache::Storage::Record encode(const RecordInformation&, const WebCore::DOMCacheEngine::Record&);
+ struct DecodedRecord {
+ DecodedRecord(double insertionTime, uint64_t size, WebCore::DOMCacheEngine::Record&& record)
+ : insertionTime(insertionTime)
+ , size(size)
+ , record(WTFMove(record))
+ { }
+
+ double insertionTime { 0 };
+ uint64_t size { 0 };
+ WebCore::DOMCacheEngine::Record record;
+ };
+ static std::optional<DecodedRecord> decodeRecordHeader(const NetworkCache::Storage::Record&);
+
private:
Vector<RecordInformation>* recordsFromURL(const WebCore::URL&);
const Vector<RecordInformation>* recordsFromURL(const WebCore::URL&) const;
RecordInformation& addRecord(Vector<RecordInformation>*, const WebCore::DOMCacheEngine::Record&);
+ void storeRecords(Vector<WebCore::DOMCacheEngine::Record>&&, WebCore::DOMCacheEngine::RecordIdentifiersCallback&&);
+
RecordInformation toRecordInformation(const WebCore::DOMCacheEngine::Record&);
void finishOpening(WebCore::DOMCacheEngine::CompletionCallback&&, std::optional<WebCore::DOMCacheEngine::Error>&&);
@@ -89,7 +106,7 @@
void retrieveRecord(const RecordInformation&, Ref<ReadRecordTaskCounter>&&);
void readRecordsList(WebCore::DOMCacheEngine::CompletionCallback&&);
- void writeRecordToDisk(const RecordInformation&, WebCore::DOMCacheEngine::Record&&, Ref<AsynchronousPutTaskCounter>&&);
+ void writeRecordToDisk(const RecordInformation&, WebCore::DOMCacheEngine::Record&&, Ref<AsynchronousPutTaskCounter>&&, uint64_t previousRecordSize);
void updateRecordToDisk(RecordInformation&, WebCore::DOMCacheEngine::Record&&, Ref<AsynchronousPutTaskCounter>&&);
void removeRecordFromDisk(const RecordInformation&);
void readRecordFromDisk(const RecordInformation&, WTF::Function<void(Expected<WebCore::DOMCacheEngine::Record, WebCore::DOMCacheEngine::Error>&&)>&&);
Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -51,10 +51,11 @@
return WebCore::pathByAppendingComponent(cachesRootPath, ASCIILiteral("cacheslist"));
}
-Caches::Caches(Engine& engine, String&& origin)
+Caches::Caches(Engine& engine, String&& origin, uint64_t quota)
: m_engine(&engine)
, m_origin(WTFMove(origin))
, m_rootPath(cachesRootPath(engine, m_origin))
+ , m_quota(quota)
{
}
@@ -84,7 +85,7 @@
}
m_storage = storage.releaseNonNull();
m_storage->writeWithoutWaiting();
- readCachesFromDisk([this, callback = WTFMove(callback)](Expected<Vector<Cache>, Error>&& result) {
+ readCachesFromDisk([this, callback = WTFMove(callback)](Expected<Vector<Cache>, Error>&& result) mutable {
makeDirty();
if (!result.hasValue()) {
@@ -96,12 +97,28 @@
return;
}
m_caches = WTFMove(result.value());
- m_isInitialized = true;
- callback(std::nullopt);
+ initializeSize(WTFMove(callback));
+ });
+}
- auto pendingCallbacks = WTFMove(m_pendingInitializationCallbacks);
- for (auto& callback : pendingCallbacks)
+void Caches::initializeSize(WebCore::DOMCacheEngine::CompletionCallback&& callback)
+{
+ uint64_t size = 0;
+ m_storage->traverse({ }, 0, [protectedThis = makeRef(*this), this, protectedStorage = makeRef(*m_storage), callback = WTFMove(callback), size](const auto* storage, const auto& information) mutable {
+ if (!storage) {
+ m_size = size;
+ m_isInitialized = true;
callback(std::nullopt);
+
+ auto pendingCallbacks = WTFMove(m_pendingInitializationCallbacks);
+ for (auto& callback : pendingCallbacks)
+ callback(std::nullopt);
+
+ return;
+ }
+ auto decoded = Cache::decodeRecordHeader(*storage);
+ if (decoded)
+ size += decoded->size;
});
}
@@ -299,11 +316,23 @@
});
}
-void Caches::writeRecord(const Cache& cache, const RecordInformation& recordInformation, Record&& record, CompletionCallback&& callback)
+void Caches::requestSpace(uint64_t spaceRequired, WebCore::DOMCacheEngine::CompletionCallback&& callback)
{
+ // FIXME: Implement quota increase request.
+ ASSERT(m_quota < m_size + spaceRequired);
+ callback(Error::QuotaExceeded);
+}
+
+void Caches::writeRecord(const Cache& cache, const RecordInformation& recordInformation, Record&& record, uint64_t previousRecordSize, CompletionCallback&& callback)
+{
ASSERT(m_isInitialized);
- // FIXME: Check for storage quota.
+ ASSERT(m_size >= previousRecordSize);
+ m_size += recordInformation.size;
+ m_size -= previousRecordSize;
+
+ ASSERT(m_size <= m_quota);
+
if (!shouldPersist()) {
m_volatileStorage.set(recordInformation.key, WTFMove(record));
return;
@@ -345,10 +374,19 @@
});
}
-void Caches::removeRecord(const NetworkCache::Key& key)
+void Caches::removeRecord(const RecordInformation& record)
{
ASSERT(m_isInitialized);
+ ASSERT(m_size >= record.size);
+ m_size -= record.size;
+ removeCacheEntry(record.key);
+}
+
+void Caches::removeCacheEntry(const NetworkCache::Key& key)
+{
+ ASSERT(m_isInitialized);
+
if (!shouldPersist()) {
m_volatileStorage.remove(key);
return;
Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -36,7 +36,7 @@
class Caches : public RefCounted<Caches> {
public:
- static Ref<Caches> create(Engine& engine, String&& origin) { return adoptRef(*new Caches { engine, WTFMove(origin) }); }
+ static Ref<Caches> create(Engine& engine, String&& origin, uint64_t quota) { return adoptRef(*new Caches { engine, WTFMove(origin), quota }); }
void initialize(WebCore::DOMCacheEngine::CompletionCallback&&);
void open(const String& name, WebCore::DOMCacheEngine::CacheIdentifierCallback&&);
@@ -54,16 +54,22 @@
void readRecordsList(Cache&, NetworkCache::Storage::TraverseHandler&&);
void readRecord(const NetworkCache::Key&, WTF::Function<void(Expected<WebCore::DOMCacheEngine::Record, WebCore::DOMCacheEngine::Error>&&)>&&);
- void writeRecord(const Cache&, const RecordInformation&, WebCore::DOMCacheEngine::Record&&, WebCore::DOMCacheEngine::CompletionCallback&&);
- void removeRecord(const NetworkCache::Key&);
+ bool hasEnoughSpace(uint64_t spaceRequired) const { return m_quota >= m_size + spaceRequired; }
+ void requestSpace(uint64_t spaceRequired, WebCore::DOMCacheEngine::CompletionCallback&&);
+ void writeRecord(const Cache&, const RecordInformation&, WebCore::DOMCacheEngine::Record&&, uint64_t previousRecordSize, WebCore::DOMCacheEngine::CompletionCallback&&);
+
+ void removeCacheEntry(const NetworkCache::Key&);
+ void removeRecord(const RecordInformation&);
+
const NetworkCache::Salt& salt() const;
bool shouldPersist() const { return !m_rootPath.isNull(); }
private:
- Caches(Engine&, String&& origin);
+ Caches(Engine&, String&& origin, uint64_t quota);
+ void initializeSize(WebCore::DOMCacheEngine::CompletionCallback&&);
void readCachesFromDisk(WTF::Function<void(Expected<Vector<Cache>, WebCore::DOMCacheEngine::Error>&&)>&&);
void writeCachesToDisk(WebCore::DOMCacheEngine::CompletionCallback&&);
@@ -77,6 +83,8 @@
uint64_t m_updateCounter { 0 };
String m_origin;
String m_rootPath;
+ uint64_t m_quota { 0 };
+ uint64_t m_size { 0 };
Vector<Cache> m_caches;
Vector<Cache> m_removedCaches;
RefPtr<NetworkCache::Storage> m_storage;
Modified: trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheStorage.cpp (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheStorage.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cache/NetworkCacheStorage.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -861,7 +861,7 @@
ioQueue().dispatch([this, &traverseOperation] {
traverseRecordsFiles(recordsPath(), traverseOperation.type, [this, &traverseOperation](const String& fileName, const String& hashString, const String& type, bool isBlob, const String& recordDirectoryPath) {
- ASSERT(type == traverseOperation.type);
+ ASSERT(type == traverseOperation.type || traverseOperation.type.isEmpty());
if (isBlob)
return;
Modified: trunk/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm (223072 => 223073)
--- trunk/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm 2017-10-09 22:17:05 UTC (rev 223073)
@@ -107,6 +107,7 @@
if (!parameters.cacheStorageDirectory.isNull()) {
m_cacheStorageDirectory = parameters.cacheStorageDirectory;
+ m_cacheStoragePerOriginQuota = parameters.cacheStoragePerOriginQuota;
SandboxExtension::consumePermanently(parameters.cacheStorageDirectoryExtensionHandle);
}
Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (223072 => 223073)
--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -261,6 +261,7 @@
encoder << record.responseHeadersGuard;
encoder << record.response;
encoder << record.updateResponseCounter;
+ encoder << record.responseBodySize;
WTF::switchOn(record.responseBody, [&](const Ref<SharedBuffer>& buffer) {
encoder << true;
@@ -309,6 +310,10 @@
if (!decoder.decode(updateResponseCounter))
return std::nullopt;
+ uint64_t responseBodySize;
+ if (!decoder.decode(responseBodySize))
+ return std::nullopt;
+
WebCore::DOMCacheEngine::ResponseBody responseBody;
bool hasSharedBufferBody;
if (!decoder.decode(hasSharedBufferBody))
@@ -332,7 +337,7 @@
}
}
- return {{ WTFMove(identifier), WTFMove(updateResponseCounter), WTFMove(requestHeadersGuard), WTFMove(request), WTFMove(options), WTFMove(referrer), WTFMove(responseHeadersGuard), WTFMove(response), WTFMove(responseBody) }};
+ return {{ WTFMove(identifier), WTFMove(updateResponseCounter), WTFMove(requestHeadersGuard), WTFMove(request), WTFMove(options), WTFMove(referrer), WTFMove(responseHeadersGuard), WTFMove(response), WTFMove(responseBody), responseBodySize }};
}
void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTrackingRegions& eventTrackingRegions)
Modified: trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp (223072 => 223073)
--- trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -111,7 +111,8 @@
copy->m_applicationCacheDirectory = this->m_applicationCacheDirectory;
copy->m_applicationCacheFlatFileSubdirectoryName = this->m_applicationCacheFlatFileSubdirectoryName;
copy->m_cacheStorageDirectory = this->m_cacheStorageDirectory;
- copy->m_diskCacheDirectory = this->m_diskCacheDirectory;
+ copy->m_cacheStorageDirectory = this->m_cacheStorageDirectory;
+ copy->m_cacheStoragePerOriginQuota = this->m_cacheStoragePerOriginQuota;
copy->m_mediaCacheDirectory = this->m_mediaCacheDirectory;
copy->m_indexedDBDatabaseDirectory = this->m_indexedDBDatabaseDirectory;
copy->m_injectedBundlePath = this->m_injectedBundlePath;
Modified: trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h (223072 => 223073)
--- trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h 2017-10-09 22:17:05 UTC (rev 223073)
@@ -69,6 +69,7 @@
const WTF::String& cacheStorageDirectory() const { return m_cacheStorageDirectory; }
void setCacheStorageDirectory(WTF::String&& cacheStorageDirectory) { m_cacheStorageDirectory = WTFMove(cacheStorageDirectory); }
+ uint64_t cacheStoragePerOriginQuota() const { return m_cacheStoragePerOriginQuota; }
const WTF::String& diskCacheDirectory() const { return m_diskCacheDirectory; }
void setDiskCacheDirectory(const WTF::String& diskCacheDirectory) { m_diskCacheDirectory = diskCacheDirectory; }
@@ -152,6 +153,7 @@
WTF::String m_applicationCacheDirectory;
WTF::String m_applicationCacheFlatFileSubdirectoryName;
WTF::String m_cacheStorageDirectory;
+ uint64_t m_cacheStoragePerOriginQuota { 400 * 1024 };
WTF::String m_diskCacheDirectory;
WTF::String m_mediaCacheDirectory;
WTF::String m_indexedDBDatabaseDirectory;
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (223072 => 223073)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2017-10-09 21:57:52 UTC (rev 223072)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2017-10-09 22:17:05 UTC (rev 223073)
@@ -434,6 +434,7 @@
parameters.urlSchemesRegisteredForCustomProtocols.append(scheme);
parameters.cacheStorageDirectory = m_configuration->cacheStorageDirectory();
+ parameters.cacheStoragePerOriginQuota = m_configuration->cacheStoragePerOriginQuota();
if (!parameters.cacheStorageDirectory.isEmpty())
SandboxExtension::createHandleForReadWriteDirectory(parameters.cacheStorageDirectory, parameters.cacheStorageDirectoryExtensionHandle);