489
490static inline ResourceRequest constructRevalidationRequest(const Key& key, const ResourceRequest& request, const Entry* entry)
491{
492 ResourceRequest revalidationRequest = request;
493 if (!key.partition().isEmpty())
494 revalidationRequest.setCachePartition(key.partition());
495 ASSERT_WITH_MESSAGE(key.range().isEmpty(), "range is not supported");
496
497 revalidationRequest.makeUnconditional();
498 if (entry) {
499 String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
500 if (!eTag.isEmpty())
501 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
502
503 String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
504 if (!lastModified.isEmpty())
505 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
506 }
507
508 revalidationRequest.setPriority(WebCore::ResourceLoadPriority::Low);
509
510 return revalidationRequest;
511}
512
513class AsyncRevalidation {
514 WTF_MAKE_FAST_ALLOCATED;
515public:
516 typedef Function<void (bool)> AsyncRevalidationCompletionHandler;
517 AsyncRevalidation(Cache& cache, const GlobalFrameID& frameID, const ResourceRequest& request, std::unique_ptr<NetworkCache::Entry> entry, AsyncRevalidationCompletionHandler&& handler)
518 : m_timer(*this, &AsyncRevalidation::staleWhileRevalidateEnding)
519 , m_completionHandler(WTFMove(handler))
520 {
521 auto key = entry->key();
522 auto revalidationRequest = constructRevalidationRequest(key, request, entry.get());
523 auto age = WebCore::computeCurrentAge(entry->response(), entry->timeStamp());
524 auto lifetime = WebCore::computeFreshnessLifetimeForHTTPFamily(entry->response(), entry->timeStamp());
525 auto responseMaxStaleness = entry->response().cacheControlStaleWhileRevalidate();
526 ASSERT(responseMaxStaleness);
527 m_timer.startOneShot(*responseMaxStaleness - (age - lifetime));
528 m_load = makeUnique<SpeculativeLoad>(cache, frameID, revalidationRequest, WTFMove(entry), [this, key, revalidationRequest](std::unique_ptr<Entry> revalidatedEntry) {
529 ASSERT(!revalidatedEntry || !revalidatedEntry->needsValidation());
530 ASSERT(!revalidatedEntry || revalidatedEntry->key() == key);
531 m_completionHandler(revalidatedEntry.get());
532 });
533 }
534
535 const SpeculativeLoad& load() const { return *m_load; }
536
537 void staleWhileRevalidateEnding() { m_completionHandler(true); }
538
539private:
540 std::unique_ptr<SpeculativeLoad> m_load;
541 Timer m_timer;
542 AsyncRevalidationCompletionHandler m_completionHandler;
543};
544
545void SpeculativeLoadManager::startAsyncRevalidationIfNeeded(const ResourceRequest& request, const NetworkCache::Key& key, std::unique_ptr<Entry> entry, const GlobalFrameID& frameID)
546{
547 auto* pendingAsyncRevalidation = m_pendingAsyncRevalidations.get(key);
548 if (pendingAsyncRevalidation && canUsePendingPreload(pendingAsyncRevalidation->load(), request))
549 return;
550
551 auto revalidator = makeUnique<AsyncRevalidation>(m_cache, frameID, request, WTFMove(entry), [this, key](bool ending) {
552 if (ending) {
553 m_pendingAsyncRevalidations.take(key);
554 LOG(NetworkCache, "(NetworkProcess) Async revalidation completed for '%s':", key.identifier().utf8().data());
555 }
556 });
557 m_pendingAsyncRevalidations.add(key, WTFMove(revalidator));
558}
559