void ImageDocumentParser::finish() { if (!isStopped() && document()->imageElement() && document()->cachedImage()) { ImageResource* cachedImage = document()->cachedImage(); DocumentLoader* loader = document()->loader(); cachedImage->setResponse(loader->response()); cachedImage->setLoadFinishTime(loader->timing().responseEnd()); cachedImage->finish(); // Report the natural image size in the page title, regardless of zoom level. // At a zoom level of 1 the image is guaranteed to have an integer size. IntSize size = flooredIntSize(cachedImage->imageSizeForLayoutObject(document()->imageElement()->layoutObject(), 1.0f)); if (size.width()) { // Compute the title, we use the decoded filename of the resource, falling // back on the (decoded) hostname if there is no path. String fileName = decodeURLEscapeSequences(document()->url().lastPathComponent()); if (fileName.isEmpty()) fileName = document()->url().host(); document()->setTitle(imageTitle(fileName, size)); } document()->imageUpdated(); } // TODO(esprehn): These null checks on Document don't make sense, document() // will ASSERT if it was null. Do these want to check isDetached() ? if (document()) document()->finishedParsing(); }
ResourceLoadTiming* PerformanceTiming::resourceLoadTiming() const { DocumentLoader* loader = documentLoader(); if (!loader) return nullptr; return loader->response().resourceLoadTiming(); }
bool PageCache::canCachePageContainingThisFrame(Frame& frame) { for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling()) { if (!canCachePageContainingThisFrame(*child)) return false; } FrameLoader& frameLoader = frame.loader(); DocumentLoader* documentLoader = frameLoader.documentLoader(); Document* document = frame.document(); return documentLoader && (documentLoader->mainDocumentError().isNull() || (documentLoader->mainDocumentError().isCancellation() && documentLoader->subresourceLoadersArePageCacheAcceptable())) // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs). && !(documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty()) && (!frameLoader.subframeLoader().containsPlugins() || frame.page()->settings().pageCacheSupportsPlugins()) && !(frame.isMainFrame() && document->url().protocolIs("https") && documentLoader->response().cacheControlContainsNoStore()) && frameLoader.history().currentItem() && !frameLoader.quickRedirectComing() && !documentLoader->isLoading() && !documentLoader->isStopping() && document->canSuspendActiveDOMObjectsForPageCache() // FIXME: We should investigating caching frames that have an associated // application cache. <rdar://problem/5917899> tracks that work. && documentLoader->applicationCacheHost()->canCacheInPageCache() && frameLoader.client().canCachePage(); }
static bool isSecure(DocumentLoader& documentLoader) { auto& response = documentLoader.response(); return response.url().protocolIs("https") && response.certificateInfo() && !response.certificateInfo()->containsNonRootSHA1SignedCertificate(); }
bool PageCache::canCachePageContainingThisFrame(Frame* frame) { for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { if (!canCachePageContainingThisFrame(child)) return false; } FrameLoader* frameLoader = frame->loader(); DocumentLoader* documentLoader = frameLoader->documentLoader(); Document* document = frame->document(); return documentLoader && documentLoader->mainDocumentError().isNull() // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs). && !(documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty()) && (!frameLoader->subframeLoader()->containsPlugins() || frame->page()->settings()->pageCacheSupportsPlugins()) && (!document->url().protocolIs("https") || (!documentLoader->response().cacheControlContainsNoCache() && !documentLoader->response().cacheControlContainsNoStore())) && (!document->domWindow() || !document->domWindow()->hasEventListeners(eventNames().unloadEvent)) #if ENABLE(SQL_DATABASE) && !DatabaseManager::manager().hasOpenDatabases(document) #endif #if ENABLE(SHARED_WORKERS) && !SharedWorkerRepository::hasSharedWorkers(document) #endif && frameLoader->history()->currentItem() && !frameLoader->quickRedirectComing() && !documentLoader->isLoadingInAPISense() && !documentLoader->isStopping() && document->canSuspendActiveDOMObjects() // FIXME: We should investigating caching frames that have an associated // application cache. <rdar://problem/5917899> tracks that work. && documentLoader->applicationCacheHost()->canCacheInPageCache() && frameLoader->client()->canCachePage(); }
WebString WebDocument::applicationID() const { const char* kChromeApplicationHeader = "x-chrome-application"; // First check if the document's response included a header indicating the // application it should go with. const Document* document = constUnwrap<Document>(); Frame* frame = document->frame(); if (!frame) return WebString(); DocumentLoader* loader = frame->loader()->documentLoader(); if (!loader) return WebString(); WebString headerValue = loader->response().httpHeaderField(kChromeApplicationHeader); if (!headerValue.isEmpty()) return headerValue; // Otherwise, fall back to looking for the meta tag. RefPtr<NodeList> metaTags = const_cast<Document*>(document)->getElementsByTagName("meta"); for (unsigned i = 0; i < metaTags->length(); ++i) { Element* element = static_cast<Element*>(metaTags->item(i)); if (element->getAttribute("http-equiv").lower() == kChromeApplicationHeader) { return element->getAttribute("value"); } } return WebString(); }
void WebFrameLoaderClient::updateGlobalHistory() { DocumentLoader* loader = core(m_webFrame)->loader()->documentLoader(); WebView* webView = m_webFrame->webView(); SharedPtr<WebHistoryDelegate> historyDelegate = webView->historyDelegate(); if (historyDelegate) { String url(loader->urlForHistory().string()); String title(loader->title()); String redirectSource(loader->clientRedirectSourceForHistory()); OwnPtr<WebURLResponse> urlResponse(WebURLResponse::createInstance(loader->response())); OwnPtr<WebMutableURLRequest> urlRequest(WebMutableURLRequest::createInstance(loader->originalRequestCopy())); OwnPtr<WebNavigationData> navigationData(WebNavigationData::createInstance(url.utf8().data(), title.utf8().data(), urlRequest.get(), urlResponse.get(), loader->substituteData().isValid(), redirectSource.utf8().data())); historyDelegate->didNavigateWithNavigationData(webView, navigationData.get(), m_webFrame); return; } WebHistory* history = WebHistory::sharedHistory(); if (!history) return; history->visitedURL(strdup(loader->urlForHistory().string().utf8().data()), strdup(loader->title().utf8().data()), strdup(loader->originalRequestCopy().httpMethod().utf8().data()), loader->urlForHistoryReflectsFailure()); }
unsigned long long PerformanceTiming::connectEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return connectStart(); ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return connectStart(); // connectEnd will be zero when a network request is not made. Rather than // exposing a special value that indicates no new connection, we "backfill" // with connectStart. double connectEnd = timing->connectEnd(); if (connectEnd == 0.0 || loader->response().connectionReused()) return connectStart(); return monotonicTimeToIntegerMilliseconds(connectEnd); }
unsigned long long PerformanceTiming::connectEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return connectStart(); ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return connectStart(); // connectEnd will be -1 when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart. int connectEnd = timing->connectEnd; if (connectEnd < 0 || loader->response().connectionReused()) return connectStart(); return resourceLoadTimeRelativeToAbsolute(connectEnd); }
PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal) { DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); KURL unreachableURL = documentLoader ? documentLoader->unreachableURL() : KURL(); KURL url; KURL originalURL; if (!unreachableURL.isEmpty()) { url = unreachableURL; originalURL = unreachableURL; } else { originalURL = documentLoader ? documentLoader->originalURL() : KURL(); if (useOriginal) url = originalURL; else if (documentLoader) url = documentLoader->requestURL(); } LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data()); // Frames that have never successfully loaded any content // may have no URL at all. Currently our history code can't // deal with such things, so we nip that in the bud here. // Later we may want to learn to live with nil for URL. // See bug 3368236 and related bugs for more information. if (url.isEmpty()) url = blankURL(); if (originalURL.isEmpty()) originalURL = blankURL(); Frame* parentFrame = m_frame->tree()->parent(); String parent = parentFrame ? parentFrame->tree()->uniqueName() : ""; String title = documentLoader ? documentLoader->title() : ""; RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->uniqueName(), parent, title); item->setOriginalURLString(originalURL.string()); if (!unreachableURL.isEmpty() || !documentLoader || documentLoader->response().httpStatusCode() >= 400) item->setLastVisitWasFailure(true); // Save form state if this is a POST if (documentLoader) { if (useOriginal) item->setFormInfoFromRequest(documentLoader->originalRequest()); else item->setFormInfoFromRequest(documentLoader->request()); } // Set the item for which we will save document state m_frameLoadComplete = false; m_previousItem = m_currentItem; m_currentItem = item; return item.release(); }
unsigned long long PerformanceTiming::responseStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return requestStart(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); ASSERT(timing.responseStart >= 0); return resourceLoadTimeRelativeToAbsolute(timing.responseStart); }
WebCore::CertificateInfo WebFrame::certificateInfo() const { if (!m_coreFrame) return CertificateInfo(); DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader(); if (!documentLoader) return CertificateInfo(); return documentLoader->response().certificateInfo(); }
CertificateInfo WebFrame::certificateInfo() const { if (!m_coreFrame) return { }; DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader(); if (!documentLoader) return { }; return documentLoader->response().certificateInfo().valueOrCompute([] { return CertificateInfo(); }); }
static PassRefPtr<InspectorObject> buildObjectForFrameResource(Frame* frame) { FrameLoader* frameLoader = frame->loader(); DocumentLoader* loader = frameLoader->documentLoader(); RefPtr<InspectorObject> resourceObject = InspectorObject::create(); resourceObject->setString("url", loader->url().string()); resourceObject->setObject("loader", buildObjectForDocumentLoader(loader)); resourceObject->setObject("request", buildObjectForResourceRequest(loader->request())); resourceObject->setObject("response", buildObjectForResourceResponse(loader->response())); return resourceObject; }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); if (timing.secureConnectionStart < 0) return 0; return resourceLoadTimeRelativeToAbsolute(timing.secureConnectionStart); }
unsigned long long PerformanceTiming::connectStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupEnd(); ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return domainLookupEnd(); // connectStart will be zero when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd. double connectStart = timing->connectStart; if (connectStart == 0.0 || loader->response().connectionReused()) return domainLookupEnd(); // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's // connect phase should not. So if there is DNS time, trim it from the start. if (timing->dnsEnd > 0.0 && timing->dnsEnd > connectStart) connectStart = timing->dnsEnd; return monotonicTimeToIntegerMilliseconds(connectStart); }
unsigned long long PerformanceTiming::domainLookupEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupStart(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); // This will be -1 when a DNS request is not performed. // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart. if (timing.domainLookupEnd < 0) return domainLookupStart(); return resourceLoadTimeRelativeToAbsolute(timing.domainLookupEnd); }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return 0; double sslStart = timing->sslStart(); if (sslStart == 0.0) return 0; return monotonicTimeToIntegerMilliseconds(sslStart); }
void FrameLoaderClientAndroid::updateGlobalHistory() { ASSERT(m_frame); DocumentLoader* docLoader = m_frame->loader()->documentLoader(); ASSERT(docLoader); // Code copied from FrameLoader.cpp:createHistoryItem // Only add this URL to the database if it is a valid page if (docLoader->unreachableURL().isEmpty() && docLoader->response().httpStatusCode() < 400) { m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false); if (!docLoader->serverRedirectSourceForHistory().isNull()) m_webFrame->updateVisitedHistory(KURL(ParsedURLString, docLoader->serverRedirectDestinationForHistory()), false); } }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return 0; int sslStart = timing->sslStart; if (sslStart < 0) return 0; return resourceLoadTimeRelativeToAbsolute(sslStart); }
void HistoryController::initializeItem(HistoryItem* item) { DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); ASSERT(documentLoader); KURL unreachableURL = documentLoader->unreachableURL(); KURL url; KURL originalURL; if (!unreachableURL.isEmpty()) { url = unreachableURL; originalURL = unreachableURL; } else { url = documentLoader->url(); originalURL = documentLoader->originalURL(); } // Frames that have never successfully loaded any content // may have no URL at all. Currently our history code can't // deal with such things, so we nip that in the bud here. // Later we may want to learn to live with nil for URL. // See bug 3368236 and related bugs for more information. if (url.isEmpty()) url = blankURL(); if (originalURL.isEmpty()) originalURL = blankURL(); Frame* parentFrame = m_frame->tree()->parent(); String parent = parentFrame ? parentFrame->tree()->uniqueName() : ""; StringWithDirection title = documentLoader->title(); item->setURL(url); item->setTarget(m_frame->tree()->uniqueName()); item->setParent(parent); // FIXME: should store title directionality in history as well. item->setTitle(title.string()); item->setOriginalURLString(originalURL.string()); if (!unreachableURL.isEmpty() || documentLoader->response().httpStatusCode() >= 400) item->setLastVisitWasFailure(true); // Save form state if this is a POST item->setFormInfoFromRequest(documentLoader->request()); }
String WebFrame::mimeTypeForResourceWithURL(const URL& url) const { if (!m_coreFrame) return String(); DocumentLoader* loader = m_coreFrame->loader().documentLoader(); if (!loader) return String(); // First, try the main resource. if (loader->url() == url) return loader->response().mimeType(); // Next, try subresources. RefPtr<ArchiveResource> resource = loader->subresource(url); if (resource) return resource->mimeType(); return page()->cachedResponseMIMETypeForURL(url); }
String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const { if (!m_coreFrame) return String(); DocumentLoader* loader = m_coreFrame->loader()->documentLoader(); if (!loader) return String(); // First, try the main resource. if (loader->url() == url) return loader->response().suggestedFilename(); // Next, try subresources. RefPtr<ArchiveResource> resource = loader->subresource(url); if (!resource) return String(); return resource->response().suggestedFilename(); }
unsigned long long PerformanceTiming::connectStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupEnd(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); // connectStart will be -1 when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd. int connectStart = timing.connectStart; if (connectStart < 0) return domainLookupEnd(); // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's // connect phase should not. So if there is DNS time, trim it from the start. if (timing.domainLookupEnd >= 0 && timing.domainLookupEnd > connectStart) connectStart = timing.domainLookupEnd; return resourceLoadTimeRelativeToAbsolute(connectStart); }
void WebFrameLoaderClient::updateGlobalHistory() { DocumentLoader* loader = core(m_webFrame)->loader()->documentLoader(); WebView* webView = m_webFrame->webView(); COMPtr<IWebHistoryDelegate> historyDelegate; webView->historyDelegate(&historyDelegate); if (historyDelegate) { COMPtr<IWebURLResponse> urlResponse(AdoptCOM, WebURLResponse::createInstance(loader->response())); COMPtr<IWebURLRequest> urlRequest(AdoptCOM, WebMutableURLRequest::createInstance(loader->originalRequestCopy())); COMPtr<IWebNavigationData> navigationData(AdoptCOM, WebNavigationData::createInstance( loader->urlForHistory(), loader->title(), urlRequest.get(), urlResponse.get(), loader->substituteData().isValid(), loader->clientRedirectSourceForHistory())); historyDelegate->didNavigateWithNavigationData(webView, navigationData.get(), m_webFrame); return; } WebHistory* history = WebHistory::sharedHistory(); if (!history) return; history->visitedURL(loader->urlForHistory(), loader->title(), loader->originalRequestCopy().httpMethod(), loader->urlForHistoryReflectsFailure(), !loader->clientRedirectSourceForHistory()); }
static bool canCacheFrame(Frame& frame, DiagnosticLoggingClient& diagnosticLoggingClient, unsigned indentLevel) { PCLOG("+---"); FrameLoader& frameLoader = frame.loader(); // Prevent page caching if a subframe is still in provisional load stage. // We only do this check for subframes because the main frame is reused when navigating to a new page. if (!frame.isMainFrame() && frameLoader.state() == FrameStateProvisional) { PCLOG(" -Frame is in provisional load stage"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::provisionalLoadKey()); return false; } DocumentLoader* documentLoader = frameLoader.documentLoader(); if (!documentLoader) { PCLOG(" -There is no DocumentLoader object"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noDocumentLoaderKey()); return false; } URL currentURL = documentLoader->url(); URL newURL = frameLoader.provisionalDocumentLoader() ? frameLoader.provisionalDocumentLoader()->url() : URL(); if (!newURL.isEmpty()) PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):"); else PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:"); bool isCacheable = true; if (!documentLoader->mainDocumentError().isNull()) { PCLOG(" -Main document has an error"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::mainDocumentErrorKey()); if (documentLoader->mainDocumentError().isCancellation() && documentLoader->subresourceLoadersArePageCacheAcceptable()) PCLOG(" -But, it was a cancellation and all loaders during the cancelation were loading images or XHR."); else isCacheable = false; } // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs). if (documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty()) { PCLOG(" -Frame is an error page"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isErrorPageKey()); isCacheable = false; } if (frameLoader.subframeLoader().containsPlugins() && !frame.page()->settings().pageCacheSupportsPlugins()) { PCLOG(" -Frame contains plugins"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::hasPluginsKey()); isCacheable = false; } if (frame.isMainFrame() && frame.document() && frame.document()->url().protocolIs("https") && documentLoader->response().cacheControlContainsNoStore()) { PCLOG(" -Frame is HTTPS, and cache control prohibits storing"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::httpsNoStoreKey()); isCacheable = false; } if (frame.isMainFrame() && !frameLoader.history().currentItem()) { PCLOG(" -Main frame has no current history item"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noCurrentHistoryItemKey()); isCacheable = false; } if (frameLoader.quickRedirectComing()) { PCLOG(" -Quick redirect is coming"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::quirkRedirectComingKey()); isCacheable = false; } if (documentLoader->isLoading()) { PCLOG(" -DocumentLoader is still loading"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isLoadingKey()); isCacheable = false; } if (documentLoader->isStopping()) { PCLOG(" -DocumentLoader is in the middle of stopping"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::documentLoaderStoppingKey()); isCacheable = false; } Vector<ActiveDOMObject*> unsuspendableObjects; if (frame.document() && !frame.document()->canSuspendActiveDOMObjectsForDocumentSuspension(&unsuspendableObjects)) { PCLOG(" -The document cannot suspend its active DOM Objects"); for (auto* activeDOMObject : unsuspendableObjects) { PCLOG(" - Unsuspendable: ", activeDOMObject->activeDOMObjectName()); diagnosticLoggingClient.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::unsuspendableDOMObjectKey(), activeDOMObject->activeDOMObjectName(), ShouldSample::Yes); UNUSED_PARAM(activeDOMObject); } logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::cannotSuspendActiveDOMObjectsKey()); isCacheable = false; } // FIXME: We should investigating caching frames that have an associated // application cache. <rdar://problem/5917899> tracks that work. if (!documentLoader->applicationCacheHost()->canCacheInPageCache()) { PCLOG(" -The DocumentLoader uses an application cache"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::applicationCacheKey()); isCacheable = false; } if (!frameLoader.client().canCachePage()) { PCLOG(" -The client says this frame cannot be cached"); logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::deniedByClientKey()); isCacheable = false; } for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling()) { if (!canCacheFrame(*child, diagnosticLoggingClient, indentLevel + 1)) isCacheable = false; } PCLOG(isCacheable ? " Frame CAN be cached" : " Frame CANNOT be cached"); PCLOG("+---"); return isCacheable; }