Chromium Code Reviews| Index: third_party/WebKit/Source/core/loader/FrameLoader.cpp |
| diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp |
| index 106c4f26e566f077b9d9832b1beb426dc3fb2e7a..4037cecb2ea45a697096fcd002e273dc2c64b600 100644 |
| --- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp |
| +++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp |
| @@ -189,8 +189,7 @@ FrameLoader::FrameLoader(LocalFrame* frame) |
| &FrameLoader::checkTimerFired), |
| m_forcedSandboxFlags(SandboxNone), |
| m_dispatchingDidClearWindowObjectInMainWorld(false), |
| - m_protectProvisionalLoader(false), |
| - m_isNavigationHandledByClient(false) { |
| + m_protectProvisionalLoader(false) { |
| DCHECK(m_frame); |
| TRACE_EVENT_OBJECT_CREATED_WITH_ID("loading", "FrameLoader", this); |
| takeObjectSnapshot(); |
| @@ -703,8 +702,7 @@ static bool shouldSendFinishNotification(LocalFrame* frame) { |
| return true; |
| } |
| -static bool shouldSendCompleteNotification(LocalFrame* frame, |
| - bool isNavigationHandledByClient) { |
| +static bool shouldSendCompleteNotification(LocalFrame* frame) { |
| // FIXME: We might have already sent stop notifications and be re-completing. |
| if (!frame->isLoading()) |
| return false; |
| @@ -744,7 +742,7 @@ void FrameLoader::checkCompleted() { |
| return; |
| } |
| - if (shouldSendCompleteNotification(m_frame, m_isNavigationHandledByClient)) { |
| + if (shouldSendCompleteNotification(m_frame)) { |
| m_progressTracker->progressCompleted(); |
| // Retry restoring scroll offset since finishing loading disables content |
| // size clamping. |
| @@ -865,9 +863,6 @@ void FrameLoader::loadInSameDocument( |
| // scroll should cancel it. |
| detachDocumentLoader(m_provisionalDocumentLoader); |
| - // PlzNavigate: A fragment scroll should clear ongoing client navigations. |
| - clearNavigationHandledByClient(); |
| - |
| if (!m_frame->host()) |
| return; |
| saveScrollState(); |
| @@ -1245,13 +1240,6 @@ void FrameLoader::stopAllLoaders() { |
| m_inStopAllLoaders = true; |
| - if (m_isNavigationHandledByClient) { |
| - client()->dispatchDidFailProvisionalLoad( |
| - ResourceError::cancelledError(String()), StandardCommit); |
| - } |
| - |
| - clearNavigationHandledByClient(); |
| - |
| for (Frame* child = m_frame->tree().firstChild(); child; |
| child = child->tree().nextSibling()) { |
| if (child->isLocalFrame()) |
| @@ -1383,10 +1371,7 @@ void FrameLoader::commitProvisionalLoad() { |
| client()->transitionToCommittedForNewPage(); |
| - // PlzNavigate: We need to ensure that script initiated navigations are |
| - // honored. |
| - if (!m_isNavigationHandledByClient) |
| - m_frame->navigationScheduler().cancel(); |
| + m_frame->navigationScheduler().cancel(); |
| m_frame->editor().clearLastEditCommand(); |
| @@ -1515,6 +1500,8 @@ void FrameLoader::loadFailed(DocumentLoader* loader, |
| HistoryCommitType historyCommitType = |
| loadTypeToCommitType(loader->loadType()); |
| if (loader == m_provisionalDocumentLoader) { |
| + if (!m_provisionalDocumentLoader->didStart()) |
| + InspectorInstrumentation::frameClearedScheduledClientNavigation(m_frame); |
| m_provisionalDocumentLoader->setSentDidFinishLoad(); |
| client()->dispatchDidFailProvisionalLoad(error, historyCommitType); |
| if (loader != m_provisionalDocumentLoader) |
| @@ -1626,7 +1613,7 @@ bool FrameLoader::shouldClose(bool isReload) { |
| return shouldClose; |
| } |
| -bool FrameLoader::shouldContinueForNavigationPolicy( |
| +NavigationPolicy FrameLoader::shouldContinueForNavigationPolicy( |
| const ResourceRequest& request, |
| const SubstituteData& substituteData, |
| DocumentLoader* loader, |
| @@ -1638,7 +1625,7 @@ bool FrameLoader::shouldContinueForNavigationPolicy( |
| HTMLFormElement* form) { |
| // Don't ask if we are loading an empty URL. |
| if (request.url().isEmpty() || substituteData.isValid()) |
| - return true; |
| + return NavigationPolicyCurrentTab; |
| // If we're loading content into |m_frame| (NavigationPolicyCurrentTab), check |
| // against the parent's Content Security Policy and kill the load if that |
| @@ -1656,7 +1643,7 @@ bool FrameLoader::shouldContinueForNavigationPolicy( |
| // page load. |
| m_frame->document()->enforceSandboxFlags(SandboxOrigin); |
| m_frame->owner()->dispatchLoad(); |
| - return false; |
| + return NavigationPolicyIgnore; |
| } |
| } |
| } |
| @@ -1666,48 +1653,36 @@ bool FrameLoader::shouldContinueForNavigationPolicy( |
| if (isFormSubmission && |
| !m_frame->document()->contentSecurityPolicy()->allowFormAction( |
| request.url())) |
| - return false; |
| + return NavigationPolicyIgnore; |
| bool replacesCurrentHistoryItem = |
| frameLoadType == FrameLoadTypeReplaceCurrentItem; |
| policy = client()->decidePolicyForNavigation(request, loader, type, policy, |
| replacesCurrentHistoryItem, |
| isClientRedirect, form); |
| - if (policy == NavigationPolicyCurrentTab) |
| - return true; |
| - if (policy == NavigationPolicyIgnore) |
| - return false; |
| - if (policy == NavigationPolicyHandledByClient) { |
| - setNavigationHandledByClient(); |
| - // Mark the frame as loading since the embedder is handling the navigation. |
| - m_progressTracker->progressStarted(frameLoadType); |
| - |
| - m_frame->navigationScheduler().cancel(); |
| - |
| - // If this is a form submit, dispatch that a form is being submitted |
| - // since the embedder is handling the navigation. |
| - if (form) |
| - client()->dispatchWillSubmitForm(form); |
| - |
| - m_frame->document()->cancelParsing(); |
| - |
| - return false; |
| + if (policy == NavigationPolicyCurrentTab || |
| + policy == NavigationPolicyIgnore || |
| + policy == NavigationPolicyHandledByClient || |
| + policy == NavigationPolicyHandledByClientForInitialHistory) { |
| + return policy; |
| } |
| + |
| if (!LocalDOMWindow::allowPopUp(*m_frame) && |
| !UserGestureIndicator::utilizeUserGesture()) |
| - return false; |
| + return NavigationPolicyIgnore; |
| client()->loadURLExternally(request, policy, String(), |
| replacesCurrentHistoryItem); |
| - return false; |
| + return NavigationPolicyIgnore; |
| } |
| -bool FrameLoader::checkLoadCanStart(FrameLoadRequest& frameLoadRequest, |
| - FrameLoadType type, |
| - NavigationPolicy navigationPolicy, |
| - NavigationType navigationType) { |
| +NavigationPolicy FrameLoader::checkLoadCanStart( |
| + FrameLoadRequest& frameLoadRequest, |
| + FrameLoadType type, |
| + NavigationPolicy navigationPolicy, |
| + NavigationType navigationType) { |
| if (m_frame->document()->pageDismissalEventBeingDispatched() != |
| Document::NoDismissal) { |
| - return false; |
| + return NavigationPolicyIgnore; |
| } |
| // Record the latest requiredCSP value that will be used when sending this |
| @@ -1716,25 +1691,12 @@ bool FrameLoader::checkLoadCanStart(FrameLoadRequest& frameLoadRequest, |
| recordLatestRequiredCSP(); |
| modifyRequestForCSP(resourceRequest, nullptr); |
| - if (!shouldContinueForNavigationPolicy( |
| - resourceRequest, frameLoadRequest.substituteData(), nullptr, |
| - frameLoadRequest.shouldCheckMainWorldContentSecurityPolicy(), |
| - navigationType, navigationPolicy, type, |
| - frameLoadRequest.clientRedirect() == |
| - ClientRedirectPolicy::ClientRedirect, |
| - frameLoadRequest.form())) { |
| - return false; |
| - } |
| - |
| - m_frame->document()->cancelParsing(); |
| - detachDocumentLoader(m_provisionalDocumentLoader); |
| - |
| - // beforeunload fired above, and detaching a DocumentLoader can fire events, |
| - // which can detach this frame. |
| - if (!m_frame->host()) |
| - return false; |
| - |
| - return true; |
| + return shouldContinueForNavigationPolicy( |
| + resourceRequest, frameLoadRequest.substituteData(), nullptr, |
| + frameLoadRequest.shouldCheckMainWorldContentSecurityPolicy(), |
| + navigationType, navigationPolicy, type, |
| + frameLoadRequest.clientRedirect() == ClientRedirectPolicy::ClientRedirect, |
| + frameLoadRequest.form()); |
| } |
| void FrameLoader::startLoad(FrameLoadRequest& frameLoadRequest, |
| @@ -1751,50 +1713,46 @@ void FrameLoader::startLoad(FrameLoadRequest& frameLoadRequest, |
| ? WebURLRequest::FrameTypeTopLevel |
| : WebURLRequest::FrameTypeNested); |
| - if (!checkLoadCanStart(frameLoadRequest, type, navigationPolicy, |
| - navigationType)) { |
| - if (m_isNavigationHandledByClient) { |
| - // PlzNavigate: if the navigation is a commit of a client-handled |
| - // navigation, record that there is no longer a navigation handled by the |
| - // client. |
| - if (!frameLoadRequest.resourceRequest().checkForBrowserSideNavigation()) { |
| - clearNavigationHandledByClient(); |
| - } else { |
| - DocumentLoader* loader = createDocumentLoader( |
| - resourceRequest, frameLoadRequest, type, navigationType); |
| - // PlzNavigate: If the navigation is handled by the client, then the |
| - // didFinishDocumentLoad() event occurs before the |
| - // didStartProvisionalLoad() notification which occurs after the |
| - // navigation |
| - // is committed. This causes a number of layout tests to fail. We |
| - // workaround this by invoking the didStartProvisionalLoad() |
| - // notification |
| - // here. Consumers of the didStartProvisionalLoad() notification rely on |
| - // the provisional loader and save navigation state in it. We want to |
| - // avoid |
| - // this dependency on the provisional loader. For now we create a |
| - // temporary |
| - // loader and pass it to the didStartProvisionalLoad() function. |
| - // TODO(ananta) |
| - // We should get rid of the dependency on the DocumentLoader in |
| - // consumers |
| - // of |
| - // the didStartProvisionalLoad() notification. |
| - client()->dispatchDidStartProvisionalLoad(loader); |
| - DCHECK(loader); |
| - loader->setSentDidFinishLoad(); |
| - loader->detachFromFrame(); |
| - } |
| + bool hadPlaceholderClientDocumentLoader = |
| + m_provisionalDocumentLoader && !m_provisionalDocumentLoader->didStart(); |
| + navigationPolicy = checkLoadCanStart(frameLoadRequest, type, navigationPolicy, |
| + navigationType); |
| + if (navigationPolicy == NavigationPolicyIgnore) { |
| + if (hadPlaceholderClientDocumentLoader && |
| + !resourceRequest.checkForBrowserSideNavigation()) { |
| + detachDocumentLoader(m_provisionalDocumentLoader); |
| } |
| return; |
| } |
| + // For PlzNavigate placeholder DocumentLoaders, don't send failure callbacks |
| + // for a placeholder simply being replaced with a new DocumentLoader. |
| + if (hadPlaceholderClientDocumentLoader) |
| + m_provisionalDocumentLoader->setSentDidFinishLoad(); |
| + m_frame->document()->cancelParsing(); |
| + detachDocumentLoader(m_provisionalDocumentLoader); |
| + |
| + // beforeunload fired above, and detaching a DocumentLoader can fire events, |
| + // which can detach this frame. |
|
clamy
2017/03/02 14:37:18
How likely is it that detaching the DocumentLoader
Nate Chapin
2017/03/02 19:39:18
In my experience, the primary user of this feature
clamy
2017/03/03 13:45:34
My question here was about the brief interval of t
Nate Chapin
2017/03/03 20:19:14
I believe that is correct. Though the possibly of
|
| + if (!m_frame->host()) |
| + return; |
| + |
| + m_progressTracker->progressStarted(type); |
|
clamy
2017/03/02 14:37:18
Can we now call this all the time? We had an issue
Nate Chapin
2017/03/02 19:39:18
Yes, see change to ProgressTracker.cpp. Alternatel
clamy
2017/03/03 13:45:34
Acknowledged.
|
| + // TODO(japhet): This case wants to flag the frame as loading and do nothing |
| + // else. It'd be nice if it could go through the placeholder DocumentLoader |
| + // path, too. |
| + if (navigationPolicy == NavigationPolicyHandledByClientForInitialHistory) |
| + return; |
| + DCHECK(navigationPolicy == NavigationPolicyCurrentTab || |
| + navigationPolicy == NavigationPolicyHandledByClient); |
| + |
| m_provisionalDocumentLoader = createDocumentLoader( |
| resourceRequest, frameLoadRequest, type, navigationType); |
| // PlzNavigate: We need to ensure that script initiated navigations are |
| // honored. |
| - if (!m_isNavigationHandledByClient) { |
| + if (!hadPlaceholderClientDocumentLoader || |
| + navigationPolicy == NavigationPolicyHandledByClient) { |
| m_frame->navigationScheduler().cancel(); |
| m_checkTimer.stop(); |
| } |
| @@ -1802,29 +1760,23 @@ void FrameLoader::startLoad(FrameLoadRequest& frameLoadRequest, |
| if (frameLoadRequest.form()) |
| client()->dispatchWillSubmitForm(frameLoadRequest.form()); |
| - bool isNavigationHandledByClient = m_isNavigationHandledByClient; |
| - // If the loader wasn't waiting for the client to handle a navigation, update |
| - // the progress tracker. Otherwise don't, as it was already notified before |
| - // sending the navigation to teh client. |
| - if (!m_isNavigationHandledByClient) |
| - m_progressTracker->progressStarted(type); |
| - else |
| - m_isNavigationHandledByClient = false; |
| - |
| m_provisionalDocumentLoader->appendRedirect( |
| m_provisionalDocumentLoader->getRequest().url()); |
| - // TODO(ananta) |
| + // TODO(ananta): |
| // We should get rid of the dependency on the DocumentLoader in consumers of |
| // the didStartProvisionalLoad() notification. |
| client()->dispatchDidStartProvisionalLoad(m_provisionalDocumentLoader); |
| DCHECK(m_provisionalDocumentLoader); |
| - m_provisionalDocumentLoader->startLoadingMainResource(); |
| - |
| - // This should happen after the request is sent, so we don't use |
| - // clearNavigationHandledByClient() above. |
| - if (isNavigationHandledByClient) |
| + if (navigationPolicy == NavigationPolicyCurrentTab) { |
| + m_provisionalDocumentLoader->startLoadingMainResource(); |
| + // This should happen after the request is sent, so that the state |
| + // the inspector stored in the matching frameScheduledClientNavigation() |
| + // is available while sending the request. |
| InspectorInstrumentation::frameClearedScheduledClientNavigation(m_frame); |
| + } else { |
| + InspectorInstrumentation::frameScheduledClientNavigation(m_frame); |
| + } |
| takeObjectSnapshot(); |
| } |
| @@ -2032,14 +1984,4 @@ DocumentLoader* FrameLoader::createDocumentLoader( |
| return loader; |
| } |
| -void FrameLoader::setNavigationHandledByClient() { |
| - m_isNavigationHandledByClient = true; |
| - InspectorInstrumentation::frameScheduledClientNavigation(m_frame); |
| -} |
| - |
| -void FrameLoader::clearNavigationHandledByClient() { |
| - m_isNavigationHandledByClient = false; |
| - InspectorInstrumentation::frameClearedScheduledClientNavigation(m_frame); |
| -} |
| - |
| } // namespace blink |