TEST(ImageResourceTest, DecodedDataRemainsWhileHasClients) { ResourcePtr<ImageResource> cachedImage = new ImageResource(ResourceRequest(), nullptr); cachedImage->setLoading(true); MockImageResourceClient client(cachedImage); // Send the image response. cachedImage->responseReceived(ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()), nullptr); Vector<unsigned char> jpeg = jpegImage(); cachedImage->responseReceived(ResourceResponse(KURL(), "image/jpeg", jpeg.size(), nullAtom, String()), nullptr); cachedImage->appendData(reinterpret_cast<const char*>(jpeg.data()), jpeg.size()); cachedImage->finish(); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->image()->isNull()); ASSERT_TRUE(client.notifyFinishedCalled()); // The prune comes when the ImageResource still has clients. The image should not be deleted. cachedImage->prune(); ASSERT_TRUE(cachedImage->hasClients()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->image()->isNull()); // The ImageResource no longer has clients. The image should be deleted by prune. client.removeAsClient(); cachedImage->prune(); ASSERT_FALSE(cachedImage->hasClients()); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_TRUE(cachedImage->image()->isNull()); }
TEST(RawResourceTest, RevalidationSucceededForResourceWithoutBody) { ResourcePtr<Resource> resource = new RawResource(ResourceRequest("data:text/html,"), Resource::Raw); ResourceResponse response; response.setHTTPStatusCode(200); resource->responseReceived(response, nullptr); resource->finish(); memoryCache()->add(resource.get()); // Simulate a successful revalidation. resource->setRevalidatingRequest(ResourceRequest("data:text/html,")); OwnPtr<DummyClient> client = adoptPtr(new DummyClient); resource->addClient(client.get()); ResourceResponse revalidatingResponse; revalidatingResponse.setHTTPStatusCode(304); resource->responseReceived(revalidatingResponse, nullptr); EXPECT_FALSE(resource->isCacheValidator()); EXPECT_EQ(200, resource->response().httpStatusCode()); EXPECT_EQ(nullptr, resource->resourceBuffer()); EXPECT_EQ(memoryCache()->resourceForURL(KURL(ParsedURLString, "data:text/html,")), resource.get()); memoryCache()->remove(resource.get()); resource->removeClient(client.get()); EXPECT_FALSE(resource->hasClients()); EXPECT_FALSE(client->called()); EXPECT_EQ(0u, client->data().size()); }
void MemoryCache::dumpLRULists(bool includeLive) const { printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n"); int size = m_allResources.size(); for (int i = size - 1; i >= 0; i--) { printf("\n\nList %d: ", i); MemoryCacheEntry* current = m_allResources[i].m_tail; while (current) { ResourcePtr<Resource> currentResource = current->m_resource; if (includeLive || !currentResource->hasClients()) printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", currentResource->decodedSize() / 1024.0f, (currentResource->encodedSize() + currentResource->overheadSize()) / 1024.0f, current->m_accessCount, currentResource->hasClients(), currentResource->isPurgeable(), currentResource->wasPurged()); current = current->m_previousInAllResourcesList; } } }
TEST(RawResourceTest, RemoveClientDuringCallback) { ResourcePtr<Resource> raw = new RawResource(ResourceRequest("data:text/html,"), Resource::Raw); raw->setLoading(false); // Create a non-null response. ResourceResponse response = raw->response(); response.setURL(KURL(ParsedURLString, "http://600.613/")); raw->setResponse(response); EXPECT_FALSE(raw->response().isNull()); OwnPtr<DummyClient> dummyClient = adoptPtr(new DummyClient()); OwnPtr<RemovingClient> removingClient = adoptPtr(new RemovingClient(dummyClient.get())); raw->addClient(dummyClient.get()); raw->addClient(removingClient.get()); testing::runPendingTasks(); EXPECT_FALSE(raw->hasClients()); }
ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request) { ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw); TRACE_EVENT0("blink", "ResourceFetcher::requestResource"); KURL url = request.resourceRequest().url(); WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), ResourceTypeName(type)); // If only the fragment identifiers differ, it is the same resource. url = MemoryCache::removeFragmentIdentifierIfNeeded(url); if (!url.isValid()) return 0; if (!canRequest(type, url, request.options(), request.originRestriction())) return 0; if (LocalFrame* f = frame()) f->loaderClient()->dispatchWillRequestResource(&request); // See if we can use an existing resource from the cache. ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url); const RevalidationPolicy policy = determineRevalidationPolicy(type, request, resource.get()); switch (policy) { case Reload: memoryCache()->remove(resource.get()); // Fall through case Load: resource = createResourceForLoading(type, request, request.charset()); break; case Revalidate: resource = createResourceForRevalidation(request, resource.get()); break; case Use: memoryCache()->updateForAccess(resource.get()); break; } if (!resource) return 0; if (!resource->hasClients()) m_deadStatsRecorder.update(policy); if (policy != Use) resource->setIdentifier(createUniqueIdentifier()); ResourceLoadPriority priority = loadPriority(type, request); if (priority != resource->resourceRequest().priority()) { resource->mutableResourceRequest().setPriority(priority); resource->didChangePriority(priority, 0); } if (resourceNeedsLoad(resource.get(), request, policy)) { if (!shouldLoadNewResource(type)) { if (memoryCache()->contains(resource.get())) memoryCache()->remove(resource.get()); return 0; } resource->load(this, request.options()); // For asynchronous loads that immediately fail, it's sufficient to return a // null Resource, as it indicates that something prevented the load from starting. // If there's a network error, that failure will happen asynchronously. However, if // a sync load receives a network error, it will have already happened by this point. // In that case, the requester should have access to the relevant ResourceError, so // we need to return a non-null Resource. if (resource->errorOccurred()) { if (memoryCache()->contains(resource.get())) memoryCache()->remove(resource.get()); return 0; } } requestLoadStarted(resource.get(), request, policy == Use ? ResourceLoadingFromCache : ResourceLoadingFromNetwork); ASSERT(resource->url() == url.string()); m_documentResources.set(resource->url(), resource); return resource; }