OLD | NEW |
1 /* | 1 /* |
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) |
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) | 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) |
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) | 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) |
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) | 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. | 6 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
rights reserved. |
7 | 7 |
8 This library is free software; you can redistribute it and/or | 8 This library is free software; you can redistribute it and/or |
9 modify it under the terms of the GNU Library General Public | 9 modify it under the terms of the GNU Library General Public |
10 License as published by the Free Software Foundation; either | 10 License as published by the Free Software Foundation; either |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 , m_requestedFromNetworkingLayer(false) | 158 , m_requestedFromNetworkingLayer(false) |
159 , m_loading(false) | 159 , m_loading(false) |
160 , m_switchingClientsToRevalidatedResource(false) | 160 , m_switchingClientsToRevalidatedResource(false) |
161 , m_type(type) | 161 , m_type(type) |
162 , m_status(Pending) | 162 , m_status(Pending) |
163 , m_wasPurged(false) | 163 , m_wasPurged(false) |
164 , m_needsSynchronousCacheHit(false) | 164 , m_needsSynchronousCacheHit(false) |
165 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK | 165 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK |
166 , m_deleted(false) | 166 , m_deleted(false) |
167 #endif | 167 #endif |
| 168 , m_resourceToRevalidate(nullptr) |
| 169 , m_proxyResource(nullptr) |
168 { | 170 { |
169 ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests car
eless updates of the enum. | 171 ASSERT(m_type == unsigned(type)); // m_type is a bitfield, so this tests car
eless updates of the enum. |
170 InstanceCounters::incrementCounter(InstanceCounters::ResourceCounter); | 172 InstanceCounters::incrementCounter(InstanceCounters::ResourceCounter); |
171 memoryCache()->registerLiveResource(*this); | 173 memoryCache()->registerLiveResource(*this); |
172 | 174 |
173 // Currently we support the metadata caching only for HTTP family. | 175 // Currently we support the metadata caching only for HTTP family. |
174 if (m_resourceRequest.url().protocolIsInHTTPFamily()) | 176 if (m_resourceRequest.url().protocolIsInHTTPFamily()) |
175 m_cacheHandler = CacheHandler::create(this); | 177 m_cacheHandler = CacheHandler::create(this); |
176 | 178 |
177 if (!m_resourceRequest.url().hasFragmentIdentifier()) | 179 if (!m_resourceRequest.url().hasFragmentIdentifier()) |
178 return; | 180 return; |
179 KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceR
equest.url()); | 181 KURL urlForCache = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceR
equest.url()); |
180 if (urlForCache.hasFragmentIdentifier()) | 182 if (urlForCache.hasFragmentIdentifier()) |
181 return; | 183 return; |
182 m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier(
); | 184 m_fragmentIdentifierForRequest = m_resourceRequest.url().fragmentIdentifier(
); |
183 m_resourceRequest.setURL(urlForCache); | 185 m_resourceRequest.setURL(urlForCache); |
184 } | 186 } |
185 | 187 |
186 Resource::~Resource() | 188 Resource::~Resource() |
187 { | 189 { |
| 190 ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() check
s this. |
188 ASSERT(canDelete()); | 191 ASSERT(canDelete()); |
189 RELEASE_ASSERT(!memoryCache()->contains(this)); | 192 RELEASE_ASSERT(!memoryCache()->contains(this)); |
190 RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this)); | 193 RELEASE_ASSERT(!ResourceCallback::callbackHandler()->isScheduled(this)); |
191 assertAlive(); | 194 assertAlive(); |
192 | 195 |
193 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK | 196 #ifdef ENABLE_RESOURCE_IS_DELETED_CHECK |
194 m_deleted = true; | 197 m_deleted = true; |
195 #endif | 198 #endif |
196 InstanceCounters::decrementCounter(InstanceCounters::ResourceCounter); | 199 InstanceCounters::decrementCounter(InstanceCounters::ResourceCounter); |
197 } | 200 } |
198 | 201 |
199 void Resource::dispose() | 202 void Resource::dispose() |
200 { | 203 { |
201 } | 204 } |
202 | 205 |
203 DEFINE_TRACE(Resource) | 206 DEFINE_TRACE(Resource) |
204 { | 207 { |
205 visitor->trace(m_loader); | 208 visitor->trace(m_loader); |
| 209 visitor->trace(m_resourceToRevalidate); |
| 210 visitor->trace(m_proxyResource); |
206 #if ENABLE(OILPAN) | 211 #if ENABLE(OILPAN) |
207 visitor->trace(m_cacheHandler); | 212 visitor->trace(m_cacheHandler); |
208 #endif | 213 #endif |
209 } | 214 } |
210 | 215 |
211 void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& optio
ns) | 216 void Resource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& optio
ns) |
212 { | 217 { |
213 m_options = options; | 218 m_options = options; |
214 m_loading = true; | 219 m_loading = true; |
215 | 220 |
216 ResourceRequest request(m_revalidatingRequest.isNull() ? m_resourceRequest :
m_revalidatingRequest); | |
217 if (!accept().isEmpty()) | 221 if (!accept().isEmpty()) |
218 request.setHTTPAccept(accept()); | 222 m_resourceRequest.setHTTPAccept(accept()); |
219 | 223 |
220 // FIXME: It's unfortunate that the cache layer and below get to know anythi
ng about fragment identifiers. | 224 // FIXME: It's unfortunate that the cache layer and below get to know anythi
ng about fragment identifiers. |
221 // We should look into removing the expectation of that knowledge from the p
latform network stacks. | 225 // We should look into removing the expectation of that knowledge from the p
latform network stacks. |
| 226 ResourceRequest request(m_resourceRequest); |
222 if (!m_fragmentIdentifierForRequest.isNull()) { | 227 if (!m_fragmentIdentifierForRequest.isNull()) { |
223 KURL url = request.url(); | 228 KURL url = request.url(); |
224 url.setFragmentIdentifier(m_fragmentIdentifierForRequest); | 229 url.setFragmentIdentifier(m_fragmentIdentifierForRequest); |
225 request.setURL(url); | 230 request.setURL(url); |
226 m_fragmentIdentifierForRequest = String(); | 231 m_fragmentIdentifierForRequest = String(); |
227 } | 232 } |
228 m_status = Pending; | 233 m_status = Pending; |
229 if (m_loader) { | 234 if (m_loader) { |
230 ASSERT(m_revalidatingRequest.isNull()); | |
231 RELEASE_ASSERT(m_options.synchronousPolicy == RequestSynchronously); | 235 RELEASE_ASSERT(m_options.synchronousPolicy == RequestSynchronously); |
232 m_loader->changeToSynchronous(); | 236 m_loader->changeToSynchronous(); |
233 return; | 237 return; |
234 } | 238 } |
235 m_loader = ResourceLoader::create(fetcher, this, request, options); | 239 m_loader = ResourceLoader::create(fetcher, this, request, options); |
236 m_loader->start(); | 240 m_loader->start(); |
237 } | 241 } |
238 | 242 |
239 void Resource::checkNotify() | 243 void Resource::checkNotify() |
240 { | 244 { |
241 if (isLoading()) | 245 if (isLoading()) |
242 return; | 246 return; |
243 | 247 |
244 ResourceClientWalker<ResourceClient> w(m_clients); | 248 ResourceClientWalker<ResourceClient> w(m_clients); |
245 while (ResourceClient* c = w.next()) | 249 while (ResourceClient* c = w.next()) |
246 c->notifyFinished(this); | 250 c->notifyFinished(this); |
247 } | 251 } |
248 | 252 |
249 void Resource::appendData(const char* data, unsigned length) | 253 void Resource::appendData(const char* data, unsigned length) |
250 { | 254 { |
251 TRACE_EVENT0("blink", "Resource::appendData"); | 255 TRACE_EVENT0("blink", "Resource::appendData"); |
252 ASSERT(m_revalidatingRequest.isNull()); | 256 ASSERT(!m_resourceToRevalidate); |
253 ASSERT(!errorOccurred()); | 257 ASSERT(!errorOccurred()); |
254 if (m_options.dataBufferingPolicy == DoNotBufferData) | 258 if (m_options.dataBufferingPolicy == DoNotBufferData) |
255 return; | 259 return; |
256 if (m_data) | 260 if (m_data) |
257 m_data->append(data, length); | 261 m_data->append(data, length); |
258 else | 262 else |
259 m_data = SharedBuffer::createPurgeable(data, length); | 263 m_data = SharedBuffer::createPurgeable(data, length); |
260 setEncodedSize(m_data->size()); | 264 setEncodedSize(m_data->size()); |
261 } | 265 } |
262 | 266 |
263 void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer) | 267 void Resource::setResourceBuffer(PassRefPtr<SharedBuffer> resourceBuffer) |
264 { | 268 { |
265 ASSERT(m_revalidatingRequest.isNull()); | 269 ASSERT(!m_resourceToRevalidate); |
266 ASSERT(!errorOccurred()); | 270 ASSERT(!errorOccurred()); |
267 ASSERT(m_options.dataBufferingPolicy == BufferData); | 271 ASSERT(m_options.dataBufferingPolicy == BufferData); |
268 m_data = resourceBuffer; | 272 m_data = resourceBuffer; |
269 setEncodedSize(m_data->size()); | 273 setEncodedSize(m_data->size()); |
270 } | 274 } |
271 | 275 |
272 void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy) | 276 void Resource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy) |
273 { | 277 { |
274 m_options.dataBufferingPolicy = dataBufferingPolicy; | 278 m_options.dataBufferingPolicy = dataBufferingPolicy; |
275 m_data.clear(); | 279 m_data.clear(); |
276 setEncodedSize(0); | 280 setEncodedSize(0); |
277 } | 281 } |
278 | 282 |
279 void Resource::markClientsFinished() | |
280 { | |
281 while (!m_clients.isEmpty()) { | |
282 HashCountedSet<ResourceClient*>::iterator it = m_clients.begin(); | |
283 for (int i = it->value; i; i--) { | |
284 m_finishedClients.add(it->key); | |
285 m_clients.remove(it); | |
286 } | |
287 } | |
288 } | |
289 | |
290 void Resource::error(Resource::Status status) | 283 void Resource::error(Resource::Status status) |
291 { | 284 { |
292 if (!m_revalidatingRequest.isNull()) | 285 if (m_resourceToRevalidate) |
293 m_revalidatingRequest = ResourceRequest(); | 286 revalidationFailed(); |
294 | 287 |
295 if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded())) | 288 if (!m_error.isNull() && (m_error.isCancellation() || !isPreloaded())) |
296 memoryCache()->remove(this); | 289 memoryCache()->remove(this); |
297 | 290 |
298 setStatus(status); | 291 setStatus(status); |
299 ASSERT(errorOccurred()); | 292 ASSERT(errorOccurred()); |
300 m_data.clear(); | 293 m_data.clear(); |
301 | 294 |
302 setLoading(false); | 295 setLoading(false); |
303 checkNotify(); | 296 checkNotify(); |
304 markClientsFinished(); | |
305 } | 297 } |
306 | 298 |
307 void Resource::finishOnePart() | 299 void Resource::finishOnePart() |
308 { | 300 { |
309 setLoading(false); | 301 setLoading(false); |
310 checkNotify(); | 302 checkNotify(); |
311 } | 303 } |
312 | 304 |
313 void Resource::finish() | 305 void Resource::finish() |
314 { | 306 { |
315 ASSERT(m_revalidatingRequest.isNull()); | 307 ASSERT(!m_resourceToRevalidate); |
316 ASSERT(!errorOccurred()); | 308 ASSERT(!errorOccurred()); |
317 finishOnePart(); | 309 finishOnePart(); |
318 markClientsFinished(); | |
319 if (!errorOccurred()) | 310 if (!errorOccurred()) |
320 m_status = Cached; | 311 m_status = Cached; |
321 } | 312 } |
322 | 313 |
323 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin) const | 314 bool Resource::passesAccessControlCheck(SecurityOrigin* securityOrigin) const |
324 { | 315 { |
325 String ignoredErrorDescription; | 316 String ignoredErrorDescription; |
326 return passesAccessControlCheck(securityOrigin, ignoredErrorDescription); | 317 return passesAccessControlCheck(securityOrigin, ignoredErrorDescription); |
327 } | 318 } |
328 | 319 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 } | 424 } |
434 | 425 |
435 bool Resource::unlock() | 426 bool Resource::unlock() |
436 { | 427 { |
437 if (!m_data) | 428 if (!m_data) |
438 return false; | 429 return false; |
439 | 430 |
440 if (!m_data->isLocked()) | 431 if (!m_data->isLocked()) |
441 return true; | 432 return true; |
442 | 433 |
443 if (!memoryCache()->contains(this) || hasClients() || m_handleCount > 1 || !
m_revalidatingRequest.isNull() || !m_loadFinishTime || !isSafeToUnlock()) | 434 if (!memoryCache()->contains(this) || hasClients() || m_handleCount > 1 || m
_proxyResource || m_resourceToRevalidate || !m_loadFinishTime || !isSafeToUnlock
()) |
444 return false; | 435 return false; |
445 | 436 |
446 m_data->unlock(); | 437 m_data->unlock(); |
447 return true; | 438 return true; |
448 } | 439 } |
449 | 440 |
450 bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const | 441 bool Resource::hasRightHandleCountApartFromCache(unsigned targetCount) const |
451 { | 442 { |
452 return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0
); | 443 return m_handleCount == targetCount + (memoryCache()->contains(this) ? 1 : 0
); |
453 } | 444 } |
454 | 445 |
455 void Resource::responseReceived(const ResourceResponse& response, PassOwnPtr<Web
DataConsumerHandle>) | 446 void Resource::responseReceived(const ResourceResponse& response, PassOwnPtr<Web
DataConsumerHandle>) |
456 { | 447 { |
| 448 setResponse(response); |
457 m_responseTimestamp = currentTime(); | 449 m_responseTimestamp = currentTime(); |
458 | |
459 if (!m_revalidatingRequest.isNull()) { | |
460 if (response.httpStatusCode() == 304) { | |
461 revalidationSucceeded(response); | |
462 return; | |
463 } | |
464 revalidationFailed(); | |
465 } | |
466 | |
467 setResponse(response); | |
468 String encoding = response.textEncodingName(); | 450 String encoding = response.textEncodingName(); |
469 if (!encoding.isNull()) | 451 if (!encoding.isNull()) |
470 setEncoding(encoding); | 452 setEncoding(encoding); |
| 453 |
| 454 if (!m_resourceToRevalidate) |
| 455 return; |
| 456 if (response.httpStatusCode() == 304) |
| 457 revalidationSucceeded(response); |
| 458 else |
| 459 revalidationFailed(); |
471 } | 460 } |
472 | 461 |
473 void Resource::setSerializedCachedMetadata(const char* data, size_t size) | 462 void Resource::setSerializedCachedMetadata(const char* data, size_t size) |
474 { | 463 { |
475 // We only expect to receive cached metadata from the platform once. | 464 // We only expect to receive cached metadata from the platform once. |
476 // If this triggers, it indicates an efficiency problem which is most | 465 // If this triggers, it indicates an efficiency problem which is most |
477 // likely unexpected in code designed to improve performance. | 466 // likely unexpected in code designed to improve performance. |
478 ASSERT(!m_cachedMetadata); | 467 ASSERT(!m_cachedMetadata); |
479 ASSERT(m_revalidatingRequest.isNull()); | 468 ASSERT(!m_resourceToRevalidate); |
480 | 469 |
481 m_cachedMetadata = CachedMetadata::deserialize(data, size); | 470 m_cachedMetadata = CachedMetadata::deserialize(data, size); |
482 } | 471 } |
483 | 472 |
484 CachedMetadataHandler* Resource::cacheHandler() | 473 CachedMetadataHandler* Resource::cacheHandler() |
485 { | 474 { |
486 return m_cacheHandler.get(); | 475 return m_cacheHandler.get(); |
487 } | 476 } |
488 | 477 |
489 void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t s
ize, CachedMetadataHandler::CacheType cacheType) | 478 void Resource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t s
ize, CachedMetadataHandler::CacheType cacheType) |
(...skipping 20 matching lines...) Expand all Loading... |
510 { | 499 { |
511 m_cachedMetadata.clear(); | 500 m_cachedMetadata.clear(); |
512 | 501 |
513 if (cacheType == CachedMetadataHandler::SendToPlatform) | 502 if (cacheType == CachedMetadataHandler::SendToPlatform) |
514 Platform::current()->cacheMetadata(m_response.url(), m_response.response
Time(), 0, 0); | 503 Platform::current()->cacheMetadata(m_response.url(), m_response.response
Time(), 0, 0); |
515 } | 504 } |
516 | 505 |
517 bool Resource::canDelete() const | 506 bool Resource::canDelete() const |
518 { | 507 { |
519 return !hasClients() && !m_loader && !m_preloadCount && hasRightHandleCountA
partFromCache(0) | 508 return !hasClients() && !m_loader && !m_preloadCount && hasRightHandleCountA
partFromCache(0) |
520 && !m_protectorCount; | 509 && !m_protectorCount && !m_resourceToRevalidate && !m_proxyResource; |
521 } | 510 } |
522 | 511 |
523 bool Resource::hasOneHandle() const | 512 bool Resource::hasOneHandle() const |
524 { | 513 { |
525 return hasRightHandleCountApartFromCache(1); | 514 return hasRightHandleCountApartFromCache(1); |
526 } | 515 } |
527 | 516 |
528 CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const | 517 CachedMetadata* Resource::cachedMetadata(unsigned dataTypeID) const |
529 { | 518 { |
530 if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID) | 519 if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID) |
531 return nullptr; | 520 return nullptr; |
532 return m_cachedMetadata.get(); | 521 return m_cachedMetadata.get(); |
533 } | 522 } |
534 | 523 |
535 void Resource::clearLoader() | 524 void Resource::clearLoader() |
536 { | 525 { |
537 m_loader = nullptr; | 526 m_loader = nullptr; |
538 } | 527 } |
539 | 528 |
| 529 void Resource::addClient(ResourceClient* client) |
| 530 { |
| 531 if (addClientToSet(client)) |
| 532 didAddClient(client); |
| 533 } |
| 534 |
540 void Resource::didAddClient(ResourceClient* c) | 535 void Resource::didAddClient(ResourceClient* c) |
541 { | 536 { |
542 if (!isLoading() && !stillNeedsLoad()) { | 537 if (!isLoading() && !stillNeedsLoad()) |
543 c->notifyFinished(this); | 538 c->notifyFinished(this); |
544 if (m_clients.contains(c)) { | |
545 m_finishedClients.add(c); | |
546 m_clients.remove(c); | |
547 } | |
548 } | |
549 } | 539 } |
550 | 540 |
551 static bool shouldSendCachedDataSynchronouslyForType(Resource::Type type) | 541 static bool shouldSendCachedDataSynchronouslyForType(Resource::Type type) |
552 { | 542 { |
553 // Some resources types default to return data synchronously. | 543 // Some resources types default to return data synchronously. |
554 // For most of these, it's because there are layout tests that | 544 // For most of these, it's because there are layout tests that |
555 // expect data to return synchronously in case of cache hit. In | 545 // expect data to return synchronously in case of cache hit. In |
556 // the case of fonts, there was a performance regression. | 546 // the case of fonts, there was a performance regression. |
557 // FIXME: Get to the point where we don't need to special-case sync/async | 547 // FIXME: Get to the point where we don't need to special-case sync/async |
558 // behavior for different resource types. | 548 // behavior for different resource types. |
559 if (type == Resource::Image) | 549 if (type == Resource::Image) |
560 return true; | 550 return true; |
561 if (type == Resource::CSSStyleSheet) | 551 if (type == Resource::CSSStyleSheet) |
562 return true; | 552 return true; |
563 if (type == Resource::Script) | 553 if (type == Resource::Script) |
564 return true; | 554 return true; |
565 if (type == Resource::Font) | 555 if (type == Resource::Font) |
566 return true; | 556 return true; |
567 return false; | 557 return false; |
568 } | 558 } |
569 | 559 |
570 void Resource::addClient(ResourceClient* client) | 560 bool Resource::addClientToSet(ResourceClient* client) |
571 { | 561 { |
572 ASSERT(!isPurgeable()); | 562 ASSERT(!isPurgeable()); |
573 | 563 |
574 if (m_preloadResult == PreloadNotReferenced) { | 564 if (m_preloadResult == PreloadNotReferenced) { |
575 if (isLoaded()) | 565 if (isLoaded()) |
576 m_preloadResult = PreloadReferencedWhileComplete; | 566 m_preloadResult = PreloadReferencedWhileComplete; |
577 else if (m_requestedFromNetworkingLayer) | 567 else if (m_requestedFromNetworkingLayer) |
578 m_preloadResult = PreloadReferencedWhileLoading; | 568 m_preloadResult = PreloadReferencedWhileLoading; |
579 else | 569 else |
580 m_preloadResult = PreloadReferenced; | 570 m_preloadResult = PreloadReferenced; |
581 } | 571 } |
582 if (!hasClients()) | 572 if (!hasClients()) |
583 memoryCache()->makeLive(this); | 573 memoryCache()->makeLive(this); |
584 | 574 |
585 if (!m_revalidatingRequest.isNull()) { | |
586 m_clients.add(client); | |
587 return; | |
588 } | |
589 | |
590 // If we have existing data to send to the new client and the resource type
supprts it, send it asynchronously. | 575 // If we have existing data to send to the new client and the resource type
supprts it, send it asynchronously. |
591 if (!m_response.isNull() && !shouldSendCachedDataSynchronouslyForType(type()
) && !m_needsSynchronousCacheHit) { | 576 if (!m_response.isNull() && !m_proxyResource && !shouldSendCachedDataSynchro
nouslyForType(type()) && !m_needsSynchronousCacheHit) { |
592 m_clientsAwaitingCallback.add(client); | 577 m_clientsAwaitingCallback.add(client); |
593 ResourceCallback::callbackHandler()->schedule(this); | 578 ResourceCallback::callbackHandler()->schedule(this); |
594 return; | 579 return false; |
595 } | 580 } |
596 | 581 |
597 m_clients.add(client); | 582 m_clients.add(client); |
598 didAddClient(client); | 583 return true; |
599 return; | |
600 } | 584 } |
601 | 585 |
602 void Resource::removeClient(ResourceClient* client) | 586 void Resource::removeClient(ResourceClient* client) |
603 { | 587 { |
604 ASSERT(hasClient(client)); | 588 if (m_clientsAwaitingCallback.contains(client)) { |
605 if (m_finishedClients.contains(client)) | 589 ASSERT(!m_clients.contains(client)); |
606 m_finishedClients.remove(client); | |
607 else if (m_clientsAwaitingCallback.contains(client)) | |
608 m_clientsAwaitingCallback.remove(client); | 590 m_clientsAwaitingCallback.remove(client); |
609 else | 591 } else { |
| 592 ASSERT(m_clients.contains(client)); |
610 m_clients.remove(client); | 593 m_clients.remove(client); |
611 | 594 didRemoveClient(client); |
612 didRemoveClient(client); | 595 } |
613 | 596 |
614 if (m_clientsAwaitingCallback.isEmpty()) | 597 if (m_clientsAwaitingCallback.isEmpty()) |
615 ResourceCallback::callbackHandler()->cancel(this); | 598 ResourceCallback::callbackHandler()->cancel(this); |
616 | 599 |
617 bool deleted = deleteIfPossible(); | 600 bool deleted = deleteIfPossible(); |
618 if (!deleted && !hasClients()) { | 601 if (!deleted && !hasClients()) { |
619 memoryCache()->makeDead(this); | 602 memoryCache()->makeDead(this); |
620 if (!m_switchingClientsToRevalidatedResource) | 603 if (!m_switchingClientsToRevalidatedResource) |
621 allClientsRemoved(); | 604 allClientsRemoved(); |
622 | 605 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 // Prevent the case when there are clients waiting but no callback scheduled
. | 710 // Prevent the case when there are clients waiting but no callback scheduled
. |
728 ASSERT(m_clientsAwaitingCallback.isEmpty() || scheduled); | 711 ASSERT(m_clientsAwaitingCallback.isEmpty() || scheduled); |
729 } | 712 } |
730 | 713 |
731 void Resource::prune() | 714 void Resource::prune() |
732 { | 715 { |
733 destroyDecodedDataIfPossible(); | 716 destroyDecodedDataIfPossible(); |
734 unlock(); | 717 unlock(); |
735 } | 718 } |
736 | 719 |
| 720 void Resource::setResourceToRevalidate(Resource* resource) |
| 721 { |
| 722 ASSERT(resource); |
| 723 ASSERT(!m_resourceToRevalidate); |
| 724 ASSERT(resource != this); |
| 725 ASSERT(m_handlesToRevalidate.isEmpty()); |
| 726 ASSERT(resource->type() == type()); |
737 | 727 |
738 void Resource::revalidationSucceeded(const ResourceResponse& validatingResponse) | 728 WTF_LOG(ResourceLoading, "Resource %p setResourceToRevalidate %p", this, res
ource); |
| 729 |
| 730 // The following assert should be investigated whenever it occurs. Although
it should never fire, it currently does in rare circumstances. |
| 731 // https://bugs.webkit.org/show_bug.cgi?id=28604. |
| 732 // So the code needs to be robust to this assert failing thus the "if (m_res
ourceToRevalidate->m_proxyResource == this)" in Resource::clearResourceToRevalid
ate. |
| 733 ASSERT(!resource->m_proxyResource); |
| 734 |
| 735 resource->m_proxyResource = this; |
| 736 m_resourceToRevalidate = resource; |
| 737 } |
| 738 |
| 739 void Resource::clearResourceToRevalidate() |
| 740 { |
| 741 ASSERT(m_resourceToRevalidate); |
| 742 if (m_switchingClientsToRevalidatedResource) |
| 743 return; |
| 744 |
| 745 // 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. |
| 746 if (m_resourceToRevalidate->m_proxyResource == this) { |
| 747 m_resourceToRevalidate->m_proxyResource = nullptr; |
| 748 m_resourceToRevalidate->deleteIfPossible(); |
| 749 } |
| 750 m_handlesToRevalidate.clear(); |
| 751 m_resourceToRevalidate = nullptr; |
| 752 deleteIfPossible(); |
| 753 } |
| 754 |
| 755 void Resource::switchClientsToRevalidatedResource() |
| 756 { |
| 757 ASSERT(m_resourceToRevalidate); |
| 758 ASSERT(memoryCache()->contains(m_resourceToRevalidate)); |
| 759 ASSERT(!memoryCache()->contains(this)); |
| 760 |
| 761 WTF_LOG(ResourceLoading, "Resource %p switchClientsToRevalidatedResource %p"
, this, m_resourceToRevalidate.get()); |
| 762 |
| 763 m_resourceToRevalidate->m_identifier = m_identifier; |
| 764 |
| 765 m_switchingClientsToRevalidatedResource = true; |
| 766 for (ResourcePtrBase* handle : m_handlesToRevalidate) { |
| 767 handle->m_resource = m_resourceToRevalidate; |
| 768 m_resourceToRevalidate->registerHandle(handle); |
| 769 --m_handleCount; |
| 770 } |
| 771 ASSERT(!m_handleCount); |
| 772 m_handlesToRevalidate.clear(); |
| 773 |
| 774 Vector<ResourceClient*> clientsToMove; |
| 775 for (const auto& clientHashEntry : m_clients) { |
| 776 unsigned count = clientHashEntry.value; |
| 777 while (count--) |
| 778 clientsToMove.append(clientHashEntry.key); |
| 779 } |
| 780 |
| 781 unsigned moveCount = clientsToMove.size(); |
| 782 for (unsigned n = 0; n < moveCount; ++n) |
| 783 removeClient(clientsToMove[n]); |
| 784 ASSERT(m_clients.isEmpty()); |
| 785 |
| 786 for (unsigned n = 0; n < moveCount; ++n) |
| 787 m_resourceToRevalidate->addClientToSet(clientsToMove[n]); |
| 788 for (unsigned n = 0; n < moveCount; ++n) { |
| 789 // Calling didAddClient may do anything, including trying to cancel reva
lidation. |
| 790 // Assert that it didn't succeed. |
| 791 ASSERT(m_resourceToRevalidate); |
| 792 // Calling didAddClient for a client may end up removing another client.
In that case it won't be in the set anymore. |
| 793 if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n])) |
| 794 m_resourceToRevalidate->didAddClient(clientsToMove[n]); |
| 795 } |
| 796 m_switchingClientsToRevalidatedResource = false; |
| 797 } |
| 798 |
| 799 void Resource::updateResponseAfterRevalidation(const ResourceResponse& validatin
gResponse) |
739 { | 800 { |
740 m_responseTimestamp = currentTime(); | 801 m_responseTimestamp = currentTime(); |
741 m_response.setResourceLoadTiming(validatingResponse.resourceLoadTiming()); | |
742 | 802 |
743 // RFC2616 10.3.5 | 803 // RFC2616 10.3.5 |
744 // Update cached headers from the 304 response | 804 // Update cached headers from the 304 response |
745 const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields(); | 805 const HTTPHeaderMap& newHeaders = validatingResponse.httpHeaderFields(); |
746 for (const auto& header : newHeaders) { | 806 for (const auto& header : newHeaders) { |
747 // Entity headers should not be sent by servers when generating a 304 | 807 // Entity headers should not be sent by servers when generating a 304 |
748 // response; misconfigured servers send them anyway. We shouldn't allow | 808 // response; misconfigured servers send them anyway. We shouldn't allow |
749 // such headers to update the original request. We'll base this on the | 809 // such headers to update the original request. We'll base this on the |
750 // list defined by RFC2616 7.1, with a few additions for extension heade
rs | 810 // list defined by RFC2616 7.1, with a few additions for extension heade
rs |
751 // we care about. | 811 // we care about. |
752 if (!shouldUpdateHeaderAfterRevalidation(header.key)) | 812 if (!shouldUpdateHeaderAfterRevalidation(header.key)) |
753 continue; | 813 continue; |
754 m_response.setHTTPHeaderField(header.key, header.value); | 814 m_response.setHTTPHeaderField(header.key, header.value); |
755 } | 815 } |
| 816 } |
756 | 817 |
| 818 void Resource::revalidationSucceeded(const ResourceResponse& response) |
| 819 { |
| 820 ASSERT(m_resourceToRevalidate); |
| 821 ASSERT(!memoryCache()->contains(m_resourceToRevalidate)); |
| 822 ASSERT(m_resourceToRevalidate->isLoaded()); |
| 823 |
| 824 // Calling evict() can potentially delete revalidatingResource, which we use |
| 825 // below. This mustn't be the case since revalidation means it is loaded |
| 826 // and so canDelete() is false. |
| 827 ASSERT(!canDelete()); |
| 828 |
| 829 m_resourceToRevalidate->updateResponseAfterRevalidation(response); |
| 830 memoryCache()->replace(m_resourceToRevalidate, this); |
| 831 |
| 832 switchClientsToRevalidatedResource(); |
757 assertAlive(); | 833 assertAlive(); |
758 m_resourceRequest = m_revalidatingRequest; | 834 // clearResourceToRevalidate deletes this. |
759 m_revalidatingRequest = ResourceRequest(); | 835 clearResourceToRevalidate(); |
760 } | 836 } |
761 | 837 |
762 void Resource::revalidationFailed() | 838 void Resource::revalidationFailed() |
763 { | 839 { |
764 m_resourceRequest = m_revalidatingRequest; | 840 ASSERT(WTF::isMainThread()); |
765 m_revalidatingRequest = ResourceRequest(); | 841 WTF_LOG(ResourceLoading, "Revalidation failed for %p", this); |
766 m_data.clear(); | 842 ASSERT(resourceToRevalidate()); |
767 destroyDecodedDataForFailedRevalidation(); | 843 clearResourceToRevalidate(); |
768 } | 844 } |
769 | 845 |
770 void Resource::registerHandle(ResourcePtrBase* h) | 846 void Resource::registerHandle(ResourcePtrBase* h) |
771 { | 847 { |
772 assertAlive(); | 848 assertAlive(); |
773 ++m_handleCount; | 849 ++m_handleCount; |
| 850 if (m_resourceToRevalidate) |
| 851 m_handlesToRevalidate.add(h); |
774 } | 852 } |
775 | 853 |
776 void Resource::unregisterHandle(ResourcePtrBase* h) | 854 void Resource::unregisterHandle(ResourcePtrBase* h) |
777 { | 855 { |
778 assertAlive(); | 856 assertAlive(); |
779 ASSERT(m_handleCount > 0); | 857 ASSERT(m_handleCount > 0); |
780 --m_handleCount; | 858 --m_handleCount; |
781 | 859 |
| 860 if (m_resourceToRevalidate) |
| 861 m_handlesToRevalidate.remove(h); |
| 862 |
782 if (!m_handleCount) { | 863 if (!m_handleCount) { |
783 if (deleteIfPossible()) | 864 if (deleteIfPossible()) |
784 return; | 865 return; |
785 unlock(); | 866 unlock(); |
786 } else if (m_handleCount == 1 && memoryCache()->contains(this)) { | 867 } else if (m_handleCount == 1 && memoryCache()->contains(this)) { |
787 unlock(); | 868 unlock(); |
788 if (!hasClients()) | 869 if (!hasClients()) |
789 memoryCache()->prune(this); | 870 memoryCache()->prune(this); |
790 } | 871 } |
791 } | 872 } |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 return "ImportResource"; | 1108 return "ImportResource"; |
1028 case Resource::Media: | 1109 case Resource::Media: |
1029 return "Media"; | 1110 return "Media"; |
1030 } | 1111 } |
1031 ASSERT_NOT_REACHED(); | 1112 ASSERT_NOT_REACHED(); |
1032 return "Unknown"; | 1113 return "Unknown"; |
1033 } | 1114 } |
1034 #endif // !LOG_DISABLED | 1115 #endif // !LOG_DISABLED |
1035 | 1116 |
1036 } // namespace blink | 1117 } // namespace blink |
OLD | NEW |