diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/loader/FrameLoader.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/loader/FrameLoader.cpp')
-rw-r--r-- | Source/WebCore/loader/FrameLoader.cpp | 1380 |
1 files changed, 628 insertions, 752 deletions
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 5ca806300..c3cc3c559 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -12,13 +12,13 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -43,12 +43,11 @@ #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "Console.h" #include "ContentSecurityPolicy.h" #include "DOMImplementation.h" #include "DOMWindow.h" #include "DatabaseManager.h" -#include "DiagnosticLoggingClient.h" -#include "DiagnosticLoggingKeys.h" #include "Document.h" #include "DocumentLoadTiming.h" #include "DocumentLoader.h" @@ -66,19 +65,16 @@ #include "FrameNetworkingContext.h" #include "FrameTree.h" #include "FrameView.h" -#include "GCController.h" #include "HTMLAnchorElement.h" #include "HTMLFormElement.h" #include "HTMLInputElement.h" #include "HTMLNames.h" #include "HTMLObjectElement.h" #include "HTMLParserIdioms.h" -#include "HTTPHeaderNames.h" #include "HTTPParsers.h" #include "HistoryController.h" #include "HistoryItem.h" #include "IconController.h" -#include "IgnoreOpensDuringUnloadCountIncrementer.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" #include "LoaderStrategy.h" @@ -86,24 +82,20 @@ #include "MIMETypeRegistry.h" #include "MainFrame.h" #include "MemoryCache.h" +#include "Page.h" +#include "PageActivityAssertionToken.h" #include "PageCache.h" -#include "PageThrottler.h" #include "PageTransitionEvent.h" #include "PlatformStrategies.h" #include "PluginData.h" +#include "PluginDatabase.h" #include "PluginDocument.h" #include "PolicyChecker.h" #include "ProgressTracker.h" #include "ResourceHandle.h" -#include "ResourceLoadInfo.h" #include "ResourceRequest.h" -#include "SVGDocument.h" -#include "SVGLocatable.h" -#include "SVGNames.h" -#include "SVGPreserveAspectRatio.h" -#include "SVGViewElement.h" -#include "SVGViewSpec.h" #include "SchemeRegistry.h" +#include "ScriptCallStack.h" #include "ScriptController.h" #include "ScriptSourceCode.h" #include "ScrollAnimator.h" @@ -114,7 +106,6 @@ #include "Settings.h" #include "SubframeLoader.h" #include "TextResourceDecoder.h" -#include "UserContentController.h" #include "WindowFeatures.h" #include "XMLDocumentParser.h" #include <wtf/CurrentTime.h> @@ -123,12 +114,22 @@ #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> -#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) -#include "Archive.h" +#if ENABLE(SHARED_WORKERS) +#include "SharedWorkerRepository.h" #endif -#if ENABLE(DATA_DETECTION) -#include "DataDetection.h" +#if ENABLE(SVG) +#include "SVGDocument.h" +#include "SVGLocatable.h" +#include "SVGNames.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGSVGElement.h" +#include "SVGViewElement.h" +#include "SVGViewSpec.h" +#endif + +#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) +#include "Archive.h" #endif #if PLATFORM(IOS) @@ -143,7 +144,10 @@ namespace WebCore { using namespace HTMLNames; + +#if ENABLE(SVG) using namespace SVGNames; +#endif static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; @@ -154,17 +158,17 @@ const int memoryLevelThresholdToPrunePageCache = 20; bool isBackForwardLoadType(FrameLoadType type) { switch (type) { - case FrameLoadType::Standard: - case FrameLoadType::Reload: - case FrameLoadType::ReloadFromOrigin: - case FrameLoadType::Same: - case FrameLoadType::RedirectWithLockedBackForwardList: - case FrameLoadType::Replace: - return false; - case FrameLoadType::Back: - case FrameLoadType::Forward: - case FrameLoadType::IndexedBackForward: - return true; + case FrameLoadTypeStandard: + case FrameLoadTypeReload: + case FrameLoadTypeReloadFromOrigin: + case FrameLoadTypeSame: + case FrameLoadTypeRedirectWithLockedBackForwardList: + case FrameLoadTypeReplace: + return false; + case FrameLoadTypeBack: + case FrameLoadTypeForward: + case FrameLoadTypeIndexedBackForward: + return true; } ASSERT_NOT_REACHED(); return false; @@ -176,29 +180,11 @@ bool isBackForwardLoadType(FrameLoadType type) // non-member lets us exclude it from the header file, thus keeping FrameLoader.h's // API simpler. // -static bool isDocumentSandboxed(Frame& frame, SandboxFlags mask) +static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask) { - return frame.document() && frame.document()->isSandboxed(mask); + return frame->document() && frame->document()->isSandboxed(mask); } -struct ForbidPromptsScope { - ForbidPromptsScope(Page* page) : m_page(page) - { - if (!m_page) - return; - m_page->forbidPrompts(); - } - - ~ForbidPromptsScope() - { - if (!m_page) - return; - m_page->allowPrompts(); - } - - Page* m_page; -}; - class FrameLoader::FrameProgressTracker { public: explicit FrameProgressTracker(Frame& frame) @@ -244,20 +230,23 @@ FrameLoader::FrameLoader(Frame& frame, FrameLoaderClient& client) , m_icon(std::make_unique<IconController>(frame)) , m_mixedContentChecker(frame) , m_state(FrameStateProvisional) - , m_loadType(FrameLoadType::Standard) + , m_loadType(FrameLoadTypeStandard) + , m_delegateIsHandlingProvisionalLoadError(false) , m_quickRedirectComing(false) , m_sentRedirectNotification(false) , m_inStopAllLoaders(false) , m_isExecutingJavaScriptFormAction(false) , m_didCallImplicitClose(true) , m_wasUnloadEventEmitted(false) + , m_pageDismissalEventBeingDispatched(NoDismissal) , m_isComplete(false) , m_needsClear(false) - , m_checkTimer(*this, &FrameLoader::checkTimerFired) + , m_checkTimer(this, &FrameLoader::checkTimerFired) , m_shouldCallCheckCompleted(false) , m_shouldCallCheckLoadComplete(false) , m_opener(nullptr) , m_loadingFromCachedPage(false) + , m_suppressOpenerInNewFrame(false) , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false) , m_loadsSynchronously(false) , m_forcedSandboxFlags(SandboxNone) @@ -268,8 +257,9 @@ FrameLoader::~FrameLoader() { setOpener(nullptr); - for (auto& frame : m_openedFrames) - frame->loader().m_opener = nullptr; + HashSet<Frame*>::iterator end = m_openedFrames.end(); + for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it) + (*it)->loader().m_opener = 0; m_client.frameLoaderDestroyed(); @@ -280,7 +270,7 @@ FrameLoader::~FrameLoader() void FrameLoader::init() { // This somewhat odd set of steps gives the frame an initial empty document. - setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).ptr()); + setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).get()); setProvisionalDocumentLoader(m_policyDocumentLoader.get()); m_provisionalDocumentLoader->startLoadingMainResource(); @@ -299,8 +289,8 @@ void FrameLoader::initForSynthesizedDocument(const URL&) // FrameLoader::checkCompleted() will overwrite the URL of the document to be activeDocumentLoader()->documentURL(). RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()); - loader->attachToFrame(m_frame); - loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String())); + loader->setFrame(&m_frame); + loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String(), String())); loader->setCommitted(true); setDocumentLoader(loader.get()); @@ -315,7 +305,6 @@ void FrameLoader::initForSynthesizedDocument(const URL&) m_needsClear = true; m_networkingContext = m_client.createNetworkingContext(); - m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame); } #endif @@ -335,32 +324,40 @@ void FrameLoader::setDefersLoading(bool defers) } } -void FrameLoader::changeLocation(const FrameLoadRequest& request) +void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const URL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh) { - urlSelected(request, nullptr); + urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"), + 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL); } -void FrameLoader::urlSelected(const URL& url, const String& passedTarget, Event* triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy) +void FrameLoader::urlSelected(const URL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer) { - NewFrameOpenerPolicy newFrameOpenerPolicy = shouldSendReferrer == NeverSendReferrer ? NewFrameOpenerPolicy::Suppress : NewFrameOpenerPolicy::Allow; - - urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget, lockHistory, lockBackForwardList, shouldSendReferrer, AllowNavigationToInvalidURL::Yes, newFrameOpenerPolicy, DoNotReplaceDocumentIfJavaScriptURL, shouldOpenExternalURLsPolicy), triggeringEvent); + urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget), + triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL); } -void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, Event* triggeringEvent) +// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the +// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed. +void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL) { + ASSERT(!m_suppressOpenerInNewFrame); + Ref<Frame> protect(m_frame); FrameLoadRequest frameRequest(passedRequest); - if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), frameRequest.shouldReplaceDocumentIfJavaScriptURL())) + if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL)) return; if (frameRequest.frameName().isEmpty()) frameRequest.setFrameName(m_frame.document()->baseTarget()); + if (shouldSendReferrer == NeverSendReferrer) + m_suppressOpenerInNewFrame = true; addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin()); - loadFrameRequest(frameRequest, triggeringEvent, nullptr); + loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer); + + m_suppressOpenerInNewFrame = false; } void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission) @@ -378,9 +375,9 @@ void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission) if (submission->action().isEmpty()) return; - if (isDocumentSandboxed(m_frame, SandboxForms)) { + if (isDocumentSandboxed(&m_frame, SandboxForms)) { // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. - m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set."); + m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set."); return; } @@ -416,7 +413,7 @@ void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission) // We do not want to submit more than one form from the same page, nor do we want to submit a single // form more than once. This flag prevents these from happening; not sure how other browsers prevent this. - // The flag is reset in each time we start dispatching a new mouse or key down event, and + // The flag is reset in each time we start handle a new mouse or key down event, and // also in setView since this part may get reused for a page from the back/forward cache. // The form multi-submit logic here is only needed when we are submitting a form that affects this frame. @@ -442,8 +439,55 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy) if (m_frame.document() && m_frame.document()->parser()) m_frame.document()->parser()->stopParsing(); - if (unloadEventPolicy != UnloadEventPolicyNone) - dispatchUnloadEvents(unloadEventPolicy); + if (unloadEventPolicy != UnloadEventPolicyNone) { + if (m_frame.document()) { + if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { + Element* currentFocusedElement = m_frame.document()->focusedElement(); + if (currentFocusedElement && currentFocusedElement->toInputElement()) + currentFocusedElement->toInputElement()->endEditing(); + if (m_pageDismissalEventBeingDispatched == NoDismissal) { + if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) { + m_pageDismissalEventBeingDispatched = PageHideDismissal; + m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document()); + } + + // FIXME: update Page Visibility state here. + // https://bugs.webkit.org/show_bug.cgi?id=116770 + + if (!m_frame.document()->inPageCache()) { + RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false)); + // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed + // while dispatching the event, so protect it to prevent writing the end + // time into freed memory. + RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader; + m_pageDismissalEventBeingDispatched = UnloadDismissal; + if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) { + DocumentLoadTiming* timing = documentLoader->timing(); + ASSERT(timing->navigationStart()); + timing->markUnloadEventStart(); + m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document()); + timing->markUnloadEventEnd(); + } else + m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document()); + } + } + m_pageDismissalEventBeingDispatched = NoDismissal; + if (m_frame.document()) + m_frame.document()->updateStyleIfNeeded(); + m_wasUnloadEventEmitted = true; + } + } + + // Dispatching the unload event could have made m_frame.document() null. + if (m_frame.document() && !m_frame.document()->inPageCache()) { + // Don't remove event listeners from a transitional empty document (see bug 28716 for more information). + bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader + && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url()); + + if (!keepEventListeners) + m_frame.document()->removeAllEventListeners(); + } + } m_isComplete = true; // to avoid calling completed() in finishedParsing() m_didCallImplicitClose = true; // don't want that one either @@ -458,8 +502,10 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy) // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537 doc->setReadyState(Document::Complete); +#if ENABLE(SQL_DATABASE) // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here? - DatabaseManager::singleton().stopDatabases(doc, 0); + DatabaseManager::manager().stopDatabases(doc, 0); +#endif } // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache. @@ -487,28 +533,18 @@ void FrameLoader::willTransitionToCommitted() if (m_frame.editor().hasComposition()) { // The text was already present in DOM, so it's better to confirm than to cancel the composition. m_frame.editor().confirmComposition(); - if (EditorClient* editorClient = m_frame.editor().client()) { + if (EditorClient* editorClient = m_frame.editor().client()) editorClient->respondToChangedSelection(&m_frame); - editorClient->discardedComposition(&m_frame); - } } } bool FrameLoader::closeURL() { history().saveDocumentState(); - + + // Should only send the pagehide event here if the current document exists and has not been placed in the page cache. Document* currentDocument = m_frame.document(); - UnloadEventPolicy unloadEventPolicy; - if (m_frame.page() && m_frame.page()->chrome().client().isSVGImageChromeClient()) { - // If this is the SVGDocument of an SVGImage, no need to dispatch events or recalcStyle. - unloadEventPolicy = UnloadEventPolicyNone; - } else { - // Should only send the pagehide event here if the current document exists and has not been placed in the page cache. - unloadEventPolicy = currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly; - } - - stopLoading(unloadEventPolicy); + stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly); m_frame.editor().clearUndoRedoOperations(); return true; @@ -581,31 +617,27 @@ void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool if (!m_frame.document()->inPageCache()) { m_frame.document()->cancelParsing(); m_frame.document()->stopActiveDOMObjects(); - bool hadLivingRenderTree = m_frame.document()->hasLivingRenderTree(); - m_frame.document()->prepareForDestruction(); - if (hadLivingRenderTree) + if (m_frame.document()->hasLivingRenderTree()) { + m_frame.document()->prepareForDestruction(); m_frame.document()->removeFocusedNodeOfSubtree(m_frame.document()); + } } // Do this after detaching the document so that the unload event works. if (clearWindowProperties) { InspectorInstrumentation::frameWindowDiscarded(&m_frame, m_frame.document()->domWindow()); - m_frame.document()->domWindow()->resetUnlessSuspendedForDocumentSuspension(); + m_frame.document()->domWindow()->resetUnlessSuspendedForPageCache(); m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->inPageCache()); } m_frame.selection().prepareForDestruction(); - - // We may call this code during object destruction, so need to make sure eventHandler is present. - if (auto eventHandler = m_frame.eventHandlerPtr()) - eventHandler->clear(); - + m_frame.eventHandler().clear(); if (clearFrameView && m_frame.view()) m_frame.view()->clear(); // Do not drop the document before the ScriptController and view are cleared // as some destructors might still try to access the document. - m_frame.setDocument(nullptr); + m_frame.setDocument(0); subframeLoader().clear(); @@ -639,22 +671,23 @@ void FrameLoader::receivedFirstData() if (!m_documentLoader) return; + if (m_frame.document()->isViewSource()) + return; double delay; - String urlString; - if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Refresh), false, delay, urlString)) + String url; + if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url)) return; - URL completedURL; - if (urlString.isEmpty()) - completedURL = m_frame.document()->url(); + if (url.isEmpty()) + url = m_frame.document()->url().string(); else - completedURL = m_frame.document()->completeURL(urlString); + url = m_frame.document()->completeURL(url).string(); - if (!protocolIsJavaScript(completedURL)) - m_frame.navigationScheduler().scheduleRedirect(m_frame.document(), delay, completedURL); + if (!protocolIsJavaScript(url)) + m_frame.navigationScheduler().scheduleRedirect(delay, url); else { String message = "Refused to refresh " + m_frame.document()->url().stringCenterEllipsizedToLength() + " to a javascript: URL"; - m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message); + m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message); } } @@ -672,7 +705,7 @@ void FrameLoader::didBeginDocument(bool dispatch) if (m_pendingStateObject) { m_frame.document()->statePopped(m_pendingStateObject.get()); - m_pendingStateObject = nullptr; + m_pendingStateObject.clear(); } if (dispatch) @@ -682,17 +715,31 @@ void FrameLoader::didBeginDocument(bool dispatch) m_frame.document()->initContentSecurityPolicy(); const Settings& settings = m_frame.settings(); - m_frame.document()->cachedResourceLoader().setImagesEnabled(settings.areImagesEnabled()); - m_frame.document()->cachedResourceLoader().setAutoLoadImages(settings.loadsImagesAutomatically()); + m_frame.document()->cachedResourceLoader()->setImagesEnabled(settings.areImagesEnabled()); + m_frame.document()->cachedResourceLoader()->setAutoLoadImages(settings.loadsImagesAutomatically()); if (m_documentLoader) { - String dnsPrefetchControl = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XDNSPrefetchControl); + String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control"); if (!dnsPrefetchControl.isEmpty()) m_frame.document()->parseDNSPrefetchControlHeader(dnsPrefetchControl); - m_frame.document()->contentSecurityPolicy()->didReceiveHeaders(ContentSecurityPolicyResponseHeaders(m_documentLoader->response())); + String policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy"); + if (!policyValue.isEmpty()) + m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce); - String headerContentLanguage = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentLanguage); + policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy-Report-Only"); + if (!policyValue.isEmpty()) + m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report); + + policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP"); + if (!policyValue.isEmpty()) + m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce); + + policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only"); + if (!policyValue.isEmpty()) + m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport); + + String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language"); if (!headerContentLanguage.isEmpty()) { size_t commaIndex = headerContentLanguage.find(','); headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate @@ -719,8 +766,6 @@ void FrameLoader::finishedParsing() m_client.dispatchDidFinishDocumentLoad(); - scrollToFragmentWithParentBoundary(m_frame.document()->url()); - checkCompleted(); if (!m_frame.view()) @@ -729,6 +774,7 @@ void FrameLoader::finishedParsing() // Check if the scrollbars are really needed for the content. // If not, remove them, relayout, and repaint. m_frame.view()->restoreScrollbar(); + scrollToFragmentWithParentBoundary(m_frame.document()->url()); } void FrameLoader::loadDone() @@ -756,6 +802,7 @@ bool FrameLoader::allAncestorsAreComplete() const void FrameLoader::checkCompleted() { + Ref<Frame> protect(m_frame); m_shouldCallCheckCompleted = false; // Have we completed before? @@ -767,7 +814,7 @@ void FrameLoader::checkCompleted() return; // Still waiting for images/scripts? - if (m_frame.document()->cachedResourceLoader().requestCount()) + if (m_frame.document()->cachedResourceLoader()->requestCount()) return; // Still waiting for elements that don't go through a FrameLoader? @@ -778,14 +825,9 @@ void FrameLoader::checkCompleted() if (!allChildrenAreComplete()) return; - // Important not to protect earlier in this function, because earlier parts - // of this function can be called in the frame's destructor, and it's not legal - // to ref an object while it's being destroyed. - Ref<Frame> protect(m_frame); - // OK, completed. m_isComplete = true; - m_requestedHistoryItem = nullptr; + m_requestedHistoryItem = 0; m_frame.document()->setReadyState(Document::Complete); #if PLATFORM(IOS) @@ -809,7 +851,7 @@ void FrameLoader::checkCompleted() checkLoadComplete(); } -void FrameLoader::checkTimerFired() +void FrameLoader::checkTimerFired(Timer<FrameLoader>&) { Ref<Frame> protect(m_frame); @@ -877,13 +919,12 @@ void FrameLoader::loadURLIntoChildFrame(const URL& url, const String& referer, F HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName()); if (childItem) { childFrame->loader().m_requestedHistoryItem = childItem; - childFrame->loader().loadDifferentDocumentItem(*childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem); + childFrame->loader().loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem); return; } } - FrameLoadRequest frameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), "_self", LockHistory::No, LockBackForwardList::Yes, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress, ReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy::ShouldNotAllow); - childFrame->loader().loadURL(frameLoadRequest, referer, FrameLoadType::RedirectWithLockedBackForwardList, 0, 0); + childFrame->loader().loadURL(url, referer, "_self", false, FrameLoadTypeRedirectWithLockedBackForwardList, 0, 0); } #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) @@ -893,9 +934,8 @@ void FrameLoader::loadArchive(PassRefPtr<Archive> archive) ASSERT(mainResource); if (!mainResource) return; - - ResourceResponse response(URL(), mainResource->mimeType(), mainResource->data()->size(), mainResource->textEncoding()); - SubstituteData substituteData(mainResource->data(), URL(), response, SubstituteData::SessionHistoryVisibility::Hidden); + + SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), URL()); ResourceRequest request(mainResource->url()); #if PLATFORM(MAC) @@ -908,6 +948,41 @@ void FrameLoader::loadArchive(PassRefPtr<Archive> archive) } #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) +ObjectContentType FrameLoader::defaultObjectContentType(const URL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages) +{ + String mimeType = mimeTypeIn; + + if (mimeType.isEmpty()) + mimeType = mimeTypeFromURL(url); + +#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL + if (mimeType.isEmpty()) { + String decodedPath = decodeURLEscapeSequences(url.path()); + mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1)); + } +#endif + + if (mimeType.isEmpty()) + return ObjectContentFrame; // Go ahead and hope that we can display the content. + +#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL + bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType); +#else + bool plugInSupportsMIMEType = false; +#endif + + if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) + return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage; + + if (plugInSupportsMIMEType) + return WebCore::ObjectContentNetscapePlugin; + + if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) + return WebCore::ObjectContentFrame; + + return WebCore::ObjectContentNone; +} + String FrameLoader::outgoingReferrer() const { // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources @@ -959,9 +1034,9 @@ void FrameLoader::setOpener(Frame* opener) void FrameLoader::handleFallbackContent() { HTMLFrameOwnerElement* owner = m_frame.ownerElement(); - if (!is<HTMLObjectElement>(owner)) + if (!owner || !owner->hasTagName(objectTag)) return; - downcast<HTMLObjectElement>(*owner).renderFallbackContent(); + toHTMLObjectElement(owner)->renderFallbackContent(); } void FrameLoader::provisionalLoadStarted() @@ -1074,18 +1149,37 @@ void FrameLoader::completed() parent->loader().checkCompleted(); if (m_frame.view()) - m_frame.view()->maintainScrollPositionAtAnchor(nullptr); + m_frame.view()->maintainScrollPositionAtAnchor(0); m_activityAssertion = nullptr; } void FrameLoader::started() { if (m_frame.page()) - m_activityAssertion = m_frame.page()->pageThrottler().pageLoadActivityToken(); + m_activityAssertion = m_frame.page()->createActivityToken(); for (Frame* frame = &m_frame; frame; frame = frame->tree().parent()) frame->loader().m_isComplete = false; } +void FrameLoader::prepareForHistoryNavigation() +{ + // If there is no currentItem, but we still want to engage in + // history navigation we need to manufacture one, and update + // the state machine of this frame to impersonate having + // loaded it. + RefPtr<HistoryItem> currentItem = history().currentItem(); + if (!currentItem) { + currentItem = HistoryItem::create(); + currentItem->setLastVisitWasFailure(true); + history().setCurrentItem(currentItem.get()); + m_frame.page()->backForward().setCurrentItem(currentItem.get()); + + ASSERT(stateMachine()->isDisplayingInitialEmptyDocument()); + stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit); + stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad); + } +} + void FrameLoader::prepareForLoadStart() { m_progressTracker->progressStarted(); @@ -1093,7 +1187,7 @@ void FrameLoader::prepareForLoadStart() if (AXObjectCache::accessibilityEnabled()) { if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) { - AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadType::Reload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted; + AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted; cache->frameLoadingEventNotification(&m_frame, loadingEvent); } } @@ -1104,11 +1198,12 @@ void FrameLoader::setupForReplace() m_client.revertToProvisionalState(m_documentLoader.get()); setState(FrameStateProvisional); m_provisionalDocumentLoader = m_documentLoader; - m_documentLoader = nullptr; + m_documentLoader = 0; detachChildren(); } -void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, Event* event, PassRefPtr<FormState> formState) +void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, + PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer) { // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader. Ref<Frame> protect(m_frame); @@ -1126,21 +1221,21 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, Event* event argsReferrer = outgoingReferrer(); String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), url, argsReferrer); - if (request.shouldSendReferrer() == NeverSendReferrer) + if (shouldSendReferrer == NeverSendReferrer) referrer = String(); - + FrameLoadType loadType; if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData) - loadType = FrameLoadType::Reload; - else if (request.lockBackForwardList() == LockBackForwardList::Yes) - loadType = FrameLoadType::RedirectWithLockedBackForwardList; + loadType = FrameLoadTypeReload; + else if (lockBackForwardList) + loadType = FrameLoadTypeRedirectWithLockedBackForwardList; else - loadType = FrameLoadType::Standard; + loadType = FrameLoadTypeStandard; if (request.resourceRequest().httpMethod() == "POST") - loadPostRequest(request, referrer, loadType, event, formState.get()); + loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get()); else - loadURL(request, referrer, loadType, event, formState.get()); + loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get()); // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual // load if frame names have changed. @@ -1154,30 +1249,17 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, Event* event } } -static ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicyToApply(Frame& sourceFrame, ShouldOpenExternalURLsPolicy propagatedPolicy) -{ - if (!sourceFrame.isMainFrame()) - return ShouldOpenExternalURLsPolicy::ShouldNotAllow; - if (ScriptController::processingUserGesture()) - return ShouldOpenExternalURLsPolicy::ShouldAllow; - return propagatedPolicy; -} - -void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String& referrer, FrameLoadType newLoadType, Event* event, PassRefPtr<FormState> prpFormState) +void FrameLoader::loadURL(const URL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType, + PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState) { if (m_inStopAllLoaders) return; Ref<Frame> protect(m_frame); - String frameName = frameLoadRequest.frameName(); - AllowNavigationToInvalidURL allowNavigationToInvalidURL = frameLoadRequest.allowNavigationToInvalidURL(); - NewFrameOpenerPolicy openerPolicy = frameLoadRequest.newFrameOpenerPolicy(); - LockHistory lockHistory = frameLoadRequest.lockHistory(); RefPtr<FormState> formState = prpFormState; bool isFormSubmission = formState; - - const URL& newURL = frameLoadRequest.resourceRequest().url(); + ResourceRequest request(newURL); if (!referrer.isEmpty()) { request.setHTTPReferrer(referrer); @@ -1186,32 +1268,29 @@ void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String } #if ENABLE(CACHE_PARTITIONING) if (&m_frame.tree().top() != &m_frame) - request.setDomainForCachePartition(m_frame.tree().top().document()->securityOrigin()->domainForCachePartition()); + request.setCachePartition(m_frame.tree().top().document()->securityOrigin()->cachePartition()); #endif addExtraFieldsToRequest(request, newLoadType, true); - if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin) + if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin) request.setCachePolicy(ReloadIgnoringCacheData); - ASSERT(newLoadType != FrameLoadType::Same); + ASSERT(newLoadType != FrameLoadTypeSame); // The search for a target frame is done earlier in the case of form submission. Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName); if (targetFrame && targetFrame != &m_frame) { - FrameLoadRequest newFrameLoadRequest(frameLoadRequest); - newFrameLoadRequest.setFrameName("_self"); - targetFrame->loader().loadURL(newFrameLoadRequest, referrer, newLoadType, event, formState.release()); + targetFrame->loader().loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release()); return; } - if (m_pageDismissalEventBeingDispatched != PageDismissalType::None) + if (m_pageDismissalEventBeingDispatched != NoDismissal) return; - NavigationAction action(request, newLoadType, isFormSubmission, event, frameLoadRequest.shouldOpenExternalURLsPolicy()); + NavigationAction action(request, newLoadType, isFormSubmission, event); if (!targetFrame && !frameName.isEmpty()) { - action = action.copyWithShouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicyToApply(m_frame, frameLoadRequest.shouldOpenExternalURLsPolicy())); - policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this, allowNavigationToInvalidURL, openerPolicy](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { - continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy); + policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { + continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue); }); return; } @@ -1237,16 +1316,16 @@ void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String // must grab this now, since this load may stop the previous load and clear this flag bool isRedirect = m_quickRedirectComing; - loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release(), allowNavigationToInvalidURL); + loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release()); if (isRedirect) { m_quickRedirectComing = false; if (m_provisionalDocumentLoader) m_provisionalDocumentLoader->setIsClientRedirect(true); - } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) { + } else if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin) { // Example of this case are sites that reload the same URL with a different cookie // driving the generated content, or a master frame with links that drive a target // frame, where the user has clicked on the same link repeatedly. - m_loadType = FrameLoadType::Same; + m_loadType = FrameLoadTypeSame; } } @@ -1257,9 +1336,7 @@ SubstituteData FrameLoader::defaultSubstituteDataForURL(const URL& url) String srcdoc = m_frame.ownerElement()->fastGetAttribute(srcdocAttr); ASSERT(!srcdoc.isNull()); CString encodedSrcdoc = srcdoc.utf8(); - - ResourceResponse response(URL(), ASCIILiteral("text/html"), encodedSrcdoc.length(), ASCIILiteral("UTF-8")); - return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), URL(), response, SubstituteData::SessionHistoryVisibility::Hidden); + return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", URL()); } void FrameLoader::load(const FrameLoadRequest& passedRequest) @@ -1281,9 +1358,8 @@ void FrameLoader::load(const FrameLoadRequest& passedRequest) } if (request.shouldCheckNewWindowPolicy()) { - NavigationAction action(request.resourceRequest(), NavigationType::Other, passedRequest.shouldOpenExternalURLsPolicy()); - policyChecker().checkNewWindowPolicy(action, request.resourceRequest(), nullptr, request.frameName(), [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { - continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress); + policyChecker().checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), request.resourceRequest(), nullptr, request.frameName(), [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { + continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue); }); return; @@ -1292,25 +1368,23 @@ void FrameLoader::load(const FrameLoadRequest& passedRequest) if (!request.hasSubstituteData()) request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url())); - Ref<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData()); - applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, request.shouldOpenExternalURLsPolicy()); - - load(loader.ptr()); + RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData()); + if (request.lockHistory() && m_documentLoader) + loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory()); + load(loader.get()); } -void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, LockHistory lockHistory, FrameLoadType type, PassRefPtr<FormState> formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL) +void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState) { - Ref<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); - applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, action.shouldOpenExternalURLsPolicy()); - - if (lockHistory == LockHistory::Yes && m_documentLoader) + RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); + if (lockHistory && m_documentLoader) loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory()); loader->setTriggeringAction(action); if (m_documentLoader) loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); - loadWithDocumentLoader(loader.ptr(), type, formState, allowNavigationToInvalidURL); + loadWithDocumentLoader(loader.get(), type, formState); } void FrameLoader::load(DocumentLoader* newDocumentLoader) @@ -1321,11 +1395,11 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader) if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) { r.setCachePolicy(ReloadIgnoringCacheData); - type = FrameLoadType::Same; - } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadType::Reload) - type = FrameLoadType::Reload; + type = FrameLoadTypeSame; + } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadTypeReload) + type = FrameLoadTypeReload; else - type = FrameLoadType::Standard; + type = FrameLoadTypeStandard; if (m_documentLoader) newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding()); @@ -1334,7 +1408,7 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader) // visiting in the history list, we treat it as a reload so the history list // is appropriately maintained. // - // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadType::Reload" ... + // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ... // shouldn't a more explicit type of reload be defined, that means roughly // "load without affecting history" ? if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) { @@ -1343,47 +1417,14 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader) // changed and updateForBackForwardNavigation() will not be called when loading is committed. history().saveDocumentAndScrollState(); - ASSERT(type == FrameLoadType::Standard); - type = FrameLoadType::Reload; + ASSERT(type == FrameLoadTypeStandard); + type = FrameLoadTypeReload; } - loadWithDocumentLoader(newDocumentLoader, type, 0, AllowNavigationToInvalidURL::Yes); + loadWithDocumentLoader(newDocumentLoader, type, 0); } -static void logNavigation(MainFrame& frame, FrameLoadType type) -{ - String navigationDescription; - switch (type) { - case FrameLoadType::Standard: - navigationDescription = ASCIILiteral("standard"); - break; - case FrameLoadType::Back: - navigationDescription = ASCIILiteral("back"); - break; - case FrameLoadType::Forward: - navigationDescription = ASCIILiteral("forward"); - break; - case FrameLoadType::IndexedBackForward: - navigationDescription = ASCIILiteral("indexedBackForward"); - break; - case FrameLoadType::Reload: - navigationDescription = ASCIILiteral("reload"); - break; - case FrameLoadType::Same: - navigationDescription = ASCIILiteral("same"); - break; - case FrameLoadType::ReloadFromOrigin: - navigationDescription = ASCIILiteral("reloadFromOrigin"); - break; - case FrameLoadType::Replace: - case FrameLoadType::RedirectWithLockedBackForwardList: - // Not logging those for now. - return; - } - frame.diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription, ShouldSample::No); -} - -void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL) +void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState) { // Retain because dispatchBeforeLoadEvent may release the last reference to it. Ref<Frame> protect(m_frame); @@ -1395,16 +1436,12 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t ASSERT(m_frame.view()); - if (m_pageDismissalEventBeingDispatched != PageDismissalType::None) + if (m_pageDismissalEventBeingDispatched != NoDismissal) return; if (m_frame.document()) m_previousURL = m_frame.document()->url(); - // Log main frame navigation types. - if (m_frame.isMainFrame()) - logNavigation(static_cast<MainFrame&>(m_frame), type); - policyChecker().setLoadType(type); RefPtr<FormState> formState = prpFormState; bool isFormSubmission = formState; @@ -1441,13 +1478,13 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t // a new URL, the parent frame shouldn't learn the URL. if (!m_stateMachine.committedFirstRealDocumentLoad() && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) { - continueLoadAfterNavigationPolicy(loader->request(), formState, false, allowNavigationToInvalidURL); + continueLoadAfterNavigationPolicy(loader->request(), formState, false); return; } } - policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) { - continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL); + policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) { + continueLoadAfterNavigationPolicy(request, formState, shouldContinue); }); } @@ -1457,16 +1494,7 @@ void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) if (!frame) return; - frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to load local resource: " + url); -} - -void FrameLoader::reportBlockedPortFailed(Frame* frame, const String& url) -{ - ASSERT(!url.isEmpty()); - if (!frame) - return; - - frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to use restricted network port: " + url); + frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url); } const ResourceRequest& FrameLoader::initialRequest() const @@ -1488,7 +1516,7 @@ bool FrameLoader::willLoadMediaElementURL(URL& url) unsigned long identifier; ResourceError error; requestFromDelegate(request, identifier, error); - notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String()), 0, -1, -1, error); + notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error); url = request.url(); @@ -1510,10 +1538,13 @@ bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) // case handles well-formed URLs that can't be loaded, and the latter // case handles malformed URLs and unknown schemes. Loading alternate content // at other times behaves like a standard load. + DocumentLoader* compareDocumentLoader = 0; if (policyChecker().delegateIsDecidingNavigationPolicy() || policyChecker().delegateIsHandlingUnimplementablePolicy()) - return m_policyDocumentLoader && unreachableURL == m_policyDocumentLoader->request().url(); + compareDocumentLoader = m_policyDocumentLoader.get(); + else if (m_delegateIsHandlingProvisionalLoadError) + compareDocumentLoader = m_provisionalDocumentLoader.get(); - return unreachableURL == m_provisionalLoadErrorBeingHandledURL; + return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url(); } void FrameLoader::reloadWithOverrideEncoding(const String& encoding) @@ -1530,17 +1561,28 @@ void FrameLoader::reloadWithOverrideEncoding(const String& encoding) // We should ask the user for confirmation in this case. request.setCachePolicy(ReturnCacheDataElseLoad); - Ref<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); - applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, m_documentLoader->shouldOpenExternalURLsPolicyToPropagate()); - - setPolicyDocumentLoader(loader.ptr()); + RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); + setPolicyDocumentLoader(loader.get()); loader->setOverrideEncoding(encoding); - loadWithDocumentLoader(loader.ptr(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes); + loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0); +} + +void FrameLoader::reloadWithOverrideURL(const URL& overrideUrl, bool endToEndReload) +{ + if (!m_documentLoader) + return; + + if (overrideUrl.isEmpty()) + return; + + ResourceRequest request = m_documentLoader->request(); + request.setURL(overrideUrl); + reloadWithRequest(request, endToEndReload); } -void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled) +void FrameLoader::reload(bool endToEndReload) { if (!m_documentLoader) return; @@ -1556,13 +1598,17 @@ void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled) if (!unreachableURL.isEmpty()) initialRequest.setURL(unreachableURL); + reloadWithRequest(initialRequest, endToEndReload); +} + +void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool endToEndReload) +{ + ASSERT(m_documentLoader); + // Create a new document loader for the reload, this will become m_documentLoader eventually, // but first it has to be the "policy" document loader, and then the "provisional" document loader. - Ref<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url())); - applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, m_documentLoader->shouldOpenExternalURLsPolicyToPropagate()); + RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url())); - loader->setUserContentExtensionsEnabled(contentBlockersEnabled); - ResourceRequest& request = loader->request(); // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment. @@ -1570,17 +1616,17 @@ void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled) // If we're about to re-post, set up action so the application can warn the user. if (request.httpMethod() == "POST") - loader->setTriggeringAction(NavigationAction(request, NavigationType::FormResubmitted)); + loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted)); loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); - loadWithDocumentLoader(loader.ptr(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes); + loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0); } void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy) { ASSERT(!m_frame.document() || !m_frame.document()->inPageCache()); - if (m_pageDismissalEventBeingDispatched != PageDismissalType::None) + if (m_pageDismissalEventBeingDispatched != NoDismissal) return; // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this. @@ -1598,7 +1644,7 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem // If no new load is in progress, we should clear the provisional item from history // before we call stopLoading. if (clearProvisionalItemPolicy == ShouldClearProvisionalItem) - history().setProvisionalItem(nullptr); + history().setProvisionalItem(0); for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) child->loader().stopAllLoaders(clearProvisionalItemPolicy); @@ -1607,7 +1653,7 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem if (m_documentLoader) m_documentLoader->stopLoading(); - setProvisionalDocumentLoader(nullptr); + setProvisionalDocumentLoader(0); m_checkTimer.stop(); @@ -1616,9 +1662,6 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete) { - // Calling stopAllLoaders can cause the frame to be deallocated, including the frame loader. - Ref<Frame> protectedFrame(m_frame); - stopAllLoaders(); #if PLATFORM(IOS) @@ -1688,7 +1731,7 @@ void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) return; if (loader) - loader->attachToFrame(m_frame); + loader->setFrame(&m_frame); if (m_policyDocumentLoader && m_policyDocumentLoader != m_provisionalDocumentLoader && m_policyDocumentLoader != m_documentLoader) @@ -1723,7 +1766,7 @@ void FrameLoader::setState(FrameState newState) void FrameLoader::clearProvisionalLoad() { - setProvisionalDocumentLoader(nullptr); + setProvisionalDocumentLoader(0); m_progressTracker->progressCompleted(); setState(FrameStateComplete); } @@ -1734,8 +1777,8 @@ void FrameLoader::commitProvisionalLoad() Ref<Frame> protect(m_frame); std::unique_ptr<CachedPage> cachedPage; - if (m_loadingFromCachedPage && history().provisionalItem()) - cachedPage = PageCache::singleton().take(*history().provisionalItem(), m_frame.page()); + if (m_loadingFromCachedPage) + cachedPage = pageCache()->take(history().provisionalItem()); LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame.tree().uniqueName().string().utf8().data(), m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "", @@ -1748,35 +1791,28 @@ void FrameLoader::commitProvisionalLoad() // page cache. We could still preemptively prune the page cache while navigating to a cached page if capacity > 1. // See <rdar://problem/11779846> for more details. if (!cachedPage) { - if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) { + if (memoryPressureHandler().hasReceivedMemoryPressure()) { LOG(MemoryPressure, "Pruning page cache because under memory pressure at: %s", __PRETTY_FUNCTION__); LOG(PageCache, "Pruning page cache to 0 due to memory pressure"); // Don't cache any page if we are under memory pressure. - PageCache::singleton().pruneToSizeNow(0, PruningReason::MemoryPressure); + pageCache()->pruneToCapacityNow(0); } else if (systemMemoryLevel() <= memoryLevelThresholdToPrunePageCache) { LOG(MemoryPressure, "Pruning page cache because system memory level is %d at: %s", systemMemoryLevel(), __PRETTY_FUNCTION__); - auto& pageCache = PageCache::singleton(); - LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache.maxSize() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache); - pageCache.pruneToSizeNow(pageCache.maxSize() / 2, PruningReason::MemoryPressure); + LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache()->capacity() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache); + pageCache()->pruneToCapacityNow(pageCache()->capacity() / 2); } } #endif willTransitionToCommitted(); - if (!m_frame.tree().parent() && history().currentItem()) { - // Check to see if we need to cache the page we are navigating away from into the back/forward cache. - // We are doing this here because we know for sure that a new page is about to be loaded. - PageCache::singleton().addIfCacheable(*history().currentItem(), m_frame.page()); + // Check to see if we need to cache the page we are navigating away from into the back/forward cache. + // We are doing this here because we know for sure that a new page is about to be loaded. + HistoryItem* item = history().currentItem(); + if (!m_frame.tree().parent() && pageCache()->canCache(m_frame.page()) && !item->isInPageCache()) + pageCache()->add(item, *m_frame.page()); -#if PLATFORM(IOS) - // For top-level navigations, have JSC throw away linked code. The immediate memory savings far - // outweigh the cost of recompiling in the case of a future backwards navigation. - GCController::singleton().deleteAllLinkedCode(); -#endif - } - - if (m_loadType != FrameLoadType::Replace) + if (m_loadType != FrameLoadTypeReplace) closeOldDataSources(); if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument()) @@ -1786,8 +1822,8 @@ void FrameLoader::commitProvisionalLoad() if (pdl && m_documentLoader) { // Check if the destination page is allowed to access the previous page's timing information. - Ref<SecurityOrigin> securityOrigin(SecurityOrigin::create(pdl->request().url())); - m_documentLoader->timing().setHasSameOriginAsPreviousDocument(securityOrigin.get().canRequest(m_previousURL)); + RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url()); + m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousURL)); } // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's @@ -1805,14 +1841,6 @@ void FrameLoader::commitProvisionalLoad() #endif prepareForCachedPageRestore(); - // Start request for the main resource and dispatch didReceiveResponse before the load is committed for - // consistency with all other loads. See https://bugs.webkit.org/show_bug.cgi?id=150927. - ResourceError mainResouceError; - unsigned long mainResourceIdentifier; - ResourceRequest mainResourceRequest(cachedPage->documentLoader()->request()); - requestFromDelegate(mainResourceRequest, mainResourceIdentifier, mainResouceError); - notifier().dispatchDidReceiveResponse(cachedPage->documentLoader(), mainResourceIdentifier, cachedPage->documentLoader()->response()); - // FIXME: This API should be turned around so that we ground CachedPage into the Page. cachedPage->restore(*m_frame.page()); @@ -1826,10 +1854,6 @@ void FrameLoader::commitProvisionalLoad() if (!title.isNull()) m_client.dispatchDidReceiveTitle(title); - // Send remaining notifications for the main resource. - notifier().sendRemainingDelegateMessages(m_documentLoader.get(), mainResourceIdentifier, mainResourceRequest, ResourceResponse(), - nullptr, static_cast<int>(m_documentLoader->response().expectedContentLength()), 0, mainResouceError); - checkCompleted(); } else didOpenURL(); @@ -1837,7 +1861,7 @@ void FrameLoader::commitProvisionalLoad() LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame.tree().uniqueName().string().utf8().data(), m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : ""); - if (m_loadType == FrameLoadType::Standard && m_documentLoader->isClientRedirect()) + if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect()) history().updateForClientRedirect(); if (m_loadingFromCachedPage) { @@ -1846,19 +1870,19 @@ void FrameLoader::commitProvisionalLoad() if (m_frame.document()->doctype() && m_frame.page()) m_frame.page()->chrome().didReceiveDocType(&m_frame); #endif - m_frame.document()->resume(ActiveDOMObject::PageCache); + m_frame.document()->documentDidResumeFromPageCache(); // Force a layout to update view size and thereby update scrollbars. #if PLATFORM(IOS) - if (!m_client.forceLayoutOnRestoreFromPageCache()) - m_frame.view()->forceLayout(); + m_client.forceLayoutWithoutRecalculatingStyles(); #else m_frame.view()->forceLayout(); #endif - // Main resource delegates were already sent, so we skip the first response here. - for (unsigned i = 1; i < m_documentLoader->responses().size(); ++i) { - const auto& response = m_documentLoader->responses()[i]; + const ResponseVector& responses = m_documentLoader->responses(); + size_t count = responses.size(); + for (size_t i = 0; i < count; i++) { + const ResourceResponse& response = responses[i]; // FIXME: If the WebKit client changes or cancels the request, this is not respected. ResourceError error; unsigned long identifier; @@ -1907,7 +1931,7 @@ void FrameLoader::transitionToCommitted(CachedPage* cachedPage) m_documentLoader->stopLoadingPlugIns(); setDocumentLoader(m_provisionalDocumentLoader.get()); - setProvisionalDocumentLoader(nullptr); + setProvisionalDocumentLoader(0); if (pdl != m_documentLoader) { ASSERT(m_state == FrameStateComplete); @@ -1925,57 +1949,57 @@ void FrameLoader::transitionToCommitted(CachedPage* cachedPage) DocumentLoader* dl = m_documentLoader.get(); switch (m_loadType) { - case FrameLoadType::Forward: - case FrameLoadType::Back: - case FrameLoadType::IndexedBackForward: - if (m_frame.page()) { - // If the first load within a frame is a navigation within a back/forward list that was attached - // without any of the items being loaded then we need to update the history in a similar manner as - // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>). - if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame()) - history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList); - - history().updateForBackForwardNavigation(); - - // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object - if (history().currentItem() && !cachedPage) - m_pendingStateObject = history().currentItem()->stateObject(); - - // Create a document view for this document, or used the cached view. - if (cachedPage) { - DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader(); - ASSERT(cachedDocumentLoader); - cachedDocumentLoader->attachToFrame(m_frame); - m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame()); - } else - m_client.transitionToCommittedForNewPage(); - } - break; - - case FrameLoadType::Reload: - case FrameLoadType::ReloadFromOrigin: - case FrameLoadType::Same: - case FrameLoadType::Replace: - history().updateForReload(); - m_client.transitionToCommittedForNewPage(); - break; - - case FrameLoadType::Standard: - history().updateForStandardLoad(); - if (m_frame.view()) - m_frame.view()->setScrollbarsSuppressed(true); - m_client.transitionToCommittedForNewPage(); - break; - - case FrameLoadType::RedirectWithLockedBackForwardList: - history().updateForRedirectWithLockedBackForwardList(); - m_client.transitionToCommittedForNewPage(); - break; - - // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). - // An exception should be thrown if we're in the FrameLoadTypeUninitialized state. - default: - ASSERT_NOT_REACHED(); + case FrameLoadTypeForward: + case FrameLoadTypeBack: + case FrameLoadTypeIndexedBackForward: + if (m_frame.page()) { + // If the first load within a frame is a navigation within a back/forward list that was attached + // without any of the items being loaded then we need to update the history in a similar manner as + // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>). + if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame()) + history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList); + + history().updateForBackForwardNavigation(); + + // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object + if (history().currentItem() && !cachedPage) + m_pendingStateObject = history().currentItem()->stateObject(); + + // Create a document view for this document, or used the cached view. + if (cachedPage) { + DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader(); + ASSERT(cachedDocumentLoader); + cachedDocumentLoader->setFrame(&m_frame); + m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame()); + } else + m_client.transitionToCommittedForNewPage(); + } + break; + + case FrameLoadTypeReload: + case FrameLoadTypeReloadFromOrigin: + case FrameLoadTypeSame: + case FrameLoadTypeReplace: + history().updateForReload(); + m_client.transitionToCommittedForNewPage(); + break; + + case FrameLoadTypeStandard: + history().updateForStandardLoad(); + if (m_frame.view()) + m_frame.view()->setScrollbarsSuppressed(true); + m_client.transitionToCommittedForNewPage(); + break; + + case FrameLoadTypeRedirectWithLockedBackForwardList: + history().updateForRedirectWithLockedBackForwardList(); + m_client.transitionToCommittedForNewPage(); + break; + + // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). + // An exception should be thrown if we're in the FrameLoadTypeUninitialized state. + default: + ASSERT_NOT_REACHED(); } m_documentLoader->writer().setMIMEType(dl->responseMIMEType()); @@ -2003,7 +2027,7 @@ void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres m_sentRedirectNotification = false; } -void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, LockBackForwardList lockBackForwardList) +void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, bool lockBackForwardList) { m_client.dispatchWillPerformClientRedirect(url, seconds, fireDate); @@ -2015,7 +2039,7 @@ void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDa // load as part of the original navigation. If we don't have a document loader, we have // no "original" load on which to base a redirect, so we treat the redirect as a normal load. // Loads triggered by JavaScript form submissions never count as quick redirects. - m_quickRedirectComing = (lockBackForwardList == LockBackForwardList::Yes || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction; + m_quickRedirectComing = (lockBackForwardList || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction; } bool FrameLoader::shouldReload(const URL& currentURL, const URL& destinationURL) @@ -2094,15 +2118,13 @@ void FrameLoader::open(CachedFrameBase& cachedFrame) ASSERT(view); view->setWasScrolledByUser(false); - Optional<IntRect> previousViewFrameRect = m_frame.view() ? m_frame.view()->frameRect() : Optional<IntRect>(Nullopt); + // Use the current ScrollView's frame rect. + if (m_frame.view()) + view->setFrameRect(m_frame.view()->frameRect()); m_frame.setView(view); - - // Use the previous ScrollView's frame rect. - if (previousViewFrameRect) - view->setFrameRect(previousViewFrameRect.value()); m_frame.setDocument(document); - document->domWindow()->resumeFromDocumentSuspension(); + document->domWindow()->resumeFromPageCache(); updateFirstPartyForCookies(); @@ -2117,12 +2139,12 @@ bool FrameLoader::isHostedByObjectElement() const bool FrameLoader::isReplacing() const { - return m_loadType == FrameLoadType::Replace; + return m_loadType == FrameLoadTypeReplace; } void FrameLoader::setReplacing() { - m_loadType = FrameLoadType::Replace; + m_loadType = FrameLoadTypeReplace; } bool FrameLoader::subframeIsLoading() const @@ -2158,7 +2180,7 @@ CachePolicy FrameLoader::subresourceCachePolicy() const if (m_isComplete) return CachePolicyVerify; - if (m_loadType == FrameLoadType::ReloadFromOrigin) + if (m_loadType == FrameLoadTypeReloadFromOrigin) return CachePolicyReload; if (Frame* parentFrame = m_frame.tree().parent()) { @@ -2167,24 +2189,18 @@ CachePolicy FrameLoader::subresourceCachePolicy() const return parentCachePolicy; } - switch (m_loadType) { - case FrameLoadType::Reload: + if (m_loadType == FrameLoadTypeReload) + return CachePolicyRevalidate; + + const ResourceRequest& request(documentLoader()->request()); +#if PLATFORM(MAC) + if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks()) return CachePolicyRevalidate; - case FrameLoadType::Back: - case FrameLoadType::Forward: - case FrameLoadType::IndexedBackForward: +#endif + + if (request.cachePolicy() == ReturnCacheDataElseLoad) return CachePolicyHistoryBuffer; - case FrameLoadType::ReloadFromOrigin: - ASSERT_NOT_REACHED(); // Already handled above. - return CachePolicyReload; - case FrameLoadType::RedirectWithLockedBackForwardList: - case FrameLoadType::Replace: - case FrameLoadType::Same: - case FrameLoadType::Standard: - return CachePolicyVerify; - } - RELEASE_ASSERT_NOT_REACHED(); return CachePolicyVerify; } @@ -2194,11 +2210,7 @@ void FrameLoader::checkLoadCompleteForThisFrame() switch (m_state) { case FrameStateProvisional: { - // FIXME: Prohibiting any provisional load failures from being sent to clients - // while handling provisional load failures is too heavy. For example, the current - // load will fail to cancel another ongoing load. That might prevent clients' page - // load state being handled properly. - if (!m_provisionalLoadErrorBeingHandledURL.isEmpty()) + if (m_delegateIsHandlingProvisionalLoadError) return; RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; @@ -2220,9 +2232,9 @@ void FrameLoader::checkLoadCompleteForThisFrame() // Only reset if we aren't already going to a new provisional item. bool shouldReset = !history().provisionalItem(); if (!pdl->isLoadingInAPISense() || pdl->isStopping()) { - m_provisionalLoadErrorBeingHandledURL = m_provisionalDocumentLoader->url(); + m_delegateIsHandlingProvisionalLoadError = true; m_client.dispatchDidFailProvisionalLoad(error); - m_provisionalLoadErrorBeingHandledURL = { }; + m_delegateIsHandlingProvisionalLoadError = false; ASSERT(!pdl->isLoading()); @@ -2263,7 +2275,7 @@ void FrameLoader::checkLoadCompleteForThisFrame() // If the user had a scroll point, scroll to it, overriding the anchor point if any. if (m_frame.page()) { - if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin) + if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) history().restoreScrollPositionAndViewState(); } @@ -2271,8 +2283,7 @@ void FrameLoader::checkLoadCompleteForThisFrame() return; m_progressTracker->progressCompleted(); - Page* page = m_frame.page(); - if (page) { + if (Page* page = m_frame.page()) { if (m_frame.isMainFrame()) page->resetRelevantPaintedObjectCounter(); } @@ -2284,14 +2295,6 @@ void FrameLoader::checkLoadCompleteForThisFrame() m_client.dispatchDidFailLoad(error); loadingEvent = AXObjectCache::AXLoadingFailed; } else { -#if ENABLE(DATA_DETECTION) - if (m_frame.settings().dataDetectorTypes() != DataDetectorTypeNone) { - RefPtr<Range> documentRange = makeRange(firstPositionInNode(m_frame.document()->documentElement()), lastPositionInNode(m_frame.document()->documentElement())); - m_frame.setDataDetectionResults(DataDetection::detectContentInRange(documentRange, m_frame.settings().dataDetectorTypes())); - if (m_frame.isMainFrame()) - m_client.dispatchDidFinishDataDetection(m_frame.dataDetectionResults()); - } -#endif m_client.dispatchDidFinishLoad(); loadingEvent = AXObjectCache::AXLoadingFinished; } @@ -2300,19 +2303,11 @@ void FrameLoader::checkLoadCompleteForThisFrame() if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) cache->frameLoadingEventNotification(&m_frame, loadingEvent); - // The above calls to dispatchDidFinishLoad() might have detached the Frame - // from its Page and also might have caused Page to be deleted. - // Don't assume 'page' is still available to use. - if (m_frame.isMainFrame() && m_frame.page()) { - ASSERT(&m_frame.page()->mainFrame() == &m_frame); - m_frame.page()->mainFrame().diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageLoadedKey(), emptyString(), error.isNull() ? DiagnosticLoggingResultPass : DiagnosticLoggingResultFail, ShouldSample::Yes); - } - return; } case FrameStateComplete: - m_loadType = FrameLoadType::Standard; + m_loadType = FrameLoadTypeStandard; frameLoadCompleted(); return; } @@ -2385,7 +2380,7 @@ void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request) // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user. String hostOnlyURLString; if (port) - hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ':', String::number(port)); + hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ":", String::number(port)); else hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host()); @@ -2433,25 +2428,19 @@ void FrameLoader::frameLoadCompleted() void FrameLoader::detachChildren() { - // detachChildren() will fire the unload event in each subframe and the - // HTML specification states that the parent document's ignore-opens-during-unload counter while - // this event is being fired in its subframes: - // https://html.spec.whatwg.org/multipage/browsers.html#unload-a-document - IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document()); - Vector<Ref<Frame>, 16> childrenToDetach; childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount()); for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling()) childrenToDetach.uncheckedAppend(*child); - for (auto& child : childrenToDetach) - child->loader().detachFromParent(); + for (unsigned i = 0; i < childrenToDetach.size(); ++i) + childrenToDetach[i]->loader().detachFromParent(); } void FrameLoader::closeAndRemoveChild(Frame* child) { child->tree().detachFromParent(); - child->setView(nullptr); + child->setView(0); if (child->ownerElement() && child->page()) child->page()->decrementSubframeCount(); child->willDetachPage(); @@ -2477,20 +2466,18 @@ void FrameLoader::checkLoadComplete() frames.append(*frame); // To process children before their parents, iterate the vector backwards. - for (auto frame = frames.rbegin(); frame != frames.rend(); ++frame) { - if ((*frame)->page()) - (*frame)->loader().checkLoadCompleteForThisFrame(); - } + for (unsigned i = frames.size(); i; --i) + frames[i - 1]->loader().checkLoadCompleteForThisFrame(); } int FrameLoader::numPendingOrLoadingRequests(bool recurse) const { if (!recurse) - return m_frame.document()->cachedResourceLoader().requestCount(); + return m_frame.document()->cachedResourceLoader()->requestCount(); int count = 0; for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame)) - count += frame->document()->cachedResourceLoader().requestCount(); + count += frame->document()->cachedResourceLoader()->requestCount(); return count; } @@ -2499,19 +2486,16 @@ String FrameLoader::userAgent(const URL& url) const return m_client.userAgent(url); } -void FrameLoader::dispatchOnloadEvents() +void FrameLoader::handledOnloadEvents() { - m_client.dispatchDidDispatchOnloadEvents(); + m_client.dispatchDidHandleOnloadEvents(); if (documentLoader()) - documentLoader()->dispatchOnloadEvents(); + documentLoader()->handledOnloadEvents(); } void FrameLoader::frameDetached() { - // Calling stopAllLoaders can cause the frame to be deallocated, including the frame loader. - Ref<Frame> protectedFrame(m_frame); - stopAllLoaders(); m_frame.document()->stopActiveDOMObjects(); detachFromParent(); @@ -2529,7 +2513,7 @@ void FrameLoader::detachFromParent() // handlers might start a new subresource load in this frame. stopAllLoaders(); - InspectorInstrumentation::frameDetachedFromParent(m_frame); + InspectorInstrumentation::frameDetachedFromParent(&m_frame); detachViewsAndDocumentLoader(); @@ -2539,7 +2523,7 @@ void FrameLoader::detachFromParent() parent->loader().closeAndRemoveChild(&m_frame); parent->loader().scheduleCheckCompleted(); } else { - m_frame.setView(nullptr); + m_frame.setView(0); m_frame.willDetachPage(); m_frame.detachFromPage(); } @@ -2548,7 +2532,7 @@ void FrameLoader::detachFromParent() void FrameLoader::detachViewsAndDocumentLoader() { m_client.detachedFromParent2(); - setDocumentLoader(nullptr); + setDocumentLoader(0); m_client.detachedFromParent3(); } @@ -2602,20 +2586,15 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading. // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest(). - } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional()) + } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional()) request.setCachePolicy(ReloadIgnoringCacheData); - if (m_overrideCachePolicyForTesting) - request.setCachePolicy(m_overrideCachePolicyForTesting.value()); - if (m_overrideResourceLoadPriorityForTesting) - request.setPriority(m_overrideResourceLoadPriorityForTesting.value()); - if (request.cachePolicy() == ReloadIgnoringCacheData) { - if (loadType == FrameLoadType::Reload) - request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0"); - else if (loadType == FrameLoadType::ReloadFromOrigin) { - request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache"); - request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache"); + if (loadType == FrameLoadTypeReload) + request.setHTTPHeaderField("Cache-Control", "max-age=0"); + else if (loadType == FrameLoadTypeReloadFromOrigin) { + request.setHTTPHeaderField("Cache-Control", "no-cache"); + request.setHTTPHeaderField("Pragma", "no-cache"); } } @@ -2659,17 +2638,16 @@ void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& request.setHTTPOrigin(origin); } -void FrameLoader::loadPostRequest(const FrameLoadRequest& request, const String& referrer, FrameLoadType loadType, Event* event, PassRefPtr<FormState> prpFormState) +void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState) { RefPtr<FormState> formState = prpFormState; - String frameName = request.frameName(); - LockHistory lockHistory = request.lockHistory(); - AllowNavigationToInvalidURL allowNavigationToInvalidURL = request.allowNavigationToInvalidURL(); - NewFrameOpenerPolicy openerPolicy = request.newFrameOpenerPolicy(); - - const ResourceRequest& inRequest = request.resourceRequest(); + // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a + // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case + // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest + // from scratch as it did all along. const URL& url = inRequest.url(); + RefPtr<FormData> formData = inRequest.httpBody(); const String& contentType = inRequest.httpContentType(); String origin = inRequest.httpOrigin(); @@ -2679,28 +2657,28 @@ void FrameLoader::loadPostRequest(const FrameLoadRequest& request, const String& workingResourceRequest.setHTTPReferrer(referrer); workingResourceRequest.setHTTPOrigin(origin); workingResourceRequest.setHTTPMethod("POST"); - workingResourceRequest.setHTTPBody(inRequest.httpBody()); + workingResourceRequest.setHTTPBody(formData); workingResourceRequest.setHTTPContentType(contentType); addExtraFieldsToRequest(workingResourceRequest, loadType, true); - NavigationAction action(workingResourceRequest, loadType, true, event, request.shouldOpenExternalURLsPolicy()); + NavigationAction action(workingResourceRequest, loadType, true, event); if (!frameName.isEmpty()) { // The search for a target frame is done earlier in the case of form submission. if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) { - targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL); + targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); return; } - policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this, allowNavigationToInvalidURL, openerPolicy](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { - continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy); + policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { + continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue); }); return; } // must grab this now, since this load may stop the previous load and clear this flag bool isRedirect = m_quickRedirectComing; - loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL); + loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); if (isRedirect) { m_quickRedirectComing = false; if (m_provisionalDocumentLoader) @@ -2708,7 +2686,7 @@ void FrameLoader::loadPostRequest(const FrameLoadRequest& request, const String& } } -unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data) +unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data) { ASSERT(m_frame.document()); String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), request.url(), outgoingReferrer()); @@ -2728,32 +2706,15 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ ResourceRequest newRequest(initialRequest); requestFromDelegate(newRequest, identifier, error); -#if ENABLE(CONTENT_EXTENSIONS) - if (error.isNull()) { - if (auto* page = m_frame.page()) { - if (auto* controller = page->userContentController()) { - if (m_documentLoader && controller->processContentExtensionRulesForLoad(newRequest, ResourceType::Raw, *m_documentLoader) == ContentExtensions::BlockedStatus::Blocked) { - newRequest = { }; - error = ResourceError(errorDomainWebKitInternal, 0, initialRequest.url(), emptyString()); - response = { }; - data = nullptr; - } - } - } - } -#endif - if (error.isNull()) { ASSERT(!newRequest.isNull()); - + if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) { - Vector<char> buffer; - platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, buffer); - data = SharedBuffer::adoptVector(buffer); + platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data); documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data); } } - notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data ? data->data() : nullptr, data ? data->size() : 0, -1, error); + notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error); return identifier; } @@ -2804,17 +2765,13 @@ void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ if (!shouldContinue) return; - // Calling stopLoading() on the provisional document loader can cause the underlying - // frame to be deallocated. - Ref<Frame> protectedFrame(m_frame); - // If we have a provisional request for a different document, a fragment scroll should cancel it. if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) { m_provisionalDocumentLoader->stopLoading(); - setProvisionalDocumentLoader(nullptr); + setProvisionalDocumentLoader(0); } - bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadType::RedirectWithLockedBackForwardList; + bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadTypeRedirectWithLockedBackForwardList; loadInSameDocument(request.url(), 0, !isRedirect); } @@ -2826,10 +2783,10 @@ bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const S // FIXME: What about load types other than Standard and Reload? - return (!isFormSubmission || equalLettersIgnoringASCIICase(httpMethod, "get")) - && loadType != FrameLoadType::Reload - && loadType != FrameLoadType::ReloadFromOrigin - && loadType != FrameLoadType::Same + return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET")) + && loadType != FrameLoadTypeReload + && loadType != FrameLoadTypeReloadFromOrigin + && loadType != FrameLoadTypeSame && !shouldReload(m_frame.document()->url(), url) // We don't want to just scroll if a link from within a // frameset is trying to reload the frameset into _top. @@ -2876,7 +2833,7 @@ bool FrameLoader::shouldClose() for (i = 0; i < targetFrames.size(); i++) { if (!targetFrames[i]->tree().isDescendantOf(&m_frame)) continue; - if (!targetFrames[i]->loader().dispatchBeforeUnloadEvent(page->chrome(), this)) + if (!targetFrames[i]->loader().handleBeforeUnloadEvent(page->chrome(), this)) break; } @@ -2891,95 +2848,36 @@ bool FrameLoader::shouldClose() return shouldClose; } -void FrameLoader::dispatchUnloadEvents(UnloadEventPolicy unloadEventPolicy) -{ - if (!m_frame.document()) - return; - - // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent. - ForbidPromptsScope forbidPrompts(m_frame.page()); - IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document()); - - if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { - auto* currentFocusedElement = m_frame.document()->focusedElement(); - if (is<HTMLInputElement>(currentFocusedElement)) - downcast<HTMLInputElement>(*currentFocusedElement).endEditing(); - if (m_pageDismissalEventBeingDispatched == PageDismissalType::None) { - if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) { - m_pageDismissalEventBeingDispatched = PageDismissalType::PageHide; - m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document()); - } - - // FIXME: update Page Visibility state here. - // https://bugs.webkit.org/show_bug.cgi?id=116770 - - if (!m_frame.document()->inPageCache()) { - Ref<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false)); - // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed - // while dispatching the event, so protect it to prevent writing the end - // time into freed memory. - RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader; - m_pageDismissalEventBeingDispatched = PageDismissalType::Unload; - if (documentLoader && documentLoader->timing().navigationStart() && !documentLoader->timing().unloadEventStart() && !documentLoader->timing().unloadEventEnd()) { - auto& timing = documentLoader->timing(); - timing.markUnloadEventStart(); - m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document()); - timing.markUnloadEventEnd(); - } else - m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document()); - } - } - m_pageDismissalEventBeingDispatched = PageDismissalType::None; - if (m_frame.document()) - m_frame.document()->updateStyleIfNeeded(); - m_wasUnloadEventEmitted = true; - } - - // Dispatching the unload event could have made m_frame.document() null. - if (!m_frame.document()) - return; - - if (m_frame.document()->inPageCache()) - return; - - // Don't remove event listeners from a transitional empty document (see bug 28716 for more information). - bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader - && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url()); - - if (!keepEventListeners) - m_frame.document()->removeAllEventListeners(); -} - -bool FrameLoader::dispatchBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated) +bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated) { DOMWindow* domWindow = m_frame.document()->domWindow(); if (!domWindow) return true; RefPtr<Document> document = m_frame.document(); - if (!document->bodyOrFrameset()) + if (!document->body()) return true; - Ref<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); - m_pageDismissalEventBeingDispatched = PageDismissalType::BeforeUnload; + RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); + m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal; - { - ForbidPromptsScope forbidPrompts(m_frame.page()); - IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(m_frame.document()); - domWindow->dispatchEvent(beforeUnloadEvent, domWindow->document()); - } + // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent. + Page* page = m_frame.page(); + page->incrementFrameHandlingBeforeUnloadEventCount(); + domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document()); + page->decrementFrameHandlingBeforeUnloadEventCount(); - m_pageDismissalEventBeingDispatched = PageDismissalType::None; + m_pageDismissalEventBeingDispatched = NoDismissal; if (!beforeUnloadEvent->defaultPrevented()) - document->defaultEventHandler(beforeUnloadEvent.ptr()); + document->defaultEventHandler(beforeUnloadEvent.get()); if (beforeUnloadEvent->returnValue().isNull()) return true; // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt, // this frame is not allowed to cause another one to be shown. if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) { - document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation.")); + document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."); return true; } @@ -2992,7 +2890,7 @@ bool FrameLoader::dispatchBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLo if (!parentDocument) return true; if (!m_frame.document() || !m_frame.document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) { - document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match.")); + document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match."); return true; } @@ -3013,7 +2911,7 @@ bool FrameLoader::dispatchBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLo return chrome.runBeforeUnloadConfirmPanel(text, &m_frame); } -void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL) +void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue) { // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a // nil policyDataSource because loading the alternate page will have passed @@ -3022,23 +2920,19 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque bool isTargetItem = history().provisionalItem() ? history().provisionalItem()->isTargetItem() : false; - bool urlIsDisallowed = allowNavigationToInvalidURL == AllowNavigationToInvalidURL::No && !request.url().isValid(); - - // Three reasons we can't continue: + // Two reasons we can't continue: // 1) Navigation policy delegate said we can't so request is nil. A primary case of this // is the user responding Cancel to the form repost nag sheet. // 2) User responded Cancel to an alert popped up by the before unload event handler. - // 3) The request's URL is invalid and navigation to invalid URLs is disallowed. - bool canContinue = shouldContinue && shouldClose() && !urlIsDisallowed; + bool canContinue = shouldContinue && shouldClose(); if (!canContinue) { // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we // need to report that the client redirect was cancelled. - // FIXME: The client should be told about ignored non-quick redirects, too. if (m_quickRedirectComing) clientRedirectCancelledOrFinished(false); - setPolicyDocumentLoader(nullptr); + setPolicyDocumentLoader(0); // If the navigation request came from the back/forward menu, and we punt on it, we have the // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity, @@ -3063,20 +2957,22 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque if (!m_frame.page()) return; +#if ENABLE(INSPECTOR) + if (Page* page = m_frame.page()) { + if (m_frame.isMainFrame()) + page->inspectorController().resume(); + } +#endif + setProvisionalDocumentLoader(m_policyDocumentLoader.get()); m_loadType = type; setState(FrameStateProvisional); - setPolicyDocumentLoader(nullptr); + setPolicyDocumentLoader(0); - if (isBackForwardLoadType(type)) { - auto& diagnosticLoggingClient = m_frame.mainFrame().diagnosticLoggingClient(); - if (history().provisionalItem()->isInPageCache()) { - diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::retrievalKey(), DiagnosticLoggingResultPass, ShouldSample::Yes); - loadProvisionalItemFromCachedPage(); - return; - } - diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::retrievalKey(), DiagnosticLoggingResultFail, ShouldSample::Yes); + if (isBackForwardLoadType(type) && history().provisionalItem()->isInPageCache()) { + loadProvisionalItemFromCachedPage(); + return; } if (!formState) { @@ -3090,7 +2986,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque } void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request, - PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy) + PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) { if (!shouldContinue) return; @@ -3105,13 +3001,11 @@ void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques mainFrame->page()->setOpenedByDOM(); mainFrame->loader().m_client.dispatchShow(); - if (openerPolicy == NewFrameOpenerPolicy::Allow) { - mainFrame->loader().setOpener(frame.ptr()); + if (!m_suppressOpenerInNewFrame) { + mainFrame->loader().setOpener(&frame.get()); mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy()); } - - NavigationAction newAction(request, action.shouldOpenExternalURLsPolicy()); - mainFrame->loader().loadWithNavigationAction(request, newAction, LockHistory::No, FrameLoadType::Standard, formState, allowNavigationToInvalidURL); + mainFrame->loader().loadWithNavigationAction(request, NavigationAction(request), false, FrameLoadTypeStandard, formState); } void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error) @@ -3137,6 +3031,8 @@ void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& i void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest) { + newRequest = ResourceRequest(resource->url()); + Page* page = m_frame.page(); if (!page) return; @@ -3149,14 +3045,14 @@ void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, Resour return; if (!page->areMemoryCacheClientCallsEnabled()) { - InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource); + InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource); m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest()); m_documentLoader->didTellClientAboutLoad(resource->url()); return; } if (m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) { - InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource); + InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource); m_documentLoader->didTellClientAboutLoad(resource->url()); return; } @@ -3164,7 +3060,7 @@ void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, Resour unsigned long identifier; ResourceError error; requestFromDelegate(newRequest, identifier, error); - InspectorInstrumentation::markResourceAsCached(*page, identifier); + InspectorInstrumentation::markResourceAsCached(page, identifier); notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error); } @@ -3177,6 +3073,8 @@ void FrameLoader::applyUserAgent(ResourceRequest& request) bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const URL& url, unsigned long requestIdentifier) { + FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptions); + Frame& topFrame = m_frame.tree().top(); if (&m_frame == &topFrame) return false; @@ -3185,12 +3083,15 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con switch (disposition) { case XFrameOptionsSameOrigin: { + FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptionsSameOrigin); RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); if (!origin->isSameSchemeHostPort(topFrame.document()->securityOrigin())) return true; for (Frame* frame = m_frame.tree().parent(); frame; frame = frame->tree().parent()) { - if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) + if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) { + FeatureObserver::observe(m_frame.document(), FeatureObserver::XFrameOptionsSameOriginWithBadAncestorChain); break; + } } return false; } @@ -3199,16 +3100,15 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con case XFrameOptionsAllowAll: return false; case XFrameOptionsConflict: - m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier); + m_frame.document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier); return true; case XFrameOptionsInvalid: - m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier); + m_frame.document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier); return false; - case XFrameOptionsNone: + default: + ASSERT_NOT_REACHED(); return false; } - ASSERT_NOT_REACHED(); - return false; } void FrameLoader::loadProvisionalItemFromCachedPage() @@ -3221,9 +3121,9 @@ void FrameLoader::loadProvisionalItemFromCachedPage() m_loadingFromCachedPage = true; // Should have timing data from previous time(s) the page was shown. - ASSERT(provisionalLoader->timing().navigationStart()); + ASSERT(provisionalLoader->timing()->navigationStart()); provisionalLoader->resetTiming(); - provisionalLoader->timing().markNavigationStart(); + provisionalLoader->timing()->markNavigationStart(); provisionalLoader->setCommitted(true); commitProvisionalLoad(); @@ -3238,7 +3138,7 @@ bool FrameLoader::shouldTreatURLAsSameAsCurrent(const URL& url) const bool FrameLoader::shouldTreatURLAsSrcdocDocument(const URL& url) const { - if (!equalLettersIgnoringASCIICase(url.string(), "about:srcdoc")) + if (!equalIgnoringCase(url.string(), "about:srcdoc")) return false; HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement(); if (!ownerElement) @@ -3252,21 +3152,38 @@ Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* a { Frame* frame = m_frame.tree().find(name); + // From http://www.whatwg.org/specs/web-apps/current-work/#seamlessLinks: + // + // If the source browsing context is the same as the browsing context + // being navigated, and this browsing context has its seamless browsing + // context flag set, and the browsing context being navigated was not + // chosen using an explicit self-navigation override, then find the + // nearest ancestor browsing context that does not have its seamless + // browsing context flag set, and continue these steps as if that + // browsing context was the one that was going to be navigated instead. + if (frame == &m_frame && name != "_self" && m_frame.document()->shouldDisplaySeamlesslyWithParent()) { + for (Frame* ancestor = &m_frame; ancestor; ancestor = ancestor->tree().parent()) { + if (!ancestor->document()->shouldDisplaySeamlesslyWithParent()) { + frame = ancestor; + break; + } + } + ASSERT(frame != &m_frame); + } + // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document. if (!activeDocument) activeDocument = m_frame.document(); if (!activeDocument->canNavigate(frame)) - return nullptr; + return 0; return frame; } -void FrameLoader::loadSameDocumentItem(HistoryItem& item) +void FrameLoader::loadSameDocumentItem(HistoryItem* item) { - ASSERT(item.documentSequenceNumber() == history().currentItem()->documentSequenceNumber()); - - Ref<Frame> protect(m_frame); + ASSERT(item->documentSequenceNumber() == history().currentItem()->documentSequenceNumber()); // Save user view state to the current history item here since we don't do a normal load. // FIXME: Does form state need to be saved here too? @@ -3274,10 +3191,10 @@ void FrameLoader::loadSameDocumentItem(HistoryItem& item) if (FrameView* view = m_frame.view()) view->setWasScrolledByUser(false); - history().setCurrentItem(&item); + history().setCurrentItem(item); // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load - loadInSameDocument(item.url(), item.stateObject(), false); + loadInSameDocument(item->url(), item->stateObject(), false); // Restore user view state from the current history item here since we don't do a normal load. history().restoreScrollPositionAndViewState(); @@ -3286,45 +3203,37 @@ void FrameLoader::loadSameDocumentItem(HistoryItem& item) // FIXME: This function should really be split into a couple pieces, some of // which should be methods of HistoryController and some of which should be // methods of FrameLoader. -void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy) +void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy) { // Remember this item so we can traverse any child items as child frames load - history().setProvisionalItem(&item); + history().setProvisionalItem(item); - if (CachedPage* cachedPage = PageCache::singleton().get(item, m_frame.page())) { - auto documentLoader = cachedPage->documentLoader(); - m_client.updateCachedDocumentLoader(*documentLoader); - documentLoader->setTriggeringAction(NavigationAction(documentLoader->request(), loadType, false)); - documentLoader->setLastCheckedRequest(ResourceRequest()); - loadWithDocumentLoader(documentLoader, loadType, 0, AllowNavigationToInvalidURL::Yes); + if (CachedPage* cachedPage = pageCache()->get(item)) { + loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0); return; } - URL itemURL = item.url(); - URL itemOriginalURL = item.originalURL(); + URL itemURL = item->url(); + URL itemOriginalURL = item->originalURL(); URL currentURL; if (documentLoader()) currentURL = documentLoader()->url(); - RefPtr<FormData> formData = item.formData(); + RefPtr<FormData> formData = item->formData(); ResourceRequest request(itemURL); - if (!item.referrer().isNull()) - request.setHTTPReferrer(item.referrer()); - - ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicyToApply(m_frame, item.shouldOpenExternalURLsPolicy()); - bool isFormSubmission = false; - Event* event = nullptr; - + if (!item->referrer().isNull()) + request.setHTTPReferrer(item->referrer()); + // If this was a repost that failed the page cache, we might try to repost the form. NavigationAction action; if (formData) { formData->generateFiles(m_frame.document()); request.setHTTPMethod("POST"); - request.setHTTPBody(WTFMove(formData)); - request.setHTTPContentType(item.formContentType()); - RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item.referrer()); + request.setHTTPBody(formData); + request.setHTTPContentType(item->formContentType()); + RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer()); addHTTPOriginIfNeeded(request, securityOrigin->toString()); // Make sure to add extra fields to the request after the Origin header is added for the FormData case. @@ -3341,54 +3250,49 @@ void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loa if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) { request.setCachePolicy(ReturnCacheDataDontLoad); - action = NavigationAction(request, loadType, isFormSubmission, event, shouldOpenExternalURLsPolicy); + action = NavigationAction(request, loadType, false); } else { request.setCachePolicy(ReturnCacheDataElseLoad); - action = NavigationAction(request, NavigationType::FormResubmitted, event, shouldOpenExternalURLsPolicy); + action = NavigationAction(request, NavigationTypeFormResubmitted); } } else { switch (loadType) { - case FrameLoadType::Reload: - case FrameLoadType::ReloadFromOrigin: - request.setCachePolicy(ReloadIgnoringCacheData); - break; - case FrameLoadType::Back: - case FrameLoadType::Forward: - case FrameLoadType::IndexedBackForward: { -#if PLATFORM(IOS) - bool allowStaleData = true; -#else - bool allowStaleData = !item.wasRestoredFromSession(); -#endif - if (allowStaleData) - request.setCachePolicy(ReturnCacheDataElseLoad); - item.setWasRestoredFromSession(false); - break; - } - case FrameLoadType::Standard: - case FrameLoadType::RedirectWithLockedBackForwardList: - break; - case FrameLoadType::Same: - default: - ASSERT_NOT_REACHED(); + case FrameLoadTypeReload: + case FrameLoadTypeReloadFromOrigin: + request.setCachePolicy(ReloadIgnoringCacheData); + break; + case FrameLoadTypeBack: + case FrameLoadTypeForward: + case FrameLoadTypeIndexedBackForward: + // If the first load within a frame is a navigation within a back/forward list that was attached + // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>). + if (m_stateMachine.committedFirstRealDocumentLoad()) + request.setCachePolicy(ReturnCacheDataElseLoad); + break; + case FrameLoadTypeStandard: + case FrameLoadTypeRedirectWithLockedBackForwardList: + break; + case FrameLoadTypeSame: + default: + ASSERT_NOT_REACHED(); } addExtraFieldsToRequest(request, loadType, true); ResourceRequest requestForOriginalURL(request); requestForOriginalURL.setURL(itemOriginalURL); - action = NavigationAction(requestForOriginalURL, loadType, isFormSubmission, event, shouldOpenExternalURLsPolicy); + action = NavigationAction(requestForOriginalURL, loadType, false); } - loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes); + loadWithNavigationAction(request, action, false, loadType, 0); } // Loads content into this frame, as specified by history item -void FrameLoader::loadItem(HistoryItem& item, FrameLoadType loadType) +void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) { - m_requestedHistoryItem = &item; + m_requestedHistoryItem = item; HistoryItem* currentItem = history().currentItem(); - bool sameDocumentNavigation = currentItem && item.shouldDoSameDocumentNavigationTo(*currentItem); + bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem); if (sameDocumentNavigation) loadSameDocumentItem(item); @@ -3400,12 +3304,13 @@ void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad() { ASSERT(m_state == FrameStateProvisional); ASSERT(!m_loadingFromCachedPage); - ASSERT(history().provisionalItem()); + // We only use cache-only loads to avoid resubmitting forms. + ASSERT(isBackForwardLoadType(m_loadType)); ASSERT(history().provisionalItem()->formData()); ASSERT(history().provisionalItem() == m_requestedHistoryItem.get()); FrameLoadType loadType = m_loadType; - HistoryItem& item = *history().provisionalItem(); + HistoryItem* item = history().provisionalItem(); stopAllLoaders(ShouldNotClearProvisionalItem); loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem); @@ -3418,18 +3323,6 @@ ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const return error; } -ResourceError FrameLoader::blockedByContentBlockerError(const ResourceRequest& request) const -{ - return m_client.blockedByContentBlockerError(request); -} - -ResourceError FrameLoader::blockedError(const ResourceRequest& request) const -{ - ResourceError error = m_client.blockedError(request); - error.setIsCancellation(true); - return error; -} - #if PLATFORM(IOS) RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loader) { @@ -3449,8 +3342,8 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() Vector<Ref<DOMWrapperWorld>> worlds; ScriptController::getAllWorlds(worlds); - for (auto& world : worlds) - dispatchDidClearWindowObjectInWorld(world); + for (size_t i = 0; i < worlds.size(); ++i) + dispatchDidClearWindowObjectInWorld(worlds[i].get()); } void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) @@ -3460,18 +3353,20 @@ void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) m_client.dispatchDidClearWindowObjectInWorld(world); +#if ENABLE(INSPECTOR) if (Page* page = m_frame.page()) - page->inspectorController().didClearWindowObjectInWorld(m_frame, world); + page->inspectorController().didClearWindowObjectInWorld(&m_frame, world); +#endif - InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world); + InspectorInstrumentation::didClearWindowObjectInWorld(&m_frame, world); } void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds() { Vector<Ref<DOMWrapperWorld>> worlds; ScriptController::getAllWorlds(worlds); - for (auto& world : worlds) - m_client.dispatchGlobalObjectAvailable(world); + for (size_t i = 0; i < worlds.size(); ++i) + m_client.dispatchGlobalObjectAvailable(worlds[i].get()); } SandboxFlags FrameLoader::effectiveSandboxFlags() const @@ -3503,6 +3398,11 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader) #endif } +void FrameLoader::didChangeIcons(IconType type) +{ + m_client.dispatchDidChangeIcons(type); +} + void FrameLoader::dispatchDidCommitLoad() { if (m_stateMachine.creatingInitialEmptyDocument()) @@ -3515,12 +3415,14 @@ void FrameLoader::dispatchDidCommitLoad() m_frame.page()->resetSeenMediaEngines(); } - InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get()); + InspectorInstrumentation::didCommitLoad(&m_frame, m_documentLoader.get()); + if (m_frame.isMainFrame()) { + m_frame.page()->featureObserver()->didCommitLoad(); #if ENABLE(REMOTE_INSPECTOR) - if (m_frame.isMainFrame()) m_frame.page()->remoteInspectorInformationDidChange(); #endif + } } void FrameLoader::tellClientAboutPastMemoryCacheLoads() @@ -3534,8 +3436,9 @@ void FrameLoader::tellClientAboutPastMemoryCacheLoads() Vector<ResourceRequest> pastLoads; m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads); - for (auto& pastLoad : pastLoads) { - CachedResource* resource = MemoryCache::singleton().resourceForRequest(pastLoad, m_frame.page()->sessionID()); + size_t size = pastLoads.size(); + for (size_t i = 0; i < size; ++i) { + CachedResource* resource = memoryCache()->resourceForRequest(pastLoads[i]); // FIXME: These loads, loaded from cache, but now gone from the cache by the time // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client. @@ -3556,8 +3459,12 @@ NetworkingContext* FrameLoader::networkingContext() const void FrameLoader::loadProgressingStatusChanged() { - if (auto* view = m_frame.mainFrame().view()) - view->loadProgressingStatusChanged(); + FrameView* view = m_frame.mainFrame().view(); + if (!view) + return; + + view->updateLayerFlushThrottlingInAllFrames(); + view->adjustTiledBackingCoverage(); } void FrameLoader::forcePageTransitionIfNeeded() @@ -3565,35 +3472,22 @@ void FrameLoader::forcePageTransitionIfNeeded() m_client.forcePageTransitionIfNeeded(); } -void FrameLoader::clearTestingOverrides() -{ - m_overrideCachePolicyForTesting = Nullopt; - m_overrideResourceLoadPriorityForTesting = Nullopt; - m_isStrictRawResourceValidationPolicyDisabledForTesting = false; -} - -void FrameLoader::applyShouldOpenExternalURLsPolicyToNewDocumentLoader(DocumentLoader& documentLoader, ShouldOpenExternalURLsPolicy propagatedPolicy) -{ - documentLoader.setShouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicyToApply(m_frame, propagatedPolicy)); -} - bool FrameLoaderClient::hasHTMLView() const { return true; } -RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) +PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) { ASSERT(!features.dialog || request.frameName().isEmpty()); - created = false; - if (!request.frameName().isEmpty() && request.frameName() != "_blank") { - if (RefPtr<Frame> frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) { + if (Frame* frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) { if (request.frameName() != "_self") { if (Page* page = frame->page()) page->chrome().focus(); } + created = false; return frame; } } @@ -3601,92 +3495,74 @@ RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLo // Sandboxed frames cannot open new auxiliary browsing contexts. if (isDocumentSandboxed(openerFrame, SandboxPopups)) { // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. - openerFrame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set."); - return nullptr; + openerFrame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set."); + return 0; } // FIXME: Setting the referrer should be the caller's responsibility. FrameLoadRequest requestWithReferrer = request; - String referrer = SecurityPolicy::generateReferrerHeader(openerFrame.document()->referrerPolicy(), request.resourceRequest().url(), openerFrame.loader().outgoingReferrer()); + String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader().outgoingReferrer()); if (!referrer.isEmpty()) requestWithReferrer.resourceRequest().setHTTPReferrer(referrer); - FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame.loader().outgoingOrigin()); + FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader().outgoingOrigin()); - Page* oldPage = openerFrame.page(); + Page* oldPage = openerFrame->page(); if (!oldPage) - return nullptr; + return 0; - ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicyToApply(openerFrame, request.shouldOpenExternalURLsPolicy()); - Page* page = oldPage->chrome().createWindow(&openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest(), shouldOpenExternalURLsPolicy)); + NavigationAction action(requestWithReferrer.resourceRequest()); + Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, action); if (!page) - return nullptr; + return 0; - RefPtr<Frame> frame = &page->mainFrame(); - - frame->loader().forceSandboxFlags(openerFrame.document()->sandboxFlags()); + page->mainFrame().loader().forceSandboxFlags(openerFrame->document()->sandboxFlags()); if (request.frameName() != "_blank") - frame->tree().setName(request.frameName()); + page->mainFrame().tree().setName(request.frameName()); page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible); - - if (!frame->page()) - return nullptr; page->chrome().setStatusbarVisible(features.statusBarVisible); - - if (!frame->page()) - return nullptr; page->chrome().setScrollbarsVisible(features.scrollbarsVisible); - - if (!frame->page()) - return nullptr; page->chrome().setMenubarVisible(features.menuBarVisible); - - if (!frame->page()) - return nullptr; page->chrome().setResizable(features.resizable); // 'x' and 'y' specify the location of the window, while 'width' and 'height' // specify the size of the viewport. We can only resize the window, so adjust // for the difference between the window size and the viewport size. - // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS. +// FIXME: We should reconcile the initialization of viewport arguments between iOS and OpenSource. #if !PLATFORM(IOS) FloatSize viewportSize = page->chrome().pageRect().size(); FloatRect windowRect = page->chrome().windowRect(); - if (features.x) - windowRect.setX(*features.x); - if (features.y) - windowRect.setY(*features.y); + if (features.xSet) + windowRect.setX(features.x); + if (features.ySet) + windowRect.setY(features.y); // Zero width and height mean using default size, not minumum one. - if (features.width && *features.width) - windowRect.setWidth(*features.width + (windowRect.width() - viewportSize.width())); - if (features.height && *features.height) - windowRect.setHeight(*features.height + (windowRect.height() - viewportSize.height())); + if (features.widthSet && features.width) + windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width())); + if (features.heightSet && features.height) + windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height())); // Ensure non-NaN values, minimum size as well as being within valid screen area. FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect); - if (!frame->page()) - return nullptr; page->chrome().setWindowRect(newWindowRect); #else // On iOS, width and height refer to the viewport dimensions. ViewportArguments arguments; // Zero width and height mean using default size, not minimum one. - if (features.width && *features.width) - arguments.width = *features.width; - if (features.height && *features.height) - arguments.height = *features.height; - frame->setViewportArguments(arguments); + if (features.widthSet && features.width) + arguments.width = features.width; + if (features.heightSet && features.height) + arguments.height = features.height; + page->mainFrame().setViewportArguments(arguments); #endif - if (!frame->page()) - return nullptr; page->chrome().show(); created = true; - return frame; + return &page->mainFrame(); } } // namespace WebCore |