Log Message
[Cache API] Add support for Cache.add/addAll https://bugs.webkit.org/show_bug.cgi?id=175677
Patch by Youenn Fablet <[email protected]> on 2017-08-21 Reviewed by Alex Christensen. LayoutTests/imported/w3c: * web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt: * web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt: * web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt: * web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt: Source/WebCore: Covered by rebased tests. Cache.addAll implementation is then as follow: - Fetch the resources in parallel. - Wait for all them to complete using FetchTaskCounter. - If an error happens in any load or if the response is not as expected for Cache API, reject the promise. - Call the batch put operation with all received FetchResponse objects. FetchTaskCounter is responsible to wait for each response to arrive. It then checks whether the response is fine, If not, the addAll promise is rejected. Otherwise, it waits for the body to be received. Introducing a helper routine to create a FetchRequest from a given RequestInfo. Introducing a helper routine to check for Vary Header '*' value in response headers. * Modules/cache/Cache.cpp: (WebCore::Cache::doMatch): (WebCore::Cache::add): (WebCore::queryCacheMatch): (WebCore::hasResponseVaryStarHeaderValue): (WebCore::FetchTaskCounter::FetchTaskCounter): (WebCore::FetchTaskCounter::~FetchTaskCounter): (WebCore::FetchTaskCounter::addRecord): (WebCore::FetchTaskCounter::isDone const): (WebCore::FetchTaskCounter::reject): (WebCore::Cache::requestFromInfo): (WebCore::Cache::addAll): (WebCore::Cache::put): (WebCore::Cache::remove): (WebCore::Cache::keys): (WebCore::toConnectionRecord): (WebCore::Cache::batchPutOperation): * Modules/cache/Cache.h:
Modified Paths
- trunk/LayoutTests/imported/w3c/ChangeLog
- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/Modules/cache/Cache.cpp
- trunk/Source/WebCore/Modules/cache/Cache.h
Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,5 +1,17 @@
2017-08-21 Youenn Fablet <[email protected]>
+ [Cache API] Add support for Cache.add/addAll
+ https://bugs.webkit.org/show_bug.cgi?id=175677
+
+ Reviewed by Alex Christensen.
+
+ * web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt:
+ * web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt:
+ * web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt:
+ * web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt:
+
+2017-08-21 Youenn Fablet <[email protected]>
+
[Cache API] Add support for CacheStorage.match
https://bugs.webkit.org/show_bug.cgi?id=175747
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,20 +1,20 @@
PASS Cache.add called with no arguments
-FAIL Cache.add called with relative URL specified as a string promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add called with non-HTTP/HTTPS URL assert_throws: Cache.add should throw a TypeError for non-HTTP/HTTPS URLs. function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add called with Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add called with POST request assert_throws: Cache.add should throw a TypeError for non-GET requests. function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add called twice with the same Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add with request with null body (not consumed) promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add with 206 response assert_throws: Cache.add should reject on partial response function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.addAll with 206 response assert_throws: Cache.addAll should reject with TypeError if any request fails function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add with request that results in a status of 404 assert_throws: Cache.add should reject if response is !ok function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add with request that results in a status of 500 assert_throws: Cache.add should reject if response is !ok function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
+PASS Cache.add called with relative URL specified as a string
+PASS Cache.add called with non-HTTP/HTTPS URL
+PASS Cache.add called with Request object
+PASS Cache.add called with POST request
+PASS Cache.add called twice with the same Request object
+PASS Cache.add with request with null body (not consumed)
+PASS Cache.add with 206 response
+PASS Cache.addAll with 206 response
+PASS Cache.add with request that results in a status of 404
+PASS Cache.add with request that results in a status of 500
PASS Cache.addAll with no arguments
PASS Cache.addAll with a mix of valid and undefined arguments
-FAIL Cache.addAll with an empty array promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with string URL arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with Request arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with a mix of succeeding and failing requests assert_throws: Cache.addAll should reject with TypeError if any request fails function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.addAll called with the same Request object specified twice assert_throws: Cache.addAll should throw InvalidStateError if the same request is added twice. function "function () { throw e }" threw object "NotSupportedError: Not implemented" that is not a DOMException InvalidStateError: property "code" is equal to 9, expected 11
+PASS Cache.addAll with an empty array
+PASS Cache.addAll with string URL arguments
+PASS Cache.addAll with Request arguments
+PASS Cache.addAll with a mix of succeeding and failing requests
+PASS Cache.addAll called with the same Request object specified twice
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,11 +1,11 @@
PASS CacheStorage.open
-FAIL CacheStorage.delete dooms, but does not delete immediately promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS CacheStorage.delete dooms, but does not delete immediately
PASS CacheStorage.open with an empty name
PASS CacheStorage.open with no arguments
PASS CacheStorage.has with existing cache
PASS CacheStorage.has with nonexistent cache
-FAIL CacheStorage.open with existing cache promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS CacheStorage.open with existing cache
PASS CacheStorage.delete with existing cache
PASS CacheStorage.delete with nonexistent cache
PASS CacheStorage names are DOMStrings not USVStrings
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,20 +1,20 @@
PASS Cache.add called with no arguments
-FAIL Cache.add called with relative URL specified as a string promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add called with non-HTTP/HTTPS URL assert_throws: Cache.add should throw a TypeError for non-HTTP/HTTPS URLs. function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add called with Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add called with POST request assert_throws: Cache.add should throw a TypeError for non-GET requests. function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add called twice with the same Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add with request with null body (not consumed) promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.add with 206 response assert_throws: Cache.add should reject on partial response function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.addAll with 206 response assert_throws: Cache.addAll should reject with TypeError if any request fails function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add with request that results in a status of 404 assert_throws: Cache.add should reject if response is !ok function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.add with request that results in a status of 500 assert_throws: Cache.add should reject if response is !ok function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
+PASS Cache.add called with relative URL specified as a string
+PASS Cache.add called with non-HTTP/HTTPS URL
+PASS Cache.add called with Request object
+PASS Cache.add called with POST request
+PASS Cache.add called twice with the same Request object
+PASS Cache.add with request with null body (not consumed)
+PASS Cache.add with 206 response
+PASS Cache.addAll with 206 response
+PASS Cache.add with request that results in a status of 404
+PASS Cache.add with request that results in a status of 500
PASS Cache.addAll with no arguments
PASS Cache.addAll with a mix of valid and undefined arguments
-FAIL Cache.addAll with an empty array promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with string URL arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with Request arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
-FAIL Cache.addAll with a mix of succeeding and failing requests assert_throws: Cache.addAll should reject with TypeError if any request fails function "function () { throw e }" threw object "NotSupportedError: Not implemented" ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Cache.addAll called with the same Request object specified twice assert_throws: Cache.addAll should throw InvalidStateError if the same request is added twice. function "function () { throw e }" threw object "NotSupportedError: Not implemented" that is not a DOMException InvalidStateError: property "code" is equal to 9, expected 11
+PASS Cache.addAll with an empty array
+PASS Cache.addAll with string URL arguments
+PASS Cache.addAll with Request arguments
+PASS Cache.addAll with a mix of succeeding and failing requests
+PASS Cache.addAll called with the same Request object specified twice
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,6 +1,6 @@
PASS Cache.put called with simple Request and Response
-PASS Cache.put called with Request and Response from fetch()
+FAIL Cache.put called with Request and Response from fetch() promise_test: Unhandled rejection with value: object "NotSupportedError: Caching a Response with data stored in a ReadableStream is not yet supported"
PASS Cache.put with Request without a body
PASS Cache.put with Response without a body
PASS Cache.put with a Response containing an empty URL
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt (220997 => 220998)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,11 +1,11 @@
PASS CacheStorage.open
-FAIL CacheStorage.delete dooms, but does not delete immediately promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS CacheStorage.delete dooms, but does not delete immediately
PASS CacheStorage.open with an empty name
PASS CacheStorage.open with no arguments
PASS CacheStorage.has with existing cache
PASS CacheStorage.has with nonexistent cache
-FAIL CacheStorage.open with existing cache promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS CacheStorage.open with existing cache
PASS CacheStorage.delete with existing cache
PASS CacheStorage.delete with nonexistent cache
PASS CacheStorage names are DOMStrings not USVStrings
Modified: trunk/Source/WebCore/ChangeLog (220997 => 220998)
--- trunk/Source/WebCore/ChangeLog 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/Source/WebCore/ChangeLog 2017-08-22 02:03:24 UTC (rev 220998)
@@ -1,3 +1,45 @@
+2017-08-21 Youenn Fablet <[email protected]>
+
+ [Cache API] Add support for Cache.add/addAll
+ https://bugs.webkit.org/show_bug.cgi?id=175677
+
+ Reviewed by Alex Christensen.
+
+ Covered by rebased tests.
+
+ Cache.addAll implementation is then as follow:
+ - Fetch the resources in parallel.
+ - Wait for all them to complete using FetchTaskCounter.
+ - If an error happens in any load or if the response is not as expected for Cache API, reject the promise.
+ - Call the batch put operation with all received FetchResponse objects.
+
+ FetchTaskCounter is responsible to wait for each response to arrive.
+ It then checks whether the response is fine,
+ If not, the addAll promise is rejected.
+ Otherwise, it waits for the body to be received.
+
+ Introducing a helper routine to create a FetchRequest from a given RequestInfo.
+ Introducing a helper routine to check for Vary Header '*' value in response headers.
+
+ * Modules/cache/Cache.cpp:
+ (WebCore::Cache::doMatch):
+ (WebCore::Cache::add):
+ (WebCore::queryCacheMatch):
+ (WebCore::hasResponseVaryStarHeaderValue):
+ (WebCore::FetchTaskCounter::FetchTaskCounter):
+ (WebCore::FetchTaskCounter::~FetchTaskCounter):
+ (WebCore::FetchTaskCounter::addRecord):
+ (WebCore::FetchTaskCounter::isDone const):
+ (WebCore::FetchTaskCounter::reject):
+ (WebCore::Cache::requestFromInfo):
+ (WebCore::Cache::addAll):
+ (WebCore::Cache::put):
+ (WebCore::Cache::remove):
+ (WebCore::Cache::keys):
+ (WebCore::toConnectionRecord):
+ (WebCore::Cache::batchPutOperation):
+ * Modules/cache/Cache.h:
+
2017-08-21 Myles C. Maxfield <[email protected]>
DataInteractionTests.ExternalSourceAttributedStringToContentEditable hits a debug assertion
Modified: trunk/Source/WebCore/Modules/cache/Cache.cpp (220997 => 220998)
--- trunk/Source/WebCore/Modules/cache/Cache.cpp 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/Source/WebCore/Modules/cache/Cache.cpp 2017-08-22 02:03:24 UTC (rev 220998)
@@ -36,6 +36,8 @@
namespace WebCore {
+static CacheStorageConnection::Record toConnectionRecord(const FetchRequest&, FetchResponse&, CacheStorageConnection::ResponseBody&&);
+
Cache::Cache(ScriptExecutionContext& context, String&& name, uint64_t identifier, Ref<CacheStorageConnection>&& connection)
: ActiveDOMObject(&context)
, m_name(WTFMove(name))
@@ -62,20 +64,17 @@
void Cache::doMatch(RequestInfo&& info, CacheQueryOptions&& options, MatchCallback&& callback)
{
- RefPtr<FetchRequest> request;
- if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
- request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
- if (request->method() != "GET" && !options.ignoreMethod) {
- callback(nullptr);
- return;
- }
- } else {
- if (UNLIKELY(!scriptExecutionContext()))
- return;
- request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
+ if (UNLIKELY(!scriptExecutionContext()))
+ return;
+
+ auto requestOrException = requestFromInfo(WTFMove(info), options.ignoreMethod);
+ if (requestOrException.hasException()) {
+ callback(nullptr);
+ return;
}
+ auto request = requestOrException.releaseReturnValue();
- queryCache(request.releaseNonNull(), WTFMove(options), [callback = WTFMove(callback)](const Vector<CacheStorageRecord>& records) mutable {
+ queryCache(request.get(), WTFMove(options), [callback = WTFMove(callback)](const Vector<CacheStorageRecord>& records) mutable {
if (records.isEmpty()) {
callback(nullptr);
return;
@@ -86,19 +85,17 @@
void Cache::matchAll(std::optional<RequestInfo>&& info, CacheQueryOptions&& options, MatchAllPromise&& promise)
{
+ if (UNLIKELY(!scriptExecutionContext()))
+ return;
+
RefPtr<FetchRequest> request;
if (info) {
- if (WTF::holds_alternative<RefPtr<FetchRequest>>(info.value())) {
- request = WTF::get<RefPtr<FetchRequest>>(info.value()).releaseNonNull();
- if (request->method() != "GET" && !options.ignoreMethod) {
- promise.resolve({ });
- return;
- }
- } else {
- if (UNLIKELY(!scriptExecutionContext()))
- return;
- request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info.value()), { }).releaseReturnValue();
+ auto requestOrException = requestFromInfo(WTFMove(info.value()), options.ignoreMethod);
+ if (requestOrException.hasException()) {
+ promise.resolve({ });
+ return;
}
+ request = requestOrException.releaseReturnValue();
}
if (!request) {
@@ -120,45 +117,175 @@
});
}
-void Cache::add(RequestInfo&&, DOMPromiseDeferred<void>&& promise)
+void Cache::add(RequestInfo&& info, DOMPromiseDeferred<void>&& promise)
{
- promise.reject(Exception { NotSupportedError, ASCIILiteral("Not implemented")});
+ addAll(Vector<RequestInfo> { WTFMove(info) }, WTFMove(promise));
}
-void Cache::addAll(Vector<RequestInfo>&&, DOMPromiseDeferred<void>&& promise)
+static inline bool hasResponseVaryStarHeaderValue(const FetchResponse& response)
{
- promise.reject(Exception { NotSupportedError, ASCIILiteral("Not implemented")});
+ auto varyValue = response.headers().internalHeaders().get(WebCore::HTTPHeaderName::Vary);
+ bool hasStar = false;
+ varyValue.split(',', false, [&](StringView view) {
+ if (!hasStar && stripLeadingAndTrailingHTTPSpaces(view.toStringWithoutCopying()) == "*")
+ hasStar = true;
+ });
+ return hasStar;
}
-void Cache::put(RequestInfo&& info, Ref<FetchResponse>&& response, DOMPromiseDeferred<void>&& promise)
+class FetchTasksHandler : public RefCounted<FetchTasksHandler> {
+public:
+ explicit FetchTasksHandler(Function<void(ExceptionOr<Vector<CacheStorageConnection::Record>>&&)>&& callback)
+ : m_callback(WTFMove(callback))
+ {
+ }
+
+ ~FetchTasksHandler()
+ {
+ if (m_callback)
+ m_callback(WTFMove(m_records));
+ }
+
+ const Vector<CacheStorageConnection::Record>& records() const { return m_records; }
+
+ size_t addRecord(CacheStorageConnection::Record&& record)
+ {
+ ASSERT(!isDone());
+ m_records.append(WTFMove(record));
+ return m_records.size() - 1;
+ }
+
+ void addResponseBody(size_t position, Ref<SharedBuffer>&& data)
+ {
+ ASSERT(!isDone());
+ m_records[position].responseBody = WTFMove(data);
+ }
+
+ bool isDone() const { return !m_callback; }
+
+ void error(Exception&& exception)
+ {
+ if (auto callback = WTFMove(m_callback))
+ callback(WTFMove(exception));
+ }
+
+private:
+ Vector<CacheStorageConnection::Record> m_records;
+ Function<void(ExceptionOr<Vector<CacheStorageConnection::Record>>&&)> m_callback;
+};
+
+ExceptionOr<Ref<FetchRequest>> Cache::requestFromInfo(RequestInfo&& info, bool ignoreMethod)
{
RefPtr<FetchRequest> request;
if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
- if (request->method() != "GET") {
- promise.reject(Exception { TypeError, ASCIILiteral("Request method is not GET") });
+ if (request->method() != "GET" && !ignoreMethod)
+ return Exception { TypeError, ASCIILiteral("Request method is not GET") };
+ } else
+ request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
+
+ if (!protocolIsInHTTPFamily(request->url()))
+ return Exception { TypeError, ASCIILiteral("Request url is not HTTP/HTTPS") };
+
+ return request.releaseNonNull();
+}
+
+void Cache::addAll(Vector<RequestInfo>&& infos, DOMPromiseDeferred<void>&& promise)
+{
+ if (UNLIKELY(!scriptExecutionContext()))
+ return;
+
+ Vector<Ref<FetchRequest>> requests;
+ requests.reserveInitialCapacity(infos.size());
+ for (auto& info : infos) {
+ bool ignoreMethod = false;
+ auto requestOrException = requestFromInfo(WTFMove(info), ignoreMethod);
+ if (requestOrException.hasException()) {
+ promise.reject(requestOrException.releaseException());
return;
}
- } else {
- if (UNLIKELY(!scriptExecutionContext()))
+ requests.uncheckedAppend(requestOrException.releaseReturnValue());
+ }
+
+ auto taskHandler = adoptRef(*new FetchTasksHandler([protectedThis = makeRef(*this), this, promise = WTFMove(promise)](ExceptionOr<Vector<CacheStorageConnection::Record>>&& result) mutable {
+ if (result.hasException()) {
+ promise.reject(result.releaseException());
return;
- request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
+ }
+ batchPutOperation(result.releaseReturnValue(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
+ promise.settle(WTFMove(result));
+ });
+ }));
+
+ for (auto& request : requests) {
+ auto& requestReference = request.get();
+ FetchResponse::fetch(*scriptExecutionContext(), requestReference, [this, request = WTFMove(request), taskHandler = taskHandler.copyRef()](ExceptionOr<FetchResponse&>&& result) mutable {
+
+ if (taskHandler->isDone())
+ return;
+
+ if (result.hasException()) {
+ taskHandler->error(result.releaseException());
+ return;
+ }
+
+ auto& response = result.releaseReturnValue();
+
+ if (!response.ok()) {
+ taskHandler->error(Exception { TypeError, ASCIILiteral("Response is not OK") });
+ return;
+ }
+
+ if (hasResponseVaryStarHeaderValue(response)) {
+ taskHandler->error(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
+ return;
+ }
+
+ if (response.status() == 206) {
+ taskHandler->error(Exception { TypeError, ASCIILiteral("Response is a 206 partial") });
+ return;
+ }
+
+ CacheQueryOptions options;
+ for (const auto& record : taskHandler->records()) {
+ if (CacheStorageConnection::queryCacheMatch(request->resourceRequest(), record.request, record.response, options)) {
+ taskHandler->error(Exception { InvalidStateError, ASCIILiteral("addAll cannot store several matching requests")});
+ return;
+ }
+ }
+ size_t recordPosition = taskHandler->addRecord(toConnectionRecord(request.get(), response, nullptr));
+
+ response.consumeBodyWhenLoaded([taskHandler = WTFMove(taskHandler), recordPosition](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
+ if (taskHandler->isDone())
+ return;
+
+ if (result.hasException()) {
+ taskHandler->error(result.releaseException());
+ return;
+ }
+ if (auto value = result.releaseReturnValue())
+ taskHandler->addResponseBody(recordPosition, value.releaseNonNull());
+ });
+ });
}
+}
- if (!protocolIsInHTTPFamily(request->url())) {
- promise.reject(Exception { TypeError, ASCIILiteral("Request url is not HTTP/HTTPS") });
+void Cache::put(RequestInfo&& info, Ref<FetchResponse>&& response, DOMPromiseDeferred<void>&& promise)
+{
+ if (UNLIKELY(!scriptExecutionContext()))
return;
+
+ bool ignoreMethod = false;
+ auto requestOrException = requestFromInfo(WTFMove(info), ignoreMethod);
+ if (requestOrException.hasException()) {
+ promise.reject(requestOrException.releaseException());
+ return;
}
+ auto request = requestOrException.releaseReturnValue();
- // FIXME: This is inefficient, we should be able to split and trim whitespaces at the same time.
- auto varyValue = response->headers().internalHeaders().get(WebCore::HTTPHeaderName::Vary);
- Vector<String> varyHeaderNames;
- varyValue.split(',', false, varyHeaderNames);
- for (auto& name : varyHeaderNames) {
- if (stripLeadingAndTrailingHTTPSpaces(name) == "*") {
- promise.reject(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
- return;
- }
+ if (hasResponseVaryStarHeaderValue(response.get())) {
+ promise.reject(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
+ return;
}
if (response->status() == 206) {
@@ -179,7 +306,7 @@
if (response->isLoading()) {
setPendingActivity(this);
- response->consumeBodyWhenLoaded([promise = WTFMove(promise), request = request.releaseNonNull(), response = WTFMove(response), this](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
+ response->consumeBodyWhenLoaded([promise = WTFMove(promise), request = WTFMove(request), response = WTFMove(response), this](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
if (result.hasException())
promise.reject(result.releaseException());
else {
@@ -195,7 +322,7 @@
return;
}
- batchPutOperation(*request, response.get(), response->consumeBody(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
+ batchPutOperation(request.get(), response.get(), response->consumeBody(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
promise.settle(WTFMove(result));
});
}
@@ -202,20 +329,16 @@
void Cache::remove(RequestInfo&& info, CacheQueryOptions&& options, DOMPromiseDeferred<IDLBoolean>&& promise)
{
- RefPtr<FetchRequest> request;
- if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
- request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
- if (request->method() != "GET" && !options.ignoreMethod) {
- promise.resolve(false);
- return;
- }
- } else {
- if (UNLIKELY(!scriptExecutionContext()))
- return;
- request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
+ if (UNLIKELY(!scriptExecutionContext()))
+ return;
+
+ auto requestOrException = requestFromInfo(WTFMove(info), options.ignoreMethod);
+ if (requestOrException.hasException()) {
+ promise.resolve(false);
+ return;
}
- batchDeleteOperation(*request, WTFMove(options), [promise = WTFMove(promise)](ExceptionOr<bool>&& result) mutable {
+ batchDeleteOperation(requestOrException.releaseReturnValue(), WTFMove(options), [promise = WTFMove(promise)](ExceptionOr<bool>&& result) mutable {
promise.settle(WTFMove(result));
});
}
@@ -222,19 +345,17 @@
void Cache::keys(std::optional<RequestInfo>&& info, CacheQueryOptions&& options, KeysPromise&& promise)
{
+ if (UNLIKELY(!scriptExecutionContext()))
+ return;
+
RefPtr<FetchRequest> request;
if (info) {
- if (WTF::holds_alternative<RefPtr<FetchRequest>>(info.value())) {
- request = WTF::get<RefPtr<FetchRequest>>(info.value()).releaseNonNull();
- if (request->method() != "GET" && !options.ignoreMethod) {
- promise.resolve(Vector<Ref<FetchRequest>> { });
- return;
- }
- } else {
- if (UNLIKELY(!scriptExecutionContext()))
- return;
- request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info.value()), { }).releaseReturnValue();
+ auto requestOrException = requestFromInfo(WTFMove(info.value()), options.ignoreMethod);
+ if (requestOrException.hasException()) {
+ promise.resolve(Vector<Ref<FetchRequest>> { });
+ return;
}
+ request = requestOrException.releaseReturnValue();
}
if (!request) {
@@ -306,7 +427,7 @@
});
}
-static inline CacheStorageConnection::Record toConnectionRecord(const FetchRequest& request, FetchResponse& response, CacheStorageConnection::ResponseBody&& responseBody)
+CacheStorageConnection::Record toConnectionRecord(const FetchRequest& request, FetchResponse& response, CacheStorageConnection::ResponseBody&& responseBody)
{
// FIXME: Add a setHTTPHeaderFields on ResourceResponseBase.
ResourceResponse cachedResponse = response.resourceResponse();
@@ -330,6 +451,11 @@
Vector<CacheStorageConnection::Record> records;
records.append(toConnectionRecord(request, response, WTFMove(responseBody)));
+ batchPutOperation(WTFMove(records), WTFMove(callback));
+}
+
+void Cache::batchPutOperation(Vector<CacheStorageConnection::Record>&& records, WTF::Function<void(ExceptionOr<void>&&)>&& callback)
+{
setPendingActivity(this);
m_connection->batchPutOperation(m_identifier, WTFMove(records), [this, callback = WTFMove(callback)](Vector<uint64_t>&&, CacheStorageConnection::Error error) {
if (!m_isStopped)
Modified: trunk/Source/WebCore/Modules/cache/Cache.h (220997 => 220998)
--- trunk/Source/WebCore/Modules/cache/Cache.h 2017-08-22 01:50:34 UTC (rev 220997)
+++ trunk/Source/WebCore/Modules/cache/Cache.h 2017-08-22 02:03:24 UTC (rev 220998)
@@ -62,6 +62,8 @@
private:
Cache(ScriptExecutionContext&, String&& name, uint64_t identifier, Ref<CacheStorageConnection>&&);
+ ExceptionOr<Ref<FetchRequest>> requestFromInfo(RequestInfo&&, bool ignoreMethod);
+
// ActiveDOMObject
void stop() final;
const char* activeDOMObjectName() const final;
@@ -72,6 +74,7 @@
void queryCache(Ref<FetchRequest>&&, CacheQueryOptions&&, WTF::Function<void(const Vector<CacheStorageRecord>&)>&&);
void batchDeleteOperation(const FetchRequest&, CacheQueryOptions&&, WTF::Function<void(ExceptionOr<bool>&&)>&&);
void batchPutOperation(const FetchRequest&, FetchResponse&, CacheStorageConnection::ResponseBody&&, WTF::Function<void(ExceptionOr<void>&&)>&&);
+ void batchPutOperation(Vector<CacheStorageConnection::Record>&&, WTF::Function<void(ExceptionOr<void>&&)>&&);
void updateRecords(Vector<CacheStorageConnection::Record>&&);
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
