72db6182e339cd3e74129443f8e3cf206da6c583
[WebKit.git] / Source / WebKit / NetworkProcess / cache / NetworkCacheEntry.cpp
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkCache.h"
28
29 #include "Logging.h"
30 #include "NetworkCacheCoders.h"
31 #include "NetworkProcess.h"
32 #include <WebCore/ResourceRequest.h>
33 #include <WebCore/SharedBuffer.h>
34 #include <wtf/text/StringBuilder.h>
35
36 namespace WebKit {
37 namespace NetworkCache {
38
39 Entry::Entry(const Key& key, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& buffer, const Vector<std::pair<String, String>>& varyingRequestHeaders)
40     : m_key(key)
41     , m_timeStamp(std::chrono::system_clock::now())
42     , m_response(response)
43     , m_varyingRequestHeaders(varyingRequestHeaders)
44     , m_buffer(WTFMove(buffer))
45 {
46     ASSERT(m_key.type() == "Resource");
47 }
48
49 Entry::Entry(const Key& key, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& redirectRequest, const Vector<std::pair<String, String>>& varyingRequestHeaders)
50     : m_key(key)
51     , m_timeStamp(std::chrono::system_clock::now())
52     , m_response(response)
53     , m_varyingRequestHeaders(varyingRequestHeaders)
54 {
55     ASSERT(m_key.type() == "Resource");
56
57     m_redirectRequest.emplace();
58     m_redirectRequest->setAsIsolatedCopy(redirectRequest);
59     // Redirect body is not needed even if exists.
60     m_redirectRequest->setHTTPBody(nullptr);
61 }
62
63 Entry::Entry(const Entry& other)
64     : m_key(other.m_key)
65     , m_timeStamp(other.m_timeStamp)
66     , m_response(other.m_response)
67     , m_varyingRequestHeaders(other.m_varyingRequestHeaders)
68     , m_redirectRequest(other.m_redirectRequest)
69     , m_buffer(other.m_buffer)
70     , m_sourceStorageRecord(other.m_sourceStorageRecord)
71 {
72 }
73
74 Entry::Entry(const Storage::Record& storageEntry)
75     : m_key(storageEntry.key)
76     , m_timeStamp(storageEntry.timeStamp)
77     , m_sourceStorageRecord(storageEntry)
78 {
79     ASSERT(m_key.type() == "Resource");
80 }
81
82 Storage::Record Entry::encodeAsStorageRecord() const
83 {
84     WTF::Persistence::Encoder encoder;
85     encoder << m_response;
86
87     bool hasVaryingRequestHeaders = !m_varyingRequestHeaders.isEmpty();
88     encoder << hasVaryingRequestHeaders;
89     if (hasVaryingRequestHeaders)
90         encoder << m_varyingRequestHeaders;
91
92     bool isRedirect = !!m_redirectRequest;
93     encoder << isRedirect;
94     if (isRedirect)
95         m_redirectRequest->encodeWithoutPlatformData(encoder);
96
97     encoder.encodeChecksum();
98
99     Data header(encoder.buffer(), encoder.bufferSize());
100     Data body;
101     if (m_buffer)
102         body = { reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size() };
103
104     return { m_key, m_timeStamp, header, body, { } };
105 }
106
107 std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storageEntry)
108 {
109     auto entry = std::make_unique<Entry>(storageEntry);
110
111     WTF::Persistence::Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
112     if (!decoder.decode(entry->m_response))
113         return nullptr;
114     entry->m_response.setSource(WebCore::ResourceResponse::Source::DiskCache);
115     if (storageEntry.bodyHash)
116         entry->m_response.setCacheBodyKey(*storageEntry.bodyHash);
117
118     bool hasVaryingRequestHeaders;
119     if (!decoder.decode(hasVaryingRequestHeaders))
120         return nullptr;
121
122     if (hasVaryingRequestHeaders) {
123         if (!decoder.decode(entry->m_varyingRequestHeaders))
124             return nullptr;
125     }
126
127     bool isRedirect;
128     if (!decoder.decode(isRedirect))
129         return nullptr;
130
131     if (isRedirect) {
132         entry->m_redirectRequest.emplace();
133         if (!entry->m_redirectRequest->decodeWithoutPlatformData(decoder))
134             return nullptr;
135     }
136
137     if (!decoder.verifyChecksum()) {
138         LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
139         return nullptr;
140     }
141
142     return entry;
143 }
144
145 #if ENABLE(SHAREABLE_RESOURCE)
146 void Entry::initializeShareableResourceHandleFromStorageRecord() const
147 {
148     auto* cache = NetworkProcess::singleton().cache();
149     if (!cache || !cache->canUseSharedMemoryForBodyData())
150         return;
151
152     auto sharedMemory = m_sourceStorageRecord.body.tryCreateSharedMemory();
153     if (!sharedMemory)
154         return;
155
156     auto shareableResource = ShareableResource::create(sharedMemory.releaseNonNull(), 0, m_sourceStorageRecord.body.size());
157     shareableResource->createHandle(m_shareableResourceHandle);
158 }
159 #endif
160
161 void Entry::initializeBufferFromStorageRecord() const
162 {
163 #if ENABLE(SHAREABLE_RESOURCE)
164     if (!shareableResourceHandle().isNull()) {
165         m_buffer = m_shareableResourceHandle.tryWrapInSharedBuffer();
166         if (m_buffer)
167             return;
168     }
169 #endif
170     m_buffer = WebCore::SharedBuffer::create(m_sourceStorageRecord.body.data(), m_sourceStorageRecord.body.size());
171 }
172
173 WebCore::SharedBuffer* Entry::buffer() const
174 {
175     if (!m_buffer)
176         initializeBufferFromStorageRecord();
177
178     return m_buffer.get();
179 }
180
181 #if ENABLE(SHAREABLE_RESOURCE)
182 ShareableResource::Handle& Entry::shareableResourceHandle() const
183 {
184     if (m_shareableResourceHandle.isNull())
185         initializeShareableResourceHandleFromStorageRecord();
186
187     return m_shareableResourceHandle;
188 }
189 #endif
190
191 bool Entry::needsValidation() const
192 {
193     return m_response.source() == WebCore::ResourceResponse::Source::DiskCacheAfterValidation;
194 }
195
196 void Entry::setNeedsValidation(bool value)
197 {
198     m_response.setSource(value ? WebCore::ResourceResponse::Source::DiskCacheAfterValidation : WebCore::ResourceResponse::Source::DiskCache);
199 }
200
201 void Entry::asJSON(StringBuilder& json, const Storage::RecordInfo& info) const
202 {
203     json.appendLiteral("{\n");
204     json.appendLiteral("\"hash\": ");
205     json.appendQuotedJSONString(m_key.hashAsString());
206     json.appendLiteral(",\n");
207     json.appendLiteral("\"bodySize\": ");
208     json.appendNumber(info.bodySize);
209     json.appendLiteral(",\n");
210     json.appendLiteral("\"worth\": ");
211     json.appendNumber(info.worth);
212     json.appendLiteral(",\n");
213     json.appendLiteral("\"partition\": ");
214     json.appendQuotedJSONString(m_key.partition());
215     json.appendLiteral(",\n");
216     json.appendLiteral("\"timestamp\": ");
217     json.appendNumber(std::chrono::duration_cast<std::chrono::milliseconds>(m_timeStamp.time_since_epoch()).count());
218     json.appendLiteral(",\n");
219     json.appendLiteral("\"URL\": ");
220     json.appendQuotedJSONString(m_response.url().string());
221     json.appendLiteral(",\n");
222     json.appendLiteral("\"bodyHash\": ");
223     json.appendQuotedJSONString(info.bodyHash);
224     json.appendLiteral(",\n");
225     json.appendLiteral("\"bodyShareCount\": ");
226     json.appendNumber(info.bodyShareCount);
227     json.appendLiteral(",\n");
228     json.appendLiteral("\"headers\": {\n");
229     bool firstHeader = true;
230     for (auto& header : m_response.httpHeaderFields()) {
231         if (!firstHeader)
232             json.appendLiteral(",\n");
233         firstHeader = false;
234         json.appendLiteral("    ");
235         json.appendQuotedJSONString(header.key);
236         json.appendLiteral(": ");
237         json.appendQuotedJSONString(header.value);
238     }
239     json.appendLiteral("\n}\n");
240     json.appendLiteral("}");
241 }
242
243 }
244 }