InspectorResource::Type InspectorResource::cachedResourceType() const { CachedResource* cachedResource = this->cachedResource(); if (!cachedResource) return Other; switch (cachedResource->type()) { case CachedResource::ImageResource: return Image; case CachedResource::FontResource: return Font; case CachedResource::CSSStyleSheet: #if ENABLE(XSLT) case CachedResource::XSLStyleSheet: #endif return Stylesheet; case CachedResource::Script: return Script; default: return Other; } }
void CachedResourceLoader::setBlockNetworkImage(bool block) { if (block == m_blockNetworkImage) return; m_blockNetworkImage = block; if (!m_autoLoadImages || m_blockNetworkImage) return; DocumentResourceMap::iterator end = m_documentResources.end(); for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) { CachedResource* resource = it->second.get(); if (resource->type() == CachedResource::ImageResource) { CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource)); image->setAutoLoadWasPreventedBySettings(false); if (image->stillNeedsLoad()) { image->setLoading(true); load(image, true); } } } }
CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request) { ASSERT(WTF::isMainThread()); KURL url = removeFragmentIdentifierIfNeeded(request.url()); #if ENABLE(CACHE_PARTITIONING) CachedResourceItem* item = m_resources.get(url); CachedResource* resource = 0; if (item) resource = item->get(request.cachePartition()); #else CachedResource* resource = m_resources.get(url); #endif bool wasPurgeable = MemoryCache::shouldMakeResourcePurgeableOnEviction() && resource && resource->isPurgeable(); if (resource && !resource->makePurgeable(false)) { ASSERT(!resource->hasClients()); evict(resource); return 0; } // Add the size back since we had subtracted it when we marked the memory as purgeable. if (wasPurgeable) adjustSize(resource->hasClients(), resource->size()); return resource; }
void InspectorPageAgent::searchInResources(ErrorString*, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<InspectorArray>* object) { RefPtr<InspectorArray> result = InspectorArray::create(); bool isRegex = optionalIsRegex ? *optionalIsRegex : false; String regexSource = isRegex ? text : createSearchRegexSource(text); bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false; RegularExpression regex(regexSource, caseSensitive ? TextCaseSensitive : TextCaseInsensitive); for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext(m_page->mainFrame())) { String content; Vector<CachedResource*> allResources = cachedResourcesForFrame(frame); for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) { CachedResource* cachedResource = *it; switch (InspectorPageAgent::cachedResourceType(*cachedResource)) { case InspectorPageAgent::StylesheetResource: case InspectorPageAgent::ScriptResource: if (decodeCachedResource(cachedResource, &content)) { int matchesCount = countRegularExpressionMatches(regex, content); if (matchesCount) result->pushValue(buildObjectForSearchMatch(frameId(frame), cachedResource->url(), matchesCount)); } break; default: break; } } if (decodeMainResource(frame, &content)) { int matchesCount = countRegularExpressionMatches(regex, content); if (matchesCount) result->pushValue(buildObjectForSearchMatch(frameId(frame), frame->document()->url(), matchesCount)); } } *object = result; }
void DocLoader::setAutoLoadImages(bool enable) { if (enable == m_autoLoadImages) return; m_autoLoadImages = enable; if (!m_autoLoadImages) return; HashMap<String, CachedResource*>::iterator end = m_docResources.end(); for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it) { CachedResource* resource = it->second; if (resource->type() == CachedResource::ImageResource) { CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage *>(resource)); CachedResource::Status status = image->status(); if (status != CachedResource::Unknown) continue; cache()->loader()->load(this, image, true); } } }
void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response) { String requestId = IdentifiersFactory::requestId(identifier); RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader); InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource; long cachedResourceSize = 0; if (loader) { CachedResource* cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url()); if (cachedResource) { type = InspectorPageAgent::cachedResourceType(*cachedResource); cachedResourceSize = cachedResource->encodedSize(); // Use mime type from cached resource in case the one in response is empty. if (resourceResponse && response.mimeType().isEmpty()) resourceResponse->setString(TypeBuilder::Network::Response::MimeType, cachedResource->response().mimeType()); m_resourcesData->addCachedResource(requestId, cachedResource); } if (m_loadingXHRSynchronously || m_resourcesData->resourceType(requestId) == InspectorPageAgent::XHRResource) type = InspectorPageAgent::XHRResource; else if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::ScriptResource) type = InspectorPageAgent::ScriptResource; else if (equalIgnoringFragmentIdentifier(response.url(), loader->frameLoader()->icon()->url())) type = InspectorPageAgent::ImageResource; else if (equalIgnoringFragmentIdentifier(response.url(), loader->url()) && !loader->isCommitted()) type = InspectorPageAgent::DocumentResource; m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response); } m_resourcesData->setResourceType(requestId, type); m_frontend->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse); // If we revalidated the resource and got Not modified, send content length following didReceiveResponse // as there will be no calls to didReceiveData from the network stack. if (cachedResourceSize && response.httpStatusCode() == 304) didReceiveData(identifier, 0, cachedResourceSize, 0); }
HRESULT WebDataSource::subresourceForURL(_In_ BSTR url, _COM_Outptr_opt_ IWebResource** resource) { if (!resource) { ASSERT_NOT_REACHED(); return E_POINTER; } *resource = nullptr; if (!m_loader) return E_UNEXPECTED; Document* doc = m_loader->frameLoader()->frame().document(); if (!doc) return E_FAIL; CachedResource* cachedResource = doc->cachedResourceLoader().cachedResource(String(url)); if (!cachedResource) return E_FAIL; *resource = WebResource::createInstance(cachedResource->resourceBuffer(), cachedResource->response()); return S_OK; }
CachedResource* CachedResourceLoader::revalidateResource(CachedResource* resource, ResourceLoadPriority priority) { ASSERT(resource); ASSERT(resource->inCache()); ASSERT(!memoryCache()->disabled()); ASSERT(resource->canUseCacheValidator()); ASSERT(!resource->resourceToRevalidate()); // Copy the URL out of the resource to be revalidated in case it gets deleted by the remove() call below. String url = resource->url(); CachedResource* newResource = createResource(resource->type(), resource->resourceRequest(), resource->encoding()); LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource, resource); newResource->setResourceToRevalidate(resource); memoryCache()->remove(resource); memoryCache()->add(newResource); newResource->setLoadPriority(priority); newResource->load(this); m_validatedURLs.add(url); return newResource; }
void MemoryCache::revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse& response) { ASSERT(revalidatingResource.resourceToRevalidate()); CachedResource& resource = *revalidatingResource.resourceToRevalidate(); ASSERT(!resource.inCache()); ASSERT(resource.isLoaded()); // Calling remove() can potentially delete revalidatingResource, which we use // below. This mustn't be the case since revalidation means it is loaded // and so canDelete() is false. ASSERT(!revalidatingResource.canDelete()); remove(revalidatingResource); auto& resources = ensureSessionResourceMap(resource.sessionID()); #if ENABLE(CACHE_PARTITIONING) auto key = std::make_pair(resource.url(), resource.cachePartition()); #else auto& key = resource.url(); #endif ASSERT(!resources.get(key)); resources.set(key, &resource); resource.setInCache(true); resource.updateResponseAfterRevalidation(response); insertInLRUList(resource); int delta = resource.size(); if (resource.decodedSize() && resource.hasClients()) insertInLiveDecodedResourcesList(resource); if (delta) adjustSize(resource.hasClients(), delta); revalidatingResource.switchClientsToRevalidatedResource(); ASSERT(!revalidatingResource.m_deleted); // this deletes the revalidating resource revalidatingResource.clearResourceToRevalidate(); }
HRESULT STDMETHODCALLTYPE WebDataSource::subresourceForURL( /* [in] */ BSTR url, /* [retval][out] */ IWebResource** resource) { if (!resource) { ASSERT_NOT_REACHED(); return E_POINTER; } *resource = 0; Document *doc = m_loader->frameLoader()->frame()->document(); if (!doc) return E_FAIL; CachedResource *cachedResource = doc->docLoader()->cachedResource(String(url)); if (!cachedResource) return E_FAIL; *resource = WebResource::createInstance(cachedResource->data(), cachedResource->response()); return S_OK; }
PassRefPtr<SharedBuffer> InspectorPageAgent::resourceData(Frame* frame, const KURL& url, String* textEncodingName) { RefPtr<SharedBuffer> buffer; FrameLoader* frameLoader = frame->loader(); DocumentLoader* loader = frameLoader->documentLoader(); if (equalIgnoringFragmentIdentifier(url, loader->url())) { *textEncodingName = frame->document()->inputEncoding(); buffer = frameLoader->documentLoader()->mainResourceData(); if (buffer) return buffer; } CachedResource* cachedResource = InspectorPageAgent::cachedResource(frame, url); if (!cachedResource) return 0; bool hasZeroSize; bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize); if (!prepared) return 0; *textEncodingName = cachedResource->encoding(); return hasZeroSize ? SharedBuffer::create() : cachedResource->data(); }
void MemoryCache::removeFromLRUList(CachedResource& resource) { // If we've never been accessed, then we're brand new and not in any list. if (!resource.accessCount()) return; #if !ASSERT_DISABLED unsigned oldListIndex = resource.m_lruIndex; #endif LRUList& list = lruListFor(resource); // Verify that the list we got is the list we want. ASSERT(resource.m_lruIndex == oldListIndex); bool removed = list.remove(&resource); ASSERT_UNUSED(removed, removed); }
static String cachedResourceTypeString(const CachedResource& cachedResource) { switch (cachedResource.type()) { case CachedResource::ImageResource: return "Image"; case CachedResource::FontResource: return "Font"; case CachedResource::CSSStyleSheet: // Fall through. #if ENABLE(XSLT) case CachedResource::XSLStyleSheet: #endif return "Stylesheet"; case CachedResource::Script: return "Script"; default: break; } return "Other"; }
static String cachedResourceTypeString(const CachedResource& cachedResource) { switch (cachedResource.type()) { case CachedResource::ImageResource: return ResourceType::image; case CachedResource::FontResource: return ResourceType::font; case CachedResource::CSSStyleSheet: // Fall through. #if ENABLE(XSLT) case CachedResource::XSLStyleSheet: #endif return ResourceType::stylesheet; case CachedResource::Script: return ResourceType::script; default: break; } return ResourceType::other; }
InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource) { switch (cachedResource.type()) { case CachedResource::ImageResource: return InspectorPageAgent::ImageResource; case CachedResource::FontResource: return InspectorPageAgent::FontResource; case CachedResource::CSSStyleSheet: // Fall through. #if ENABLE(XSLT) case CachedResource::XSLStyleSheet: #endif return InspectorPageAgent::StylesheetResource; case CachedResource::Script: return InspectorPageAgent::ScriptResource; default: break; } return InspectorPageAgent::OtherResource; }
bool MemoryCache::add(CachedResource& resource) { if (disabled()) return false; ASSERT(WTF::isMainThread()); #if ENABLE(CACHE_PARTITIONING) auto key = std::make_pair(resource.url(), resource.cachePartition()); #else auto& key = resource.url(); #endif ensureSessionResourceMap(resource.sessionID()).set(key, &resource); resource.setInCache(true); resourceAccessed(resource); LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource.url().string().latin1().data(), &resource); return true; }
CachedResource* CachedResourceLoader::loadResource(CachedResource::Type type, ResourceRequest& request, const String& charset, ResourceLoadPriority priority, const ResourceLoaderOptions& options) { ASSERT(!memoryCache()->resourceForURL(request.url())); LOG(ResourceLoading, "Loading CachedResource for '%s'.", request.url().string().latin1().data()); CachedResource* resource = createResource(type, request, charset); bool inCache = memoryCache()->add(resource); // Pretend the resource is in the cache, to prevent it from being deleted during the load() call. // FIXME: CachedResource should just use normal refcounting instead. if (!inCache) resource->setInCache(true); resource->setLoadPriority(priority); resource->load(this, options); if (!inCache) { resource->setOwningCachedResourceLoader(this); resource->setInCache(false); } // We don't support immediate loads, but we do support immediate failure. if (resource->errorOccurred()) { if (inCache) memoryCache()->remove(resource); else delete resource; return 0; } if (!request.url().protocolIsData()) m_validatedURLs.add(request.url()); return resource; }
void Loader::Host::didFinishLoading(SubresourceLoader* loader) { RefPtr<Host> myProtector(this); RequestMap::iterator i = m_requestsLoading.find(loader); if (i == m_requestsLoading.end()) return; Request* request = i->second; m_requestsLoading.remove(i); DocLoader* docLoader = request->docLoader(); // Prevent the document from being destroyed before we are done with // the docLoader that it will delete when the document gets deleted. RefPtr<Document> protector(docLoader->doc()); if (!request->isMultipart()) docLoader->decrementRequestCount(); CachedResource* resource = request->cachedResource(); ASSERT(!resource->resourceToRevalidate()); // If we got a 4xx response, we're pretending to have received a network // error, so we can't send the successful data() and finish() callbacks. if (!resource->errorOccurred()) { docLoader->setLoadInProgress(true); resource->data(loader->resourceData(), true); resource->finish(); } delete request; docLoader->setLoadInProgress(false); docLoader->checkForPendingPreloads(); #if REQUEST_DEBUG KURL u(ParsedURLString, resource->url()); printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data()); #endif servePendingRequests(); }
void Loader::Host::didFinishLoading(SubresourceLoader* loader) { RequestMap::iterator i = m_requestsLoading.find(loader); if (i == m_requestsLoading.end()) return; m_processingResource = true; Request* request = i->second; m_requestsLoading.remove(i); DocLoader* docLoader = request->docLoader(); if (!request->isMultipart()) docLoader->decrementRequestCount(); CachedResource* resource = request->cachedResource(); ASSERT(!resource->resourceToRevalidate()); // If we got a 4xx response, we're pretending to have received a network // error, so we can't send the successful data() and finish() callbacks. if (!resource->errorOccurred()) { docLoader->setLoadInProgress(true); resource->data(loader->resourceData(), true); resource->finish(); } delete request; docLoader->setLoadInProgress(false); docLoader->checkForPendingPreloads(); #if REQUEST_DEBUG KURL u(resource->url()); printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data()); #endif servePendingRequests(); m_processingResource = false; }
PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const { if (!isCommitted()) return 0; CachedResource* resource = m_cachedResourceLoader->cachedResource(url); if (!resource || !resource->isLoaded()) return archiveResourceForURL(url); if (resource->type() == CachedResource::MainResource) return 0; // FIXME: This has the side effect of making the resource non-purgeable. // It would be better if it didn't have this permanent effect. if (!resource->makePurgeable(false)) return 0; ResourceBuffer* data = resource->resourceBuffer(); if (!data) return 0; return ArchiveResource::create(data->sharedBuffer(), url, resource->response()); }
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, Vector<Node*>& nodes) { ASSERT(frame); const ResourceResponse& response = frame->loader()->documentLoader()->response(); KURL responseURL = response.url(); // it's possible to have a response without a URL here // <rdar://problem/5454935> if (responseURL.isNull()) responseURL = KURL(""); PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name()); Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; Vector<PassRefPtr<ArchiveResource> > subresources; HashSet<KURL> uniqueSubresources; Vector<Node*>::iterator it = nodes.begin(); Vector<Node*>::iterator end = nodes.end(); for (; it != end; ++it) { Frame* childFrame; if (((*it)->hasTagName(HTMLNames::frameTag) || (*it)->hasTagName(HTMLNames::iframeTag) || (*it)->hasTagName(HTMLNames::objectTag)) && (childFrame = static_cast<HTMLFrameOwnerElement*>(*it)->contentFrame())) { RefPtr<LegacyWebArchive> subframeArchive; if (Document* document = childFrame->document()) subframeArchive = LegacyWebArchive::create(document); else subframeArchive = create(childFrame); if (subframeArchive) subframeArchives.append(subframeArchive); else LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data()); } else { ListHashSet<KURL> subresourceURLs; (*it)->getSubresourceURLs(subresourceURLs); DocumentLoader* documentLoader = frame->loader()->documentLoader(); ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end(); for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) { const KURL& subresourceURL = *iter; if (uniqueSubresources.contains(subresourceURL)) continue; uniqueSubresources.add(subresourceURL); RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL); if (resource) { subresources.append(resource.release()); continue; } CachedResource *cachedResource = cache()->resourceForURL(subresourceURL); if (cachedResource) { resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response()); if (resource) { subresources.append(resource.release()); continue; } } // FIXME: should do something better than spew to console here LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data()); } } } return create(mainResource, subresources, subframeArchives); }
void CachedResourceLoader::printPreloadStats() { unsigned scripts = 0; unsigned scriptMisses = 0; unsigned stylesheets = 0; unsigned stylesheetMisses = 0; unsigned images = 0; unsigned imageMisses = 0; ListHashSet<CachedResource*>::iterator end = m_preloads.end(); for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) { CachedResource* res = *it; if (res->preloadResult() == CachedResource::PreloadNotReferenced) printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data()); else if (res->preloadResult() == CachedResource::PreloadReferencedWhileComplete) printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data()); else if (res->preloadResult() == CachedResource::PreloadReferencedWhileLoading) printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data()); if (res->type() == CachedResource::Script) { scripts++; if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading) scriptMisses++; } else if (res->type() == CachedResource::CSSStyleSheet) { stylesheets++; if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading) stylesheetMisses++; } else { images++; if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading) imageMisses++; } if (res->errorOccurred()) memoryCache()->remove(res); res->decreasePreloadCount(); } m_preloads.clear(); if (scripts) printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts); if (stylesheets) printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets); if (images) printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images); }
void ContentFilter::deliverResourceData(CachedResource& resource) { ASSERT(resource.dataBufferingPolicy() == BufferData); if (auto* resourceBuffer = resource.resourceBuffer()) m_documentLoader.dataReceived(&resource, resourceBuffer->data(), resourceBuffer->size()); }
void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const ResourceLoaderOptions& options) { if (!cachedResourceLoader->frame()) { failBeforeStarting(); return; } FrameLoader& frameLoader = cachedResourceLoader->frame()->loader(); if (options.securityCheck() == DoSecurityCheck && (frameLoader.state() == FrameStateProvisional || !frameLoader.activeDocumentLoader() || frameLoader.activeDocumentLoader()->isStopping())) { failBeforeStarting(); return; } m_options = options; m_loading = true; #if USE(QUICK_LOOK) if (!m_resourceRequest.isNull() && m_resourceRequest.url().protocolIs(QLPreviewProtocol())) { // When QuickLook is invoked to convert a document, it returns a unique URL in the // NSURLReponse for the main document. To make safeQLURLForDocumentURLAndResourceURL() // work, we need to use the QL URL not the original URL. const URL& documentURL = cachedResourceLoader->frame() ? cachedResourceLoader->frame()->loader().documentLoader()->response().url() : cachedResourceLoader->document()->url(); m_resourceRequest.setURL(safeQLURLForDocumentURLAndResourceURL(documentURL, url())); } #endif if (!accept().isEmpty()) m_resourceRequest.setHTTPAccept(accept()); if (isCacheValidator()) { CachedResource* resourceToRevalidate = m_resourceToRevalidate; ASSERT(resourceToRevalidate->canUseCacheValidator()); ASSERT(resourceToRevalidate->isLoaded()); const String& lastModified = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::LastModified); const String& eTag = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::ETag); if (!lastModified.isEmpty() || !eTag.isEmpty()) { ASSERT(cachedResourceLoader->cachePolicy(type()) != CachePolicyReload); if (cachedResourceLoader->cachePolicy(type()) == CachePolicyRevalidate) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0"); if (!lastModified.isEmpty()) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified); if (!eTag.isEmpty()) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag); } } #if ENABLE(LINK_PREFETCH) if (type() == CachedResource::LinkPrefetch || type() == CachedResource::LinkSubresource) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::Purpose, "prefetch"); #endif m_resourceRequest.setPriority(loadPriority()); if (type() != MainResource) addAdditionalRequestHeaders(cachedResourceLoader); // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers. // We should look into removing the expectation of that knowledge from the platform network stacks. ResourceRequest request(m_resourceRequest); if (!m_fragmentIdentifierForRequest.isNull()) { URL url = request.url(); url.setFragmentIdentifier(m_fragmentIdentifierForRequest); request.setURL(url); m_fragmentIdentifierForRequest = String(); } m_loader = platformStrategies()->loaderStrategy()->resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->frame(), this, request, request.priority(), options); if (!m_loader) { failBeforeStarting(); return; } m_status = Pending; }
void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response) { RefPtr<Host> protector(this); Request* request = m_requestsLoading.get(loader); // FIXME: This is a workaround for <rdar://problem/5236843> // If a load starts while the frame is still in the provisional state // (this can be the case when loading the user style sheet), committing the load then causes all // requests to be removed from the m_requestsLoading map. This means that request might be null here. // In that case we just return early. // ASSERT(request); if (!request) return; CachedResource* resource = request->cachedResource(); if (resource->isCacheValidator()) { if (response.httpStatusCode() == 304) { // 304 Not modified / Use local copy m_requestsLoading.remove(loader); loader->clearClient(); request->docLoader()->decrementRequestCount(); // Existing resource is ok, just use it updating the expiration time. cache()->revalidationSucceeded(resource, response); if (request->docLoader()->frame()) request->docLoader()->frame()->loader()->checkCompleted(); delete request; servePendingRequests(); return; } // Did not get 304 response, continue as a regular resource load. cache()->revalidationFailed(resource); } resource->setResponse(response); String encoding = response.textEncodingName(); if (!encoding.isNull()) resource->setEncoding(encoding); if (request->isMultipart()) { ASSERT(resource->isImage()); static_cast<CachedImage*>(resource)->clear(); if (request->docLoader()->frame()) request->docLoader()->frame()->loader()->checkCompleted(); } else if (response.isMultipart()) { request->setIsMultipart(true); // We don't count multiParts in a DocLoader's request count request->docLoader()->decrementRequestCount(); // If we get a multipart response, we must have a handle ASSERT(loader->handle()); if (!resource->isImage()) loader->handle()->cancel(); } }
void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& serveLowerPriority) { while (!requestsPending.isEmpty()) { Request* request = requestsPending.first(); DocLoader* docLoader = request->docLoader(); bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator(); // For named hosts - which are only http(s) hosts - we should always enforce the connection limit. // For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing // and we don't know all stylesheets yet. bool shouldLimitRequests = !m_name.isNull() || docLoader->doc()->parsing() || !docLoader->doc()->haveStylesheetsLoaded(); if (shouldLimitRequests && m_requestsLoading.size() + m_nonCachedRequestsInFlight >= m_maxRequestsInFlight) { serveLowerPriority = false; return; } requestsPending.removeFirst(); ResourceRequest resourceRequest(request->cachedResource()->url()); resourceRequest.setTargetType(cachedResourceTypeToTargetType(request->cachedResource()->type())); #if PLATFORM(APOLLO) resourceRequest.setCanLoadDataURL(request->cachedResource()->isAllowedInDataURL()); #endif if (!request->cachedResource()->accept().isEmpty()) resourceRequest.setHTTPAccept(request->cachedResource()->accept()); #if PLATFORM(APOLLO) if (request->cachedResource()->type() == CachedResource::SWF) resourceRequest.addHTTPHeaderField("x-adobe-load-swf", "1"); #endif // Do not set the referrer or HTTP origin here. That's handled by SubresourceLoader::create. /* mihnea_integration_check KURL referrer = docLoader->doc()->url(); if ((referrer.protocolIs("http") || referrer.protocolIs("https")) && referrer.path().isEmpty()) referrer.setPath("/"); resourceRequest.setHTTPReferrer(referrer.string()); FrameLoader::addHTTPOriginIfNeeded(resourceRequest, docLoader->doc()->securityOrigin()->toString()); */ if (resourceIsCacheValidator) { CachedResource* resourceToRevalidate = request->cachedResource()->resourceToRevalidate(); ASSERT(resourceToRevalidate->canUseCacheValidator()); ASSERT(resourceToRevalidate->isLoaded()); const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified"); const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag"); if (!lastModified.isEmpty() || !eTag.isEmpty()) { ASSERT(docLoader->cachePolicy() != CachePolicyReload); if (docLoader->cachePolicy() == CachePolicyRevalidate) resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0"); if (!lastModified.isEmpty()) resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified); if (!eTag.isEmpty()) resourceRequest.setHTTPHeaderField("If-None-Match", eTag); } } RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(), this, resourceRequest, request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks()); if (loader) { m_requestsLoading.add(loader.release(), request); request->cachedResource()->setRequestedFromNetworkingLayer(); #if REQUEST_DEBUG printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), request->cachedResource()->url().latin1().data()); #endif } else { docLoader->decrementRequestCount(); docLoader->setLoadInProgress(true); request->cachedResource()->error(); docLoader->setLoadInProgress(false); delete request; } } }
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, const Vector<Node*>& nodes) { ASSERT(frame); const ResourceResponse& response = frame->loader()->documentLoader()->response(); KURL responseURL = response.url(); // it's possible to have a response without a URL here // <rdar://problem/5454935> if (responseURL.isNull()) responseURL = KURL(ParsedURLString, ""); PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->uniqueName()); Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; Vector<PassRefPtr<ArchiveResource> > subresources; HashSet<KURL> uniqueSubresources; size_t nodesSize = nodes.size(); for (size_t i = 0; i < nodesSize; ++i) { Node* node = nodes[i]; Frame* childFrame; if ((node->hasTagName(HTMLNames::frameTag) || node->hasTagName(HTMLNames::iframeTag) || node->hasTagName(HTMLNames::objectTag)) && (childFrame = static_cast<HTMLFrameOwnerElement*>(node)->contentFrame())) { RefPtr<LegacyWebArchive> subframeArchive = create(childFrame->document()); if (subframeArchive) subframeArchives.append(subframeArchive); else LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->uniqueName().string().utf8().data()); } else { ListHashSet<KURL> subresourceURLs; node->getSubresourceURLs(subresourceURLs); DocumentLoader* documentLoader = frame->loader()->documentLoader(); ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end(); for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) { const KURL& subresourceURL = *iter; if (uniqueSubresources.contains(subresourceURL)) continue; uniqueSubresources.add(subresourceURL); RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL); if (resource) { subresources.append(resource.release()); continue; } CachedResource* cachedResource = memoryCache()->resourceForURL(subresourceURL); if (cachedResource) { resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response()); if (resource) { subresources.append(resource.release()); continue; } } // FIXME: should do something better than spew to console here LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data()); } } } // Add favicon if one exists for this page, if we are archiving the entire page. if (nodesSize && nodes[0]->isDocumentNode() && iconDatabase().isEnabled()) { const String& iconURL = iconDatabase().synchronousIconURLForPageURL(responseURL); if (!iconURL.isEmpty() && iconDatabase().synchronousIconDataKnownForIconURL(iconURL)) { if (Image* iconImage = iconDatabase().synchronousIconForPageURL(responseURL, IntSize(16, 16))) { if (RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), KURL(ParsedURLString, iconURL), "image/x-icon", "", "")) subresources.append(resource.release()); } } } return create(mainResource, subresources, subframeArchives); }
void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& serveLowerPriority) { while (!requestsPending.isEmpty()) { Request* request = requestsPending.first(); DocLoader* docLoader = request->docLoader(); bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator(); // If the document is fully parsed and there are no pending stylesheets there won't be any more // resources that we would want to push to the front of the queue. Just hand off the remaining resources // to the networking layer. bool parsedAndStylesheetsKnown = !docLoader->doc()->parsing() && docLoader->doc()->haveStylesheetsLoaded(); if (!parsedAndStylesheetsKnown && !resourceIsCacheValidator && m_requestsLoading.size() >= m_maxRequestsInFlight) { serveLowerPriority = false; return; } requestsPending.removeFirst(); ResourceRequest resourceRequest(request->cachedResource()->url()); if (!request->cachedResource()->accept().isEmpty()) resourceRequest.setHTTPAccept(request->cachedResource()->accept()); KURL referrer = docLoader->doc()->url(); if ((referrer.protocolIs("http") || referrer.protocolIs("https")) && referrer.path().isEmpty()) referrer.setPath("/"); resourceRequest.setHTTPReferrer(referrer.string()); FrameLoader::addHTTPOriginIfNeeded(resourceRequest, docLoader->doc()->securityOrigin()->toString()); if (resourceIsCacheValidator) { CachedResource* resourceToRevalidate = request->cachedResource()->resourceToRevalidate(); ASSERT(resourceToRevalidate->canUseCacheValidator()); ASSERT(resourceToRevalidate->isLoaded()); const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified"); const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag"); if (!lastModified.isEmpty() || !eTag.isEmpty()) { ASSERT(docLoader->cachePolicy() != CachePolicyReload); if (docLoader->cachePolicy() == CachePolicyRevalidate) resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0"); if (!lastModified.isEmpty()) resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified); if (!eTag.isEmpty()) resourceRequest.setHTTPHeaderField("If-None-Match", eTag); } } RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(), this, resourceRequest, request->shouldSkipCanLoadCheck(), request->sendResourceLoadCallbacks()); if (loader) { m_requestsLoading.add(loader.release(), request); request->cachedResource()->setRequestedFromNetworkingLayer(); #if REQUEST_DEBUG printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), request->cachedResource()->url().latin1().data()); #endif } else { docLoader->decrementRequestCount(); docLoader->setLoadInProgress(true); request->cachedResource()->error(); docLoader->setLoadInProgress(false); delete request; } } }
void MemoryCache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response) { CachedResource* resource = revalidatingResource->resourceToRevalidate(); ASSERT(resource); ASSERT(!resource->inCache()); ASSERT(resource->isLoaded()); ASSERT(revalidatingResource->inCache()); // Calling evict() can potentially delete revalidatingResource, which we use // below. This mustn't be the case since revalidation means it is loaded // and so canDelete() is false. ASSERT(!revalidatingResource->canDelete()); evict(revalidatingResource); CachedResourceMap& resources = getSessionMap(resource->sessionID()); #if ENABLE(CACHE_PARTITIONING) ASSERT(!resources.get(resource->url()) || !resources.get(resource->url())->get(resource->cachePartition())); CachedResourceItem* originMap = resources.get(resource->url()); if (!originMap) { originMap = new CachedResourceItem; resources.set(resource->url(), adoptPtr(originMap)); } originMap->set(resource->cachePartition(), resource); #else ASSERT(!resources.get(resource->url())); resources.set(resource->url(), resource); #endif resource->setInCache(true); resource->updateResponseAfterRevalidation(response); insertInLRUList(resource); int delta = resource->size(); if (resource->decodedSize() && resource->hasClients()) insertInLiveDecodedResourcesList(resource); if (delta) adjustSize(resource->hasClients(), delta); revalidatingResource->switchClientsToRevalidatedResource(); ASSERT(!revalidatingResource->m_deleted); // this deletes the revalidating resource revalidatingResource->clearResourceToRevalidate(); }
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, const Vector<Node*>& nodes, FrameFilter* frameFilter) { ASSERT(frame); const ResourceResponse& response = frame->loader().documentLoader()->response(); URL responseURL = response.url(); // it's possible to have a response without a URL here // <rdar://problem/5454935> if (responseURL.isNull()) responseURL = URL(ParsedURLString, emptyString()); RefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree().uniqueName()); Vector<PassRefPtr<LegacyWebArchive>> subframeArchives; Vector<PassRefPtr<ArchiveResource>> subresources; HashSet<URL> uniqueSubresources; size_t nodesSize = nodes.size(); for (size_t i = 0; i < nodesSize; ++i) { Node& node = *nodes[i]; Frame* childFrame; if ((isHTMLFrameElement(node) || isHTMLIFrameElement(node) || isHTMLObjectElement(node)) && (childFrame = toHTMLFrameOwnerElement(node).contentFrame())) { if (frameFilter && !frameFilter->shouldIncludeSubframe(childFrame)) continue; RefPtr<LegacyWebArchive> subframeArchive = create(childFrame->document(), frameFilter); if (subframeArchive) subframeArchives.append(subframeArchive); else LOG_ERROR("Unabled to archive subframe %s", childFrame->tree().uniqueName().string().utf8().data()); } else { ListHashSet<URL> subresourceURLs; node.getSubresourceURLs(subresourceURLs); DocumentLoader* documentLoader = frame->loader().documentLoader(); ListHashSet<URL>::iterator iterEnd = subresourceURLs.end(); for (ListHashSet<URL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) { const URL& subresourceURL = *iter; if (uniqueSubresources.contains(subresourceURL)) continue; uniqueSubresources.add(subresourceURL); RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL); if (resource) { subresources.append(resource.release()); continue; } ResourceRequest request(subresourceURL); #if ENABLE(CACHE_PARTITIONING) request.setCachePartition(frame->document()->topOrigin()->cachePartition()); #endif CachedResource* cachedResource = memoryCache()->resourceForRequest(request); if (cachedResource) { ResourceBuffer* data = cachedResource->resourceBuffer(); resource = ArchiveResource::create(data ? data->sharedBuffer() : 0, subresourceURL, cachedResource->response()); if (resource) { subresources.append(resource.release()); continue; } } // FIXME: should do something better than spew to console here LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data()); } } } // Add favicon if one exists for this page, if we are archiving the entire page. if (nodesSize && nodes[0]->isDocumentNode() && iconDatabase().isEnabled()) { const String& iconURL = iconDatabase().synchronousIconURLForPageURL(responseURL); if (!iconURL.isEmpty() && iconDatabase().synchronousIconDataKnownForIconURL(iconURL)) { if (Image* iconImage = iconDatabase().synchronousIconForPageURL(responseURL, IntSize(16, 16))) { if (RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), URL(ParsedURLString, iconURL), "image/x-icon", "", "")) subresources.append(resource.release()); } } } return create(mainResource.release(), subresources, subframeArchives); }