/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include"nsDocShell.h"
#include <algorithm>
#ifdef XP_WIN # include <process.h> # define getpid _getpid #else # include <unistd.h> // for getpid() #endif
if (aLoadInfo->GetExternalContentPolicyType() !=
ExtContentPolicy::TYPE_DOCUMENT) { returnfalse;
}
return aBrowsingContext->IsTopContent();
}
// True if loading for top level document loading in active tab. staticbool IsUrgentStart(BrowsingContext* aBrowsingContext,
nsILoadInfo* aLoadInfo, uint32_t aLoadType) {
MOZ_ASSERT(aBrowsingContext);
MOZ_ASSERT(aLoadInfo);
if (!IsTopLevelDoc(aBrowsingContext, aLoadInfo)) { returnfalse;
}
if (aLoadType &
(nsIDocShell::LOAD_CMD_NORMAL | nsIDocShell::LOAD_CMD_HISTORY)) { returntrue;
}
#ifdef DEBUG if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
nsAutoCString url; if (mLastOpenedURI) {
url = mLastOpenedURI->GetSpecOrDefault();
// Data URLs can be very long, so truncate to avoid flooding the log. const uint32_t maxURLLength = 1000; if (url.Length() > maxURLLength) {
url.Truncate(maxURLLength);
}
}
// We're counting the number of |nsDocShells| to help find leaks
--gNumberOfDocShells;
MOZ_LOG(
gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
("--DOCSHELL %p == %ld [pid = %d] [id = %" PRIu64 "] [url = %s]\n",
(void*)this, gNumberOfDocShells, getpid(), mDocShellID, url.get()));
} #endif
}
bool nsDocShell::Initialize() { if (mInitialized) { // We've already been initialized. returntrue;
}
NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, "Unexpected item type in docshell");
/* static */
already_AddRefed<nsDocShell> nsDocShell::Create(
BrowsingContext* aBrowsingContext, uint64_t aContentWindowID) {
MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
nsresult rv;
RefPtr<nsDocShell> ds = new nsDocShell(aBrowsingContext, aContentWindowID);
// Initialize the underlying nsDocLoader.
rv = ds->nsDocLoader::InitWithBrowsingContext(aBrowsingContext); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr;
}
// Create our ContentListener
ds->mContentListener = new nsDSURIContentListener(ds);
// We enable if we're in the parent process in order to support non-e10s // configurations. // Note: This check is duplicated in SharedWorkerInterfaceRequestor's // constructor. if (XRE_IsParentProcess()) {
ds->mInterceptController = new ServiceWorkerInterceptController();
}
// We want to hold a strong ref to the loadgroup, so it better hold a weak // ref to us... use an InterfaceRequestorProxy to do this.
nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(ds);
ds->mLoadGroup->SetNotificationCallbacks(proxy);
// XXX(nika): We have our BrowsingContext, so we might be able to skip this. // It could be nice to directly set up our DocLoader tree?
rv = nsDocLoader::AddDocLoaderAsChildOfRoot(ds); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr;
}
// Add |ds| as a progress listener to itself. A little weird, but simpler // than reproducing all the listener-notification logic in overrides of the // various methods via which nsDocLoader can be notified. Note that this // holds an nsWeakPtr to |ds|, so it's ok.
rv = ds->AddProgressListener(ds, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
nsIWebProgress::NOTIFY_STATE_NETWORK |
nsIWebProgress::NOTIFY_LOCATION); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr;
}
// If our BrowsingContext has private browsing enabled, update the number of // private browsing docshells. if (aBrowsingContext->UsePrivateBrowsing()) {
ds->NotifyPrivateBrowsingChanged();
}
// If our parent window is present in this process, set up our parent now.
RefPtr<WindowContext> parentWC = aBrowsingContext->GetParentWindowContext(); if (parentWC && parentWC->IsInProcess()) { // If we don't have a parent element anymore, we can't finish this load! // How'd we get here?
RefPtr<Element> parentElement = aBrowsingContext->GetEmbedderElement(); if (!parentElement) {
MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentElement"); return nullptr;
}
// We have an in-process parent window, but don't have a parent nsDocShell? // How'd we get here!
nsCOMPtr<nsIDocShell> parentShell =
parentElement->OwnerDoc()->GetDocShell(); if (!parentShell) {
MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentShell"); return nullptr;
}
parentShell->AddChild(ds);
}
// Make |ds| the primary DocShell for the given context.
aBrowsingContext->SetDocShell(ds);
// Set |ds| default load flags on load group.
ds->SetLoadGroupDefaultLoadFlags(aBrowsingContext->GetDefaultLoadFlags());
if (XRE_IsParentProcess()) {
aBrowsingContext->Canonical()->MaybeAddAsProgressListener(ds);
}
return ds.forget();
}
void nsDocShell::DestroyChildren() { for (auto* child : mChildList.ForwardRange()) {
nsCOMPtr<nsIDocShellTreeItem> shell = do_QueryObject(child);
NS_ASSERTION(shell, "docshell has null child");
// Get the an auth prompter for our window so that the parenting // of the dialogs works as it should when using tabs.
nsIPrompt* prompt;
rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
NS_ENSURE_SUCCESS(rv, rv);
*aSink = prompt; return NS_OK;
} elseif (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink))
? NS_OK
: NS_NOINTERFACE;
} elseif (aIID.Equals(NS_GET_IID(nsISHistory))) { // This is deprecated, you should instead directly get // ChildSHistory from the browsing context.
MOZ_DIAGNOSTIC_ASSERT( false, "Do not try to get a nsISHistory interface from nsIDocShell"); return NS_NOINTERFACE;
} elseif (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
nsresult rv = EnsureFind(); if (NS_FAILED(rv)) { return rv;
}
NS_IMETHODIMP
nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) { // Note: this gets called fairly early (before a pageload actually starts). // We could probably defer this even longer.
nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild(); static_cast<BrowserChild*>(browserChild.get())
->SetCancelContentJSEpoch(aEpoch); return NS_OK;
}
nsresult nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating, bool aContinueHandlingSubframeHistory) {
MOZ_ASSERT(aLoadState, "Must have a valid load state!"); // NOTE: This comparison between what appears to be internal/external load // flags is intentional, as it's ensuring that the caller isn't using any of // the flags reserved for implementations by the `nsIWebNavigation` interface. // In the future, this check may be dropped.
MOZ_ASSERT(
(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0, "Should not have these flags set");
MOZ_ASSERT(aLoadState->TargetBrowsingContext().IsNull(), "Targeting doesn't occur until InternalLoad");
if (!aLoadState->TriggeringPrincipal()) {
MOZ_ASSERT(false, "LoadURI must have a triggering principal"); return NS_ERROR_FAILURE;
}
bool oldIsNavigating = mIsNavigating; auto cleanupIsNavigating =
MakeScopeExit([&]() { mIsNavigating = oldIsNavigating; }); if (aSetNavigating) {
mIsNavigating = true;
}
PopupBlocker::PopupControlState popupState = PopupBlocker::openOverridden; if (aLoadState->HasLoadFlags(LOAD_FLAGS_ALLOW_POPUPS)) {
popupState = PopupBlocker::openAllowed; // If we allow popups as part of the navigation, ensure we fake a user // interaction, so that popups can, in fact, be allowed to open. if (WindowContext* wc = mBrowsingContext->GetCurrentWindowContext()) {
wc->NotifyUserGestureActivation();
}
}
AutoPopupStatePusher statePusher(popupState);
if (aLoadState->GetCancelContentJSEpoch().isSome()) {
SetCancelContentJSEpoch(*aLoadState->GetCancelContentJSEpoch());
}
// Note: we allow loads to get through here even if mFiredUnloadEvent is // true; that case will get handled in LoadInternal or LoadHistoryEntry, // so we pass false as the second parameter to IsNavigationAllowed. // However, we don't allow the page to change location *in the middle of* // firing beforeunload, so we do need to check if *beforeunload* is currently // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP. if (!IsNavigationAllowed(true, false)) { return NS_OK; // JS may not handle returning of an error code
}
// LoadType used to be set to a default value here, if no LoadInfo/LoadState // object was passed in. That functionality has been removed as of bug // 1492648. LoadType should now be set up by the caller at the time they // create their nsDocShellLoadState object to pass into LoadURI.
if ((!aLoadState->LoadIsFromSessionHistory() &&
!LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
LOAD_FLAGS_REPLACE_HISTORY)) ||
aContinueHandlingSubframeHistory) { // This is possibly a subframe, so handle it accordingly. // // If history exists, it will be loaded into the aLoadState object, and the // LoadType will be changed. if (MaybeHandleSubframeHistory(aLoadState,
aContinueHandlingSubframeHistory)) { // MaybeHandleSubframeHistory returns true if we need to continue loading // asynchronously. return NS_OK;
}
}
if (aLoadState->LoadIsFromSessionHistory()) {
MOZ_LOG(gSHLog, LogLevel::Debug,
("nsDocShell[%p]: loading from session history", this));
// Set up the inheriting principal in LoadState.
nsresult rv = aLoadState->SetupInheritingPrincipal(
bcType, mBrowsingContext->OriginAttributesRef());
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(aLoadState->TypeHint().IsVoid(), "Typehint should be null when calling InternalLoad from LoadURI");
MOZ_ASSERT(aLoadState->FileName().IsVoid(), "FileName should be null when calling InternalLoad from LoadURI");
MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory(), "Shouldn't be loading from an entry when calling InternalLoad " "from LoadURI");
// If we have a system triggering principal, we can assume that this load was // triggered by some UI in the browser chrome, such as the URL bar or // bookmark bar. This should count as a user interaction for the current sh // entry, so that the user may navigate back to the current entry, from the // entry that is going to be added as part of this load.
nsCOMPtr<nsIPrincipal> triggeringPrincipal =
aLoadState->TriggeringPrincipal(); if (triggeringPrincipal && triggeringPrincipal->IsSystemPrincipal()) { if (mozilla::SessionHistoryInParent()) {
WindowContext* topWc = mBrowsingContext->GetTopWindowContext(); if (topWc && !topWc->IsDiscarded()) {
MOZ_ALWAYS_SUCCEEDS(topWc->SetSHEntryHasUserInteraction(true));
}
} else { bool oshe = false;
nsCOMPtr<nsISHEntry> currentSHEntry;
GetCurrentSHEntry(getter_AddRefs(currentSHEntry), &oshe); if (currentSHEntry) {
currentSHEntry->SetHasUserInteraction(true);
}
}
}
if (aLoadState->GetOriginalURIString().isSome()) { // Save URI string in case it's needed later when // sending to search engine service in EndPageLoad()
mOriginalUriString = *aLoadState->GetOriginalURIString();
}
// StopDetector is modeled similarly to OnloadBlocker; it is a rather // dummy nsIRequest implementation which can be added to an nsILoadGroup to // detect Cancel calls. class StopDetector final : public nsIRequest { public:
StopDetector() = default;
bool nsDocShell::MaybeHandleSubframeHistory(
nsDocShellLoadState* aLoadState, bool aContinueHandlingSubframeHistory) { // First, verify if this is a subframe. // Note, it is ok to rely on docshell here and not browsing context since when // an iframe is created, it has first in-process docshell.
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
GetInProcessSameTypeParent(getter_AddRefs(parentAsItem));
nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
if (!parentDS || parentDS == static_cast<nsIDocShell*>(this)) { if (mBrowsingContext && mBrowsingContext->IsTop()) { // This is the root docshell. If we got here while // executing an onLoad Handler,this load will not go // into session history. // XXX Why is this code in a method which deals with iframes! if (aLoadState->IsFormSubmission()) { #ifdef DEBUG if (!mEODForCurrentDocument) { const MaybeDiscarded<BrowsingContext>& targetBC =
aLoadState->TargetBrowsingContext();
MOZ_ASSERT_IF(GetBrowsingContext() == targetBC.get(),
aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
} #endif
} else { bool inOnLoadHandler = false;
GetIsExecutingOnLoadHandler(&inOnLoadHandler); if (inOnLoadHandler) {
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
}
}
} returnfalse;
}
/* OK. It is a subframe. Checkout the parent's loadtype. If the parent was * loaded through a history mechanism, then get the SH entry for the child * from the parent. This is done to restore frameset navigation while going * back/forward. If the parent was loaded through any other loadType, set the * child's loadType too accordingly, so that session history does not get * confused.
*/
// Get the parent's load type
uint32_t parentLoadType;
parentDS->GetLoadType(&parentLoadType);
if (!aContinueHandlingSubframeHistory) { if (mozilla::SessionHistoryInParent()) { if (nsDocShell::Cast(parentDS.get())->IsLoadingFromSessionHistory() &&
!GetCreatedDynamically()) { if (XRE_IsContentProcess()) {
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
nsCOMPtr<nsILoadGroup> loadGroup;
GetLoadGroup(getter_AddRefs(loadGroup)); if (contentChild && loadGroup && !mCheckingSessionHistory) {
RefPtr<Document> parentDoc = parentDS->GetDocument();
parentDoc->BlockOnload();
RefPtr<BrowsingContext> browsingContext = mBrowsingContext;
Maybe<uint64_t> currentLoadIdentifier =
mBrowsingContext->GetCurrentLoadIdentifier();
RefPtr<nsDocShellLoadState> loadState = aLoadState; bool isNavigating = mIsNavigating;
RefPtr<StopDetector> stopDetector = new StopDetector();
loadGroup->AddRequest(stopDetector, nullptr); // Need to set mCheckingSessionHistory so that // GetIsAttemptingToNavigate() returns true.
mCheckingSessionHistory = true;
if (!docShell || !docShell->mCheckingSessionHistory) { return;
}
if (stopDetector->Canceled()) { return;
} if (currentLoadIdentifier ==
browsingContext->GetCurrentLoadIdentifier() &&
aResult.isSome()) {
loadState->SetLoadingSessionHistoryInfo(aResult.value()); // This is an initial subframe load from the session // history, index doesn't need to be updated.
loadState->SetLoadIsFromSessionHistory(0, false);
}
// We got the results back from the parent process, call // LoadURI again with the possibly updated data.
docShell->LoadURI(loadState, isNavigating, true);
}; auto reject = [loadGroup, stopDetector, browsingContext,
parentDoc](mozilla::ipc::ResponseRejectReason) {
RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(browsingContext->GetDocShell()); if (docShell) {
docShell->mCheckingSessionHistory = false;
} // In practise reject shouldn't be called ever.
loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
parentDoc->UnblockOnload(false);
};
contentChild->SendGetLoadingSessionHistoryInfoFromParent(
mBrowsingContext, std::move(resolve), std::move(reject)); returntrue;
}
} else {
Maybe<LoadingSessionHistoryInfo> info;
mBrowsingContext->Canonical()->GetLoadingSessionHistoryInfoFromParent(
info); if (info.isSome()) {
aLoadState->SetLoadingSessionHistoryInfo(info.value()); // This is an initial subframe load from the session // history, index doesn't need to be updated.
aLoadState->SetLoadIsFromSessionHistory(0, false);
}
}
}
} else { // Get the ShEntry for the child from the parent
nsCOMPtr<nsISHEntry> currentSH; bool oshe = false;
parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); bool dynamicallyAddedChild = GetCreatedDynamically();
if (!dynamicallyAddedChild && !oshe && currentSH) { // Only use the old SHEntry, if we're sure enough that // it wasn't originally for some other frame.
nsCOMPtr<nsISHEntry> shEntry;
currentSH->GetChildSHEntryIfHasNoDynamicallyAddedChild(
mBrowsingContext->ChildOffset(), getter_AddRefs(shEntry)); if (shEntry) {
aLoadState->SetSHEntry(shEntry);
}
}
}
}
// Make some decisions on the child frame's loadType based on the // parent's loadType, if the subframe hasn't loaded anything into it. // // In some cases privileged scripts may try to get the DOMWindow // reference of this docshell before the loading starts, causing the // initial about:blank content viewer being created and mCurrentURI being // set. To handle this case we check if mCurrentURI is about:blank and // currentSHEntry is null. bool oshe = false;
nsCOMPtr<nsISHEntry> currentChildEntry;
GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);
if (mCurrentURI && (!NS_IsAboutBlank(mCurrentURI) || currentChildEntry ||
mLoadingEntry || mActiveEntry)) { // This is a pre-existing subframe. If // 1. The load of this frame was not originally initiated by session // history directly (i.e. (!shEntry) condition succeeded, but it can // still be a history load on parent which causes this frame being // loaded), which we checked with the above assert, and // 2. mCurrentURI is not null, nor the initial about:blank, // it is possible that a parent's onLoadHandler or even self's // onLoadHandler is loading a new page in this child. Check parent's and // self's busy flag and if it is set, we don't want this onLoadHandler // load to get in to session history.
BusyFlags parentBusy = parentDS->GetBusyFlags();
BusyFlags selfBusy = GetBusyFlags();
// This is a newly created frame. Check for exception cases first. // By default the subframe will inherit the parent's loadType. if (aLoadState->LoadIsFromSessionHistory() &&
(parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK)) { // The parent was loaded normally. In this case, this *brand new* // child really shouldn't have a SHEntry. If it does, it could be // because the parent is replacing an existing frame with a new frame, // in the onLoadHandler. We don't want this url to get into session // history. Clear off shEntry, and set load type to // LOAD_BYPASS_HISTORY. bool inOnLoadHandler = false;
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); if (inOnLoadHandler) {
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
aLoadState->ClearLoadIsFromSessionHistory();
}
} elseif (parentLoadType == LOAD_REFRESH) { // Clear shEntry. For refresh loads, we have to load // what comes through the pipe, not what's in history.
aLoadState->ClearLoadIsFromSessionHistory();
} elseif ((parentLoadType == LOAD_BYPASS_HISTORY) ||
(aLoadState->LoadIsFromSessionHistory() &&
((parentLoadType & LOAD_CMD_HISTORY) ||
(parentLoadType == LOAD_RELOAD_NORMAL) ||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
(parentLoadType ==
LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) { // If the parent url, bypassed history or was loaded from // history, pass on the parent's loadType to the new child // frame too, so that the child frame will also // avoid getting into history.
aLoadState->SetLoadType(parentLoadType);
} elseif (parentLoadType == LOAD_ERROR_PAGE) { // If the parent document is an error page, we don't // want to update global/session history. However, // this child frame is not an error page.
aLoadState->SetLoadType(LOAD_BYPASS_HISTORY);
} elseif ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) { // the new frame should inherit the parent's load type so that it also // bypasses the cache and/or proxy
aLoadState->SetLoadType(parentLoadType);
}
returnfalse;
}
/* * Reset state to a new content model within the current document and the * document viewer. Called by the document before initiating an out of band * document.write().
*/
NS_IMETHODIMP
nsDocShell::PrepareForNewContentModel() { // Clear out our form control state, because the state of controls // in the pre-open() document should not affect the state of // controls that are now going to be written.
SetLayoutHistoryState(nullptr);
mEODForCurrentDocument = false; return NS_OK;
}
void nsDocShell::FirePageHideNotificationInternal( bool aIsUnload, bool aSkipCheckingDynEntries) { if (mDocumentViewer && !mFiredUnloadEvent) { // Keep an explicit reference since calling PageHide could release // mDocumentViewer
nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
mFiredUnloadEvent = true;
if (mTiming) {
mTiming->NotifyUnloadEventStart();
}
viewer->PageHide(aIsUnload);
if (mTiming) {
mTiming->NotifyUnloadEventEnd();
}
AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
uint32_t n = mChildList.Length();
kids.SetCapacity(n); for (uint32_t i = 0; i < n; i++) {
kids.AppendElement(do_QueryInterface(ChildAt(i)));
}
n = kids.Length(); for (uint32_t i = 0; i < n; ++i) {
RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get()); if (child) { // Skip checking dynamic subframe entries in our children.
child->FirePageHideNotificationInternal(aIsUnload, true);
}
}
// If the document is unloading, remove all dynamic subframe entries. if (aIsUnload && !aSkipCheckingDynEntries) {
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); if (rootSH) {
MOZ_LOG(
gSHLog, LogLevel::Debug,
("nsDocShell %p unloading, remove dynamic subframe entries", this)); if (mozilla::SessionHistoryInParent()) { if (mActiveEntry) {
mBrowsingContext->RemoveDynEntriesFromActiveSessionHistoryEntry();
}
MOZ_LOG(gSHLog, LogLevel::Debug,
("nsDocShell %p unloading, no active entries", this));
} elseif (mOSHE) {
int32_t index = rootSH->Index();
rootSH->LegacySHistory()->RemoveDynEntries(index, mOSHE);
}
}
}
// Now make sure our editor, if any, is detached before we go // any farther.
DetachEditorFromWindow();
}
}
// Emulate what non-SHIP BFCache does too. In pageshow case // add and remove a request and before that call SetCurrentURI to get // the location change notification. // For pagehide, set mFiredUnloadEvent to true, so that unload doesn't fire.
nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer); if (aShow) {
viewer->SetIsHidden(false);
mRefreshURIList = std::move(mBFCachedRefreshURIList);
RefreshURIFromQueue();
mFiredUnloadEvent = false;
RefPtr<Document> doc = viewer->GetDocument(); if (doc) {
doc->NotifyActivityChanged();
nsCOMPtr<nsPIDOMWindowInner> inner =
mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr; if (mBrowsingContext->IsTop()) {
doc->NotifyPossibleTitleChange(false);
doc->SetLoadingOrRestoredFromBFCacheTimeStampToNow(); if (inner) { // Now that we have found the inner window of the page restored // from the history, we have to make sure that // performance.navigation.type is 2. // Traditionally this type change has been done to the top level page // only.
Performance* performance = inner->GetPerformance(); if (performance) {
performance->GetDOMTiming()->NotifyRestoreStart();
}
}
}
nsCOMPtr<nsIChannel> channel = doc->GetChannel(); if (channel) {
SetLoadType(LOAD_HISTORY);
mEODForCurrentDocument = false;
mIsRestoringDocument = true;
mLoadGroup->AddRequest(channel, nullptr);
nsCOMPtr<nsIURI> uri; if (doc->FragmentDirective()) { // If we have fragment directives, then we've mutated the document // uri. Set the current URI from session history instead. if (mozilla::SessionHistoryInParent()) {
uri = mActiveEntry ? mActiveEntry->GetURI() : nullptr;
} elseif (mOSHE) {
uri = mOSHE->GetURI();
}
} if (!uri) {
uri = doc->GetDocumentURI();
}
SetCurrentURI(uri, channel, /* aFireOnLocationChange */ true, /* aIsInitialAboutBlank */ false, /* aLocationFlags */ 0);
mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
mIsRestoringDocument = false;
}
RefPtr<PresShell> presShell = GetPresShell(); if (presShell) {
presShell->Thaw(false);
}
if (inner) {
inner->FireDelayedDOMEvents(false);
}
}
} elseif (!mFiredUnloadEvent) { // XXXBFCache check again that the page can enter bfcache. // XXXBFCache should mTiming->NotifyUnloadEventStart()/End() be called here?
if (mRefreshURIList) {
RefreshURIToQueue();
mBFCachedRefreshURIList = std::move(mRefreshURIList);
} else { // If Stop was called, the list was moved to mSavedRefreshURIList after // calling SuspendRefreshURIs, which calls RefreshURIToQueue.
mBFCachedRefreshURIList = std::move(mSavedRefreshURIList);
}
nsresult nsDocShell::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) {
nsCOMPtr<nsIRunnable> runnable(aRunnable); if (NS_WARN_IF(!GetWindow())) { // Window should only be unavailable after destroyed.
MOZ_ASSERT(mIsBeingDestroyed); return NS_ERROR_FAILURE;
} return SchedulerGroup::Dispatch(runnable.forget());
}
NS_IMETHODIMP
nsDocShell::SetCurrentURIForSessionStore(nsIURI* aURI) { // Note that securityUI will set STATE_IS_INSECURE, even if // the scheme of |aURI| is "https".
SetCurrentURI(aURI, nullptr, /* aFireOnLocationChange */ true, /* aIsInitialAboutBlank */ false, /* aLocationFlags */
nsIWebProgressListener::LOCATION_CHANGE_SESSION_STORE); return NS_OK;
}
// We don't want to send a location change when we're displaying an error // page, and we don't want to change our idea of "current URI" either if (mLoadType == LOAD_ERROR_PAGE) { returnfalse;
}
if (!NS_IsAboutBlank(mCurrentURI)) {
mHasLoadedNonBlankURI = true;
}
// Don't fire onLocationChange when creating a subframe's initial about:blank // document, as this can happen when it's not safe for us to run script. if (aIsInitialAboutBlank && !mHasLoadedNonBlankURI &&
!mBrowsingContext->IsTop()) {
MOZ_ASSERT(!aRequest && aLocationFlags == 0); returnfalse;
}
int32_t charsetSource = doc->GetDocumentCharacterSetSource(); auto encoding = doc->GetDocumentCharacterSet(); // AsHTMLDocument is valid, because we called // WillIgnoreCharsetOverride() above. if (doc->AsHTMLDocument()->IsPlainText()) { switch (charsetSource) { case kCharsetFromInitialAutoDetectionASCII: // Deliberately no final version
LOGCHARSETMENU(("TEXT:UnlabeledAscii")); break; case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII: case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8")); break; case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8TLD")); break; case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8: case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
LOGCHARSETMENU(("TEXT:UnlabeledUtf8")); break; case kCharsetFromChannel: if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("TEXT:ChannelUtf8"));
} else {
LOGCHARSETMENU(("TEXT:ChannelNonUtf8"));
} break; default:
LOGCHARSETMENU(("TEXT:Bug")); break;
}
} else { switch (charsetSource) { case kCharsetFromInitialAutoDetectionASCII: // Deliberately no final version
LOGCHARSETMENU(("HTML:UnlabeledAscii")); break; case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII: case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledNonUtf8")); break; case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD: case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledNonUtf8TLD")); break; case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8: case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
LOGCHARSETMENU(("HTML:UnlabeledUtf8")); break; case kCharsetFromChannel: if (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("HTML:ChannelUtf8"));
} else {
LOGCHARSETMENU(("HTML:ChannelNonUtf8"));
} break; case kCharsetFromXmlDeclaration: case kCharsetFromMetaTag: if (isFileURL) {
LOGCHARSETMENU(("HTML:LocalLabeled"));
} elseif (encoding == UTF_8_ENCODING) {
LOGCHARSETMENU(("HTML:MetaUtf8"));
} else {
LOGCHARSETMENU(("HTML:MetaNonUtf8"));
} break; default:
LOGCHARSETMENU(("HTML:Bug")); break;
}
} return NS_OK;
}
// Mute or unmute audio contexts attached to the inner window. if (mScriptGlobal) { if (nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow()) { if (aAllowMedia) {
innerWin->UnmuteAudioContexts();
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.51Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.