Changeset 220998 in webkit


Ignore:
Timestamp:
Aug 21, 2017 7:03:24 PM (7 years ago)
Author:
commit-queue@webkit.org
Message:

[Cache API] Add support for Cache.add/addAll
https://bugs.webkit.org/show_bug.cgi?id=175677

Patch by Youenn Fablet <youenn@apple.com> 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:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r220984 r220998  
     12017-08-21  Youenn Fablet  <youenn@apple.com>
     2
     3        [Cache API] Add support for Cache.add/addAll
     4        https://bugs.webkit.org/show_bug.cgi?id=175677
     5
     6        Reviewed by Alex Christensen.
     7
     8        * web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt:
     9        * web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt:
     10        * web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt:
     11        * web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt:
     12
    1132017-08-21  Youenn Fablet  <youenn@apple.com>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-add.https-expected.txt

    r220917 r220998  
    11
    22PASS Cache.add called with no arguments
    3 FAIL Cache.add called with relative URL specified as a string promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    4 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")
    5 FAIL Cache.add called with Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    6 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")
    7 FAIL Cache.add called twice with the same Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    8 FAIL Cache.add with request with null body (not consumed) promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    9 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")
    10 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")
    11 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")
    12 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")
     3PASS Cache.add called with relative URL specified as a string
     4PASS Cache.add called with non-HTTP/HTTPS URL
     5PASS Cache.add called with Request object
     6PASS Cache.add called with POST request
     7PASS Cache.add called twice with the same Request object
     8PASS Cache.add with request with null body (not consumed)
     9PASS Cache.add with 206 response
     10PASS Cache.addAll with 206 response
     11PASS Cache.add with request that results in a status of 404
     12PASS Cache.add with request that results in a status of 500
    1313PASS Cache.addAll with no arguments
    1414PASS Cache.addAll with a mix of valid and undefined arguments
    15 FAIL Cache.addAll with an empty array promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    16 FAIL Cache.addAll with string URL arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    17 FAIL Cache.addAll with Request arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    18 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")
    19 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
     15PASS Cache.addAll with an empty array
     16PASS Cache.addAll with string URL arguments
     17PASS Cache.addAll with Request arguments
     18PASS Cache.addAll with a mix of succeeding and failing requests
     19PASS Cache.addAll called with the same Request object specified twice
    2020
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/window/cache-storage.https-expected.txt

    r220917 r220998  
    11
    22PASS CacheStorage.open
    3 FAIL CacheStorage.delete dooms, but does not delete immediately promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     3PASS CacheStorage.delete dooms, but does not delete immediately
    44PASS CacheStorage.open with an empty name
    55PASS CacheStorage.open with no arguments
    66PASS CacheStorage.has with existing cache
    77PASS CacheStorage.has with nonexistent cache
    8 FAIL CacheStorage.open with existing cache promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     8PASS CacheStorage.open with existing cache
    99PASS CacheStorage.delete with existing cache
    1010PASS CacheStorage.delete with nonexistent cache
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-add.https-expected.txt

    r220917 r220998  
    11
    22PASS Cache.add called with no arguments
    3 FAIL Cache.add called with relative URL specified as a string promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    4 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")
    5 FAIL Cache.add called with Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    6 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")
    7 FAIL Cache.add called twice with the same Request object promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    8 FAIL Cache.add with request with null body (not consumed) promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    9 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")
    10 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")
    11 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")
    12 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")
     3PASS Cache.add called with relative URL specified as a string
     4PASS Cache.add called with non-HTTP/HTTPS URL
     5PASS Cache.add called with Request object
     6PASS Cache.add called with POST request
     7PASS Cache.add called twice with the same Request object
     8PASS Cache.add with request with null body (not consumed)
     9PASS Cache.add with 206 response
     10PASS Cache.addAll with 206 response
     11PASS Cache.add with request that results in a status of 404
     12PASS Cache.add with request that results in a status of 500
    1313PASS Cache.addAll with no arguments
    1414PASS Cache.addAll with a mix of valid and undefined arguments
    15 FAIL Cache.addAll with an empty array promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    16 FAIL Cache.addAll with string URL arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    17 FAIL Cache.addAll with Request arguments promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
    18 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")
    19 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
     15PASS Cache.addAll with an empty array
     16PASS Cache.addAll with string URL arguments
     17PASS Cache.addAll with Request arguments
     18PASS Cache.addAll with a mix of succeeding and failing requests
     19PASS Cache.addAll called with the same Request object specified twice
    2020
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt

    r220928 r220998  
    11
    22PASS Cache.put called with simple Request and Response
    3 PASS Cache.put called with Request and Response from fetch()
     3FAIL 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"
    44PASS Cache.put with Request without a body
    55PASS Cache.put with Response without a body
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/cache-storage/worker/cache-storage.https-expected.txt

    r220917 r220998  
    11
    22PASS CacheStorage.open
    3 FAIL CacheStorage.delete dooms, but does not delete immediately promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     3PASS CacheStorage.delete dooms, but does not delete immediately
    44PASS CacheStorage.open with an empty name
    55PASS CacheStorage.open with no arguments
    66PASS CacheStorage.has with existing cache
    77PASS CacheStorage.has with nonexistent cache
    8 FAIL CacheStorage.open with existing cache promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     8PASS CacheStorage.open with existing cache
    99PASS CacheStorage.delete with existing cache
    1010PASS CacheStorage.delete with nonexistent cache
  • trunk/Source/WebCore/ChangeLog

    r220997 r220998  
     12017-08-21  Youenn Fablet  <youenn@apple.com>
     2
     3        [Cache API] Add support for Cache.add/addAll
     4        https://bugs.webkit.org/show_bug.cgi?id=175677
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by rebased tests.
     9
     10        Cache.addAll implementation is then as follow:
     11        - Fetch the resources in parallel.
     12        - Wait for all them to complete using FetchTaskCounter.
     13        - If an error happens in any load or if the response is not as expected for Cache API, reject the promise.
     14        - Call the batch put operation with all received FetchResponse objects.
     15
     16        FetchTaskCounter is responsible to wait for each response to arrive.
     17        It then checks whether the response is fine,
     18        If not, the addAll promise is rejected.
     19        Otherwise, it waits for the body to be received.
     20
     21        Introducing a helper routine to create a FetchRequest from a given RequestInfo.
     22        Introducing a helper routine to check for Vary Header '*' value in response headers.
     23
     24        * Modules/cache/Cache.cpp:
     25        (WebCore::Cache::doMatch):
     26        (WebCore::Cache::add):
     27        (WebCore::queryCacheMatch):
     28        (WebCore::hasResponseVaryStarHeaderValue):
     29        (WebCore::FetchTaskCounter::FetchTaskCounter):
     30        (WebCore::FetchTaskCounter::~FetchTaskCounter):
     31        (WebCore::FetchTaskCounter::addRecord):
     32        (WebCore::FetchTaskCounter::isDone const):
     33        (WebCore::FetchTaskCounter::reject):
     34        (WebCore::Cache::requestFromInfo):
     35        (WebCore::Cache::addAll):
     36        (WebCore::Cache::put):
     37        (WebCore::Cache::remove):
     38        (WebCore::Cache::keys):
     39        (WebCore::toConnectionRecord):
     40        (WebCore::Cache::batchPutOperation):
     41        * Modules/cache/Cache.h:
     42
    1432017-08-21  Myles C. Maxfield  <mmaxfield@apple.com>
    244
  • trunk/Source/WebCore/Modules/cache/Cache.cpp

    r220984 r220998  
    3737namespace WebCore {
    3838
     39static CacheStorageConnection::Record toConnectionRecord(const FetchRequest&, FetchResponse&, CacheStorageConnection::ResponseBody&&);
     40
    3941Cache::Cache(ScriptExecutionContext& context, String&& name, uint64_t identifier, Ref<CacheStorageConnection>&& connection)
    4042    : ActiveDOMObject(&context)
     
    6365void Cache::doMatch(RequestInfo&& info, CacheQueryOptions&& options, MatchCallback&& callback)
    6466{
    65     RefPtr<FetchRequest> request;
    66     if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
    67         request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
    68         if (request->method() != "GET" && !options.ignoreMethod) {
    69             callback(nullptr);
    70             return;
    71         }
    72     } else {
    73         if (UNLIKELY(!scriptExecutionContext()))
    74             return;
    75         request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
    76     }
    77 
    78     queryCache(request.releaseNonNull(), WTFMove(options), [callback = WTFMove(callback)](const Vector<CacheStorageRecord>& records) mutable {
     67    if (UNLIKELY(!scriptExecutionContext()))
     68        return;
     69
     70    auto requestOrException = requestFromInfo(WTFMove(info), options.ignoreMethod);
     71    if (requestOrException.hasException()) {
     72        callback(nullptr);
     73        return;
     74    }
     75    auto request = requestOrException.releaseReturnValue();
     76
     77    queryCache(request.get(), WTFMove(options), [callback = WTFMove(callback)](const Vector<CacheStorageRecord>& records) mutable {
    7978        if (records.isEmpty()) {
    8079            callback(nullptr);
     
    8786void Cache::matchAll(std::optional<RequestInfo>&& info, CacheQueryOptions&& options, MatchAllPromise&& promise)
    8887{
     88    if (UNLIKELY(!scriptExecutionContext()))
     89        return;
     90
    8991    RefPtr<FetchRequest> request;
    9092    if (info) {
    91         if (WTF::holds_alternative<RefPtr<FetchRequest>>(info.value())) {
    92             request = WTF::get<RefPtr<FetchRequest>>(info.value()).releaseNonNull();
    93             if (request->method() != "GET" && !options.ignoreMethod) {
    94                 promise.resolve({ });
    95                 return;
    96             }
    97         } else {
    98             if (UNLIKELY(!scriptExecutionContext()))
    99                 return;
    100             request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info.value()), { }).releaseReturnValue();
    101         }
     93        auto requestOrException = requestFromInfo(WTFMove(info.value()), options.ignoreMethod);
     94        if (requestOrException.hasException()) {
     95            promise.resolve({ });
     96            return;
     97        }
     98        request = requestOrException.releaseReturnValue();
    10299    }
    103100
     
    121118}
    122119
    123 void Cache::add(RequestInfo&&, DOMPromiseDeferred<void>&& promise)
    124 {
    125     promise.reject(Exception { NotSupportedError, ASCIILiteral("Not implemented")});
    126 }
    127 
    128 void Cache::addAll(Vector<RequestInfo>&&, DOMPromiseDeferred<void>&& promise)
    129 {
    130     promise.reject(Exception { NotSupportedError, ASCIILiteral("Not implemented")});
    131 }
    132 
    133 void Cache::put(RequestInfo&& info, Ref<FetchResponse>&& response, DOMPromiseDeferred<void>&& promise)
     120void Cache::add(RequestInfo&& info, DOMPromiseDeferred<void>&& promise)
     121{
     122    addAll(Vector<RequestInfo> { WTFMove(info) }, WTFMove(promise));
     123}
     124
     125static inline bool hasResponseVaryStarHeaderValue(const FetchResponse& response)
     126{
     127    auto varyValue = response.headers().internalHeaders().get(WebCore::HTTPHeaderName::Vary);
     128    bool hasStar = false;
     129    varyValue.split(',', false, [&](StringView view) {
     130        if (!hasStar && stripLeadingAndTrailingHTTPSpaces(view.toStringWithoutCopying()) == "*")
     131            hasStar = true;
     132    });
     133    return hasStar;
     134}
     135
     136class FetchTasksHandler : public RefCounted<FetchTasksHandler> {
     137public:
     138    explicit FetchTasksHandler(Function<void(ExceptionOr<Vector<CacheStorageConnection::Record>>&&)>&& callback)
     139        : m_callback(WTFMove(callback))
     140    {
     141    }
     142
     143    ~FetchTasksHandler()
     144    {
     145        if (m_callback)
     146            m_callback(WTFMove(m_records));
     147    }
     148
     149    const Vector<CacheStorageConnection::Record>& records() const { return m_records; }
     150
     151    size_t addRecord(CacheStorageConnection::Record&& record)
     152    {
     153        ASSERT(!isDone());
     154        m_records.append(WTFMove(record));
     155        return m_records.size() - 1;
     156    }
     157
     158    void addResponseBody(size_t position, Ref<SharedBuffer>&& data)
     159    {
     160        ASSERT(!isDone());
     161        m_records[position].responseBody = WTFMove(data);
     162    }
     163
     164    bool isDone() const { return !m_callback; }
     165
     166    void error(Exception&& exception)
     167    {
     168        if (auto callback = WTFMove(m_callback))
     169            callback(WTFMove(exception));
     170    }
     171
     172private:
     173    Vector<CacheStorageConnection::Record> m_records;
     174    Function<void(ExceptionOr<Vector<CacheStorageConnection::Record>>&&)> m_callback;
     175};
     176
     177ExceptionOr<Ref<FetchRequest>> Cache::requestFromInfo(RequestInfo&& info, bool ignoreMethod)
    134178{
    135179    RefPtr<FetchRequest> request;
    136180    if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
    137181        request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
    138         if (request->method() != "GET") {
    139             promise.reject(Exception { TypeError, ASCIILiteral("Request method is not GET") });
     182        if (request->method() != "GET" && !ignoreMethod)
     183            return Exception { TypeError, ASCIILiteral("Request method is not GET") };
     184    } else
     185        request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
     186
     187    if (!protocolIsInHTTPFamily(request->url()))
     188        return Exception { TypeError, ASCIILiteral("Request url is not HTTP/HTTPS") };
     189
     190    return request.releaseNonNull();
     191}
     192
     193void Cache::addAll(Vector<RequestInfo>&& infos, DOMPromiseDeferred<void>&& promise)
     194{
     195    if (UNLIKELY(!scriptExecutionContext()))
     196        return;
     197
     198    Vector<Ref<FetchRequest>> requests;
     199    requests.reserveInitialCapacity(infos.size());
     200    for (auto& info : infos) {
     201        bool ignoreMethod = false;
     202        auto requestOrException = requestFromInfo(WTFMove(info), ignoreMethod);
     203        if (requestOrException.hasException()) {
     204            promise.reject(requestOrException.releaseException());
    140205            return;
    141206        }
    142     } else {
    143         if (UNLIKELY(!scriptExecutionContext()))
     207        requests.uncheckedAppend(requestOrException.releaseReturnValue());
     208    }
     209
     210    auto taskHandler = adoptRef(*new FetchTasksHandler([protectedThis = makeRef(*this), this, promise = WTFMove(promise)](ExceptionOr<Vector<CacheStorageConnection::Record>>&& result) mutable {
     211        if (result.hasException()) {
     212            promise.reject(result.releaseException());
    144213            return;
    145         request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
    146     }
    147 
    148     if (!protocolIsInHTTPFamily(request->url())) {
    149         promise.reject(Exception { TypeError, ASCIILiteral("Request url is not HTTP/HTTPS") });
    150         return;
    151     }
    152 
    153     // FIXME: This is inefficient, we should be able to split and trim whitespaces at the same time.
    154     auto varyValue = response->headers().internalHeaders().get(WebCore::HTTPHeaderName::Vary);
    155     Vector<String> varyHeaderNames;
    156     varyValue.split(',', false, varyHeaderNames);
    157     for (auto& name : varyHeaderNames) {
    158         if (stripLeadingAndTrailingHTTPSpaces(name) == "*") {
    159             promise.reject(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
    160             return;
    161         }
     214        }
     215        batchPutOperation(result.releaseReturnValue(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
     216            promise.settle(WTFMove(result));
     217        });
     218    }));
     219
     220    for (auto& request : requests) {
     221        auto& requestReference = request.get();
     222        FetchResponse::fetch(*scriptExecutionContext(), requestReference, [this, request = WTFMove(request), taskHandler = taskHandler.copyRef()](ExceptionOr<FetchResponse&>&& result) mutable {
     223
     224            if (taskHandler->isDone())
     225                return;
     226
     227            if (result.hasException()) {
     228                taskHandler->error(result.releaseException());
     229                return;
     230            }
     231
     232            auto& response = result.releaseReturnValue();
     233
     234            if (!response.ok()) {
     235                taskHandler->error(Exception { TypeError, ASCIILiteral("Response is not OK") });
     236                return;
     237            }
     238
     239            if (hasResponseVaryStarHeaderValue(response)) {
     240                taskHandler->error(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
     241                return;
     242            }
     243
     244            if (response.status() == 206) {
     245                taskHandler->error(Exception { TypeError, ASCIILiteral("Response is a 206 partial") });
     246                return;
     247            }
     248
     249            CacheQueryOptions options;
     250            for (const auto& record : taskHandler->records()) {
     251                if (CacheStorageConnection::queryCacheMatch(request->resourceRequest(), record.request, record.response, options)) {
     252                    taskHandler->error(Exception { InvalidStateError, ASCIILiteral("addAll cannot store several matching requests")});
     253                    return;
     254                }
     255            }
     256            size_t recordPosition = taskHandler->addRecord(toConnectionRecord(request.get(), response, nullptr));
     257
     258            response.consumeBodyWhenLoaded([taskHandler = WTFMove(taskHandler), recordPosition](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
     259                if (taskHandler->isDone())
     260                    return;
     261
     262                if (result.hasException()) {
     263                    taskHandler->error(result.releaseException());
     264                    return;
     265                }
     266                if (auto value = result.releaseReturnValue())
     267                    taskHandler->addResponseBody(recordPosition, value.releaseNonNull());
     268            });
     269        });
     270    }
     271}
     272
     273void Cache::put(RequestInfo&& info, Ref<FetchResponse>&& response, DOMPromiseDeferred<void>&& promise)
     274{
     275    if (UNLIKELY(!scriptExecutionContext()))
     276        return;
     277
     278    bool ignoreMethod = false;
     279    auto requestOrException = requestFromInfo(WTFMove(info), ignoreMethod);
     280    if (requestOrException.hasException()) {
     281        promise.reject(requestOrException.releaseException());
     282        return;
     283    }
     284    auto request = requestOrException.releaseReturnValue();
     285
     286    if (hasResponseVaryStarHeaderValue(response.get())) {
     287        promise.reject(Exception { TypeError, ASCIILiteral("Response has a '*' Vary header value") });
     288        return;
    162289    }
    163290
     
    180307    if (response->isLoading()) {
    181308        setPendingActivity(this);
    182         response->consumeBodyWhenLoaded([promise = WTFMove(promise), request = request.releaseNonNull(), response = WTFMove(response), this](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
     309        response->consumeBodyWhenLoaded([promise = WTFMove(promise), request = WTFMove(request), response = WTFMove(response), this](ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
    183310            if (result.hasException())
    184311                promise.reject(result.releaseException());
     
    196323    }
    197324
    198     batchPutOperation(*request, response.get(), response->consumeBody(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
     325    batchPutOperation(request.get(), response.get(), response->consumeBody(), [promise = WTFMove(promise)](ExceptionOr<void>&& result) mutable {
    199326        promise.settle(WTFMove(result));
    200327    });
     
    203330void Cache::remove(RequestInfo&& info, CacheQueryOptions&& options, DOMPromiseDeferred<IDLBoolean>&& promise)
    204331{
    205     RefPtr<FetchRequest> request;
    206     if (WTF::holds_alternative<RefPtr<FetchRequest>>(info)) {
    207         request = WTF::get<RefPtr<FetchRequest>>(info).releaseNonNull();
    208         if (request->method() != "GET" && !options.ignoreMethod) {
    209             promise.resolve(false);
    210             return;
    211         }
    212     } else {
    213         if (UNLIKELY(!scriptExecutionContext()))
    214             return;
    215         request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info), { }).releaseReturnValue();
    216     }
    217 
    218     batchDeleteOperation(*request, WTFMove(options), [promise = WTFMove(promise)](ExceptionOr<bool>&& result) mutable {
     332    if (UNLIKELY(!scriptExecutionContext()))
     333        return;
     334
     335    auto requestOrException = requestFromInfo(WTFMove(info), options.ignoreMethod);
     336    if (requestOrException.hasException()) {
     337        promise.resolve(false);
     338        return;
     339    }
     340
     341    batchDeleteOperation(requestOrException.releaseReturnValue(), WTFMove(options), [promise = WTFMove(promise)](ExceptionOr<bool>&& result) mutable {
    219342        promise.settle(WTFMove(result));
    220343    });
     
    223346void Cache::keys(std::optional<RequestInfo>&& info, CacheQueryOptions&& options, KeysPromise&& promise)
    224347{
     348    if (UNLIKELY(!scriptExecutionContext()))
     349        return;
     350
    225351    RefPtr<FetchRequest> request;
    226352    if (info) {
    227         if (WTF::holds_alternative<RefPtr<FetchRequest>>(info.value())) {
    228             request = WTF::get<RefPtr<FetchRequest>>(info.value()).releaseNonNull();
    229             if (request->method() != "GET" && !options.ignoreMethod) {
    230                 promise.resolve(Vector<Ref<FetchRequest>> { });
    231                 return;
    232             }
    233         } else {
    234             if (UNLIKELY(!scriptExecutionContext()))
    235                 return;
    236             request = FetchRequest::create(*scriptExecutionContext(), WTFMove(info.value()), { }).releaseReturnValue();
    237         }
     353        auto requestOrException = requestFromInfo(WTFMove(info.value()), options.ignoreMethod);
     354        if (requestOrException.hasException()) {
     355            promise.resolve(Vector<Ref<FetchRequest>> { });
     356            return;
     357        }
     358        request = requestOrException.releaseReturnValue();
    238359    }
    239360
     
    307428}
    308429
    309 static inline CacheStorageConnection::Record toConnectionRecord(const FetchRequest& request, FetchResponse& response, CacheStorageConnection::ResponseBody&& responseBody)
     430CacheStorageConnection::Record toConnectionRecord(const FetchRequest& request, FetchResponse& response, CacheStorageConnection::ResponseBody&& responseBody)
    310431{
    311432    // FIXME: Add a setHTTPHeaderFields on ResourceResponseBase.
     
    331452    records.append(toConnectionRecord(request, response, WTFMove(responseBody)));
    332453
     454    batchPutOperation(WTFMove(records), WTFMove(callback));
     455}
     456
     457void Cache::batchPutOperation(Vector<CacheStorageConnection::Record>&& records, WTF::Function<void(ExceptionOr<void>&&)>&& callback)
     458{
    333459    setPendingActivity(this);
    334460    m_connection->batchPutOperation(m_identifier, WTFMove(records), [this, callback = WTFMove(callback)](Vector<uint64_t>&&, CacheStorageConnection::Error error) {
  • trunk/Source/WebCore/Modules/cache/Cache.h

    r220984 r220998  
    6363    Cache(ScriptExecutionContext&, String&& name, uint64_t identifier, Ref<CacheStorageConnection>&&);
    6464
     65    ExceptionOr<Ref<FetchRequest>> requestFromInfo(RequestInfo&&, bool ignoreMethod);
     66
    6567    // ActiveDOMObject
    6668    void stop() final;
     
    7375    void batchDeleteOperation(const FetchRequest&, CacheQueryOptions&&, WTF::Function<void(ExceptionOr<bool>&&)>&&);
    7476    void batchPutOperation(const FetchRequest&, FetchResponse&, CacheStorageConnection::ResponseBody&&, WTF::Function<void(ExceptionOr<void>&&)>&&);
     77    void batchPutOperation(Vector<CacheStorageConnection::Record>&&, WTF::Function<void(ExceptionOr<void>&&)>&&);
    7578
    7679    void updateRecords(Vector<CacheStorageConnection::Record>&&);
Note: See TracChangeset for help on using the changeset viewer.