[WK2] Add initial support for speculative resource revalidation to the WebKit disk...
[WebKit-https.git] / Source / WebKit2 / 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 "NetworkCacheDecoder.h"
32 #include "NetworkCacheEncoder.h"
33 #include <WebCore/ResourceRequest.h>
34 #include <WebCore/SharedBuffer.h>
35 #include <wtf/text/StringBuilder.h>
36
37 #if ENABLE(NETWORK_CACHE)
38
39 namespace WebKit {
40 namespace NetworkCache {
41
42 Entry::Entry(const Key& key, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& buffer, const Vector<std::pair<String, String>>& varyingRequestHeaders)
43     : m_key(key)
44     , m_timeStamp(std::chrono::system_clock::now())
45     , m_response(response)
46     , m_varyingRequestHeaders(varyingRequestHeaders)
47     , m_buffer(WTF::move(buffer))
48 {
49     ASSERT(m_key.type() == "resource");
50 }
51
52 Entry::Entry(const Entry& other)
53     : m_key(other.m_key)
54     , m_timeStamp(other.m_timeStamp)
55     , m_response(other.m_response)
56     , m_varyingRequestHeaders(other.m_varyingRequestHeaders)
57     , m_buffer(other.m_buffer)
58     , m_sourceStorageRecord(other.m_sourceStorageRecord)
59 {
60 }
61
62 Entry::Entry(const Storage::Record& storageEntry)
63     : m_key(storageEntry.key)
64     , m_timeStamp(storageEntry.timeStamp)
65     , m_sourceStorageRecord(storageEntry)
66 {
67     ASSERT(m_key.type() == "resource");
68 }
69
70 Storage::Record Entry::encodeAsStorageRecord() const
71 {
72     Encoder encoder;
73     encoder << m_response;
74
75     bool hasVaryingRequestHeaders = !m_varyingRequestHeaders.isEmpty();
76     encoder << hasVaryingRequestHeaders;
77     if (hasVaryingRequestHeaders)
78         encoder << m_varyingRequestHeaders;
79
80     encoder.encodeChecksum();
81
82     Data header(encoder.buffer(), encoder.bufferSize());
83     Data body;
84     if (m_buffer)
85         body = { reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size() };
86
87     return { m_key, m_timeStamp, header, body };
88 }
89
90 std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storageEntry)
91 {
92     auto entry = std::make_unique<Entry>(storageEntry);
93
94     Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
95     if (!decoder.decode(entry->m_response))
96         return nullptr;
97     entry->m_response.setSource(WebCore::ResourceResponse::Source::DiskCache);
98
99     bool hasVaryingRequestHeaders;
100     if (!decoder.decode(hasVaryingRequestHeaders))
101         return nullptr;
102
103     if (hasVaryingRequestHeaders) {
104         if (!decoder.decode(entry->m_varyingRequestHeaders))
105             return nullptr;
106     }
107
108     if (!decoder.verifyChecksum()) {
109         LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
110         return nullptr;
111     }
112
113     return entry;
114 }
115
116 #if ENABLE(SHAREABLE_RESOURCE)
117 void Entry::initializeShareableResourceHandleFromStorageRecord() const
118 {
119     RefPtr<SharedMemory> sharedMemory = m_sourceStorageRecord.body.tryCreateSharedMemory();
120     if (!sharedMemory)
121         return;
122
123     RefPtr<ShareableResource> shareableResource = ShareableResource::create(sharedMemory.release(), 0, m_sourceStorageRecord.body.size());
124     ASSERT(shareableResource);
125     shareableResource->createHandle(m_shareableResourceHandle);
126 }
127 #endif
128
129 void Entry::initializeBufferFromStorageRecord() const
130 {
131 #if ENABLE(SHAREABLE_RESOURCE)
132     if (!shareableResourceHandle().isNull()) {
133         m_buffer = m_shareableResourceHandle.tryWrapInSharedBuffer();
134         if (m_buffer)
135             return;
136     }
137 #endif
138     m_buffer = WebCore::SharedBuffer::create(m_sourceStorageRecord.body.data(), m_sourceStorageRecord.body.size());
139 }
140
141 WebCore::SharedBuffer* Entry::buffer() const
142 {
143     if (!m_buffer)
144         initializeBufferFromStorageRecord();
145
146     return m_buffer.get();
147 }
148
149 #if ENABLE(SHAREABLE_RESOURCE)
150 ShareableResource::Handle& Entry::shareableResourceHandle() const
151 {
152     if (m_shareableResourceHandle.isNull())
153         initializeShareableResourceHandleFromStorageRecord();
154
155     return m_shareableResourceHandle;
156 }
157 #endif
158
159 bool Entry::needsValidation() const
160 {
161     return m_response.source() == WebCore::ResourceResponse::Source::DiskCacheAfterValidation;
162 }
163
164 void Entry::setNeedsValidation()
165 {
166     ASSERT(m_response.source() == WebCore::ResourceResponse::Source::DiskCache);
167     m_response.setSource(WebCore::ResourceResponse::Source::DiskCacheAfterValidation);
168 }
169
170 void Entry::asJSON(StringBuilder& json, const Storage::RecordInfo& info) const
171 {
172     json.appendLiteral("{\n");
173     json.appendLiteral("\"hash\": ");
174     json.appendQuotedJSONString(m_key.hashAsString());
175     json.appendLiteral(",\n");
176     json.appendLiteral("\"bodySize\": ");
177     json.appendNumber(info.bodySize);
178     json.appendLiteral(",\n");
179     json.appendLiteral("\"worth\": ");
180     json.appendNumber(info.worth);
181     json.appendLiteral(",\n");
182     json.appendLiteral("\"partition\": ");
183     json.appendQuotedJSONString(m_key.partition());
184     json.appendLiteral(",\n");
185     json.appendLiteral("\"timestamp\": ");
186     json.appendNumber(std::chrono::duration_cast<std::chrono::milliseconds>(m_timeStamp.time_since_epoch()).count());
187     json.appendLiteral(",\n");
188     json.appendLiteral("\"URL\": ");
189     json.appendQuotedJSONString(m_response.url().string());
190     json.appendLiteral(",\n");
191     json.appendLiteral("\"bodyHash\": ");
192     json.appendQuotedJSONString(info.bodyHash);
193     json.appendLiteral(",\n");
194     json.appendLiteral("\"bodyShareCount\": ");
195     json.appendNumber(info.bodyShareCount);
196     json.appendLiteral(",\n");
197     json.appendLiteral("\"headers\": {\n");
198     bool firstHeader = true;
199     for (auto& header : m_response.httpHeaderFields()) {
200         if (!firstHeader)
201             json.appendLiteral(",\n");
202         firstHeader = false;
203         json.appendLiteral("    ");
204         json.appendQuotedJSONString(header.key);
205         json.appendLiteral(": ");
206         json.appendQuotedJSONString(header.value);
207     }
208     json.appendLiteral("\n}\n");
209     json.appendLiteral("}");
210 }
211
212 }
213 }
214
215 #endif