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
28#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
29#include "NetworkCacheSubresourcesEntry.h"
30
31#include "Logging.h"
32#include "NetworkCacheCoders.h"
33
34namespace WebKit {
35namespace NetworkCache {
36
37void SubresourceInfo::encode(WTF::Persistence::Encoder& encoder) const
38{
39 encoder << m_key;
40 encoder << m_lastSeen;
41 encoder << m_firstSeen;
42 encoder << m_isTransient;
43
44 // Do not bother serializing other data members of transient resources as they are empty.
45 if (m_isTransient)
46 return;
47
48 encoder << m_isSameSite;
49 encoder << m_firstPartyForCookies;
50 encoder << m_requestHeaders;
51 encoder.encodeEnum(m_priority);
52}
53
54bool SubresourceInfo::decode(WTF::Persistence::Decoder& decoder, SubresourceInfo& info)
55{
56 if (!decoder.decode(info.m_key))
57 return false;
58 if (!decoder.decode(info.m_lastSeen))
59 return false;
60 if (!decoder.decode(info.m_firstSeen))
61 return false;
62
63 if (!decoder.decode(info.m_isTransient))
64 return false;
65
66 if (info.m_isTransient)
67 return true;
68
69 if (!decoder.decode(info.m_isSameSite))
70 return false;
71
72 if (!decoder.decode(info.m_firstPartyForCookies))
73 return false;
74
75 if (!decoder.decode(info.m_requestHeaders))
76 return false;
77
78 if (!decoder.decodeEnum(info.m_priority))
79 return false;
80
81 return true;
82}
83
84Storage::Record SubresourcesEntry::encodeAsStorageRecord() const
85{
86 WTF::Persistence::Encoder encoder;
87 encoder << m_subresources;
88
89 encoder.encodeChecksum();
90
91 return { m_key, m_timeStamp, { encoder.buffer(), encoder.bufferSize() }, { }, { }};
92}
93
94std::unique_ptr<SubresourcesEntry> SubresourcesEntry::decodeStorageRecord(const Storage::Record& storageEntry)
95{
96 auto entry = std::make_unique<SubresourcesEntry>(storageEntry);
97
98 WTF::Persistence::Decoder decoder(storageEntry.header.data(), storageEntry.header.size());
99 if (!decoder.decode(entry->m_subresources))
100 return nullptr;
101
102 if (!decoder.verifyChecksum()) {
103 LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
104 return nullptr;
105 }
106
107 return entry;
108}
109
110SubresourcesEntry::SubresourcesEntry(const Storage::Record& storageEntry)
111 : m_key(storageEntry.key)
112 , m_timeStamp(storageEntry.timeStamp)
113{
114 ASSERT(m_key.type() == "SubResources");
115}
116
117SubresourceInfo::SubresourceInfo(const Key& key, const WebCore::ResourceRequest& request, const SubresourceInfo* previousInfo)
118 : m_key(key)
119 , m_lastSeen(WallTime::now())
120 , m_firstSeen(previousInfo ? previousInfo->firstSeen() : m_lastSeen)
121 , m_isTransient(!previousInfo)
122 , m_isSameSite(request.isSameSite())
123 , m_firstPartyForCookies(request.firstPartyForCookies())
124 , m_requestHeaders(request.httpHeaderFields())
125 , m_priority(request.priority())
126{
127}
128
129static Vector<SubresourceInfo> makeSubresourceInfoVector(const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads, Vector<SubresourceInfo>* previousSubresources)
130{
131 Vector<SubresourceInfo> result;
132 result.reserveInitialCapacity(subresourceLoads.size());
133
134 HashMap<Key, unsigned> previousMap;
135 if (previousSubresources) {
136 for (unsigned i = 0; i < previousSubresources->size(); ++i)
137 previousMap.add(previousSubresources->at(i).key(), i);
138 }
139
140 HashSet<Key> deduplicationSet;
141 for (auto& load : subresourceLoads) {
142 if (!deduplicationSet.add(load->key).isNewEntry)
143 continue;
144
145 SubresourceInfo* previousInfo = nullptr;
146 if (previousSubresources) {
147 auto it = previousMap.find(load->key);
148 if (it != previousMap.end())
149 previousInfo = &(*previousSubresources)[it->value];
150 }
151
152 result.uncheckedAppend({ load->key, load->request, previousInfo });
153
154 // FIXME: We should really consider all resources seen for the first time transient.
155 if (!previousSubresources)
156 result.last().setNonTransient();
157 }
158
159 return result;
160}
161
162SubresourcesEntry::SubresourcesEntry(Key&& key, const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads)
163 : m_key(WTFMove(key))
164 , m_timeStamp(WallTime::now())
165 , m_subresources(makeSubresourceInfoVector(subresourceLoads, nullptr))
166{
167 ASSERT(m_key.type() == "SubResources");
168}
169
170void SubresourcesEntry::updateSubresourceLoads(const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads)
171{
172 m_subresources = makeSubresourceInfoVector(subresourceLoads, &m_subresources);
173}
174
175} // namespace WebKit
176} // namespace NetworkCache
177
178#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
179