3157fc38f97100832d1acff457166e6f45ad2e7d
[WebKit-https.git] / Source / WebCore / Modules / cache / CacheStorageConnection.cpp
1
2 /*
3  * Copyright (C) 2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "CacheStorageConnection.h"
29
30 #include "CacheQueryOptions.h"
31 #include "Exception.h"
32 #include "HTTPParsers.h"
33
34 namespace WebCore {
35
36 ExceptionOr<void> CacheStorageConnection::errorToException(Error error)
37 {
38     switch (error) {
39     case Error::None:
40         return { };
41     case Error::NotImplemented:
42         return Exception { NotSupportedError, ASCIILiteral("Not implemented") };
43     default:
44         return Exception { NotSupportedError, ASCIILiteral("Internal error") };
45     }
46 }
47
48 bool CacheStorageConnection::queryCacheMatch(const ResourceRequest& request, const ResourceRequest& cachedRequest, const ResourceResponse& cachedResponse, const CacheQueryOptions& options)
49 {
50     ASSERT(options.ignoreMethod || request.httpMethod() == "GET");
51
52     URL requestURL = request.url();
53     URL cachedRequestURL = cachedRequest.url();
54
55     if (options.ignoreSearch) {
56         requestURL.setQuery({ });
57         cachedRequestURL.setQuery({ });
58     }
59     if (!equalIgnoringFragmentIdentifier(requestURL, cachedRequestURL))
60         return false;
61
62     if (options.ignoreVary)
63         return true;
64
65     String varyValue = cachedResponse.httpHeaderField(WebCore::HTTPHeaderName::Vary);
66     if (varyValue.isNull())
67         return true;
68
69     // FIXME: This is inefficient, we should be able to split and trim whitespaces at the same time.
70     Vector<String> varyHeaderNames;
71     varyValue.split(',', false, varyHeaderNames);
72     for (auto& name : varyHeaderNames) {
73         if (stripLeadingAndTrailingHTTPSpaces(name) == "*")
74             return false;
75         if (cachedRequest.httpHeaderField(name) != request.httpHeaderField(name))
76             return false;
77     }
78     return true;
79 }
80
81 void CacheStorageConnection::open(const String& origin, const String& cacheName, OpenRemoveCallback&& callback)
82 {
83     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
84     m_openAndRemoveCachePendingRequests.add(requestIdentifier, WTFMove(callback));
85
86     doOpen(requestIdentifier, origin, cacheName);
87 }
88
89 void CacheStorageConnection::remove(uint64_t cacheIdentifier, OpenRemoveCallback&& callback)
90 {
91     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
92     m_openAndRemoveCachePendingRequests.add(requestIdentifier, WTFMove(callback));
93
94     doRemove(requestIdentifier, cacheIdentifier);
95 }
96
97 void CacheStorageConnection::retrieveCaches(const String& origin, CachesCallback&& callback)
98 {
99     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
100     m_retrieveCachesPendingRequests.add(requestIdentifier, WTFMove(callback));
101
102     doRetrieveCaches(requestIdentifier, origin);
103 }
104
105 void CacheStorageConnection::retrieveRecords(uint64_t cacheIdentifier, RecordsCallback&& callback)
106 {
107     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
108     m_retrieveRecordsPendingRequests.add(requestIdentifier, WTFMove(callback));
109
110     doRetrieveRecords(requestIdentifier, cacheIdentifier);
111 }
112
113 void CacheStorageConnection::batchDeleteOperation(uint64_t cacheIdentifier, const WebCore::ResourceRequest& request, WebCore::CacheQueryOptions&& options, BatchOperationCallback&& callback)
114 {
115     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
116     m_batchDeleteAndPutPendingRequests.add(requestIdentifier, WTFMove(callback));
117
118     doBatchDeleteOperation(requestIdentifier, cacheIdentifier, request, WTFMove(options));
119 }
120
121 void CacheStorageConnection::batchPutOperation(uint64_t cacheIdentifier, Vector<WebCore::CacheStorageConnection::Record>&& records, BatchOperationCallback&& callback)
122 {
123     uint64_t requestIdentifier = ++m_lastRequestIdentifier;
124     m_batchDeleteAndPutPendingRequests.add(requestIdentifier, WTFMove(callback));
125
126     doBatchPutOperation(requestIdentifier, cacheIdentifier, WTFMove(records));
127 }
128
129 void CacheStorageConnection::openOrRemoveCompleted(uint64_t requestIdentifier, uint64_t cacheIdentifier, Error error)
130 {
131     if (auto callback = m_openAndRemoveCachePendingRequests.take(requestIdentifier))
132         callback(cacheIdentifier, error);
133 }
134
135 void CacheStorageConnection::updateCaches(uint64_t requestIdentifier, Vector<CacheInfo>&& caches)
136 {
137     if (auto callback = m_retrieveCachesPendingRequests.take(requestIdentifier))
138         callback(WTFMove(caches));
139 }
140
141 void CacheStorageConnection::updateRecords(uint64_t requestIdentifier, Vector<Record>&& records)
142 {
143     if (auto callback = m_retrieveRecordsPendingRequests.take(requestIdentifier))
144         callback(WTFMove(records));
145 }
146
147 void CacheStorageConnection::deleteRecordsCompleted(uint64_t requestIdentifier, Vector<uint64_t>&& records, Error error)
148 {
149     if (auto callback = m_batchDeleteAndPutPendingRequests.take(requestIdentifier))
150         callback(WTFMove(records), error);
151 }
152
153 void CacheStorageConnection::putRecordsCompleted(uint64_t requestIdentifier, Vector<uint64_t>&& records, Error error)
154 {
155     if (auto callback = m_batchDeleteAndPutPendingRequests.take(requestIdentifier))
156         callback(WTFMove(records), error);
157 }
158
159 CacheStorageConnection::ResponseBody CacheStorageConnection::isolatedResponseBody(const ResponseBody& body)
160 {
161     return WTF::switchOn(body, [](const Ref<FormData>& formData) {
162         return formData->isolatedCopy();
163     }, [](const Ref<SharedBuffer>& buffer) {
164         return buffer->copy();
165     }, [](const std::nullptr_t&) {
166         return CacheStorageConnection::ResponseBody { };
167     });
168 }
169
170 static inline CacheStorageConnection::ResponseBody copyResponseBody(const CacheStorageConnection::ResponseBody& body)
171 {
172     return WTF::switchOn(body, [](const Ref<FormData>& formData) {
173         return formData.copyRef();
174     }, [](const Ref<SharedBuffer>& buffer) {
175         return buffer.copyRef();
176     }, [](const std::nullptr_t&) {
177         return CacheStorageConnection::ResponseBody { };
178     });
179 }
180
181 CacheStorageConnection::Record CacheStorageConnection::Record::copy() const
182 {
183     return Record { identifier, updateResponseCounter, requestHeadersGuard, request, options, referrer, responseHeadersGuard, response, copyResponseBody(responseBody) };
184 }
185
186 } // namespace WebCore