Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(536)

Unified Diff: third_party/WebKit/Source/core/loader/DocumentLoader.cpp

Issue 2710983003: Move HistoryItem handling to DocumentLoader (Closed)
Patch Set: Address kinuko's comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/loader/DocumentLoader.cpp
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index f205367fcf98354ba7820789993b38f370f801e5..b8767260da3b54447598a4982e67326047400931 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -31,6 +31,7 @@
#include <memory>
#include "core/dom/Document.h"
+#include "core/dom/DocumentParser.h"
#include "core/dom/WeakIdentifierMap.h"
#include "core/events/Event.h"
#include "core/frame/Deprecation.h"
@@ -157,6 +158,7 @@ DEFINE_TRACE(DocumentLoader) {
visitor->trace(m_frame);
visitor->trace(m_fetcher);
visitor->trace(m_mainResource);
+ visitor->trace(m_historyItem);
visitor->trace(m_writer);
visitor->trace(m_subresourceFilter);
visitor->trace(m_documentLoadTiming);
@@ -272,12 +274,43 @@ void DocumentLoader::didObserveLoadingBehavior(
}
}
+void DocumentLoader::markAsCommitted() {
+ DCHECK_LT(m_state, Committed);
+ m_state = Committed;
+}
+
+static HistoryCommitType loadTypeToCommitType(FrameLoadType type) {
+ switch (type) {
+ case FrameLoadTypeStandard:
+ return StandardCommit;
+ case FrameLoadTypeInitialInChildFrame:
+ case FrameLoadTypeInitialHistoryLoad:
+ return InitialCommitInChildFrame;
+ case FrameLoadTypeBackForward:
+ return BackForwardCommit;
+ default:
+ break;
+ }
+ return HistoryInertCommit;
+}
+
void DocumentLoader::updateForSameDocumentNavigation(
const KURL& newURL,
- SameDocumentNavigationSource sameDocumentNavigationSource) {
+ SameDocumentNavigationSource sameDocumentNavigationSource,
+ PassRefPtr<SerializedScriptValue> data,
+ HistoryScrollRestorationType scrollRestorationType,
+ FrameLoadType type,
+ Document* initiatingDocument) {
+ if (m_frame->settings()->getHistoryEntryRequiresUserGesture() &&
+ initiatingDocument &&
+ !initiatingDocument->frame()->hasReceivedUserGesture()) {
+ type = FrameLoadTypeReplaceCurrentItem;
+ }
+
KURL oldURL = m_request.url();
m_originalRequest.setURL(newURL);
m_request.setURL(newURL);
+ setReplacesCurrentHistoryItem(type != FrameLoadTypeStandard);
if (sameDocumentNavigationSource == SameDocumentNavigationHistoryApi) {
m_request.setHTTPMethod(HTTPNames::GET);
m_request.setHTTPBody(nullptr);
@@ -286,16 +319,71 @@ void DocumentLoader::updateForSameDocumentNavigation(
if (m_isClientRedirect)
appendRedirect(oldURL);
appendRedirect(newURL);
+
+ setHistoryItemStateForCommit(
+ m_historyItem.get(), type,
+ sameDocumentNavigationSource == SameDocumentNavigationHistoryApi
+ ? HistoryNavigationType::kHistoryApi
+ : HistoryNavigationType::kFragment);
+ m_historyItem->setDocumentState(m_frame->document()->formElementsState());
+ if (sameDocumentNavigationSource == SameDocumentNavigationHistoryApi) {
+ m_historyItem->setStateObject(std::move(data));
+ m_historyItem->setScrollRestorationType(scrollRestorationType);
+ }
+ localFrameClient().dispatchDidNavigateWithinPage(
+ m_historyItem.get(), loadTypeToCommitType(type), initiatingDocument);
}
const KURL& DocumentLoader::urlForHistory() const {
return unreachableURL().isEmpty() ? url() : unreachableURL();
}
-void DocumentLoader::commitIfReady() {
- if (m_state < Committed) {
- m_state = Committed;
- frameLoader().commitProvisionalLoad();
+void DocumentLoader::setHistoryItemStateForCommit(
+ HistoryItem* oldItem,
+ FrameLoadType loadType,
+ HistoryNavigationType navigationType) {
+ if (!m_historyItem || !isBackForwardLoadType(loadType))
+ m_historyItem = HistoryItem::create();
+
+ m_historyItem->setURL(urlForHistory());
+ m_historyItem->setReferrer(SecurityPolicy::generateReferrer(
+ m_request.getReferrerPolicy(), m_historyItem->url(),
+ m_request.httpReferrer()));
+ m_historyItem->setFormInfoFromRequest(m_request);
+
+ // Don't propagate state from the old item to the new item if there isn't an
+ // old item (obviously), or if this is a back/forward navigation, since we
+ // explicitly want to restore the state we just committed.
+ if (!oldItem || isBackForwardLoadType(loadType))
+ return;
+ // Don't propagate state from the old item if this is a different-document
+ // navigation, unless the before and after pages are logically related. This
+ // means they have the same url (ignoring fragment) and the new item was
+ // loaded via reload or client redirect.
+ HistoryCommitType historyCommitType = loadTypeToCommitType(loadType);
+ if (navigationType == HistoryNavigationType::kDifferentDocument &&
+ (historyCommitType != HistoryInertCommit ||
+ !equalIgnoringFragmentIdentifier(oldItem->url(), m_historyItem->url())))
+ return;
+ m_historyItem->setDocumentSequenceNumber(oldItem->documentSequenceNumber());
+ m_historyItem->setScrollOffset(oldItem->getScrollOffset());
+ m_historyItem->setDidSaveScrollOrScaleState(
+ oldItem->didSaveScrollOrScaleState());
+ m_historyItem->setVisualViewportScrollOffset(
+ oldItem->visualViewportScrollOffset());
+ m_historyItem->setPageScaleFactor(oldItem->pageScaleFactor());
+ m_historyItem->setScrollRestorationType(oldItem->scrollRestorationType());
+
+ // The item sequence number determines whether items are "the same", such
+ // back/forward navigation between items with the same item sequence number is
+ // a no-op. Only treat this as identical if the navigation did not create a
+ // back/forward entry and the url is identical or it was loaded via
+ // history.replaceState().
+ if (historyCommitType == HistoryInertCommit &&
+ (navigationType == HistoryNavigationType::kHistoryApi ||
+ oldItem->url() == m_historyItem->url())) {
+ m_historyItem->setStateObject(oldItem->stateObject());
+ m_historyItem->setItemSequenceNumber(oldItem->itemSequenceNumber());
}
}
@@ -317,10 +405,36 @@ void DocumentLoader::notifyFinished(Resource* resource) {
m_mainResource.get());
}
- frameLoader().loadFailed(this, m_mainResource->resourceError());
+ loadFailed(m_mainResource->resourceError());
clearMainResourceHandle();
}
+void DocumentLoader::loadFailed(const ResourceError& error) {
+ if (!error.isCancellation() && m_frame->owner()) {
+ // FIXME: For now, fallback content doesn't work cross process.
+ if (m_frame->owner()->isLocal())
+ m_frame->deprecatedLocalOwner()->renderFallbackContent();
+ }
+
+ HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType);
+ FrameLoader& loader = frameLoader();
+ if (m_state < Committed) {
+ if (m_state == NotStarted)
+ probe::frameClearedScheduledClientNavigation(m_frame);
+ m_state = SentDidFinishLoad;
+ localFrameClient().dispatchDidFailProvisionalLoad(error, historyCommitType);
+ if (!m_frame)
+ return;
+ loader.detachProvisionalDocumentLoader(this);
+ } else if (m_state == Committed) {
+ if (m_frame->document()->parser())
+ m_frame->document()->parser()->stopParsing();
+ m_state = SentDidFinishLoad;
+ localFrameClient().dispatchDidFailLoad(error, historyCommitType);
+ }
+ loader.checkCompleted();
+}
+
void DocumentLoader::finishedLoading(double finishTime) {
DCHECK(m_frame->loader().stateMachine()->creatingInitialEmptyDocument() ||
!m_frame->page()->suspended() ||
@@ -332,11 +446,6 @@ void DocumentLoader::finishedLoading(double finishTime) {
if (!responseEndTime)
responseEndTime = monotonicallyIncreasingTime();
timing().setResponseEnd(responseEndTime);
-
- commitIfReady();
- if (!m_frame)
- return;
-
if (!maybeCreateArchive()) {
// If this is an empty document, it will not have actually been created yet.
// Commit dummy data so that DocumentWriter::begin() gets called and creates
@@ -400,7 +509,7 @@ bool DocumentLoader::redirectReceived(
// If a redirection happens during a back/forward navigation, don't restore
// any state from the old HistoryItem. There is a provisional history item for
// back/forward navigation only. In the other case, clearing it is a no-op.
- frameLoader().clearProvisionalHistoryItem();
+ m_historyItem.clear();
localFrameClient().dispatchDidReceiveServerRedirectForProvisionalLoad();
@@ -546,6 +655,20 @@ void DocumentLoader::ensureWriter(const AtomicString& mimeType,
if (m_writer)
return;
+ // Set history state before commitProvisionalLoad() so that we still have
+ // access to the previous committed DocumentLoader's HistoryItem, in case we
+ // need to copy state from it.
+ if (!frameLoader().stateMachine()->creatingInitialEmptyDocument()) {
+ setHistoryItemStateForCommit(frameLoader().documentLoader()->historyItem(),
+ m_loadType,
+ HistoryNavigationType::kDifferentDocument);
+ }
+
+ DCHECK_EQ(m_state, Provisional);
+ frameLoader().commitProvisionalLoad();
+ if (!m_frame)
+ return;
+
const AtomicString& encoding = response().textEncodingName();
// Prepare a DocumentInit before clearing the frame, because it may need to
@@ -580,12 +703,12 @@ void DocumentLoader::ensureWriter(const AtomicString& mimeType,
}
void DocumentLoader::commitData(const char* bytes, size_t length) {
- DCHECK_EQ(m_state, Committed);
ensureWriter(m_response.mimeType());
+ DCHECK_GE(m_state, Committed);
// This can happen if document.close() is called by an event handler while
// there's still pending incoming data.
- if (m_frame && !m_frame->document()->parsing())
+ if (!m_frame || !m_frame->document()->parsing())
return;
if (length)
@@ -636,9 +759,6 @@ void DocumentLoader::processData(const char* data, size_t length) {
if (isArchiveMIMEType(response().mimeType()))
return;
- commitIfReady();
- if (!m_frame)
- return;
commitData(data, length);
// If we are sending data to MediaDocument, we should stop here and cancel the
@@ -663,7 +783,7 @@ void DocumentLoader::detachFromFrame() {
m_fetcher->stopFetching();
if (m_frame && !sentDidFinishLoad())
- frameLoader().loadFailed(this, ResourceError::cancelledError(url()));
+ loadFailed(ResourceError::cancelledError(url()));
// If that load cancellation triggered another detach, leave.
// (fast/frames/detach-frame-nested-no-crash.html is an example of this.)
@@ -700,6 +820,8 @@ bool DocumentLoader::maybeCreateArchive() {
// The origin is the MHTML file, we need to set the base URL to the document
// encoded in the MHTML so relative URLs are resolved properly.
ensureWriter(mainResource->mimeType(), mainResource->url());
+ if (!m_frame)
+ return false;
// The Document has now been created.
m_frame->document()->enforceSandboxFlags(SandboxAll);
@@ -787,7 +909,8 @@ void DocumentLoader::didInstallNewDocument(Document* document) {
document->setReadyState(Document::Loading);
document->initContentSecurityPolicy(m_contentSecurityPolicy.release());
- frameLoader().didInstallNewDocument();
+ if (m_historyItem && isBackForwardLoadType(m_loadType))
+ document->setStateForNewFormElements(m_historyItem->getDocumentState());
String suboriginHeader = m_response.httpHeaderField(HTTPNames::Suborigin);
if (!suboriginHeader.isNull()) {
@@ -842,7 +965,22 @@ void DocumentLoader::didInstallNewDocument(Document* document) {
void DocumentLoader::didCommitNavigation() {
if (frameLoader().stateMachine()->creatingInitialEmptyDocument())
return;
- frameLoader().receivedFirstData();
+
+ if (!m_frame->loader().stateMachine()->committedMultipleRealLoads() &&
+ m_loadType == FrameLoadTypeStandard) {
+ m_frame->loader().stateMachine()->advanceTo(
+ FrameLoaderStateMachine::CommittedMultipleRealLoads);
+ }
+
+ localFrameClient().dispatchDidCommitLoad(m_historyItem.get(),
+ loadTypeToCommitType(m_loadType));
+
+ // When the embedder gets notified (above) that the new navigation has
+ // committed, the embedder will drop the old Content Security Policy and
+ // therefore now is a good time to report to the embedder the Content
+ // Security Policies that have accumulated so far for the new navigation.
+ m_frame->securityContext()->contentSecurityPolicy()->reportAccumulatedHeaders(
+ &localFrameClient());
// didObserveLoadingBehavior() must be called after dispatchDidCommitLoad() is
// called for the metrics tracking logic to handle it properly.
« no previous file with comments | « third_party/WebKit/Source/core/loader/DocumentLoader.h ('k') | third_party/WebKit/Source/core/loader/FrameLoader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698