blob: 1fe48994ff0ae9d5075b9793f603ee6ee4af7766 [file] [log] [blame]
eseidel94980f22006-01-09 09:29:48 +00001/*
eseidel94980f22006-01-09 09:29:48 +00002 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
darin91298e52006-06-12 01:10:17 +00005 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
darind51eb592007-05-24 22:56:33 +00006 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
eseidel94980f22006-01-09 09:29:48 +00007
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
ddkilzerc8eccec2007-09-26 02:29:57 +000020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
eseidel94980f22006-01-09 09:29:48 +000022*/
23
24#include "config.h"
darine775cf72006-07-09 22:48:56 +000025#include "CachedResource.h"
darinbbe64662006-01-16 17:52:23 +000026
eseidel94980f22006-01-09 09:29:48 +000027#include "Cache.h"
antti@apple.com72e4a842008-09-05 09:28:11 +000028#include "CachedResourceHandle.h"
andersca53b9d2a2007-07-20 22:52:25 +000029#include "DocLoader.h"
ggaren1f92a1a2007-08-09 03:59:32 +000030#include "Frame.h"
kmcculloadfd67d2007-03-03 02:18:43 +000031#include "FrameLoader.h"
ggaren1f92a1a2007-08-09 03:59:32 +000032#include "KURL.h"
darin91298e52006-06-12 01:10:17 +000033#include "Request.h"
ggaren1f92a1a2007-08-09 03:59:32 +000034#include "SystemTime.h"
darin91298e52006-06-12 01:10:17 +000035#include <wtf/Vector.h>
eseidel94980f22006-01-09 09:29:48 +000036
darinbbe64662006-01-16 17:52:23 +000037namespace WebCore {
eseidel94980f22006-01-09 09:29:48 +000038
antti@apple.comb4122c52008-03-25 19:21:00 +000039CachedResource::CachedResource(const String& url, Type type)
weinig@apple.comc5002662007-12-12 07:26:19 +000040 : m_url(url)
41 , m_lastDecodedAccessTime(0)
antti@apple.comb4122c52008-03-25 19:21:00 +000042 , m_sendResourceLoadCallbacks(true)
antti@apple.com6c76e542008-03-13 21:20:31 +000043 , m_preloadCount(0)
44 , m_preloadResult(PreloadNotReferenced)
45 , m_requestedFromNetworkingLayer(false)
antti@apple.comb4122c52008-03-25 19:21:00 +000046 , m_inCache(false)
47 , m_loading(false)
andersca53b9d2a2007-07-20 22:52:25 +000048 , m_docLoader(0)
antti@apple.com72e4a842008-09-05 09:28:11 +000049 , m_handleCount(0)
50 , m_resourceToRevalidate(0)
51 , m_isBeingRevalidated(false)
52 , m_expirationDate(0)
hyattc4404492006-10-19 09:21:54 +000053{
hyattc4404492006-10-19 09:21:54 +000054 m_type = type;
55 m_status = Pending;
hyatt4724d0f2007-04-03 01:11:35 +000056 m_encodedSize = 0;
ggaren568a2dd2007-08-13 02:41:29 +000057 m_decodedSize = 0;
hyattc4404492006-10-19 09:21:54 +000058 m_request = 0;
hyatt2ce79842007-03-25 05:53:42 +000059
hyattc4404492006-10-19 09:21:54 +000060 m_accessCount = 0;
ggaren408a6df2007-08-08 07:01:39 +000061 m_inLiveDecodedResourcesList = false;
hyatt2ce79842007-03-25 05:53:42 +000062
63 m_nextInAllResourcesList = 0;
64 m_prevInAllResourcesList = 0;
65
66 m_nextInLiveResourcesList = 0;
67 m_prevInLiveResourcesList = 0;
68
hyattc4404492006-10-19 09:21:54 +000069#ifndef NDEBUG
70 m_deleted = false;
71 m_lruIndex = 0;
72#endif
kmcculloadfd67d2007-03-03 02:18:43 +000073 m_errorOccurred = false;
hyattc4404492006-10-19 09:21:54 +000074}
75
darine775cf72006-07-09 22:48:56 +000076CachedResource::~CachedResource()
eseidel94980f22006-01-09 09:29:48 +000077{
hyattc4404492006-10-19 09:21:54 +000078 ASSERT(!inCache());
79 ASSERT(!m_deleted);
ap@webkit.org86cf11e2008-05-02 13:07:43 +000080 ASSERT(url().isNull() || cache()->resourceForURL(url()) != this);
hyattc4404492006-10-19 09:21:54 +000081#ifndef NDEBUG
eseidel94980f22006-01-09 09:29:48 +000082 m_deleted = true;
hyattc4404492006-10-19 09:21:54 +000083#endif
antti@apple.com72e4a842008-09-05 09:28:11 +000084
85 ASSERT(cache()->resourceForURL(url()) != this);
andersca53b9d2a2007-07-20 22:52:25 +000086
antti@apple.com72e4a842008-09-05 09:28:11 +000087 if (m_resourceToRevalidate)
88 m_resourceToRevalidate->m_isBeingRevalidated = false;
89
andersca53b9d2a2007-07-20 22:52:25 +000090 if (m_docLoader)
91 m_docLoader->removeCachedResource(this);
darin91298e52006-06-12 01:10:17 +000092}
antti@apple.comb4122c52008-03-25 19:21:00 +000093
94void CachedResource::load(DocLoader* docLoader, bool incremental, bool skipCanLoadCheck, bool sendResourceLoadCallbacks)
95{
96 m_sendResourceLoadCallbacks = sendResourceLoadCallbacks;
97 cache()->loader()->load(docLoader, this, incremental, skipCanLoadCheck, sendResourceLoadCallbacks);
98 m_loading = true;
99}
darin91298e52006-06-12 01:10:17 +0000100
darine775cf72006-07-09 22:48:56 +0000101void CachedResource::finish()
eseidel94980f22006-01-09 09:29:48 +0000102{
hyattc4404492006-10-19 09:21:54 +0000103 m_status = Cached;
eseidel94980f22006-01-09 09:29:48 +0000104}
105
darine775cf72006-07-09 22:48:56 +0000106bool CachedResource::isExpired() const
eseidel94980f22006-01-09 09:29:48 +0000107{
antti@apple.com72e4a842008-09-05 09:28:11 +0000108 if (!m_expirationDate)
hyattc4404492006-10-19 09:21:54 +0000109 return false;
eseidel94980f22006-01-09 09:29:48 +0000110 time_t now = time(0);
antti@apple.com72e4a842008-09-05 09:28:11 +0000111 return difftime(now, m_expirationDate) >= 0;
eseidel94980f22006-01-09 09:29:48 +0000112}
antti@apple.com72e4a842008-09-05 09:28:11 +0000113
114void CachedResource::setResponse(const ResourceResponse& response)
115{
116 m_response = response;
117 m_expirationDate = response.expirationDate();
118}
119
hyattc4404492006-10-19 09:21:54 +0000120void CachedResource::setRequest(Request* request)
eseidel94980f22006-01-09 09:29:48 +0000121{
hyattc4404492006-10-19 09:21:54 +0000122 if (request && !m_request)
eseidel94980f22006-01-09 09:29:48 +0000123 m_status = Pending;
hyattc4404492006-10-19 09:21:54 +0000124 m_request = request;
125 if (canDelete() && !inCache())
eseidel94980f22006-01-09 09:29:48 +0000126 delete this;
eseidel94980f22006-01-09 09:29:48 +0000127}
128
hyatt@apple.com2c814c42008-04-12 04:09:22 +0000129void CachedResource::addClient(CachedResourceClient *c)
eseidel94980f22006-01-09 09:29:48 +0000130{
antti@apple.com6c76e542008-03-13 21:20:31 +0000131 if (m_preloadResult == PreloadNotReferenced) {
132 if (isLoaded())
133 m_preloadResult = PreloadReferencedWhileComplete;
134 else if (m_requestedFromNetworkingLayer)
135 m_preloadResult = PreloadReferencedWhileLoading;
136 else
137 m_preloadResult = PreloadReferenced;
138 }
antti@apple.com60381cb2008-08-25 20:41:11 +0000139 if (!hasClients() && inCache())
hyatt2ce79842007-03-25 05:53:42 +0000140 cache()->addToLiveResourcesSize(this);
mjsba7cd532006-01-24 00:56:32 +0000141 m_clients.add(c);
eseidel94980f22006-01-09 09:29:48 +0000142}
143
hyatt@apple.com2c814c42008-04-12 04:09:22 +0000144void CachedResource::removeClient(CachedResourceClient *c)
eseidel94980f22006-01-09 09:29:48 +0000145{
hyattf56c4412007-03-15 00:28:21 +0000146 ASSERT(m_clients.contains(c));
eseidel94980f22006-01-09 09:29:48 +0000147 m_clients.remove(c);
hyattc4404492006-10-19 09:21:54 +0000148 if (canDelete() && !inCache())
149 delete this;
antti@apple.com60381cb2008-08-25 20:41:11 +0000150 else if (!hasClients() && inCache()) {
hyatt2ce79842007-03-25 05:53:42 +0000151 cache()->removeFromLiveResourcesSize(this);
ggaren408a6df2007-08-08 07:01:39 +0000152 cache()->removeFromLiveDecodedResourcesList(this);
mitz@apple.com9d7e4262008-09-04 18:15:25 +0000153 allClientsRemoved();
ggaren1aba8372007-08-16 23:43:43 +0000154 cache()->prune();
hyattc4404492006-10-19 09:21:54 +0000155 }
eseidel94980f22006-01-09 09:29:48 +0000156}
157
antti@apple.com72e4a842008-09-05 09:28:11 +0000158void CachedResource::deleteIfPossible()
159{
160 if (canDelete() && !inCache())
161 delete this;
162}
163
ggaren568a2dd2007-08-13 02:41:29 +0000164void CachedResource::setDecodedSize(unsigned size)
165{
166 if (size == m_decodedSize)
167 return;
168
169 int delta = size - m_decodedSize;
170
171 // The object must now be moved to a different queue, since its size has been changed.
172 // We have to remove explicitly before updating m_decodedSize, so that we find the correct previous
173 // queue.
174 if (inCache())
175 cache()->removeFromLRUList(this);
176
177 m_decodedSize = size;
178
179 if (inCache()) {
180 // Now insert into the new LRU list.
181 cache()->insertInLRUList(this);
182
183 // Insert into or remove from the live decoded list if necessary.
antti@apple.com60381cb2008-08-25 20:41:11 +0000184 if (m_decodedSize && !m_inLiveDecodedResourcesList && hasClients())
ggaren568a2dd2007-08-13 02:41:29 +0000185 cache()->insertInLiveDecodedResourcesList(this);
186 else if (!m_decodedSize && m_inLiveDecodedResourcesList)
187 cache()->removeFromLiveDecodedResourcesList(this);
188
189 // Update the cache's size totals.
antti@apple.com60381cb2008-08-25 20:41:11 +0000190 cache()->adjustSize(hasClients(), delta);
ggaren568a2dd2007-08-13 02:41:29 +0000191 }
192}
193
hyattc3e15802007-03-07 07:42:45 +0000194void CachedResource::setEncodedSize(unsigned size)
eseidel94980f22006-01-09 09:29:48 +0000195{
hyattc3e15802007-03-07 07:42:45 +0000196 if (size == m_encodedSize)
hyattc4404492006-10-19 09:21:54 +0000197 return;
198
hyatt04a8e082007-04-03 23:31:15 +0000199 // The size cannot ever shrink (unless it is being nulled out because of an error). If it ever does, assert.
200 ASSERT(size == 0 || size >= m_encodedSize);
hyattdc0dceb2007-04-02 23:41:57 +0000201
ggaren568a2dd2007-08-13 02:41:29 +0000202 int delta = size - m_encodedSize;
eseidel94980f22006-01-09 09:29:48 +0000203
204 // The object must now be moved to a different queue, since its size has been changed.
hyattc3e15802007-03-07 07:42:45 +0000205 // We have to remove explicitly before updating m_encodedSize, so that we find the correct previous
hyattc4404492006-10-19 09:21:54 +0000206 // queue.
207 if (inCache())
208 cache()->removeFromLRUList(this);
eseidel94980f22006-01-09 09:29:48 +0000209
hyattc3e15802007-03-07 07:42:45 +0000210 m_encodedSize = size;
hyattc4404492006-10-19 09:21:54 +0000211
212 if (inCache()) {
213 // Now insert into the new LRU list.
214 cache()->insertInLRUList(this);
215
216 // Update the cache's size totals.
antti@apple.com60381cb2008-08-25 20:41:11 +0000217 cache()->adjustSize(hasClients(), delta);
hyatt2ce79842007-03-25 05:53:42 +0000218 }
219}
220
ggarenfbd237b2007-08-10 02:30:30 +0000221void CachedResource::didAccessDecodedData(double timeStamp)
hyatt2ce79842007-03-25 05:53:42 +0000222{
ggarenfbd237b2007-08-10 02:30:30 +0000223 m_lastDecodedAccessTime = timeStamp;
ggaren1f92a1a2007-08-09 03:59:32 +0000224
hyatt2ce79842007-03-25 05:53:42 +0000225 if (inCache()) {
ggaren408a6df2007-08-08 07:01:39 +0000226 if (m_inLiveDecodedResourcesList) {
227 cache()->removeFromLiveDecodedResourcesList(this);
228 cache()->insertInLiveDecodedResourcesList(this);
229 }
ggaren1aba8372007-08-16 23:43:43 +0000230 cache()->prune();
hyattc4404492006-10-19 09:21:54 +0000231 }
eseidel94980f22006-01-09 09:29:48 +0000232}
antti@apple.com72e4a842008-09-05 09:28:11 +0000233
234void CachedResource::setResourceToRevalidate(CachedResource* resource)
235{
236 ASSERT(resource);
237 ASSERT(!m_resourceToRevalidate);
238 ASSERT(resource != this);
239 ASSERT(!resource->m_isBeingRevalidated);
240 ASSERT(m_handlesToRevalidate.isEmpty());
241 ASSERT(resource->type() == type());
242 resource->m_isBeingRevalidated = true;
243 m_resourceToRevalidate = resource;
244}
245
246void CachedResource::clearResourceToRevalidate()
247{
248 ASSERT(m_resourceToRevalidate);
249 ASSERT(m_resourceToRevalidate->m_isBeingRevalidated);
250 m_resourceToRevalidate->m_isBeingRevalidated = false;
251 m_resourceToRevalidate->deleteIfPossible();
252 m_handlesToRevalidate.clear();
253 m_resourceToRevalidate = 0;
254 deleteIfPossible();
255}
256
257void CachedResource::switchClientsToRevalidatedResource()
258{
259 ASSERT(m_resourceToRevalidate);
260 ASSERT(!inCache());
261
262 HashSet<CachedResourceHandleBase*>::iterator end = m_handlesToRevalidate.end();
263 for (HashSet<CachedResourceHandleBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
264 CachedResourceHandleBase* handle = *it;
265 handle->m_resource = m_resourceToRevalidate;
266 m_resourceToRevalidate->registerHandle(handle);
267 --m_handleCount;
268 }
269 ASSERT(!m_handleCount);
270 m_handlesToRevalidate.clear();
271
272 Vector<CachedResourceClient*> clientsToMove;
273 HashCountedSet<CachedResourceClient*>::iterator end2 = m_clients.end();
274 for (HashCountedSet<CachedResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
275 CachedResourceClient* client = it->first;
276 unsigned count = it->second;
277 while (count) {
278 clientsToMove.append(client);
279 --count;
280 }
281 }
282 // Equivalent of calling removeClient() for all clients
283 m_clients.clear();
284
285 unsigned moveCount = clientsToMove.size();
286 for (unsigned n = 0; n < moveCount; ++n)
287 m_resourceToRevalidate->addClient(clientsToMove[n]);
288}
289
290bool CachedResource::canUseCacheValidator() const
291{
292 return !m_loading && (!m_response.httpHeaderField("Last-Modified").isEmpty() || !m_response.httpHeaderField("ETag").isEmpty());
293}
294
295bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const
296{
297 if (m_loading)
298 return false;
299 String cacheControl = m_response.httpHeaderField("Cache-Control");
300 // FIXME: It would be better to tokenize the field.
301 if (cachePolicy == CachePolicyCache)
302 return !cacheControl.isEmpty() && (cacheControl.contains("no-cache", false) || (isExpired() && cacheControl.contains("must-revalidate", false)));
303 return isExpired() || cacheControl.contains("no-cache", false);
304}
eseidel94980f22006-01-09 09:29:48 +0000305
darinbbe64662006-01-16 17:52:23 +0000306}