Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(474)

Side by Side Diff: sky/engine/core/fetch/Resource.cpp

Issue 1223793006: Delete sky/engine/core/fetch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/core/fetch/Resource.h ('k') | sky/engine/core/fetch/ResourceClient.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 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)
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
7
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
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22 */
23
24 #include "sky/engine/core/fetch/Resource.h"
25
26 #include "gen/sky/core/FetchInitiatorTypeNames.h"
27 #include "sky/engine/core/fetch/MemoryCache.h"
28 #include "sky/engine/core/fetch/ResourceClient.h"
29 #include "sky/engine/core/fetch/ResourceClientWalker.h"
30 #include "sky/engine/core/fetch/ResourceFetcher.h"
31 #include "sky/engine/core/fetch/ResourceLoader.h"
32 #include "sky/engine/core/fetch/ResourcePtr.h"
33 #include "sky/engine/platform/Logging.h"
34 #include "sky/engine/platform/SharedBuffer.h"
35 #include "sky/engine/platform/TraceEvent.h"
36 #include "sky/engine/platform/weborigin/KURL.h"
37 #include "sky/engine/public/platform/Platform.h"
38 #include "sky/engine/wtf/CurrentTime.h"
39 #include "sky/engine/wtf/MathExtras.h"
40 #include "sky/engine/wtf/RefCountedLeakCounter.h"
41 #include "sky/engine/wtf/StdLibExtras.h"
42 #include "sky/engine/wtf/Vector.h"
43 #include "sky/engine/wtf/text/CString.h"
44
45 using namespace WTF;
46
47 namespace blink {
48
49 // These response headers are not copied from a revalidated response to the
50 // cached response headers. For compatibility, this list is based on Chromium's
51 // net/http/http_response_headers.cc.
52 const char* const headersToIgnoreAfterRevalidation[] = {
53 "allow",
54 "connection",
55 "etag",
56 "expires",
57 "keep-alive",
58 "last-modified"
59 "proxy-authenticate",
60 "proxy-connection",
61 "trailer",
62 "transfer-encoding",
63 "upgrade",
64 "www-authenticate",
65 "x-frame-options",
66 "x-xss-protection",
67 };
68
69 // Some header prefixes mean "Don't copy this header from a 304 response.".
70 // Rather than listing all the relevant headers, we can consolidate them into
71 // this list, also grabbed from Chromium's net/http/http_response_headers.cc.
72 const char* const headerPrefixesToIgnoreAfterRevalidation[] = {
73 "content-",
74 "x-content-",
75 "x-webkit-"
76 };
77
78 static inline bool shouldUpdateHeaderAfterRevalidation(const AtomicString& heade r)
79 {
80 for (size_t i = 0; i < WTF_ARRAY_LENGTH(headersToIgnoreAfterRevalidation); i ++) {
81 if (equalIgnoringCase(header, headersToIgnoreAfterRevalidation[i]))
82 return false;
83 }
84 for (size_t i = 0; i < WTF_ARRAY_LENGTH(headerPrefixesToIgnoreAfterRevalidat ion); i++) {
85 if (header.startsWith(headerPrefixesToIgnoreAfterRevalidation[i], false) )
86 return false;
87 }
88 return true;
89 }
90
91 DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, cachedResourceLeakCounter, ("Res ource"));
92 unsigned Resource::s_instanceCount = 0;
93
94 Resource::Resource(const ResourceRequest& request, Type type)
95 : m_resourceRequest(request)
96 , m_responseTimestamp(currentTime())
97 , m_cancelTimer(this, &Resource::cancelTimerFired)
98 , m_loadFinishTime(0)
99 , m_identifier(0)
100 , m_encodedSize(0)
101 , m_decodedSize(0)
102 , m_handleCount(0)
103 , m_protectorCount(0)
104 , m_requestedFromNetworkingLayer(false)
105 , m_loading(false)
106 , m_switchingClientsToRevalidatedResource(false)
107 , m_type(type)
108 , m_status(Pending)
109 , m_wasPurged(false)
110 , m_needsSynchronousCacheHit(false)
111 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
112 , m_deleted(false)
113 #endif
114 , m_resourceToRevalidate(nullptr)
115 , m_proxyResource(nullptr)
116 {
117 ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests car eless updates of the enum.
118 ++s_instanceCount;
119 #ifndef NDEBUG
120 cachedResourceLeakCounter.increment();
121 #endif
122 memoryCache()->registerLiveResource(*this);
123
124 if (!m_resourceRequest.url().hasFragmentIdentifier())
125 return;
126 KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceR equest.url());
127 if (urlForCache.hasFragmentIdentifier())
128 return;
129 m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier( );
130 m_resourceRequest.setURL(urlForCache);
131 }
132
133 Resource::~Resource()
134 {
135 ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() check s this.
136 ASSERT(canDelete());
137 RELEASE_ASSERT(!memoryCache()->contains(this));
138 RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this));
139 ASSERT(url().isNull() || memoryCache()->resourceForURL(KURL(ParsedURLString, url())) != this);
140 assertAlive();
141
142 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK
143 m_deleted = true;
144 #endif
145 #ifndef NDEBUG
146 cachedResourceLeakCounter.decrement();
147 #endif
148 --s_instanceCount;
149 }
150
151 void Resource::dispose()
152 {
153 }
154
155 void Resource::failBeforeStarting()
156 {
157 WTF_LOG(ResourceLoading, "Cannot start loading '%s'", url().string().latin1( ).data());
158 error(Resource::LoadError);
159 }
160
161 void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& optio ns)
162 {
163 if (!fetcher->frame()) {
164 failBeforeStarting();
165 return;
166 }
167
168 m_options = options;
169 m_loading = true;
170
171 if (!accept().isEmpty())
172 m_resourceRequest.setHTTPAccept(accept());
173
174 // FIXME: It's unfortunate that the cache layer and below get to know anythi ng about fragment identifiers.
175 // We should look into removing the expectation of that knowledge from the p latform network stacks.
176 ResourceRequest request(m_resourceRequest);
177 if (!m_fragmentIdentifierForRequest.isNull()) {
178 KURL url = request.url();
179 url.setFragmentIdentifier(m_fragmentIdentifierForRequest);
180 request.setURL(url);
181 m_fragmentIdentifierForRequest = String();
182 }
183 m_status = Pending;
184 m_loader = ResourceLoader::create(fetcher, this, request, options);
185 m_loader->start();
186 }
187
188 void Resource::checkNotify()
189 {
190 if (isLoading())
191 return;
192
193 ResourceClientWalker<ResourceClient> w(m_clients);
194 while (ResourceClient* c = w.next())
195 c->notifyFinished(this);
196 }
197
198 void Resource::appendData(const char* data, int length)
199 {
200 TRACE_EVENT0("blink", "Resource::appendData");
201 ASSERT(!m_resourceToRevalidate);
202 ASSERT(!errorOccurred());
203 if (m_options.dataBufferingPolicy == DoNotBufferData)
204 return;
205 if (m_data)
206 m_data->append(data, length);
207 else
208 m_data = SharedBuffer::createPurgeable(data, length);
209 setEncodedSize(m_data->size());
210 }
211
212 void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer)
213 {
214 ASSERT(!m_resourceToRevalidate);
215 ASSERT(!errorOccurred());
216 ASSERT(m_options.dataBufferingPolicy == BufferData);
217 m_data = resourceBuffer;
218 setEncodedSize(m_data->size());
219 }
220
221 void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
222 {
223 m_options.dataBufferingPolicy = dataBufferingPolicy;
224 m_data.clear();
225 setEncodedSize(0);
226 }
227
228 void Resource::error(Resource::Status status)
229 {
230 if (m_resourceToRevalidate)
231 revalidationFailed();
232
233 if (!m_error.isNull())
234 memoryCache()->remove(this);
235
236 setStatus(status);
237 ASSERT(errorOccurred());
238 m_data.clear();
239
240 setLoading(false);
241 checkNotify();
242 }
243
244 void Resource::finishOnePart()
245 {
246 setLoading(false);
247 checkNotify();
248 }
249
250 void Resource::finish(double finishTime)
251 {
252 ASSERT(!m_resourceToRevalidate);
253 ASSERT(!errorOccurred());
254 m_loadFinishTime = finishTime;
255 finishOnePart();
256 if (!errorOccurred())
257 m_status = Cached;
258 }
259
260 static double currentAge(const ResourceResponse& response, double responseTimest amp)
261 {
262 // RFC2616 13.2.3
263 // No compensation for latency as that is not terribly important in practice
264 double dateValue = response.date();
265 double apparentAge = std::isfinite(dateValue) ? std::max(0., responseTimesta mp - dateValue) : 0;
266 double ageValue = response.age();
267 double correctedReceivedAge = std::isfinite(ageValue) ? std::max(apparentAge , ageValue) : apparentAge;
268 double residentTime = currentTime() - responseTimestamp;
269 return correctedReceivedAge + residentTime;
270 }
271
272 static double freshnessLifetime(ResourceResponse& response, double responseTimes tamp)
273 {
274 #if !OS(ANDROID)
275 // On desktop, local files should be reloaded in case they change.
276 if (response.url().isLocalFile())
277 return 0;
278 #endif
279
280 // Cache other non-http / non-filesystem resources liberally.
281 if (!response.url().protocolIsInHTTPFamily()
282 && !response.url().protocolIs("filesystem"))
283 return std::numeric_limits<double>::max();
284
285 // RFC2616 13.2.4
286 double maxAgeValue = response.cacheControlMaxAge();
287 if (std::isfinite(maxAgeValue))
288 return maxAgeValue;
289 double expiresValue = response.expires();
290 double dateValue = response.date();
291 double creationTime = std::isfinite(dateValue) ? dateValue : responseTimesta mp;
292 if (std::isfinite(expiresValue))
293 return expiresValue - creationTime;
294 double lastModifiedValue = response.lastModified();
295 if (std::isfinite(lastModifiedValue))
296 return (creationTime - lastModifiedValue) * 0.1;
297 // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0.
298 return 0;
299 }
300
301 static bool canUseResponse(ResourceResponse& response, double responseTimestamp)
302 {
303 if (response.isNull())
304 return false;
305
306 // FIXME: Why isn't must-revalidate considered a reason we can't use the res ponse?
307 if (response.cacheControlContainsNoCache() || response.cacheControlContainsN oStore())
308 return false;
309
310 if (response.httpStatusCode() == 303) {
311 // Must not be cached.
312 return false;
313 }
314
315 if (response.httpStatusCode() == 302 || response.httpStatusCode() == 307) {
316 // Default to not cacheable unless explicitly allowed.
317 bool hasMaxAge = std::isfinite(response.cacheControlMaxAge());
318 bool hasExpires = std::isfinite(response.expires());
319 // TODO: consider catching Cache-Control "private" and "public" here.
320 if (!hasMaxAge && !hasExpires)
321 return false;
322 }
323
324 return currentAge(response, responseTimestamp) <= freshnessLifetime(response , responseTimestamp);
325 }
326
327 void Resource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
328 {
329 m_requestedFromNetworkingLayer = true;
330 }
331
332 bool Resource::unlock()
333 {
334 if (!m_data)
335 return false;
336
337 if (!m_data->isLocked())
338 return true;
339
340 if (!memoryCache()->contains(this) || hasClients() || m_handleCount > 1 || m _proxyResource || m_resourceToRevalidate || !m_loadFinishTime || !isSafeToUnlock ())
341 return false;
342
343 m_data->unlock();
344 return true;
345 }
346
347 bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const
348 {
349 return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0 );
350 }
351
352 void Resource::responseReceived(const ResourceResponse& response)
353 {
354 setResponse(response);
355 m_responseTimestamp = currentTime();
356 String encoding = response.textEncodingName();
357 if (!encoding.isNull())
358 setEncoding(encoding);
359
360 if (!m_resourceToRevalidate)
361 return;
362 if (response.httpStatusCode() == 304)
363 revalidationSucceeded(response);
364 else
365 revalidationFailed();
366 }
367
368 bool Resource::canDelete() const
369 {
370 return !hasClients() && !m_loader && hasRightHandleCountApartFromCache(0)
371 && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource;
372 }
373
374 bool Resource::hasOneHandle() const
375 {
376 return hasRightHandleCountApartFromCache(1);
377 }
378
379 void Resource::clearLoader()
380 {
381 m_loader = nullptr;
382 }
383
384 void Resource::addClient(ResourceClient* client)
385 {
386 if (addClientToSet(client))
387 didAddClient(client);
388 }
389
390 void Resource::didAddClient(ResourceClient* c)
391 {
392 if (!isLoading() && !stillNeedsLoad())
393 c->notifyFinished(this);
394 }
395
396 static bool shouldSendCachedDataSynchronouslyForType(Resource::Type type)
397 {
398 // Some resources types default to return data synchronously.
399 // For most of these, it's because there are layout tests that
400 // expect data to return synchronously in case of cache hit. In
401 // the case of fonts, there was a performance regression.
402 // FIXME: Get to the point where we don't need to special-case sync/async
403 // behavior for different resource types.
404 if (type == Resource::Image)
405 return true;
406 if (type == Resource::Font)
407 return true;
408 return false;
409 }
410
411 bool Resource::addClientToSet(ResourceClient* client)
412 {
413 ASSERT(!isPurgeable());
414
415 if (!hasClients())
416 memoryCache()->makeLive(this);
417
418 // If we have existing data to send to the new client and the resource type supprts it, send it asynchronously.
419 if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchro nouslyForType(type()) && !m_needsSynchronousCacheHit) {
420 m_clientsAwaitingCallback.add(client);
421 ResourceCallback::callbackHandler()->schedule(this);
422 return false;
423 }
424
425 m_clients.add(client);
426 return true;
427 }
428
429 void Resource::removeClient(ResourceClient* client)
430 {
431 if (m_clientsAwaitingCallback.contains(client)) {
432 ASSERT(!m_clients.contains(client));
433 m_clientsAwaitingCallback.remove(client);
434 } else {
435 ASSERT(m_clients.contains(client));
436 m_clients.remove(client);
437 didRemoveClient(client);
438 }
439
440 if (m_clientsAwaitingCallback.isEmpty())
441 ResourceCallback::callbackHandler()->cancel(this);
442
443 bool deleted = deleteIfPossible();
444 if (!deleted && !hasClients()) {
445 memoryCache()->makeDead(this);
446 if (!m_switchingClientsToRevalidatedResource)
447 allClientsRemoved();
448
449 // RFC2616 14.9.2:
450 // "no-store: ... MUST make a best-effort attempt to remove the informat ion from volatile storage as promptly as possible"
451 // "... History buffers MAY store such responses as part of their normal operation."
452 // We allow non-secure content to be reused in history, but we do not al low secure content to be reused.
453 if (hasCacheControlNoStoreHeader() && url().protocolIs("https")) {
454 memoryCache()->remove(this);
455 memoryCache()->prune();
456 } else {
457 memoryCache()->prune(this);
458 }
459 }
460 // This object may be dead here.
461 }
462
463 void Resource::allClientsRemoved()
464 {
465 if (!m_loader)
466 return;
467 if (m_type == MainResource || m_type == Raw)
468 cancelTimerFired(&m_cancelTimer);
469 else if (!m_cancelTimer.isActive())
470 m_cancelTimer.startOneShot(0, FROM_HERE);
471
472 unlock();
473 }
474
475 void Resource::cancelTimerFired(Timer<Resource>* timer)
476 {
477 ASSERT_UNUSED(timer, timer == &m_cancelTimer);
478 if (hasClients() || !m_loader)
479 return;
480 ResourcePtr<Resource> protect(this);
481 m_loader->cancelIfNotFinishing();
482 if (m_status != Cached)
483 memoryCache()->remove(this);
484 }
485
486 bool Resource::deleteIfPossible()
487 {
488 if (canDelete() && !memoryCache()->contains(this)) {
489 dispose();
490 memoryCache()->unregisterLiveResource(*this);
491 #if !ENABLE(OILPAN)
492 delete this;
493 #endif
494 return true;
495 }
496 return false;
497 }
498
499 void Resource::setDecodedSize(size_t decodedSize)
500 {
501 if (decodedSize == m_decodedSize)
502 return;
503 size_t oldSize = size();
504 m_decodedSize = decodedSize;
505 memoryCache()->update(this, oldSize, size());
506 memoryCache()->updateDecodedResource(this, UpdateForPropertyChange);
507 }
508
509 void Resource::setEncodedSize(size_t encodedSize)
510 {
511 if (encodedSize == m_encodedSize)
512 return;
513 size_t oldSize = size();
514 m_encodedSize = encodedSize;
515 memoryCache()->update(this, oldSize, size());
516 }
517
518 void Resource::didAccessDecodedData()
519 {
520 memoryCache()->updateDecodedResource(this, UpdateForAccess);
521 memoryCache()->prune();
522 }
523
524 void Resource::finishPendingClients()
525 {
526 // We're going to notify clients one by one. It is simple if the client does nothing.
527 // However there are a couple other things that can happen.
528 //
529 // 1. Clients can be added during the loop. Make sure they are not processed .
530 // 2. Clients can be removed during the loop. Make sure they are always avai lable to be
531 // removed. Also don't call removed clients or add them back.
532
533 // Handle case (1) by saving a list of clients to notify. A separate list al so ensure
534 // a client is either in m_clients or m_clientsAwaitingCallback.
535 Vector<ResourceClient*> clientsToNotify;
536 copyToVector(m_clientsAwaitingCallback, clientsToNotify);
537
538 for (size_t i = 0; i < clientsToNotify.size(); ++i) {
539 ResourceClient* client = clientsToNotify[i];
540
541 // Handle case (2) to skip removed clients.
542 if (!m_clientsAwaitingCallback.remove(client))
543 continue;
544 m_clients.add(client);
545 didAddClient(client);
546 }
547
548 // It is still possible for the above loop to finish a new client synchronou sly.
549 // If there's no client waiting we should deschedule.
550 bool scheduled = ResourceCallback::callbackHandler()->isScheduled(this);
551 if (scheduled && m_clientsAwaitingCallback.isEmpty())
552 ResourceCallback::callbackHandler()->cancel(this);
553
554 // Prevent the case when there are clients waiting but no callback scheduled .
555 ASSERT(m_clientsAwaitingCallback.isEmpty() || scheduled);
556 }
557
558 void Resource::prune()
559 {
560 destroyDecodedDataIfPossible();
561 unlock();
562 }
563
564 void Resource::setResourceToRevalidate(Resource* resource)
565 {
566 ASSERT(resource);
567 ASSERT(!m_resourceToRevalidate);
568 ASSERT(resource != this);
569 ASSERT(m_handlesToRevalidate.isEmpty());
570 ASSERT(resource->type() == type());
571
572 WTF_LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, res ource);
573
574 // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances.
575 // https://bugs.webkit.org/show_bug.cgi?id=28604.
576 // So the code needs to be robust to this assert failing thus the "if (m_res ourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalid ate.
577 ASSERT(!resource->m_proxyResource);
578
579 resource->m_proxyResource = this;
580 m_resourceToRevalidate = resource;
581 }
582
583 void Resource::clearResourceToRevalidate()
584 {
585 ASSERT(m_resourceToRevalidate);
586 if (m_switchingClientsToRevalidatedResource)
587 return;
588
589 // A resource may start revalidation before this method has been called, so check that this resource is still the proxy resource before clearing it out.
590 if (m_resourceToRevalidate->m_proxyResource == this) {
591 m_resourceToRevalidate->m_proxyResource = nullptr;
592 m_resourceToRevalidate->deleteIfPossible();
593 }
594 m_handlesToRevalidate.clear();
595 m_resourceToRevalidate = nullptr;
596 deleteIfPossible();
597 }
598
599 void Resource::switchClientsToRevalidatedResource()
600 {
601 ASSERT(m_resourceToRevalidate);
602 ASSERT(memoryCache()->contains(m_resourceToRevalidate));
603 ASSERT(!memoryCache()->contains(this));
604
605 WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p" , this, m_resourceToRevalidate.get());
606
607 m_resourceToRevalidate->m_identifier = m_identifier;
608
609 m_switchingClientsToRevalidatedResource = true;
610 HashSet<ResourcePtrBase*>::iterator end = m_handlesToRevalidate.end();
611 for (HashSet<ResourcePtrBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
612 ResourcePtrBase* handle = *it;
613 handle->m_resource = m_resourceToRevalidate;
614 m_resourceToRevalidate->registerHandle(handle);
615 --m_handleCount;
616 }
617 ASSERT(!m_handleCount);
618 m_handlesToRevalidate.clear();
619
620 Vector<ResourceClient*> clientsToMove;
621 HashCountedSet<ResourceClient*>::iterator end2 = m_clients.end();
622 for (HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); it != end2; ++it) {
623 ResourceClient* client = it->key;
624 unsigned count = it->value;
625 while (count) {
626 clientsToMove.append(client);
627 --count;
628 }
629 }
630
631 unsigned moveCount = clientsToMove.size();
632 for (unsigned n = 0; n < moveCount; ++n)
633 removeClient(clientsToMove[n]);
634 ASSERT(m_clients.isEmpty());
635
636 for (unsigned n = 0; n < moveCount; ++n)
637 m_resourceToRevalidate->addClientToSet(clientsToMove[n]);
638 for (unsigned n = 0; n < moveCount; ++n) {
639 // Calling didAddClient may do anything, including trying to cancel reva lidation.
640 // Assert that it didn't succeed.
641 ASSERT(m_resourceToRevalidate);
642 // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore.
643 if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n]))
644 m_resourceToRevalidate->didAddClient(clientsToMove[n]);
645 }
646 m_switchingClientsToRevalidatedResource = false;
647 }
648
649 void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatin gResponse)
650 {
651 m_responseTimestamp = currentTime();
652
653 // RFC2616 10.3.5
654 // Update cached headers from the 304 response
655 const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields();
656 HTTPHeaderMap::const_iterator end = newHeaders.end();
657 for (HTTPHeaderMap::const_iterator it = newHeaders.begin(); it != end; ++it) {
658 // Entity headers should not be sent by servers when generating a 304
659 // response; misconfigured servers send them anyway. We shouldn't allow
660 // such headers to update the original request. We'll base this on the
661 // list defined by RFC2616 7.1, with a few additions for extension heade rs
662 // we care about.
663 if (!shouldUpdateHeaderAfterRevalidation(it->key))
664 continue;
665 m_response.setHTTPHeaderField(it->key, it->value);
666 }
667 }
668
669 void Resource::revalidationSucceeded(const ResourceResponse& response)
670 {
671 ASSERT(m_resourceToRevalidate);
672 ASSERT(!memoryCache()->contains(m_resourceToRevalidate));
673 ASSERT(m_resourceToRevalidate->isLoaded());
674
675 // Calling evict() can potentially delete revalidatingResource, which we use
676 // below. This mustn't be the case since revalidation means it is loaded
677 // and so canDelete() is false.
678 ASSERT(!canDelete());
679
680 m_resourceToRevalidate->updateResponseAfterRevalidation(response);
681 memoryCache()->replace(m_resourceToRevalidate, this);
682
683 switchClientsToRevalidatedResource();
684 assertAlive();
685 // clearResourceToRevalidate deletes this.
686 clearResourceToRevalidate();
687 }
688
689 void Resource::revalidationFailed()
690 {
691 ASSERT(WTF::isMainThread());
692 WTF_LOG(ResourceLoading, "Revalidation failed for %p", this);
693 ASSERT(resourceToRevalidate());
694 clearResourceToRevalidate();
695 }
696
697 void Resource::registerHandle(ResourcePtrBase* h)
698 {
699 assertAlive();
700 ++m_handleCount;
701 if (m_resourceToRevalidate)
702 m_handlesToRevalidate.add(h);
703 }
704
705 void Resource::unregisterHandle(ResourcePtrBase* h)
706 {
707 assertAlive();
708 ASSERT(m_handleCount > 0);
709 --m_handleCount;
710
711 if (m_resourceToRevalidate)
712 m_handlesToRevalidate.remove(h);
713
714 if (!m_handleCount) {
715 if (deleteIfPossible())
716 return;
717 unlock();
718 } else if (m_handleCount == 1 && memoryCache()->contains(this)) {
719 unlock();
720 if (!hasClients())
721 memoryCache()->prune(this);
722 }
723 }
724
725 bool Resource::hasCacheControlNoStoreHeader()
726 {
727 return m_response.cacheControlContainsNoStore() || m_resourceRequest.cacheCo ntrolContainsNoStore();
728 }
729
730 bool Resource::mustRevalidateDueToCacheHeaders()
731 {
732 return !canUseResponse(m_response, m_responseTimestamp) || m_resourceRequest .cacheControlContainsNoCache() || m_resourceRequest.cacheControlContainsNoStore( );
733 }
734
735 bool Resource::canUseCacheValidator()
736 {
737 if (m_loading || errorOccurred())
738 return false;
739
740 if (hasCacheControlNoStoreHeader())
741 return false;
742 return m_response.hasCacheValidatorFields() || m_resourceRequest.hasCacheVal idatorFields();
743 }
744
745 bool Resource::isPurgeable() const
746 {
747 return m_data && !m_data->isLocked();
748 }
749
750 bool Resource::wasPurged() const
751 {
752 return m_wasPurged;
753 }
754
755 bool Resource::lock()
756 {
757 if (!m_data)
758 return true;
759 if (m_data->isLocked())
760 return true;
761
762 ASSERT(!hasClients());
763
764 if (!m_data->lock()) {
765 m_wasPurged = true;
766 return false;
767 }
768 return true;
769 }
770
771 size_t Resource::overheadSize() const
772 {
773 static const int kAverageClientsHashMapSize = 384;
774 return sizeof(Resource) + m_response.memoryUsage() + kAverageClientsHashMapS ize + m_resourceRequest.url().string().length() * 2;
775 }
776
777 void Resource::didChangePriority(ResourceLoadPriority loadPriority, int intraPri orityValue)
778 {
779 if (m_loader)
780 m_loader->didChangePriority(loadPriority, intraPriorityValue);
781 }
782
783 Resource::ResourceCallback* Resource::ResourceCallback::callbackHandler()
784 {
785 DEFINE_STATIC_LOCAL(ResourceCallback, callbackHandler, ());
786 return &callbackHandler;
787 }
788
789 Resource::ResourceCallback::ResourceCallback()
790 : m_callbackTimer(this, &ResourceCallback::timerFired)
791 {
792 }
793
794 void Resource::ResourceCallback::schedule(Resource* resource)
795 {
796 if (!m_callbackTimer.isActive())
797 m_callbackTimer.startOneShot(0, FROM_HERE);
798 resource->assertAlive();
799 m_resourcesWithPendingClients.add(resource);
800 }
801
802 void Resource::ResourceCallback::cancel(Resource* resource)
803 {
804 resource->assertAlive();
805 m_resourcesWithPendingClients.remove(resource);
806 if (m_callbackTimer.isActive() && m_resourcesWithPendingClients.isEmpty())
807 m_callbackTimer.stop();
808 }
809
810 bool Resource::ResourceCallback::isScheduled(Resource* resource) const
811 {
812 return m_resourcesWithPendingClients.contains(resource);
813 }
814
815 void Resource::ResourceCallback::timerFired(Timer<ResourceCallback>*)
816 {
817 HashSet<Resource*>::iterator end = m_resourcesWithPendingClients.end();
818 Vector<ResourcePtr<Resource> > resources;
819 for (HashSet<Resource*>::iterator it = m_resourcesWithPendingClients.begin() ; it != end; ++it)
820 resources.append(*it);
821 m_resourcesWithPendingClients.clear();
822
823 for (size_t i = 0; i < resources.size(); i++) {
824 resources[i]->assertAlive();
825 resources[i]->finishPendingClients();
826 resources[i]->assertAlive();
827 }
828
829 for (size_t i = 0; i < resources.size(); i++)
830 resources[i]->assertAlive();
831 }
832
833 static const char* initatorTypeNameToString(const AtomicString& initiatorTypeNam e)
834 {
835 if (initiatorTypeName == FetchInitiatorTypeNames::css)
836 return "CSS resource";
837 if (initiatorTypeName == FetchInitiatorTypeNames::document)
838 return "Document";
839 if (initiatorTypeName == FetchInitiatorTypeNames::icon)
840 return "Icon";
841 if (initiatorTypeName == FetchInitiatorTypeNames::internal)
842 return "Internal resource";
843 if (initiatorTypeName == FetchInitiatorTypeNames::link)
844 return "Link element resource";
845 if (initiatorTypeName == FetchInitiatorTypeNames::processinginstruction)
846 return "Processing instruction";
847 if (initiatorTypeName == FetchInitiatorTypeNames::xml)
848 return "XML resource";
849 return "Resource";
850 }
851
852 const char* Resource::resourceTypeToString(Type type, const FetchInitiatorInfo& initiatorInfo)
853 {
854 switch (type) {
855 case Resource::MainResource:
856 return "Main resource";
857 case Resource::Image:
858 return "Image";
859 case Resource::Font:
860 return "Font";
861 case Resource::Raw:
862 return initatorTypeNameToString(initiatorInfo.name);
863 case Resource::LinkPrefetch:
864 return "Link prefetch resource";
865 case Resource::LinkSubresource:
866 return "Link subresource";
867 case Resource::ImportResource:
868 return "Imported resource";
869 case Resource::Media:
870 return "Media";
871 }
872 ASSERT_NOT_REACHED();
873 return initatorTypeNameToString(initiatorInfo.name);
874 }
875
876 #if !LOG_DISABLED
877 const char* ResourceTypeName(Resource::Type type)
878 {
879 switch (type) {
880 case Resource::MainResource:
881 return "MainResource";
882 case Resource::Image:
883 return "Image";
884 case Resource::Font:
885 return "Font";
886 case Resource::Raw:
887 return "Raw";
888 case Resource::LinkPrefetch:
889 return "LinkPrefetch";
890 case Resource::LinkSubresource:
891 return "LinkSubresource";
892 case Resource::ImportResource:
893 return "ImportResource";
894 case Resource::Media:
895 return "Media";
896 }
897 ASSERT_NOT_REACHED();
898 return "Unknown";
899 }
900 #endif // !LOG_DISABLED
901
902 }
OLDNEW
« no previous file with comments | « sky/engine/core/fetch/Resource.h ('k') | sky/engine/core/fetch/ResourceClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698