void HistoryController::updateForCommit() { FrameLoader& frameLoader = m_frame.loader(); LOG(History, "HistoryController %p updateForCommit: Updating History for commit in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); FrameLoadType type = frameLoader.loadType(); if (isBackForwardLoadType(type) || isReplaceLoadTypeWithProvisionalItem(type) || (isReloadTypeWithProvisionalItem(type) && !frameLoader.provisionalDocumentLoader()->unreachableURL().isEmpty())) { // Once committed, we want to use current item for saving DocState, and // the provisional item for restoring state. // Note previousItem must be set before we close the URL, which will // happen when the data source is made non-provisional below // FIXME: https://bugs.webkit.org/show_bug.cgi?id=146842 // We should always have a provisional item when committing, but we sometimes don't. // Not having one leads to us not having a m_currentItem later, which is also a terrible known issue. // We should get to the bottom of this. ASSERT(m_provisionalItem); setCurrentItem(m_provisionalItem.get()); m_provisionalItem = nullptr; // Tell all other frames in the tree to commit their provisional items and // restore their scroll position. We'll avoid this frame (which has already // committed) and its children (which will be replaced). m_frame.mainFrame().loader().history().recursiveUpdateForCommit(); } }
void HistoryController::updateForCommit() { FrameLoader* frameLoader = m_frame->loader(); #if !LOG_DISABLED if (frameLoader->documentLoader()) LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader->documentLoader()->title().string().utf8().data()); #endif FrameLoadType type = frameLoader->loadType(); if (isBackForwardLoadType(type) || isReplaceLoadTypeWithProvisionalItem(type) || (isReloadTypeWithProvisionalItem(type) && !frameLoader->provisionalDocumentLoader()->unreachableURL().isEmpty())) { // Once committed, we want to use current item for saving DocState, and // the provisional item for restoring state. // Note previousItem must be set before we close the URL, which will // happen when the data source is made non-provisional below m_frameLoadComplete = false; m_previousItem = m_currentItem; ASSERT(m_provisionalItem); m_currentItem = m_provisionalItem; m_provisionalItem = 0; // Tell all other frames in the tree to commit their provisional items and // restore their scroll position. We'll avoid this frame (which has already // committed) and its children (which will be replaced). Page* page = m_frame->page(); ASSERT(page); page->mainFrame()->loader()->history()->recursiveUpdateForCommit(); } }
NavigationPolicy FrameLoaderClientImpl::decidePolicyForNavigation(const ResourceRequest& request, DocumentLoader* loader, NavigationType type, NavigationPolicy policy, bool replacesCurrentHistoryItem) { if (!m_webFrame->client()) return NavigationPolicyIgnore; if (policy == NavigationPolicyNewBackgroundTab && !allowCreatingBackgroundTabs() && !UIEventWithKeyState::newTabModifierSetFromIsolatedWorld()) policy = NavigationPolicyNewForegroundTab; WebDataSourceImpl* ds = WebDataSourceImpl::fromDocumentLoader(loader); // Newly created child frames may need to be navigated to a history item // during a back/forward navigation. This will only happen when the parent // is a LocalFrame doing a back/forward navigation that has not completed. // (If the load has completed and the parent later adds a frame with script, // we do not want to use a history item for it.) bool isHistoryNavigationInNewChildFrame = m_webFrame->parent() && m_webFrame->parent()->isWebLocalFrame() && isBackForwardLoadType(toWebLocalFrameImpl(m_webFrame->parent())->frame()->loader().loadType()) && !toWebLocalFrameImpl(m_webFrame->parent())->frame()->document()->loadEventFinished(); WrappedResourceRequest wrappedResourceRequest(request); WebFrameClient::NavigationPolicyInfo navigationInfo(wrappedResourceRequest); navigationInfo.navigationType = static_cast<WebNavigationType>(type); navigationInfo.defaultPolicy = static_cast<WebNavigationPolicy>(policy); navigationInfo.extraData = ds ? ds->extraData() : nullptr; navigationInfo.replacesCurrentHistoryItem = replacesCurrentHistoryItem; navigationInfo.isHistoryNavigationInNewChildFrame = isHistoryNavigationInNewChildFrame; WebNavigationPolicy webPolicy = m_webFrame->client()->decidePolicyForNavigation(navigationInfo); return static_cast<NavigationPolicy>(webPolicy); }
void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument) { NavigationAction action = loader->triggeringAction(); if (action.isEmpty()) { action = NavigationAction(request.url(), NavigationTypeOther); loader->setTriggeringAction(action); } // Don't ask more than once for the same request or if we are loading an empty URL. // This avoids confusion on the part of the client. if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { function(argument, request, 0, true); loader->setLastCheckedRequest(request); return; } // We are always willing to show alternate content for unreachable URLs; // treat it like a reload so it maintains the right state for b/f list. if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { if (isBackForwardLoadType(m_loadType)) m_loadType = FrameLoadTypeReload; function(argument, request, 0, true); return; } loader->setLastCheckedRequest(request); m_callback.set(request, formState.get(), function, argument); m_delegateIsDecidingNavigationPolicy = true; m_frame->loader()->client()->dispatchDecidePolicyForNavigationAction(&PolicyChecker::continueAfterNavigationPolicy, action, request, formState); m_delegateIsDecidingNavigationPolicy = false; }
bool DocumentLoader::shouldContinueForNavigationPolicy(const ResourceRequest& request) { NavigationAction action = triggeringAction(); if (action.isEmpty()) { action = NavigationAction(request, NavigationTypeOther); setTriggeringAction(action); } // Don't ask if we are loading an empty URL. if (!request.isNull() && request.url().isEmpty()) return true; // We are always willing to show alternate content for unreachable URLs; // treat it like a reload so it maintains the right state for b/f list. if (m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty()) { if (isBackForwardLoadType(frameLoader()->loadType())) frameLoader()->setLoadType(FrameLoadTypeReload); return true; } // If we're loading content into a subframe, check against the parent's Content Security Policy // and kill the load if that check fails. if (m_frame->ownerElement() && !m_frame->ownerElement()->document()->contentSecurityPolicy()->allowChildFrameFromSource(request.url())) return false; PolicyAction policy = frameLoader()->client()->decidePolicyForNavigationAction(action, request); if (policy == PolicyDownload) { ResourceRequest mutableRequest(request); frameLoader()->setOriginalURLForDownloadRequest(mutableRequest); frameLoader()->client()->startDownload(mutableRequest); } return policy == PolicyUse; }
void FrameLoaderClientBlackBerry::dispatchDidFailProvisionalLoad(const ResourceError& error) { if (isMainFrame()) { m_loadError = error; m_webPagePrivate->setLoadState(WebPagePrivate::Failed); if (error.domain() == ResourceError::platformErrorDomain && (error.errorCode() == BlackBerry::Platform::FilterStream::StatusErrorAlreadyHandled)) { // Error has already been displayed by client. return; } if (error.domain().isEmpty() && !error.errorCode() && error.failingURL().isEmpty() && error.localizedDescription().isEmpty()) { // Don't try to display empty errors returned from the unimplemented error functions in FrameLoaderClientBlackBerry - there's nothing to display anyway. return; } } if (m_webPagePrivate->m_dumpRenderTree) m_webPagePrivate->m_dumpRenderTree->didFailProvisionalLoadForFrame(m_frame); if (!isMainFrame()) return; String errorPage = m_webPagePrivate->m_client->getErrorPage(error.errorCode() , error.localizedDescription().isEmpty() ? "" : error.localizedDescription().utf8().data() , error.failingURL().isEmpty() ? "" : error.failingURL().utf8().data()); // Make sure we're still in the provisionalLoad state - getErrorPage runs a // nested event loop while it's waiting for client resources to load so // there's a small window for the user to hit stop. if (m_frame->loader()->provisionalDocumentLoader()) { SubstituteData errorData(utf8Buffer(errorPage), "text/html", "utf-8", KURL(KURL(), error.failingURL())); ResourceRequest originalRequest = m_frame->loader()->provisionalDocumentLoader()->originalRequest(); // Loading using SubstituteData will replace the original request with our // error data. This must be done within dispatchDidFailProvisionalLoad, // and do NOT call stopAllLoaders first, because the loader checks the // provisionalDocumentLoader to decide the load type; if called any other // way, the error page is added to the end of the history instead of // replacing the failed load. // // If this comes from a back/forward navigation, we need to save the current viewstate // to original historyitem, and prevent the restore of view state to the error page. if (isBackForwardLoadType(m_frame->loader()->loadType())) { m_frame->loader()->history()->saveScrollPositionAndViewStateToItem(m_frame->loader()->history()->currentItem()); ASSERT(m_frame->loader()->history()->provisionalItem()); m_frame->loader()->history()->provisionalItem()->viewState().shouldSaveViewState = false; } m_loadingErrorPage = true; m_frame->loader()->load(originalRequest, errorData, false); } }
static NavigationType navigationType(FrameLoadType frameLoadType, bool isFormSubmission, bool haveEvent) { if (isFormSubmission) return NavigationTypeFormSubmitted; if (haveEvent) return NavigationTypeLinkClicked; if (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin) return NavigationTypeReload; if (isBackForwardLoadType(frameLoadType)) return NavigationTypeBackForward; return NavigationTypeOther; }
void FrameLoaderClientBlackBerry::dispatchWillSendRequest(DocumentLoader* docLoader, long unsigned int, ResourceRequest& request, const ResourceResponse&) { // If the request is being loaded by the provisional document loader, then // it is a new top level request which has not been commited. bool isMainResourceLoad = docLoader && docLoader == docLoader->frameLoader()->provisionalDocumentLoader(); // TargetType for subresource loads should have been set in CachedResource::load(). if (isMainResourceLoad && request.targetType() == ResourceRequest::TargetIsUnspecified) request.setTargetType(isMainFrame() ? ResourceRequest::TargetIsMainFrame : ResourceRequest::TargetIsSubframe); // Any processing which is done for all loads (both main and subresource) should go here. NetworkRequest platformRequest; request.initializePlatformRequest(platformRequest, cookiesEnabled()); m_webPagePrivate->m_client->populateCustomHeaders(platformRequest); const NetworkRequest::HeaderList& headerLists = platformRequest.getHeaderListRef(); for (NetworkRequest::HeaderList::const_iterator it = headerLists.begin(); it != headerLists.end(); ++it) { std::string headerString = it->first; std::string headerValueString = it->second; request.setHTTPHeaderField(String::fromUTF8WithLatin1Fallback(headerString.data(), headerString.length()), String::fromUTF8WithLatin1Fallback(headerValueString.data(), headerValueString.length())); } if (!isMainResourceLoad) { // Do nothing for now. // Any processing which is done only for subresources should go here. return; } // All processing beyond this point is done only for main resource loads. if (m_clientRedirectIsPending && isMainFrame()) { String originalUrl = m_frame->document()->url().string(); String finalUrl = request.url().string(); m_webPagePrivate->m_client->notifyClientRedirect(originalUrl.characters(), originalUrl.length(), finalUrl.characters(), finalUrl.length()); } FrameLoader* loader = m_frame->loader(); ASSERT(loader); if (isBackForwardLoadType(loader->loadType())) { // Do not use the passed DocumentLoader because it is the loader that // will be used for the new request (the DESTINATION of the history // navigation - we want to use the current DocumentLoader to record the // SOURCE). DocumentLoader* docLoader = m_frame->loader()->documentLoader(); ASSERT(docLoader); m_historyNavigationSourceURLs.add(docLoader->url()); m_historyNavigationSourceURLs.add(docLoader->originalURL()); } }
void HistoryController::updateForCommit() { FrameLoader* frameLoader = m_frame->loader(); #if !LOG_DISABLED if (m_frame->document()) LOG(History, "WebCoreHistory: Updating History for commit in frame %s", m_frame->document()->title().utf8().data()); #endif FrameLoadType type = frameLoader->loadType(); if (isBackForwardLoadType(type) || (isReloadTypeWithProvisionalItem(type) && !frameLoader->documentLoader()->unreachableURL().isEmpty())) { // Once committed, we want to use current item for saving DocState, and // the provisional item for restoring state. // Note previousItem must be set before we close the URL, which will // happen when the data source is made non-provisional below m_previousItem = m_currentItem; ASSERT(m_provisionalItem); m_currentItem = m_provisionalItem; m_provisionalItem = 0; // Tell all other frames in the tree to commit their provisional items and // restore their scroll position. We'll avoid this frame (which has already // committed) and its children (which will be replaced). Page* page = m_frame->page(); ASSERT(page); page->mainFrame()->loader()->history()->recursiveUpdateForCommit(); } switch (type) { case FrameLoadTypeBackForward: updateForBackForwardNavigation(); return; case FrameLoadTypeReload: case FrameLoadTypeReloadFromOrigin: case FrameLoadTypeSame: updateForReload(); return; case FrameLoadTypeStandard: updateForStandardLoad(); return; case FrameLoadTypeRedirectWithLockedBackForwardList: updateForRedirectWithLockedBackForwardList(); return; case FrameLoadTypeInitialInChildFrame: updateForInitialLoadInChildFrame(); return; default: ASSERT_NOT_REACHED(); } }
void HistoryController::updateForCommit() { FrameLoader* frameLoader = m_frame->loader(); #if !LOG_DISABLED if (frameLoader->documentLoader()) LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader->documentLoader()->title().utf8().data()); #endif FrameLoadType type = frameLoader->loadType(); if (isBackForwardLoadType(type) || ((type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin) && !frameLoader->provisionalDocumentLoader()->unreachableURL().isEmpty())) { // Once committed, we want to use current item for saving DocState, and // the provisional item for restoring state. // Note previousItem must be set before we close the URL, which will // happen when the data source is made non-provisional below m_previousItem = m_currentItem; ASSERT(m_provisionalItem); m_currentItem = m_provisionalItem; m_provisionalItem = 0; } }
void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, bool didReceiveRedirectResponse, DocumentLoader* loader, PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function) { NavigationAction action = loader->triggeringAction(); if (action.isEmpty()) { action = NavigationAction(request, NavigationType::Other, loader->shouldOpenExternalURLsPolicyToPropagate()); loader->setTriggeringAction(action); } // Don't ask more than once for the same request or if we are loading an empty URL. // This avoids confusion on the part of the client. if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { function(request, 0, true); loader->setLastCheckedRequest(request); return; } // We are always willing to show alternate content for unreachable URLs; // treat it like a reload so it maintains the right state for b/f list. if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { if (isBackForwardLoadType(m_loadType)) m_loadType = FrameLoadType::Reload; function(request, 0, true); return; } if (!isAllowedByContentSecurityPolicy(request.url(), m_frame.ownerElement(), didReceiveRedirectResponse)) { function(request, 0, false); return; } loader->setLastCheckedRequest(request); m_callback.set(request, formState.get(), WTFMove(function)); #if USE(QUICK_LOOK) // Always allow QuickLook-generated URLs based on the protocol scheme. if (!request.isNull() && request.url().protocolIs(QLPreviewProtocol())) { continueAfterNavigationPolicy(PolicyUse); return; } #endif #if ENABLE(CONTENT_FILTERING) if (m_contentFilterUnblockHandler.canHandleRequest(request)) { RefPtr<Frame> frame { &m_frame }; m_contentFilterUnblockHandler.requestUnblockAsync([frame](bool unblocked) { if (unblocked) frame->loader().reload(); }); continueAfterNavigationPolicy(PolicyIgnore); return; } m_contentFilterUnblockHandler = { }; #endif m_delegateIsDecidingNavigationPolicy = true; m_suggestedFilename = action.downloadAttribute(); m_frame.loader().client().dispatchDecidePolicyForNavigationAction(action, request, formState, [this](PolicyAction action) { continueAfterNavigationPolicy(action); }); m_delegateIsDecidingNavigationPolicy = false; }