1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDocShell.h"
13 #define getpid _getpid
15 #include <unistd.h> // for getpid()
18 #include "mozilla/ArrayUtils.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/AutoRestore.h"
21 #include "mozilla/BasePrincipal.h"
22 #include "mozilla/Casting.h"
23 #include "mozilla/Encoding.h"
24 #include "mozilla/EventStateManager.h"
25 #include "mozilla/HTMLEditor.h"
26 #include "mozilla/LoadInfo.h"
27 #include "mozilla/Logging.h"
28 #include "mozilla/MediaFeatureChange.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/ResultExtensions.h"
31 #include "mozilla/Services.h"
32 #include "mozilla/StartupTimeline.h"
33 #include "mozilla/Telemetry.h"
34 #include "mozilla/Unused.h"
36 #include "mozilla/dom/ClientChannelHelper.h"
37 #include "mozilla/dom/ClientHandle.h"
38 #include "mozilla/dom/ClientInfo.h"
39 #include "mozilla/dom/ClientManager.h"
40 #include "mozilla/dom/ClientSource.h"
41 #include "mozilla/dom/ContentChild.h"
42 #include "mozilla/dom/DocGroup.h"
43 #include "mozilla/dom/Element.h"
44 #include "mozilla/dom/HTMLAnchorElement.h"
45 #include "mozilla/dom/PerformanceNavigation.h"
46 #include "mozilla/dom/PermissionMessageUtils.h"
47 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
48 #include "mozilla/dom/ScreenOrientation.h"
49 #include "mozilla/dom/ScriptSettings.h"
50 #include "mozilla/dom/ServiceWorkerInterceptController.h"
51 #include "mozilla/dom/ServiceWorkerUtils.h"
52 #include "mozilla/dom/TabChild.h"
53 #include "mozilla/dom/TabGroup.h"
54 #include "mozilla/dom/ToJSValue.h"
55 #include "mozilla/dom/ChildSHistory.h"
58 #include "mozilla/net/ReferrerPolicy.h"
60 #include "nsIApplicationCacheChannel.h"
61 #include "nsIApplicationCacheContainer.h"
62 #include "nsIAppShell.h"
63 #include "nsIAsyncVerifyRedirectCallback.h"
64 #include "nsIAuthPrompt.h"
65 #include "nsIAuthPrompt2.h"
66 #include "nsICachingChannel.h"
67 #include "nsICaptivePortalService.h"
68 #include "nsIChannel.h"
69 #include "nsIChannelEventSink.h"
70 #include "nsIClassOfService.h"
71 #include "nsICommandManager.h"
72 #include "nsIConsoleReportCollector.h"
73 #include "nsIContent.h"
74 #include "nsIContentInlines.h"
75 #include "nsIContentSecurityPolicy.h"
76 #include "nsIContentViewer.h"
77 #include "nsIController.h"
78 #include "nsICookieService.h"
79 #include "nsIDocShellTreeItem.h"
80 #include "nsIDocShellTreeOwner.h"
81 #include "nsIDocument.h"
82 #include "nsIDocumentLoaderFactory.h"
83 #include "nsIDOMStorage.h"
84 #include "nsIDOMWindow.h"
85 #include "nsIEditingSession.h"
86 #include "nsIExternalProtocolService.h"
87 #include "nsIFormPOSTActionChannel.h"
89 #include "nsIGlobalObject.h"
90 #include "nsIHttpChannel.h"
91 #include "nsIHttpChannelInternal.h"
92 #include "nsIIDNService.h"
93 #include "nsIInputStreamChannel.h"
94 #include "nsIInterfaceRequestorUtils.h"
95 #include "nsIJARChannel.h"
96 #include "nsILayoutHistoryState.h"
97 #include "nsILoadInfo.h"
98 #include "nsIMultiPartChannel.h"
99 #include "nsINestedURI.h"
100 #include "nsINetworkPredictor.h"
102 #include "nsINSSErrorsService.h"
103 #include "nsIObserverService.h"
104 #include "nsIOService.h"
105 #include "nsIPrincipal.h"
106 #include "nsIPrivacyTransitionObserver.h"
107 #include "nsIPrompt.h"
108 #include "nsIPromptFactory.h"
109 #include "nsIReflowObserver.h"
110 #include "nsIScriptChannel.h"
111 #include "nsIScriptObjectPrincipal.h"
112 #include "nsIScriptSecurityManager.h"
113 #include "nsIScrollableFrame.h"
114 #include "nsIScrollObserver.h"
115 #include "nsISecureBrowserUI.h"
116 #include "nsISecurityUITelemetry.h"
117 #include "nsISeekableStream.h"
118 #include "nsISelectionDisplay.h"
119 #include "nsISHContainer.h"
120 #include "nsISHEntry.h"
121 #include "nsISHistory.h"
122 #include "nsISHistoryInternal.h"
123 #include "nsISiteSecurityService.h"
124 #include "nsISocketProvider.h"
125 #include "nsIStringBundle.h"
126 #include "nsIStructuredCloneContainer.h"
127 #include "nsISupportsPrimitives.h"
128 #include "nsITabChild.h"
129 #include "nsITextToSubURI.h"
130 #include "nsITimedChannel.h"
131 #include "nsITimer.h"
132 #include "nsITransportSecurityInfo.h"
133 #include "nsIUploadChannel.h"
134 #include "nsIURIFixup.h"
135 #include "nsIURILoader.h"
136 #include "nsIURIMutator.h"
138 #include "nsIViewSourceChannel.h"
139 #include "nsIWebBrowserChrome.h"
140 #include "nsIWebBrowserChrome3.h"
141 #include "nsIWebBrowserChromeFocus.h"
142 #include "nsIWebBrowserFind.h"
143 #include "nsIWebProgress.h"
144 #include "nsIWidget.h"
145 #include "nsIWindowWatcher.h"
146 #include "nsIWritablePropertyBag2.h"
147 #include "nsIWyciwygChannel.h"
149 #include "nsPICommandUpdater.h"
150 #include "nsPIDOMWindow.h"
151 #include "nsPILoadGroupInternal.h"
152 #include "nsPIWindowRoot.h"
154 #include "IHistory.h"
155 #include "IUrlClassifierUITelemetry.h"
157 #include "mozIThirdPartyUtil.h"
160 #include "nsArrayUtils.h"
161 #include "nsAutoPtr.h"
162 #include "nsCDefaultURIFixup.h"
163 #include "nsCExternalHandlerService.h"
164 #include "nsContentDLF.h"
165 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
166 #include "nsContentSecurityManager.h"
167 #include "nsContentUtils.h"
168 #include "nsCURILoader.h"
169 #include "nsDocShellCID.h"
170 #include "nsDocShellEditorData.h"
171 #include "nsDocShellEnumerator.h"
172 #include "nsDocShellLoadInfo.h"
173 #include "nsDocShellLoadTypes.h"
174 #include "nsDOMCID.h"
175 #include "nsDOMNavigationTiming.h"
176 #include "nsDSURIContentListener.h"
178 #include "nsEscape.h"
179 #include "nsFocusManager.h"
180 #include "nsGlobalWindow.h"
181 #include "nsJSEnvironment.h"
182 #include "nsNetCID.h"
183 #include "nsNetUtil.h"
184 #include "nsObjectLoadingContent.h"
185 #include "nsPingListener.h"
187 #include "nsQueryObject.h"
189 #include "nsRefreshTimer.h"
190 #include "nsSandboxFlags.h"
191 #include "nsSHistory.h"
192 #include "nsStructuredCloneContainer.h"
193 #include "nsSubDocumentFrame.h"
195 #include "nsViewManager.h"
196 #include "nsViewSourceHandler.h"
197 #include "nsWhitespaceTokenizer.h"
198 #include "nsWidgetsCID.h"
199 #include "nsXULAppAPI.h"
201 #include "GeckoProfiler.h"
202 #include "Navigator.h"
203 #include "NullPrincipal.h"
205 #include "URIUtils.h"
207 #include "timeline/JavascriptTimelineMarker.h"
210 #include "nsIFaviconService.h"
211 #include "mozIPlacesPendingOperation.h"
215 #include "nsIDocumentViewerPrint.h"
216 #include "nsIWebBrowserPrint.h"
219 #ifdef MOZ_TOOLKIT_SEARCH
220 #include "nsIBrowserSearchService.h"
223 using namespace mozilla
;
224 using namespace mozilla::dom
;
225 using namespace mozilla::net
;
227 // Threshold value in ms for META refresh based redirects
228 #define REFRESH_REDIRECT_TIMER 15000
230 // Hint for native dispatch of events on how long to delay after
231 // all documents have loaded in milliseconds before favoring normal
232 // native event dispatch priorites over performance
233 // Can be overridden with docshell.event_starvation_delay_hint pref.
234 #define NS_EVENT_STARVATION_DELAY_HINT 2000
236 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
238 // True means sUseErrorPages has been added to
239 // preferences var cache.
240 static bool gAddedPreferencesVarCache
= false;
242 // Number of documents currently loading
243 static int32_t gNumberOfDocumentsLoading
= 0;
245 // Global count of existing docshells.
246 static int32_t gDocShellCount
= 0;
248 // Global count of docshells with the private attribute set
249 static uint32_t gNumberOfPrivateDocShells
= 0;
251 // True means we validate window targets to prevent frameset
252 // spoofing. Initialize this to a non-bolean value so we know to check
253 // the pref on the creation of the first docshell.
254 static uint32_t gValidateOrigin
= 0xffffffff;
257 static mozilla::LazyLogModule
gDocShellLog("nsDocShell");
259 static mozilla::LazyLogModule
gDocShellLeakLog("nsDocShellLeak");;
261 const char kBrandBundleURL
[] = "chrome://branding/locale/brand.properties";
262 const char kAppstringsBundleURL
[] = "chrome://global/locale/appstrings.properties";
264 bool nsDocShell::sUseErrorPages
= false;
266 // Global reference to the URI fixup service.
267 nsIURIFixup
* nsDocShell::sURIFixup
= nullptr;
270 FavorPerformanceHint(bool aPerfOverStarvation
)
272 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
274 appShell
->FavorPerformanceHint(
276 Preferences::GetUint("docshell.event_starvation_delay_hint",
277 NS_EVENT_STARVATION_DELAY_HINT
));
282 IncreasePrivateDocShellCount()
284 gNumberOfPrivateDocShells
++;
285 if (gNumberOfPrivateDocShells
> 1 ||
286 !XRE_IsContentProcess()) {
290 mozilla::dom::ContentChild
* cc
= mozilla::dom::ContentChild::GetSingleton();
291 cc
->SendPrivateDocShellsExist(true);
295 DecreasePrivateDocShellCount()
297 MOZ_ASSERT(gNumberOfPrivateDocShells
> 0);
298 gNumberOfPrivateDocShells
--;
299 if (!gNumberOfPrivateDocShells
) {
300 if (XRE_IsContentProcess()) {
301 dom::ContentChild
* cc
= dom::ContentChild::GetSingleton();
302 cc
->SendPrivateDocShellsExist(false);
306 nsCOMPtr
<nsIObserverService
> obsvc
= services::GetObserverService();
308 obsvc
->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
313 nsDocShell::nsDocShell()
315 , mForcedCharset(nullptr)
316 , mParentCharset(nullptr)
317 , mTreeOwner(nullptr)
318 , mChromeEventHandler(nullptr)
319 , mDefaultScrollbarPref(Scrollbar_Auto
, Scrollbar_Auto
)
320 , mCharsetReloadState(eCharsetReloadInit
)
321 , mOrientationLock(eScreenOrientation_None
)
322 , mParentCharsetSource(0)
325 , mItemType(typeContent
)
326 , mPreviousTransIndex(-1)
327 , mLoadedTransIndex(-1)
330 , mBusyFlags(BUSY_FLAGS_NONE
)
331 , mAppType(nsIDocShell::APP_TYPE_UNKNOWN
)
333 , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL
)
336 , mFrameType(FRAME_TYPE_REGULAR
)
337 , mPrivateBrowsingId(0)
338 , mDisplayMode(nsIDocShell::DISPLAY_MODE_BROWSER
)
339 , mJSRunToCompletionDepth(0)
340 , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE
)
341 , mFullscreenAllowed(CHECK_ATTRIBUTES
)
342 , mCreatingDocument(false)
344 , mInEnsureScriptEnv(false)
347 , mAllowSubframes(true)
348 , mAllowPlugins(true)
349 , mAllowJavascript(true)
350 , mAllowMetaRedirects(true)
353 , mAllowDNSPrefetch(true)
354 , mAllowWindowControl(true)
355 , mAllowContentRetargeting(true)
356 , mAllowContentRetargetingOnChildren(true)
357 , mUseErrorPages(false)
358 , mObserveErrorPages(true)
359 , mCSSErrorReportingEnabled(false)
361 , mAllowKeywordFixup(false)
362 , mIsOffScreenBrowser(false)
364 , mDisableMetaRefreshWhenInactive(false)
366 , mUseGlobalHistory(false)
367 , mUseRemoteTabs(false)
368 , mUseTrackingProtection(false)
369 , mDeviceSizeIsPageSize(false)
370 , mWindowDraggingAllowed(false)
371 , mInFrameSwap(false)
372 , mInheritPrivateBrowsingId(true)
373 , mCanExecuteScripts(false)
374 , mFiredUnloadEvent(false)
375 , mEODForCurrentDocument(false)
376 , mURIResultedInDocument(false)
377 , mIsBeingDestroyed(false)
378 , mIsExecutingOnLoadHandler(false)
379 , mIsPrintingOrPP(false)
380 , mSavingOldViewer(false)
381 , mDynamicallyCreated(false)
382 , mAffectPrivateSessionLifetime(true)
384 , mHasLoadedNonBlankURI(false)
385 , mBlankTiming(false)
390 AssertOriginAttributesMatchPrivateBrowsing();
392 nsContentUtils::GenerateUUIDInPlace(mHistoryID
);
394 if (gDocShellCount
++ == 0) {
395 NS_ASSERTION(sURIFixup
== nullptr,
396 "Huh, sURIFixup not null in first nsDocShell ctor!");
398 CallGetService(NS_URIFIXUP_CONTRACTID
, &sURIFixup
);
401 MOZ_LOG(gDocShellLeakLog
, LogLevel::Debug
, ("DOCSHELL %p created\n", this));
404 // We're counting the number of |nsDocShells| to help find leaks
405 ++gNumberOfDocShells
;
406 if (!PR_GetEnv("MOZ_QUIET")) {
407 printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
411 nsIDToCString(mHistoryID
).get());
416 nsDocShell::~nsDocShell()
418 MOZ_ASSERT(!mObserved
);
420 // Avoid notifying observers while we're in the dtor.
421 mIsBeingDestroyed
= true;
425 if (mSessionHistory
) {
426 mSessionHistory
->LegacySHistoryInternal()->SetRootDocShell(nullptr);
429 if (--gDocShellCount
== 0) {
430 NS_IF_RELEASE(sURIFixup
);
433 MOZ_LOG(gDocShellLeakLog
, LogLevel::Debug
, ("DOCSHELL %p destroyed\n", this));
436 // We're counting the number of |nsDocShells| to help find leaks
437 --gNumberOfDocShells
;
438 if (!PR_GetEnv("MOZ_QUIET")) {
439 printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
443 nsIDToCString(mHistoryID
).get());
451 MOZ_ASSERT(!mIsBeingDestroyed
);
453 nsresult rv
= nsDocLoader::Init();
454 NS_ENSURE_SUCCESS(rv
, rv
);
456 NS_ASSERTION(mLoadGroup
, "Something went wrong!");
458 mContentListener
= new nsDSURIContentListener(this);
459 rv
= mContentListener
->Init();
460 NS_ENSURE_SUCCESS(rv
, rv
);
462 // If parent intercept is not enabled then we must forward to
463 // the network controller from docshell. We also enable if we're
464 // in the parent process in order to support non-e10s configurations.
465 if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
466 mInterceptController
= new ServiceWorkerInterceptController();
469 // We want to hold a strong ref to the loadgroup, so it better hold a weak
470 // ref to us... use an InterfaceRequestorProxy to do this.
471 nsCOMPtr
<nsIInterfaceRequestor
> proxy
=
472 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor
*>(this));
473 mLoadGroup
->SetNotificationCallbacks(proxy
);
475 rv
= nsDocLoader::AddDocLoaderAsChildOfRoot(this);
476 NS_ENSURE_SUCCESS(rv
, rv
);
478 // Add as |this| a progress listener to itself. A little weird, but
479 // simpler than reproducing all the listener-notification logic in
480 // overrides of the various methods via which nsDocLoader can be
481 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
482 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
|
483 nsIWebProgress::NOTIFY_STATE_NETWORK
);
487 nsDocShell::DestroyChildren()
489 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
490 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
491 while (iter
.HasMore()) {
492 shell
= do_QueryObject(iter
.GetNext());
493 NS_ASSERTION(shell
, "docshell has null child");
496 shell
->SetTreeOwner(nullptr);
500 nsDocLoader::DestroyChildren();
503 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell
,
505 mSessionStorageManager
,
507 mInitialClientSource
,
510 NS_IMPL_ADDREF_INHERITED(nsDocShell
, nsDocLoader
)
511 NS_IMPL_RELEASE_INHERITED(nsDocShell
, nsDocLoader
)
513 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell
)
514 NS_INTERFACE_MAP_ENTRY(nsIDocShell
)
515 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem
)
516 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation
)
517 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
518 NS_INTERFACE_MAP_ENTRY(nsIScrollable
)
519 NS_INTERFACE_MAP_ENTRY(nsITextScroll
)
520 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI
)
521 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
522 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
523 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor
)
524 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider
)
525 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
526 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices
)
527 NS_INTERFACE_MAP_ENTRY(nsILinkHandler
)
528 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands
)
529 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager
)
530 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController
,
531 mInterceptController
)
532 NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner
)
533 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader
)
536 nsDocShell::GetInterface(const nsIID
& aIID
, void** aSink
)
538 MOZ_ASSERT(aSink
, "null out param");
542 if (aIID
.Equals(NS_GET_IID(nsICommandManager
))) {
543 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE
);
544 *aSink
= mCommandManager
;
545 } else if (aIID
.Equals(NS_GET_IID(nsIURIContentListener
))) {
546 *aSink
= mContentListener
;
547 } else if ((aIID
.Equals(NS_GET_IID(nsIScriptGlobalObject
)) ||
548 aIID
.Equals(NS_GET_IID(nsIGlobalObject
)) ||
549 aIID
.Equals(NS_GET_IID(nsPIDOMWindowOuter
)) ||
550 aIID
.Equals(NS_GET_IID(mozIDOMWindowProxy
)) ||
551 aIID
.Equals(NS_GET_IID(nsIDOMWindow
))) &&
552 NS_SUCCEEDED(EnsureScriptEnvironment())) {
553 return mScriptGlobal
->QueryInterface(aIID
, aSink
);
554 } else if (aIID
.Equals(NS_GET_IID(nsIDocument
)) &&
555 NS_SUCCEEDED(EnsureContentViewer())) {
556 nsCOMPtr
<nsIDocument
> doc
= mContentViewer
->GetDocument();
558 return *aSink
? NS_OK
: NS_NOINTERFACE
;
559 } else if (aIID
.Equals(NS_GET_IID(nsIApplicationCacheContainer
))) {
562 // Return application cache associated with this docshell, if any
564 nsCOMPtr
<nsIContentViewer
> contentViewer
;
565 GetContentViewer(getter_AddRefs(contentViewer
));
566 if (!contentViewer
) {
567 return NS_ERROR_NO_INTERFACE
;
570 nsCOMPtr
<nsIDocument
> doc
= contentViewer
->GetDocument();
571 NS_ASSERTION(doc
, "Should have a document.");
573 return NS_ERROR_NO_INTERFACE
;
577 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
578 ("nsDocShell[%p]: returning app cache container %p",
581 return doc
->QueryInterface(aIID
, aSink
);
582 } else if (aIID
.Equals(NS_GET_IID(nsIPrompt
)) &&
583 NS_SUCCEEDED(EnsureScriptEnvironment())) {
585 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
586 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
587 NS_ENSURE_SUCCESS(rv
, rv
);
589 // Get the an auth prompter for our window so that the parenting
590 // of the dialogs works as it should when using tabs.
592 rv
= wwatch
->GetNewPrompter(mScriptGlobal
->AsOuter(), &prompt
);
593 NS_ENSURE_SUCCESS(rv
, rv
);
597 } else if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
)) ||
598 aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
))) {
599 return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL
, aIID
, aSink
)) ?
600 NS_OK
: NS_NOINTERFACE
;
601 } else if (aIID
.Equals(NS_GET_IID(nsISHistory
))) {
602 RefPtr
<ChildSHistory
> shistory
= GetSessionHistory();
604 // XXX(nika): Stop exposing nsISHistory through GetInterface.
605 nsCOMPtr
<nsISHistory
> legacy
= shistory
->LegacySHistory();
606 legacy
.forget(aSink
);
609 return NS_NOINTERFACE
;
610 } else if (aIID
.Equals(NS_GET_IID(nsIWebBrowserFind
))) {
611 nsresult rv
= EnsureFind();
617 NS_ADDREF((nsISupports
*)*aSink
);
619 } else if (aIID
.Equals(NS_GET_IID(nsIEditingSession
))) {
620 nsCOMPtr
<nsIEditingSession
> es
;
621 GetEditingSession(getter_AddRefs(es
));
623 return *aSink
? NS_OK
: NS_NOINTERFACE
;
624 } else if (aIID
.Equals(NS_GET_IID(nsISelectionDisplay
))) {
625 nsIPresShell
* shell
= GetPresShell();
627 return shell
->QueryInterface(aIID
, aSink
);
629 } else if (aIID
.Equals(NS_GET_IID(nsIDocShellTreeOwner
))) {
630 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
631 nsresult rv
= GetTreeOwner(getter_AddRefs(treeOwner
));
632 if (NS_SUCCEEDED(rv
) && treeOwner
) {
633 return treeOwner
->QueryInterface(aIID
, aSink
);
635 } else if (aIID
.Equals(NS_GET_IID(nsITabChild
))) {
636 *aSink
= GetTabChild().take();
637 return *aSink
? NS_OK
: NS_ERROR_FAILURE
;
638 } else if (aIID
.Equals(NS_GET_IID(nsIContentFrameMessageManager
))) {
639 RefPtr
<TabChild
> tabChild
= TabChild::GetFrom(this);
640 nsCOMPtr
<nsIContentFrameMessageManager
> mm
;
642 mm
= tabChild
->GetMessageManager();
644 if (nsPIDOMWindowOuter
* win
= GetWindow()) {
645 mm
= do_QueryInterface(win
->GetParentTarget());
650 return nsDocLoader::GetInterface(aIID
, aSink
);
653 NS_IF_ADDREF(((nsISupports
*)*aSink
));
654 return *aSink
? NS_OK
: NS_NOINTERFACE
;
658 nsDocShell::LoadURI(nsIURI
* aURI
,
659 nsIDocShellLoadInfo
* aLoadInfo
,
663 MOZ_ASSERT(aLoadInfo
|| (aLoadFlags
& EXTRA_LOAD_FLAGS
) == 0,
665 MOZ_ASSERT((aLoadFlags
& 0xf) == 0, "Should not have these flags set");
667 // Note: we allow loads to get through here even if mFiredUnloadEvent is
668 // true; that case will get handled in LoadInternal or LoadHistoryEntry,
669 // so we pass false as the second parameter to IsNavigationAllowed.
670 // However, we don't allow the page to change location *in the middle of*
671 // firing beforeunload, so we do need to check if *beforeunload* is currently
672 // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
673 if (!IsNavigationAllowed(true, false)) {
674 return NS_OK
; // JS may not handle returning of an error code
677 nsCOMPtr
<nsIURI
> referrer
;
678 nsCOMPtr
<nsIURI
> originalURI
;
679 Maybe
<nsCOMPtr
<nsIURI
>> resultPrincipalURI
;
680 bool loadReplace
= false;
681 nsCOMPtr
<nsIInputStream
> postStream
;
682 nsCOMPtr
<nsIInputStream
> headersStream
;
683 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
684 bool inheritPrincipal
= false;
685 bool principalIsExplicit
= false;
686 bool sendReferrer
= true;
687 uint32_t referrerPolicy
= RP_Unset
;
688 bool isSrcdoc
= false;
689 nsCOMPtr
<nsISHEntry
> shEntry
;
692 bool forceAllowDataURI
= false;
693 bool originalFrameSrc
= false;
694 nsCOMPtr
<nsIDocShell
> sourceDocShell
;
695 nsCOMPtr
<nsIURI
> baseURI
;
697 uint32_t loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
701 if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI
) &&
702 mItemType
== typeContent
&& !NS_IsAboutBlank(aURI
)) {
703 StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI
);
706 // Extract the info from the DocShellLoadInfo struct...
708 aLoadInfo
->GetReferrer(getter_AddRefs(referrer
));
709 aLoadInfo
->GetOriginalURI(getter_AddRefs(originalURI
));
710 GetMaybeResultPrincipalURI(aLoadInfo
, resultPrincipalURI
);
711 aLoadInfo
->GetLoadReplace(&loadReplace
);
712 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
713 aLoadInfo
->GetLoadType(<
);
714 // Get the appropriate loadType from nsIDocShellLoadInfo type
715 loadType
= ConvertDocShellInfoLoadTypeToLoadType(lt
);
717 aLoadInfo
->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal
));
718 aLoadInfo
->GetInheritPrincipal(&inheritPrincipal
);
719 aLoadInfo
->GetPrincipalIsExplicit(&principalIsExplicit
);
720 aLoadInfo
->GetSHEntry(getter_AddRefs(shEntry
));
721 aLoadInfo
->GetTarget(getter_Copies(target
));
722 aLoadInfo
->GetPostDataStream(getter_AddRefs(postStream
));
723 aLoadInfo
->GetHeadersStream(getter_AddRefs(headersStream
));
724 aLoadInfo
->GetSendReferrer(&sendReferrer
);
725 aLoadInfo
->GetReferrerPolicy(&referrerPolicy
);
726 aLoadInfo
->GetIsSrcdocLoad(&isSrcdoc
);
727 aLoadInfo
->GetSrcdocData(srcdoc
);
728 aLoadInfo
->GetSourceDocShell(getter_AddRefs(sourceDocShell
));
729 aLoadInfo
->GetBaseURI(getter_AddRefs(baseURI
));
730 aLoadInfo
->GetForceAllowDataURI(&forceAllowDataURI
);
731 aLoadInfo
->GetOriginalFrameSrc(&originalFrameSrc
);
734 MOZ_LOG(gDocShellLeakLog
, LogLevel::Debug
,
735 ("nsDocShell[%p]: loading %s with flags 0x%08x",
736 this, aURI
->GetSpecOrDefault().get(), aLoadFlags
));
739 !LOAD_TYPE_HAS_FLAGS(loadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
740 // First verify if this is a subframe.
741 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
742 GetSameTypeParent(getter_AddRefs(parentAsItem
));
743 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
744 uint32_t parentLoadType
;
746 if (parentDS
&& parentDS
!= static_cast<nsIDocShell
*>(this)) {
747 /* OK. It is a subframe. Checkout the
748 * parent's loadtype. If the parent was loaded thro' a history
749 * mechanism, then get the SH entry for the child from the parent.
750 * This is done to restore frameset navigation while going back/forward.
751 * If the parent was loaded through any other loadType, set the
752 * child's loadType too accordingly, so that session history does not
756 // Get the parent's load type
757 parentDS
->GetLoadType(&parentLoadType
);
759 // Get the ShEntry for the child from the parent
760 nsCOMPtr
<nsISHEntry
> currentSH
;
762 parentDS
->GetCurrentSHEntry(getter_AddRefs(currentSH
), &oshe
);
763 bool dynamicallyAddedChild
= mDynamicallyCreated
;
764 if (!dynamicallyAddedChild
&& !oshe
&& currentSH
) {
765 currentSH
->HasDynamicallyAddedChild(&dynamicallyAddedChild
);
767 if (!dynamicallyAddedChild
) {
768 // Only use the old SHEntry, if we're sure enough that
769 // it wasn't originally for some other frame.
770 parentDS
->GetChildSHEntry(mChildOffset
, getter_AddRefs(shEntry
));
773 // Make some decisions on the child frame's loadType based on the
774 // parent's loadType, if the subframe hasn't loaded anything into it.
776 // In some cases privileged scripts may try to get the DOMWindow
777 // reference of this docshell before the loading starts, causing the
778 // initial about:blank content viewer being created and mCurrentURI being
779 // set. To handle this case we check if mCurrentURI is about:blank and
780 // currentSHEntry is null.
781 nsCOMPtr
<nsISHEntry
> currentChildEntry
;
782 GetCurrentSHEntry(getter_AddRefs(currentChildEntry
), &oshe
);
783 if (!mCurrentURI
|| (NS_IsAboutBlank(mCurrentURI
) && !currentChildEntry
)) {
784 // This is a newly created frame. Check for exception cases first.
785 // By default the subframe will inherit the parent's loadType.
786 if (shEntry
&& (parentLoadType
== LOAD_NORMAL
||
787 parentLoadType
== LOAD_LINK
||
788 parentLoadType
== LOAD_NORMAL_EXTERNAL
)) {
789 // The parent was loaded normally. In this case, this *brand new*
790 // child really shouldn't have a SHEntry. If it does, it could be
791 // because the parent is replacing an existing frame with a new frame,
792 // in the onLoadHandler. We don't want this url to get into session
793 // history. Clear off shEntry, and set load type to
794 // LOAD_BYPASS_HISTORY.
795 bool inOnLoadHandler
= false;
796 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
797 if (inOnLoadHandler
) {
798 loadType
= LOAD_NORMAL_REPLACE
;
801 } else if (parentLoadType
== LOAD_REFRESH
) {
802 // Clear shEntry. For refresh loads, we have to load
803 // what comes thro' the pipe, not what's in history.
805 } else if ((parentLoadType
== LOAD_BYPASS_HISTORY
) ||
807 ((parentLoadType
& LOAD_CMD_HISTORY
) ||
808 (parentLoadType
== LOAD_RELOAD_NORMAL
) ||
809 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) ||
810 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE
) ||
811 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE
)))) {
812 // If the parent url, bypassed history or was loaded from
813 // history, pass on the parent's loadType to the new child
814 // frame too, so that the child frame will also
815 // avoid getting into history.
816 loadType
= parentLoadType
;
817 } else if (parentLoadType
== LOAD_ERROR_PAGE
) {
818 // If the parent document is an error page, we don't
819 // want to update global/session history. However,
820 // this child frame is not an error page.
821 loadType
= LOAD_BYPASS_HISTORY
;
822 } else if ((parentLoadType
== LOAD_RELOAD_BYPASS_CACHE
) ||
823 (parentLoadType
== LOAD_RELOAD_BYPASS_PROXY
) ||
824 (parentLoadType
== LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
)) {
825 // the new frame should inherit the parent's load type so that it also
826 // bypasses the cache and/or proxy
827 loadType
= parentLoadType
;
830 // This is a pre-existing subframe. If
831 // 1. The load of this frame was not originally initiated by session
832 // history directly (i.e. (!shEntry) condition succeeded, but it can
833 // still be a history load on parent which causes this frame being
835 // 2. mCurrentURI is not null, nor the initial about:blank,
836 // it is possible that a parent's onLoadHandler or even self's
837 // onLoadHandler is loading a new page in this child. Check parent's and
838 // self's busy flag and if it is set, we don't want this onLoadHandler
839 // load to get in to session history.
840 uint32_t parentBusy
= BUSY_FLAGS_NONE
;
841 uint32_t selfBusy
= BUSY_FLAGS_NONE
;
842 parentDS
->GetBusyFlags(&parentBusy
);
843 GetBusyFlags(&selfBusy
);
844 if (parentBusy
& BUSY_FLAGS_BUSY
||
845 selfBusy
& BUSY_FLAGS_BUSY
) {
846 loadType
= LOAD_NORMAL_REPLACE
;
852 // This is the root docshell. If we got here while
853 // executing an onLoad Handler,this load will not go
854 // into session history.
855 bool inOnLoadHandler
= false;
856 GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
857 if (inOnLoadHandler
) {
858 loadType
= LOAD_NORMAL_REPLACE
;
865 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
866 ("nsDocShell[%p]: loading from session history", this));
869 return LoadHistoryEntry(shEntry
, loadType
);
872 // On history navigation via Back/Forward buttons, don't execute
873 // automatic JavaScript redirection such as |location.href = ...| or
876 // LOAD_NORMAL: window.open(...) etc.
877 // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
878 if ((loadType
== LOAD_NORMAL
|| loadType
== LOAD_STOP_CONTENT
) &&
879 ShouldBlockLoadingForBackButton()) {
883 // Perform the load...
885 // We need a principalToInherit.
887 // If principalIsExplicit is not set there are 4 possibilities:
888 // (1) If the system principal or an expanded principal was passed
889 // in and we're a typeContent docshell, inherit the principal
890 // from the current document instead.
891 // (2) In all other cases when the principal passed in is not null,
892 // use that principal.
893 // (3) If the caller has allowed inheriting from the current document,
894 // or if we're being called from system code (eg chrome JS or pure
895 // C++) then inheritPrincipal should be true and InternalLoad will get
896 // a principal from the current document. If none of these things are
898 // (4) we don't pass a principal into the channel, and a principal will be
899 // created later from the channel's internal data.
901 // If principalIsExplicit *is* set, there are 4 possibilities
902 // (1) If the system principal or an expanded principal was passed in
903 // and we're a typeContent docshell, return an error.
904 // (2) In all other cases when the principal passed in is not null,
905 // use that principal.
906 // (3) If the caller has allowed inheriting from the current document,
907 // then inheritPrincipal should be true and InternalLoad will get
908 // a principal from the current document. If none of these things are
910 // (4) we dont' pass a principal into the channel, and a principal will be
911 // created later from the channel's internal data.
912 nsCOMPtr
<nsIPrincipal
> principalToInherit
= triggeringPrincipal
;
913 if (principalToInherit
&& mItemType
!= typeChrome
) {
914 if (nsContentUtils::IsSystemPrincipal(principalToInherit
)) {
915 if (principalIsExplicit
) {
916 return NS_ERROR_DOM_SECURITY_ERR
;
918 principalToInherit
= nullptr;
919 inheritPrincipal
= true;
920 } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit
)) {
921 if (principalIsExplicit
) {
922 return NS_ERROR_DOM_SECURITY_ERR
;
924 // Don't inherit from the current page. Just do the safe thing
925 // and pretend that we were loaded by a nullprincipal.
927 // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
928 // have origin attributes.
929 principalToInherit
= NullPrincipal::CreateWithInheritedAttributes(this);
930 inheritPrincipal
= false;
933 if (!principalToInherit
&& !inheritPrincipal
&& !principalIsExplicit
) {
934 // See if there's system or chrome JS code running
935 inheritPrincipal
= nsContentUtils::LegacyIsCallerChromeOrNativeCode();
938 if (aLoadFlags
& LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL
) {
939 inheritPrincipal
= false;
940 // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
941 // enabled, we will set firstPartyDomain on the origin attributes.
942 principalToInherit
= NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty
);
945 // If the triggeringPrincipal is not passed explicitly, we first try to create
946 // a principal from the referrer, since the referrer URI reflects the web origin
947 // that triggered the load. If there is no referrer URI, we fall back to using
948 // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
949 // and no referrer simulate a load that was triggered by the system.
950 // It's important to note that this block of code needs to appear *after* the block
951 // where we munge the principalToInherit, because otherwise we would never enter
952 // code blocks checking if the principalToInherit is null and we will end up with
953 // a wrong inheritPrincipal flag.
954 if (!triggeringPrincipal
) {
956 nsresult rv
= CreatePrincipalFromReferrer(referrer
,
957 getter_AddRefs(triggeringPrincipal
));
958 NS_ENSURE_SUCCESS(rv
, rv
);
961 triggeringPrincipal
= nsContentUtils::GetSystemPrincipal();
967 if (inheritPrincipal
) {
968 flags
|= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL
;
972 flags
|= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
;
975 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
976 flags
|= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
979 if (aLoadFlags
& LOAD_FLAGS_FIRST_LOAD
) {
980 flags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
983 if (aLoadFlags
& LOAD_FLAGS_BYPASS_CLASSIFIER
) {
984 flags
|= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
;
987 if (aLoadFlags
& LOAD_FLAGS_FORCE_ALLOW_COOKIES
) {
988 flags
|= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
;
992 flags
|= INTERNAL_LOAD_FLAGS_IS_SRCDOC
;
995 if (forceAllowDataURI
) {
996 flags
|= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI
;
999 if (originalFrameSrc
) {
1000 flags
|= INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC
;
1003 return InternalLoad(aURI
,
1009 triggeringPrincipal
,
1013 nullptr, // No type hint
1014 VoidString(), // No forced download
1018 nullptr, // No SHEntry
1023 nullptr, // No nsIDocShell
1024 nullptr); // No nsIRequest
1028 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo
** aLoadInfo
)
1030 nsDocShellLoadInfo
* loadInfo
= new nsDocShellLoadInfo();
1031 nsCOMPtr
<nsIDocShellLoadInfo
> localRef(loadInfo
);
1033 localRef
.forget(aLoadInfo
);
1038 * Reset state to a new content model within the current document and the
1039 * document viewer. Called by the document before initiating an out of band
1043 nsDocShell::PrepareForNewContentModel()
1045 mEODForCurrentDocument
= false;
1050 nsDocShell::FirePageHideNotification(bool aIsUnload
)
1052 FirePageHideNotificationInternal(aIsUnload
, false);
1057 nsDocShell::FirePageHideNotificationInternal(bool aIsUnload
,
1058 bool aSkipCheckingDynEntries
)
1060 if (mContentViewer
&& !mFiredUnloadEvent
) {
1061 // Keep an explicit reference since calling PageHide could release
1063 nsCOMPtr
<nsIContentViewer
> contentViewer(mContentViewer
);
1064 mFiredUnloadEvent
= true;
1067 mTiming
->NotifyUnloadEventStart();
1070 contentViewer
->PageHide(aIsUnload
);
1073 mTiming
->NotifyUnloadEventEnd();
1076 AutoTArray
<nsCOMPtr
<nsIDocShell
>, 8> kids
;
1077 uint32_t n
= mChildList
.Length();
1078 kids
.SetCapacity(n
);
1079 for (uint32_t i
= 0; i
< n
; i
++) {
1080 kids
.AppendElement(do_QueryInterface(ChildAt(i
)));
1084 for (uint32_t i
= 0; i
< n
; ++i
) {
1085 RefPtr
<nsDocShell
> child
= static_cast<nsDocShell
*>(kids
[i
].get());
1087 // Skip checking dynamic subframe entries in our children.
1088 child
->FirePageHideNotificationInternal(aIsUnload
, true);
1092 // If the document is unloading, remove all dynamic subframe entries.
1093 if (aIsUnload
&& !aSkipCheckingDynEntries
) {
1094 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
1095 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mOSHE
));
1096 if (rootSH
&& container
) {
1097 int32_t index
= rootSH
->Index();
1098 rootSH
->LegacySHistoryInternal()->RemoveDynEntries(index
, container
);
1102 // Now make sure our editor, if any, is detached before we go
1104 DetachEditorFromWindow();
1109 nsDocShell::DispatchToTabGroup(TaskCategory aCategory
,
1110 already_AddRefed
<nsIRunnable
>&& aRunnable
)
1112 // Hold the ref so we won't forget to release it.
1113 nsCOMPtr
<nsIRunnable
> runnable(aRunnable
);
1114 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
1116 // Window should only be unavailable after destroyed.
1117 MOZ_ASSERT(mIsBeingDestroyed
);
1118 return NS_ERROR_FAILURE
;
1121 if (win
->GetDocGroup()) {
1122 return win
->GetDocGroup()->Dispatch(aCategory
, runnable
.forget());
1124 RefPtr
<mozilla::dom::TabGroup
> tabGroup
= win
->TabGroup();
1125 return tabGroup
->Dispatch(aCategory
, runnable
.forget());
1129 nsDocShell::DispatchLocationChangeEvent()
1131 return DispatchToTabGroup(
1132 TaskCategory::Other
,
1133 NewRunnableMethod("nsDocShell::FireDummyOnLocationChange",
1135 &nsDocShell::FireDummyOnLocationChange
));
1139 nsDocShell::MaybeInitTiming()
1141 if (mTiming
&& !mBlankTiming
) {
1145 bool canBeReset
= false;
1147 if (mScriptGlobal
&& mBlankTiming
) {
1148 nsPIDOMWindowInner
* innerWin
=
1149 mScriptGlobal
->AsOuter()->GetCurrentInnerWindow();
1150 if (innerWin
&& innerWin
->GetPerformance()) {
1151 mTiming
= innerWin
->GetPerformance()->GetDOMTiming();
1152 mBlankTiming
= false;
1157 mTiming
= new nsDOMNavigationTiming(this);
1161 mTiming
->NotifyNavigationStart(
1162 mIsActive
? nsDOMNavigationTiming::DocShellState::eActive
1163 : nsDOMNavigationTiming::DocShellState::eInactive
);
1169 nsDocShell::MaybeResetInitTiming(bool aReset
)
1176 nsDOMNavigationTiming
*
1177 nsDocShell::GetNavigationTiming() const
1183 // Bug 13871: Prevent frameset spoofing
1185 // This routine answers: 'Is origin's document from same domain as
1186 // target's document?'
1188 // file: uris are considered the same domain for the purpose of
1189 // frame navigation regardless of script accessibility (bug 420425)
1192 nsDocShell::ValidateOrigin(nsIDocShellTreeItem
* aOriginTreeItem
,
1193 nsIDocShellTreeItem
* aTargetTreeItem
)
1195 // We want to bypass this check for chrome callers, but only if there's
1196 // JS on the stack. System callers still need to do it.
1197 if (nsContentUtils::GetCurrentJSContext() &&
1198 nsContentUtils::IsCallerChrome()) {
1202 MOZ_ASSERT(aOriginTreeItem
&& aTargetTreeItem
, "need two docshells");
1204 // Get origin document principal
1205 nsCOMPtr
<nsIDocument
> originDocument
= aOriginTreeItem
->GetDocument();
1206 NS_ENSURE_TRUE(originDocument
, false);
1208 // Get target principal
1209 nsCOMPtr
<nsIDocument
> targetDocument
= aTargetTreeItem
->GetDocument();
1210 NS_ENSURE_TRUE(targetDocument
, false);
1213 nsresult rv
= originDocument
->NodePrincipal()->Equals(
1214 targetDocument
->NodePrincipal(), &equal
);
1215 if (NS_SUCCEEDED(rv
) && equal
) {
1219 // Not strictly equal, special case if both are file: uris
1220 bool originIsFile
= false;
1221 bool targetIsFile
= false;
1222 nsCOMPtr
<nsIURI
> originURI
;
1223 nsCOMPtr
<nsIURI
> targetURI
;
1224 nsCOMPtr
<nsIURI
> innerOriginURI
;
1225 nsCOMPtr
<nsIURI
> innerTargetURI
;
1227 rv
= originDocument
->NodePrincipal()->GetURI(getter_AddRefs(originURI
));
1228 if (NS_SUCCEEDED(rv
) && originURI
) {
1229 innerOriginURI
= NS_GetInnermostURI(originURI
);
1232 rv
= targetDocument
->NodePrincipal()->GetURI(getter_AddRefs(targetURI
));
1233 if (NS_SUCCEEDED(rv
) && targetURI
) {
1234 innerTargetURI
= NS_GetInnermostURI(targetURI
);
1237 return innerOriginURI
&& innerTargetURI
&&
1238 NS_SUCCEEDED(innerOriginURI
->SchemeIs("file", &originIsFile
)) &&
1239 NS_SUCCEEDED(innerTargetURI
->SchemeIs("file", &targetIsFile
)) &&
1240 originIsFile
&& targetIsFile
;
1244 nsDocShell::GetEldestPresContext(nsPresContext
** aPresContext
)
1246 NS_ENSURE_ARG_POINTER(aPresContext
);
1247 *aPresContext
= nullptr;
1249 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
1251 nsCOMPtr
<nsIContentViewer
> prevViewer
;
1252 viewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
1254 return viewer
->GetPresContext(aPresContext
);
1256 viewer
= prevViewer
;
1263 nsDocShell::GetPresContext(nsPresContext
** aPresContext
)
1265 NS_ENSURE_ARG_POINTER(aPresContext
);
1266 *aPresContext
= nullptr;
1268 if (!mContentViewer
) {
1272 return mContentViewer
->GetPresContext(aPresContext
);
1275 NS_IMETHODIMP_(nsIPresShell
*)
1276 nsDocShell::GetPresShell()
1278 RefPtr
<nsPresContext
> presContext
;
1279 (void)GetPresContext(getter_AddRefs(presContext
));
1280 return presContext
? presContext
->GetPresShell() : nullptr;
1284 nsDocShell::GetEldestPresShell(nsIPresShell
** aPresShell
)
1286 nsresult rv
= NS_OK
;
1288 NS_ENSURE_ARG_POINTER(aPresShell
);
1289 *aPresShell
= nullptr;
1291 RefPtr
<nsPresContext
> presContext
;
1292 (void)GetEldestPresContext(getter_AddRefs(presContext
));
1295 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1302 nsDocShell::GetContentViewer(nsIContentViewer
** aContentViewer
)
1304 NS_ENSURE_ARG_POINTER(aContentViewer
);
1306 *aContentViewer
= mContentViewer
;
1307 NS_IF_ADDREF(*aContentViewer
);
1312 nsDocShell::SetChromeEventHandler(EventTarget
* aChromeEventHandler
)
1314 // Weak reference. Don't addref.
1315 mChromeEventHandler
= aChromeEventHandler
;
1317 if (mScriptGlobal
) {
1318 mScriptGlobal
->SetChromeEventHandler(mChromeEventHandler
);
1325 nsDocShell::GetChromeEventHandler(EventTarget
** aChromeEventHandler
)
1327 NS_ENSURE_ARG_POINTER(aChromeEventHandler
);
1328 nsCOMPtr
<EventTarget
> handler
= mChromeEventHandler
;
1329 handler
.forget(aChromeEventHandler
);
1334 nsDocShell::SetCurrentURI(nsIURI
* aURI
)
1336 // Note that securityUI will set STATE_IS_INSECURE, even if
1337 // the scheme of |aURI| is "https".
1338 SetCurrentURI(aURI
, nullptr, true, 0);
1343 nsDocShell::SetCurrentURI(nsIURI
* aURI
, nsIRequest
* aRequest
,
1344 bool aFireOnLocationChange
, uint32_t aLocationFlags
)
1346 MOZ_ASSERT(!mIsBeingDestroyed
);
1348 MOZ_LOG(gDocShellLeakLog
, LogLevel::Debug
,
1349 ("DOCSHELL %p SetCurrentURI %s\n",
1350 this, aURI
? aURI
->GetSpecOrDefault().get() : ""));
1352 // We don't want to send a location change when we're displaying an error
1353 // page, and we don't want to change our idea of "current URI" either
1354 if (mLoadType
== LOAD_ERROR_PAGE
) {
1360 if (!NS_IsAboutBlank(mCurrentURI
)) {
1361 mHasLoadedNonBlankURI
= true;
1364 bool isRoot
= false; // Is this the root docshell
1365 bool isSubFrame
= false; // Is this a subframe navigation?
1367 nsCOMPtr
<nsIDocShellTreeItem
> root
;
1369 GetSameTypeRootTreeItem(getter_AddRefs(root
));
1370 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this)) {
1371 // This is the root docshell
1375 mLSHE
->GetIsSubFrame(&isSubFrame
);
1378 if (!isSubFrame
&& !isRoot
) {
1380 * We don't want to send OnLocationChange notifications when
1381 * a subframe is being loaded for the first time, while
1382 * visiting a frameset page
1387 if (aFireOnLocationChange
) {
1388 FireOnLocationChange(this, aRequest
, aURI
, aLocationFlags
);
1390 return !aFireOnLocationChange
;
1394 nsDocShell::GetCharset(nsACString
& aCharset
)
1396 aCharset
.Truncate();
1398 nsIPresShell
* presShell
= GetPresShell();
1399 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
1400 nsIDocument
* doc
= presShell
->GetDocument();
1401 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
1402 doc
->GetDocumentCharacterSet()->Name(aCharset
);
1407 nsDocShell::GatherCharsetMenuTelemetry()
1409 nsCOMPtr
<nsIContentViewer
> viewer
;
1410 GetContentViewer(getter_AddRefs(viewer
));
1415 nsIDocument
* doc
= viewer
->GetDocument();
1416 if (!doc
|| doc
->WillIgnoreCharsetOverride()) {
1420 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED
, true);
1422 bool isFileURL
= false;
1423 nsIURI
* url
= doc
->GetOriginalURI();
1425 url
->SchemeIs("file", &isFileURL
);
1428 int32_t charsetSource
= doc
->GetDocumentCharacterSetSource();
1429 switch (charsetSource
) {
1430 case kCharsetFromTopLevelDomain
:
1431 // Unlabeled doc on a domain that we map to a fallback encoding
1432 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 7);
1434 case kCharsetFromFallback
:
1435 case kCharsetFromDocTypeDefault
:
1436 case kCharsetFromCache
:
1437 case kCharsetFromParentFrame
:
1438 case kCharsetFromHintPrevDoc
:
1439 // Changing charset on an unlabeled doc.
1441 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 0);
1443 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 1);
1446 case kCharsetFromAutoDetection
:
1447 // Changing charset on unlabeled doc where chardet fired
1449 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 2);
1451 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 3);
1454 case kCharsetFromMetaPrescan
:
1455 case kCharsetFromMetaTag
:
1456 case kCharsetFromChannel
:
1457 // Changing charset on a doc that had a charset label.
1458 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 4);
1460 case kCharsetFromParentForced
:
1461 case kCharsetFromUserForced
:
1462 // Changing charset on a document that already had an override.
1463 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 5);
1465 case kCharsetFromIrreversibleAutoDetection
:
1466 case kCharsetFromOtherComponent
:
1467 case kCharsetFromByteOrderMark
:
1468 case kCharsetUninitialized
:
1470 // Bug. This isn't supposed to happen.
1471 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION
, 6);
1478 nsDocShell::SetCharset(const nsACString
& aCharset
)
1480 // set the charset override
1481 return SetForcedCharset(aCharset
);
1485 nsDocShell::SetForcedCharset(const nsACString
& aCharset
)
1487 if (aCharset
.IsEmpty()) {
1488 mForcedCharset
= nullptr;
1491 const Encoding
* encoding
= Encoding::ForLabel(aCharset
);
1493 // Reject unknown labels
1494 return NS_ERROR_INVALID_ARG
;
1496 if (!encoding
->IsAsciiCompatible() && encoding
!= ISO_2022_JP_ENCODING
) {
1497 // Reject XSS hazards
1498 return NS_ERROR_INVALID_ARG
;
1500 mForcedCharset
= encoding
;
1505 nsDocShell::GetForcedCharset(nsACString
& aResult
)
1507 if (mForcedCharset
) {
1508 mForcedCharset
->Name(aResult
);
1516 nsDocShell::SetParentCharset(const Encoding
*& aCharset
,
1517 int32_t aCharsetSource
,
1518 nsIPrincipal
* aPrincipal
)
1520 mParentCharset
= aCharset
;
1521 mParentCharsetSource
= aCharsetSource
;
1522 mParentCharsetPrincipal
= aPrincipal
;
1526 nsDocShell::GetParentCharset(const Encoding
*& aCharset
,
1527 int32_t* aCharsetSource
,
1528 nsIPrincipal
** aPrincipal
)
1530 aCharset
= mParentCharset
;
1531 *aCharsetSource
= mParentCharsetSource
;
1532 NS_IF_ADDREF(*aPrincipal
= mParentCharsetPrincipal
);
1536 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded
)
1538 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1539 *aHasMixedActiveContentLoaded
= doc
&& doc
->GetHasMixedActiveContentLoaded();
1544 nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked
)
1546 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1547 *aHasMixedActiveContentBlocked
=
1548 doc
&& doc
->GetHasMixedActiveContentBlocked();
1553 nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded
)
1555 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1556 *aHasMixedDisplayContentLoaded
=
1557 doc
&& doc
->GetHasMixedDisplayContentLoaded();
1562 nsDocShell::GetHasMixedDisplayContentBlocked(
1563 bool* aHasMixedDisplayContentBlocked
)
1565 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1566 *aHasMixedDisplayContentBlocked
=
1567 doc
&& doc
->GetHasMixedDisplayContentBlocked();
1572 nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked
)
1574 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1575 *aHasTrackingContentBlocked
= doc
&& doc
->GetHasTrackingContentBlocked();
1580 nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded
)
1582 nsCOMPtr
<nsIDocument
> doc(GetDocument());
1583 *aHasTrackingContentLoaded
= doc
&& doc
->GetHasTrackingContentLoaded();
1588 nsDocShell::GetAllowPlugins(bool* aAllowPlugins
)
1590 NS_ENSURE_ARG_POINTER(aAllowPlugins
);
1592 *aAllowPlugins
= mAllowPlugins
;
1597 nsDocShell::SetAllowPlugins(bool aAllowPlugins
)
1599 mAllowPlugins
= aAllowPlugins
;
1600 // XXX should enable or disable a plugin host
1605 nsDocShell::GetAllowJavascript(bool* aAllowJavascript
)
1607 NS_ENSURE_ARG_POINTER(aAllowJavascript
);
1609 *aAllowJavascript
= mAllowJavascript
;
1614 nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled
)
1616 MOZ_ASSERT(aEnabled
);
1617 *aEnabled
= mCSSErrorReportingEnabled
;
1622 nsDocShell::SetCssErrorReportingEnabled(bool aEnabled
)
1624 mCSSErrorReportingEnabled
= aEnabled
;
1629 nsDocShell::SetAllowJavascript(bool aAllowJavascript
)
1631 mAllowJavascript
= aAllowJavascript
;
1632 RecomputeCanExecuteScripts();
1637 nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing
)
1639 NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing
);
1640 AssertOriginAttributesMatchPrivateBrowsing();
1641 *aUsePrivateBrowsing
= mPrivateBrowsingId
> 0;
1646 nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
)
1648 if (!CanSetOriginAttributes()) {
1649 bool changed
= aUsePrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1651 return changed
? NS_ERROR_FAILURE
: NS_OK
;
1654 return SetPrivateBrowsing(aUsePrivateBrowsing
);
1658 nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing
)
1660 MOZ_ASSERT(!mIsBeingDestroyed
);
1662 bool changed
= aUsePrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1664 mPrivateBrowsingId
= aUsePrivateBrowsing
? 1 : 0;
1666 if (mItemType
!= typeChrome
) {
1667 mOriginAttributes
.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing
);
1670 if (mAffectPrivateSessionLifetime
) {
1671 if (aUsePrivateBrowsing
) {
1672 IncreasePrivateDocShellCount();
1674 DecreasePrivateDocShellCount();
1679 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
1680 while (iter
.HasMore()) {
1681 nsCOMPtr
<nsILoadContext
> shell
= do_QueryObject(iter
.GetNext());
1683 shell
->SetPrivateBrowsing(aUsePrivateBrowsing
);
1688 nsTObserverArray
<nsWeakPtr
>::ForwardIterator
iter(mPrivacyObservers
);
1689 while (iter
.HasMore()) {
1690 nsWeakPtr ref
= iter
.GetNext();
1691 nsCOMPtr
<nsIPrivacyTransitionObserver
> obs
= do_QueryReferent(ref
);
1693 mPrivacyObservers
.RemoveElement(ref
);
1695 obs
->PrivateModeChanged(aUsePrivateBrowsing
);
1700 AssertOriginAttributesMatchPrivateBrowsing();
1705 nsDocShell::GetHasLoadedNonBlankURI(bool* aResult
)
1707 NS_ENSURE_ARG_POINTER(aResult
);
1709 *aResult
= mHasLoadedNonBlankURI
;
1714 nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs
)
1716 NS_ENSURE_ARG_POINTER(aUseRemoteTabs
);
1718 *aUseRemoteTabs
= mUseRemoteTabs
;
1723 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs
)
1725 if (aUseRemoteTabs
) {
1726 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
1727 NS_LITERAL_CSTRING("1"));
1730 mUseRemoteTabs
= aUseRemoteTabs
;
1735 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime
)
1737 MOZ_ASSERT(!mIsBeingDestroyed
);
1739 bool change
= aAffectLifetime
!= mAffectPrivateSessionLifetime
;
1740 if (change
&& UsePrivateBrowsing()) {
1741 AssertOriginAttributesMatchPrivateBrowsing();
1742 if (aAffectLifetime
) {
1743 IncreasePrivateDocShellCount();
1745 DecreasePrivateDocShellCount();
1748 mAffectPrivateSessionLifetime
= aAffectLifetime
;
1750 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
1751 while (iter
.HasMore()) {
1752 nsCOMPtr
<nsIDocShell
> shell
= do_QueryObject(iter
.GetNext());
1754 shell
->SetAffectPrivateSessionLifetime(aAffectLifetime
);
1761 nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime
)
1763 *aAffectLifetime
= mAffectPrivateSessionLifetime
;
1768 nsDocShell::AddWeakPrivacyTransitionObserver(
1769 nsIPrivacyTransitionObserver
* aObserver
)
1771 nsWeakPtr weakObs
= do_GetWeakReference(aObserver
);
1773 return NS_ERROR_NOT_AVAILABLE
;
1775 return mPrivacyObservers
.AppendElement(weakObs
) ? NS_OK
: NS_ERROR_FAILURE
;
1779 nsDocShell::AddWeakReflowObserver(nsIReflowObserver
* aObserver
)
1781 nsWeakPtr weakObs
= do_GetWeakReference(aObserver
);
1783 return NS_ERROR_FAILURE
;
1785 return mReflowObservers
.AppendElement(weakObs
) ? NS_OK
: NS_ERROR_FAILURE
;
1789 nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver
* aObserver
)
1791 nsWeakPtr obs
= do_GetWeakReference(aObserver
);
1792 return mReflowObservers
.RemoveElement(obs
) ? NS_OK
: NS_ERROR_FAILURE
;
1796 nsDocShell::NotifyReflowObservers(bool aInterruptible
,
1797 DOMHighResTimeStamp aStart
,
1798 DOMHighResTimeStamp aEnd
)
1800 nsTObserverArray
<nsWeakPtr
>::ForwardIterator
iter(mReflowObservers
);
1801 while (iter
.HasMore()) {
1802 nsWeakPtr ref
= iter
.GetNext();
1803 nsCOMPtr
<nsIReflowObserver
> obs
= do_QueryReferent(ref
);
1805 mReflowObservers
.RemoveElement(ref
);
1806 } else if (aInterruptible
) {
1807 obs
->ReflowInterruptible(aStart
, aEnd
);
1809 obs
->Reflow(aStart
, aEnd
);
1816 nsDocShell::GetAllowMetaRedirects(bool* aReturn
)
1818 NS_ENSURE_ARG_POINTER(aReturn
);
1820 *aReturn
= mAllowMetaRedirects
;
1825 nsDocShell::SetAllowMetaRedirects(bool aValue
)
1827 mAllowMetaRedirects
= aValue
;
1832 nsDocShell::GetAllowSubframes(bool* aAllowSubframes
)
1834 NS_ENSURE_ARG_POINTER(aAllowSubframes
);
1836 *aAllowSubframes
= mAllowSubframes
;
1841 nsDocShell::SetAllowSubframes(bool aAllowSubframes
)
1843 mAllowSubframes
= aAllowSubframes
;
1848 nsDocShell::GetAllowImages(bool* aAllowImages
)
1850 NS_ENSURE_ARG_POINTER(aAllowImages
);
1852 *aAllowImages
= mAllowImages
;
1857 nsDocShell::SetAllowImages(bool aAllowImages
)
1859 mAllowImages
= aAllowImages
;
1864 nsDocShell::GetAllowMedia(bool* aAllowMedia
)
1866 *aAllowMedia
= mAllowMedia
;
1871 nsDocShell::SetAllowMedia(bool aAllowMedia
)
1873 mAllowMedia
= aAllowMedia
;
1875 // Mute or unmute audio contexts attached to the inner window.
1876 if (mScriptGlobal
) {
1877 if (nsPIDOMWindowInner
* innerWin
=
1878 mScriptGlobal
->AsOuter()->GetCurrentInnerWindow()) {
1880 innerWin
->UnmuteAudioContexts();
1882 innerWin
->MuteAudioContexts();
1891 nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch
)
1893 *aAllowDNSPrefetch
= mAllowDNSPrefetch
;
1898 nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch
)
1900 mAllowDNSPrefetch
= aAllowDNSPrefetch
;
1905 nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl
)
1907 *aAllowWindowControl
= mAllowWindowControl
;
1912 nsDocShell::SetAllowWindowControl(bool aAllowWindowControl
)
1914 mAllowWindowControl
= aAllowWindowControl
;
1919 nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting
)
1921 *aAllowContentRetargeting
= mAllowContentRetargeting
;
1926 nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting
)
1928 mAllowContentRetargetingOnChildren
= aAllowContentRetargeting
;
1929 mAllowContentRetargeting
= aAllowContentRetargeting
;
1934 nsDocShell::GetAllowContentRetargetingOnChildren(
1935 bool* aAllowContentRetargetingOnChildren
)
1937 *aAllowContentRetargetingOnChildren
= mAllowContentRetargetingOnChildren
;
1942 nsDocShell::SetAllowContentRetargetingOnChildren(
1943 bool aAllowContentRetargetingOnChildren
)
1945 mAllowContentRetargetingOnChildren
= aAllowContentRetargetingOnChildren
;
1950 nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId
)
1952 *aInheritPrivateBrowsingId
= mInheritPrivateBrowsingId
;
1957 nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId
)
1959 mInheritPrivateBrowsingId
= aInheritPrivateBrowsingId
;
1964 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed
)
1966 NS_ENSURE_ARG_POINTER(aFullscreenAllowed
);
1968 // Browsers and apps have their mFullscreenAllowed retrieved from their
1969 // corresponding iframe in their parent upon creation.
1970 if (mFullscreenAllowed
!= CHECK_ATTRIBUTES
) {
1971 *aFullscreenAllowed
= (mFullscreenAllowed
== PARENT_ALLOWS
);
1975 // Assume false until we determine otherwise...
1976 *aFullscreenAllowed
= false;
1978 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
1982 if (nsCOMPtr
<Element
> frameElement
= win
->GetFrameElementInternal()) {
1983 if (frameElement
->IsXULElement()) {
1984 if (frameElement
->HasAttr(kNameSpaceID_None
,
1985 nsGkAtoms::disablefullscreen
)) {
1986 // Document inside this frame is explicitly disabled.
1990 // We do not allow document inside any containing element other
1991 // than iframe to enter fullscreen.
1992 if (frameElement
->IsHTMLElement(nsGkAtoms::iframe
)) {
1993 // If any ancestor iframe does not have allowfullscreen attribute
1994 // set, then fullscreen is not allowed.
1995 if (!frameElement
->HasAttr(kNameSpaceID_None
,
1996 nsGkAtoms::allowfullscreen
) &&
1997 !frameElement
->HasAttr(kNameSpaceID_None
,
1998 nsGkAtoms::mozallowfullscreen
)) {
2001 } else if (frameElement
->IsHTMLElement(nsGkAtoms::embed
)) {
2002 // Respect allowfullscreen only if this is a rewritten YouTube embed.
2003 nsCOMPtr
<nsIObjectLoadingContent
> objectLoadingContent
=
2004 do_QueryInterface(frameElement
);
2005 if (!objectLoadingContent
) {
2008 nsObjectLoadingContent
* olc
=
2009 static_cast<nsObjectLoadingContent
*>(objectLoadingContent
.get());
2010 if (!olc
->IsRewrittenYoutubeEmbed()) {
2013 // We don't have to check prefixed attributes because Flash does not
2015 if (!frameElement
->HasAttr(kNameSpaceID_None
,
2016 nsGkAtoms::allowfullscreen
)) {
2020 // neither iframe nor embed
2026 // If we have no parent then we're the root docshell; no ancestor of the
2027 // original docshell doesn't have a allowfullscreen attribute, so
2028 // report fullscreen as allowed.
2029 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
2031 *aFullscreenAllowed
= true;
2035 // Otherwise, we have a parent, continue the checking for
2036 // mozFullscreenAllowed in the parent docshell's ancestors.
2037 return parent
->GetFullscreenAllowed(aFullscreenAllowed
);
2041 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed
)
2043 if (!nsIDocShell::GetIsMozBrowser()) {
2044 // Only allow setting of fullscreenAllowed on content/process boundaries.
2045 // At non-boundaries the fullscreenAllowed attribute is calculated based on
2046 // whether all enclosing frames have the "mozFullscreenAllowed" attribute
2047 // set to "true". fullscreenAllowed is set at the process boundaries to
2048 // propagate the value of the parent's "mozFullscreenAllowed" attribute
2049 // across process boundaries.
2050 return NS_ERROR_UNEXPECTED
;
2052 mFullscreenAllowed
= (aFullscreenAllowed
? PARENT_ALLOWS
: PARENT_PROHIBITS
);
2056 ScreenOrientationInternal
2057 nsDocShell::OrientationLock()
2059 return mOrientationLock
;
2063 nsDocShell::SetOrientationLock(ScreenOrientationInternal aOrientationLock
)
2065 mOrientationLock
= aOrientationLock
;
2069 nsDocShell::GetMayEnableCharacterEncodingMenu(
2070 bool* aMayEnableCharacterEncodingMenu
)
2072 *aMayEnableCharacterEncodingMenu
= false;
2073 if (!mContentViewer
) {
2076 nsIDocument
* doc
= mContentViewer
->GetDocument();
2080 if (doc
->WillIgnoreCharsetOverride()) {
2084 *aMayEnableCharacterEncodingMenu
= true;
2089 nsDocShell::GetDocShellEnumerator(int32_t aItemType
, int32_t aDirection
,
2090 nsISimpleEnumerator
** aResult
)
2092 NS_ENSURE_ARG_POINTER(aResult
);
2095 RefPtr
<nsDocShellEnumerator
> docShellEnum
;
2096 if (aDirection
== ENUMERATE_FORWARDS
) {
2097 docShellEnum
= new nsDocShellForwardsEnumerator
;
2099 docShellEnum
= new nsDocShellBackwardsEnumerator
;
2102 nsresult rv
= docShellEnum
->SetEnumDocShellType(aItemType
);
2103 if (NS_FAILED(rv
)) {
2107 rv
= docShellEnum
->SetEnumerationRootItem((nsIDocShellTreeItem
*)this);
2108 if (NS_FAILED(rv
)) {
2112 rv
= docShellEnum
->First();
2113 if (NS_FAILED(rv
)) {
2117 rv
= docShellEnum
->QueryInterface(NS_GET_IID(nsISimpleEnumerator
),
2124 nsDocShell::GetAppType(uint32_t* aAppType
)
2126 *aAppType
= mAppType
;
2131 nsDocShell::SetAppType(uint32_t aAppType
)
2133 mAppType
= aAppType
;
2138 nsDocShell::GetAllowAuth(bool* aAllowAuth
)
2140 *aAllowAuth
= mAllowAuth
;
2145 nsDocShell::SetAllowAuth(bool aAllowAuth
)
2147 mAllowAuth
= aAllowAuth
;
2152 nsDocShell::GetZoom(float* aZoom
)
2154 NS_ENSURE_ARG_POINTER(aZoom
);
2160 nsDocShell::SetZoom(float aZoom
)
2162 return NS_ERROR_NOT_IMPLEMENTED
;
2166 nsDocShell::GetMarginWidth(int32_t* aWidth
)
2168 NS_ENSURE_ARG_POINTER(aWidth
);
2170 *aWidth
= mMarginWidth
;
2175 nsDocShell::SetMarginWidth(int32_t aWidth
)
2177 mMarginWidth
= aWidth
;
2182 nsDocShell::GetMarginHeight(int32_t* aHeight
)
2184 NS_ENSURE_ARG_POINTER(aHeight
);
2186 *aHeight
= mMarginHeight
;
2191 nsDocShell::SetMarginHeight(int32_t aHeight
)
2193 mMarginHeight
= aHeight
;
2198 nsDocShell::GetBusyFlags(uint32_t* aBusyFlags
)
2200 NS_ENSURE_ARG_POINTER(aBusyFlags
);
2202 *aBusyFlags
= mBusyFlags
;
2207 nsDocShell::TabToTreeOwner(bool aForward
, bool aForDocumentNavigation
, bool* aTookFocus
)
2209 NS_ENSURE_ARG_POINTER(aTookFocus
);
2211 nsCOMPtr
<nsIWebBrowserChromeFocus
> chromeFocus
= do_GetInterface(mTreeOwner
);
2214 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusNextElement(aForDocumentNavigation
));
2216 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusPrevElement(aForDocumentNavigation
));
2219 *aTookFocus
= false;
2226 nsDocShell::GetSecurityUI(nsISecureBrowserUI
** aSecurityUI
)
2228 NS_IF_ADDREF(*aSecurityUI
= mSecurityUI
);
2233 nsDocShell::SetSecurityUI(nsISecureBrowserUI
* aSecurityUI
)
2235 MOZ_ASSERT(!mIsBeingDestroyed
);
2237 mSecurityUI
= aSecurityUI
;
2238 mSecurityUI
->SetDocShell(this);
2243 nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate
** aLoadURIDelegate
)
2245 NS_IF_ADDREF(*aLoadURIDelegate
= mLoadURIDelegate
);
2250 nsDocShell::SetLoadURIDelegate(nsILoadURIDelegate
* aLoadURIDelegate
)
2252 mLoadURIDelegate
= aLoadURIDelegate
;
2257 nsDocShell::GetUseErrorPages(bool* aUseErrorPages
)
2259 *aUseErrorPages
= UseErrorPages();
2264 nsDocShell::SetUseErrorPages(bool aUseErrorPages
)
2266 // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
2267 if (mObserveErrorPages
) {
2268 mObserveErrorPages
= false;
2270 mUseErrorPages
= aUseErrorPages
;
2275 nsDocShell::GetPreviousTransIndex(int32_t* aPreviousTransIndex
)
2277 *aPreviousTransIndex
= mPreviousTransIndex
;
2282 nsDocShell::GetLoadedTransIndex(int32_t* aLoadedTransIndex
)
2284 *aLoadedTransIndex
= mLoadedTransIndex
;
2289 nsDocShell::HistoryPurged(int32_t aNumEntries
)
2291 // These indices are used for fastback cache eviction, to determine
2292 // which session history entries are candidates for content viewer
2293 // eviction. We need to adjust by the number of entries that we
2294 // just purged from history, so that we look at the right session history
2295 // entries during eviction.
2296 mPreviousTransIndex
= std::max(-1, mPreviousTransIndex
- aNumEntries
);
2297 mLoadedTransIndex
= std::max(0, mLoadedTransIndex
- aNumEntries
);
2299 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
2300 while (iter
.HasMore()) {
2301 nsCOMPtr
<nsIDocShell
> shell
= do_QueryObject(iter
.GetNext());
2303 shell
->HistoryPurged(aNumEntries
);
2311 nsDocShell::HistoryTransactionRemoved(int32_t aIndex
)
2313 // These indices are used for fastback cache eviction, to determine
2314 // which session history entries are candidates for content viewer
2315 // eviction. We need to adjust by the number of entries that we
2316 // just purged from history, so that we look at the right session history
2317 // entries during eviction.
2318 if (aIndex
== mPreviousTransIndex
) {
2319 mPreviousTransIndex
= -1;
2320 } else if (aIndex
< mPreviousTransIndex
) {
2321 --mPreviousTransIndex
;
2323 if (mLoadedTransIndex
== aIndex
) {
2324 mLoadedTransIndex
= 0;
2325 } else if (aIndex
< mLoadedTransIndex
) {
2326 --mLoadedTransIndex
;
2329 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
2330 while (iter
.HasMore()) {
2331 nsCOMPtr
<nsIDocShell
> shell
= do_QueryObject(iter
.GetNext());
2333 static_cast<nsDocShell
*>(shell
.get())->HistoryTransactionRemoved(aIndex
);
2341 nsDocShell::SetRecordProfileTimelineMarkers(bool aValue
)
2343 bool currentValue
= nsIDocShell::GetRecordProfileTimelineMarkers();
2344 if (currentValue
== aValue
) {
2348 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
2354 MOZ_ASSERT(!timelines
->HasConsumer(this));
2355 timelines
->AddConsumer(this);
2356 MOZ_ASSERT(timelines
->HasConsumer(this));
2357 UseEntryScriptProfiling();
2359 MOZ_ASSERT(timelines
->HasConsumer(this));
2360 timelines
->RemoveConsumer(this);
2361 MOZ_ASSERT(!timelines
->HasConsumer(this));
2362 UnuseEntryScriptProfiling();
2369 nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue
)
2371 *aValue
= !!mObserved
;
2376 nsDocShell::PopProfileTimelineMarkers(
2378 JS::MutableHandle
<JS::Value
> aOut
)
2380 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
2385 nsTArray
<dom::ProfileTimelineMarker
> store
;
2386 SequenceRooter
<dom::ProfileTimelineMarker
> rooter(aCx
, &store
);
2388 timelines
->PopMarkers(this, aCx
, store
);
2390 if (!ToJSValue(aCx
, store
, aOut
)) {
2391 JS_ClearPendingException(aCx
);
2392 return NS_ERROR_UNEXPECTED
;
2399 nsDocShell::Now(DOMHighResTimeStamp
* aWhen
)
2401 *aWhen
= (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
2406 nsDocShell::SetWindowDraggingAllowed(bool aValue
)
2408 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
2409 if (!aValue
&& mItemType
== typeChrome
&& !parent
) {
2410 // Window dragging is always allowed for top level
2411 // chrome docshells.
2412 return NS_ERROR_FAILURE
;
2414 mWindowDraggingAllowed
= aValue
;
2419 nsDocShell::GetWindowDraggingAllowed(bool* aValue
)
2421 // window dragging regions in CSS (-moz-window-drag:drag)
2422 // can be slow. Default behavior is to only allow it for
2423 // chrome top level windows.
2424 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
2425 if (mItemType
== typeChrome
&& !parent
) {
2426 // Top level chrome window
2429 *aValue
= mWindowDraggingAllowed
;
2434 nsIDOMStorageManager
*
2435 nsDocShell::TopSessionStorageManager()
2439 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
2440 rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
2441 if (NS_FAILED(rv
)) {
2449 nsDocShell
* topDocShell
= static_cast<nsDocShell
*>(topItem
.get());
2450 if (topDocShell
!= this) {
2451 return topDocShell
->TopSessionStorageManager();
2454 if (!mSessionStorageManager
) {
2455 mSessionStorageManager
=
2456 do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
2459 return mSessionStorageManager
;
2463 nsDocShell::GetCurrentDocumentChannel(nsIChannel
** aResult
)
2465 NS_IF_ADDREF(*aResult
= GetCurrentDocChannel());
2470 nsDocShell::GetCurrentDocChannel()
2472 if (mContentViewer
) {
2473 nsIDocument
* doc
= mContentViewer
->GetDocument();
2475 return doc
->GetChannel();
2482 nsDocShell::AddWeakScrollObserver(nsIScrollObserver
* aObserver
)
2484 nsWeakPtr weakObs
= do_GetWeakReference(aObserver
);
2486 return NS_ERROR_FAILURE
;
2488 return mScrollObservers
.AppendElement(weakObs
) ? NS_OK
: NS_ERROR_FAILURE
;
2492 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver
* aObserver
)
2494 nsWeakPtr obs
= do_GetWeakReference(aObserver
);
2495 return mScrollObservers
.RemoveElement(obs
) ? NS_OK
: NS_ERROR_FAILURE
;
2499 nsDocShell::NotifyAsyncPanZoomStarted()
2501 nsTObserverArray
<nsWeakPtr
>::ForwardIterator
iter(mScrollObservers
);
2502 while (iter
.HasMore()) {
2503 nsWeakPtr ref
= iter
.GetNext();
2504 nsCOMPtr
<nsIScrollObserver
> obs
= do_QueryReferent(ref
);
2506 obs
->AsyncPanZoomStarted();
2508 mScrollObservers
.RemoveElement(ref
);
2514 nsDocShell::NotifyAsyncPanZoomStopped()
2516 nsTObserverArray
<nsWeakPtr
>::ForwardIterator
iter(mScrollObservers
);
2517 while (iter
.HasMore()) {
2518 nsWeakPtr ref
= iter
.GetNext();
2519 nsCOMPtr
<nsIScrollObserver
> obs
= do_QueryReferent(ref
);
2521 obs
->AsyncPanZoomStopped();
2523 mScrollObservers
.RemoveElement(ref
);
2529 nsDocShell::NotifyScrollObservers()
2531 nsTObserverArray
<nsWeakPtr
>::ForwardIterator
iter(mScrollObservers
);
2532 while (iter
.HasMore()) {
2533 nsWeakPtr ref
= iter
.GetNext();
2534 nsCOMPtr
<nsIScrollObserver
> obs
= do_QueryReferent(ref
);
2536 obs
->ScrollPositionChanged();
2538 mScrollObservers
.RemoveElement(ref
);
2544 //*****************************************************************************
2545 // nsDocShell::nsIDocShellTreeItem
2546 //*****************************************************************************
2549 nsDocShell::GetName(nsAString
& aName
)
2556 nsDocShell::SetName(const nsAString
& aName
)
2563 nsDocShell::NameEquals(const nsAString
& aName
, bool* aResult
)
2565 NS_ENSURE_ARG_POINTER(aResult
);
2566 *aResult
= mName
.Equals(aName
);
2571 nsDocShell::GetCustomUserAgent(nsAString
& aCustomUserAgent
)
2573 aCustomUserAgent
= mCustomUserAgent
;
2578 nsDocShell::SetCustomUserAgent(const nsAString
& aCustomUserAgent
)
2580 mCustomUserAgent
= aCustomUserAgent
;
2581 RefPtr
<nsGlobalWindowInner
> win
= mScriptGlobal
?
2582 mScriptGlobal
->GetCurrentInnerWindowInternal() : nullptr;
2584 Navigator
* navigator
= win
->Navigator();
2586 navigator
->ClearUserAgentCache();
2590 uint32_t childCount
= mChildList
.Length();
2591 for (uint32_t i
= 0; i
< childCount
; ++i
) {
2592 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(ChildAt(i
));
2594 childShell
->SetCustomUserAgent(aCustomUserAgent
);
2601 nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride
)
2603 NS_ENSURE_ARG_POINTER(aTouchEventsOverride
);
2605 *aTouchEventsOverride
= mTouchEventsOverride
;
2610 nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride
)
2612 if (!(aTouchEventsOverride
== nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE
||
2613 aTouchEventsOverride
== nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED
||
2614 aTouchEventsOverride
== nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED
)) {
2615 return NS_ERROR_INVALID_ARG
;
2618 mTouchEventsOverride
= aTouchEventsOverride
;
2620 uint32_t childCount
= mChildList
.Length();
2621 for (uint32_t i
= 0; i
< childCount
; ++i
) {
2622 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(ChildAt(i
));
2624 childShell
->SetTouchEventsOverride(aTouchEventsOverride
);
2630 /* virtual */ int32_t
2631 nsDocShell::ItemType()
2637 nsDocShell::GetItemType(int32_t* aItemType
)
2639 NS_ENSURE_ARG_POINTER(aItemType
);
2641 *aItemType
= ItemType();
2646 nsDocShell::SetItemType(int32_t aItemType
)
2648 NS_ENSURE_ARG((aItemType
== typeChrome
) || (typeContent
== aItemType
));
2650 // Only allow setting the type on root docshells. Those would be the ones
2651 // that have the docloader service as mParent or have no mParent at all.
2652 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
2653 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
2654 NS_ENSURE_TRUE(docLoaderService
, NS_ERROR_UNEXPECTED
);
2656 NS_ENSURE_STATE(!mParent
|| mParent
== docLoaderService
);
2658 mItemType
= aItemType
;
2660 // disable auth prompting for anything but content
2661 mAllowAuth
= mItemType
== typeContent
;
2663 RefPtr
<nsPresContext
> presContext
= nullptr;
2664 GetPresContext(getter_AddRefs(presContext
));
2666 presContext
->UpdateIsChrome();
2673 nsDocShell::GetParent(nsIDocShellTreeItem
** aParent
)
2678 CallQueryInterface(mParent
, aParent
);
2680 // Note that in the case when the parent is not an nsIDocShellTreeItem we
2681 // don't want to throw; we just want to return null.
2685 already_AddRefed
<nsDocShell
>
2686 nsDocShell::GetParentDocshell()
2688 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryInterface(GetAsSupports(mParent
));
2689 return docshell
.forget().downcast
<nsDocShell
>();
2693 nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal
* aPrincipal
)
2695 MOZ_ASSERT(!mIsBeingDestroyed
);
2697 // If there is an existing document then there is no need to create
2698 // a client for a future initial about:blank document.
2699 if (mScriptGlobal
&& mScriptGlobal
->GetCurrentInnerWindowInternal() &&
2700 mScriptGlobal
->GetCurrentInnerWindowInternal()->GetExtantDoc()) {
2701 MOZ_DIAGNOSTIC_ASSERT(
2702 mScriptGlobal
->GetCurrentInnerWindowInternal()->GetClientInfo().isSome());
2703 MOZ_DIAGNOSTIC_ASSERT(!mInitialClientSource
);
2707 // Don't recreate the initial client source. We call this multiple times
2708 // when DoChannelLoad() is called before CreateAboutBlankContentViewer.
2709 if (mInitialClientSource
) {
2713 // Don't pre-allocate the client when we are sandboxed. The inherited
2714 // principal does not take sandboxing into account.
2715 // TODO: Refactor sandboxing principal code out so we can use it here.
2716 if (!aPrincipal
&& mSandboxFlags
) {
2720 nsIPrincipal
* principal
= aPrincipal
? aPrincipal
2721 : GetInheritedPrincipal(false);
2723 // Sometimes there is no principal available when we are called from
2724 // CreateAboutBlankContentViewer. For example, sometimes the principal
2725 // is only extracted from the load context after the document is created
2726 // in nsDocument::ResetToURI(). Ideally we would do something similar
2727 // here, but for now lets just avoid the issue by not preallocating the
2733 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
2738 mInitialClientSource
=
2739 ClientManager::CreateSource(ClientType::Window
,
2740 win
->EventTargetFor(TaskCategory::Other
),
2742 MOZ_DIAGNOSTIC_ASSERT(mInitialClientSource
);
2744 // Mark the initial client as execution ready, but owned by the docshell.
2745 // If the client is actually used this will cause ClientSource to force
2746 // the creation of the initial about:blank by calling nsDocShell::GetDocument().
2747 mInitialClientSource
->DocShellExecutionReady(this);
2749 // Next, check to see if the parent is controlled.
2750 nsCOMPtr
<nsIDocShell
> parent
= GetParentDocshell();
2751 nsPIDOMWindowOuter
* parentOuter
= parent
? parent
->GetWindow() : nullptr;
2752 nsPIDOMWindowInner
* parentInner
=
2753 parentOuter
? parentOuter
->GetCurrentInnerWindow() : nullptr;
2758 nsCOMPtr
<nsIURI
> uri
;
2759 MOZ_ALWAYS_SUCCEEDS(
2760 NS_NewURI(getter_AddRefs(uri
), NS_LITERAL_CSTRING("about:blank")));
2762 // We're done if there is no parent controller or if this docshell
2763 // is not permitted to control for some reason.
2764 Maybe
<ServiceWorkerDescriptor
> controller(parentInner
->GetController());
2765 if (controller
.isNothing() || !ServiceWorkerAllowedToControlWindow(principal
, uri
)) {
2769 mInitialClientSource
->InheritController(controller
.ref());
2773 nsDocShell::GetInitialClientInfo() const
2775 if (mInitialClientSource
) {
2776 Maybe
<ClientInfo
> result
;
2777 result
.emplace(mInitialClientSource
->Info());
2781 nsGlobalWindowInner
* innerWindow
=
2782 mScriptGlobal
? mScriptGlobal
->GetCurrentInnerWindowInternal() : nullptr;
2783 nsIDocument
* doc
= innerWindow
? innerWindow
->GetExtantDoc() : nullptr;
2785 if (!doc
|| !doc
->IsInitialDocument()) {
2786 return Maybe
<ClientInfo
>();
2789 return innerWindow
->GetClientInfo();
2793 nsDocShell::RecomputeCanExecuteScripts()
2795 bool old
= mCanExecuteScripts
;
2796 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
2798 // If we have no tree owner, that means that we've been detached from the
2799 // docshell tree (this is distinct from having no parent dochshell, which
2800 // is the case for root docshells). It would be nice to simply disallow
2801 // script in detached docshells, but bug 986542 demonstrates that this
2802 // behavior breaks at least one website.
2804 // So instead, we use our previous value, unless mAllowJavascript has been
2805 // explicitly set to false.
2807 mCanExecuteScripts
= mCanExecuteScripts
&& mAllowJavascript
;
2808 // If scripting has been explicitly disabled on our docshell, we're done.
2809 } else if (!mAllowJavascript
) {
2810 mCanExecuteScripts
= false;
2811 // If we have a parent, inherit.
2812 } else if (parent
) {
2813 mCanExecuteScripts
= parent
->mCanExecuteScripts
;
2814 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2817 mCanExecuteScripts
= true;
2820 // Inform our active DOM window.
2822 // This will pass the outer, which will be in the scope of the active inner.
2823 if (mScriptGlobal
&& mScriptGlobal
->GetGlobalJSObject()) {
2824 xpc::Scriptability
& scriptability
=
2825 xpc::Scriptability::Get(mScriptGlobal
->GetGlobalJSObject());
2826 scriptability
.SetDocShellAllowsScript(mCanExecuteScripts
);
2829 // If our value has changed, our children might be affected. Recompute their
2831 if (old
!= mCanExecuteScripts
) {
2832 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
2833 while (iter
.HasMore()) {
2834 static_cast<nsDocShell
*>(iter
.GetNext())->RecomputeCanExecuteScripts();
2840 nsDocShell::SetDocLoaderParent(nsDocLoader
* aParent
)
2842 bool wasFrame
= IsFrame();
2844 bool wasPrivate
= UsePrivateBrowsing();
2847 nsresult rv
= nsDocLoader::SetDocLoaderParent(aParent
);
2848 NS_ENSURE_SUCCESS(rv
, rv
);
2850 nsCOMPtr
<nsISupportsPriority
> priorityGroup
= do_QueryInterface(mLoadGroup
);
2851 if (wasFrame
!= IsFrame() && priorityGroup
) {
2852 priorityGroup
->AdjustPriority(wasFrame
? -1 : 1);
2855 // Curse ambiguous nsISupports inheritance!
2856 nsISupports
* parent
= GetAsSupports(aParent
);
2858 // If parent is another docshell, we inherit all their flags for
2859 // allowing plugins, scripting etc.
2861 nsString customUserAgent
;
2862 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(parent
));
2863 if (parentAsDocShell
) {
2864 if (mAllowPlugins
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowPlugins(&value
))) {
2865 SetAllowPlugins(value
);
2867 if (mAllowJavascript
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowJavascript(&value
))) {
2868 SetAllowJavascript(value
);
2870 if (mAllowMetaRedirects
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowMetaRedirects(&value
))) {
2871 SetAllowMetaRedirects(value
);
2873 if (mAllowSubframes
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowSubframes(&value
))) {
2874 SetAllowSubframes(value
);
2876 if (mAllowImages
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowImages(&value
))) {
2877 SetAllowImages(value
);
2879 SetAllowMedia(parentAsDocShell
->GetAllowMedia() && mAllowMedia
);
2880 if (mAllowWindowControl
&& NS_SUCCEEDED(parentAsDocShell
->GetAllowWindowControl(&value
))) {
2881 SetAllowWindowControl(value
);
2883 SetAllowContentRetargeting(mAllowContentRetargeting
&&
2884 parentAsDocShell
->GetAllowContentRetargetingOnChildren());
2885 if (NS_SUCCEEDED(parentAsDocShell
->GetIsActive(&value
))) {
2888 if (NS_SUCCEEDED(parentAsDocShell
->GetCustomUserAgent(customUserAgent
)) &&
2889 !customUserAgent
.IsEmpty()) {
2890 SetCustomUserAgent(customUserAgent
);
2892 if (NS_FAILED(parentAsDocShell
->GetAllowDNSPrefetch(&value
))) {
2895 SetAllowDNSPrefetch(mAllowDNSPrefetch
&& value
);
2896 if (mInheritPrivateBrowsingId
) {
2897 value
= parentAsDocShell
->GetAffectPrivateSessionLifetime();
2898 SetAffectPrivateSessionLifetime(value
);
2901 if (NS_SUCCEEDED(parentAsDocShell
->GetDefaultLoadFlags(&flags
))) {
2902 SetDefaultLoadFlags(flags
);
2904 uint32_t touchEventsOverride
;
2905 if (NS_SUCCEEDED(parentAsDocShell
->GetTouchEventsOverride(&touchEventsOverride
))) {
2906 SetTouchEventsOverride(touchEventsOverride
);
2910 nsCOMPtr
<nsILoadContext
> parentAsLoadContext(do_QueryInterface(parent
));
2911 if (parentAsLoadContext
&& mInheritPrivateBrowsingId
&&
2912 NS_SUCCEEDED(parentAsLoadContext
->GetUsePrivateBrowsing(&value
))) {
2913 SetPrivateBrowsing(value
);
2916 nsCOMPtr
<nsIURIContentListener
> parentURIListener(do_GetInterface(parent
));
2917 if (parentURIListener
) {
2918 mContentListener
->SetParentContentListener(parentURIListener
);
2921 // Our parent has changed. Recompute scriptability.
2922 RecomputeCanExecuteScripts();
2924 NS_ASSERTION(mInheritPrivateBrowsingId
|| wasPrivate
== UsePrivateBrowsing(),
2925 "Private browsing state changed while inheritance was disabled");
2931 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem
** aParent
)
2933 NS_ENSURE_ARG_POINTER(aParent
);
2936 if (nsIDocShell::GetIsMozBrowser()) {
2940 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
2941 do_QueryInterface(GetAsSupports(mParent
));
2946 if (parent
->ItemType() == mItemType
) {
2947 parent
.swap(*aParent
);
2953 nsDocShell::GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell
** aParent
)
2955 NS_ENSURE_ARG_POINTER(aParent
);
2958 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
2959 do_QueryInterface(GetAsSupports(mParent
));
2964 if (parent
->ItemType() == mItemType
) {
2965 nsCOMPtr
<nsIDocShell
> parentDS
= do_QueryInterface(parent
);
2966 parentDS
.forget(aParent
);
2972 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2974 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2976 RefPtr
<nsDocShell
> root
= this;
2977 RefPtr
<nsDocShell
> parent
= root
->GetParentDocshell();
2980 parent
= root
->GetParentDocshell();
2983 root
.forget(aRootTreeItem
);
2988 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2990 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2991 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
2993 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2994 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent
)),
2997 *aRootTreeItem
= parent
;
2999 (*aRootTreeItem
)->GetSameTypeParent(getter_AddRefs(parent
)),
3002 NS_ADDREF(*aRootTreeItem
);
3007 nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserBoundaries(nsIDocShell
** aRootTreeItem
)
3009 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
3010 *aRootTreeItem
= static_cast<nsIDocShell
*>(this);
3012 nsCOMPtr
<nsIDocShell
> parent
;
3013 NS_ENSURE_SUCCESS(GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent
)),
3016 *aRootTreeItem
= parent
;
3017 NS_ENSURE_SUCCESS((*aRootTreeItem
)->
3018 GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent
)),
3021 NS_ADDREF(*aRootTreeItem
);
3027 nsDocShell::CanAccessItem(nsIDocShellTreeItem
* aTargetItem
,
3028 nsIDocShellTreeItem
* aAccessingItem
,
3029 bool aConsiderOpener
)
3031 MOZ_ASSERT(aTargetItem
, "Must have target item!");
3033 if (!gValidateOrigin
|| !aAccessingItem
) {
3038 // XXXbz should we care if aAccessingItem or the document therein is
3039 // chrome? Should those get extra privileges?
3041 // For historical context, see:
3043 // Bug 13871: Prevent frameset spoofing
3044 // Bug 103638: Targets with same name in different windows open in wrong
3045 // window with javascript
3046 // Bug 408052: Adopt "ancestor" frame navigation policy
3048 // Now do a security check.
3050 // Disallow navigation if the two frames are not part of the same app, or if
3051 // they have different is-in-browser-element states.
3053 // Allow navigation if
3054 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
3055 // the frame hierarchy or
3056 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
3057 // 3) aTargetItem is a top-level frame and aAccessingItem can target
3058 // its opener per rule (1) or (2).
3060 if (aTargetItem
== aAccessingItem
) {
3061 // A frame is allowed to navigate itself.
3065 nsCOMPtr
<nsIDocShell
> targetDS
= do_QueryInterface(aTargetItem
);
3066 nsCOMPtr
<nsIDocShell
> accessingDS
= do_QueryInterface(aAccessingItem
);
3067 if (!targetDS
|| !accessingDS
) {
3068 // We must be able to convert both to nsIDocShell.
3072 if (targetDS
->GetIsInIsolatedMozBrowserElement() !=
3073 accessingDS
->GetIsInIsolatedMozBrowserElement()) {
3077 nsCOMPtr
<nsIDocShellTreeItem
> accessingRoot
;
3078 aAccessingItem
->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot
));
3079 nsCOMPtr
<nsIDocShell
> accessingRootDS
= do_QueryInterface(accessingRoot
);
3081 nsCOMPtr
<nsIDocShellTreeItem
> targetRoot
;
3082 aTargetItem
->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot
));
3083 nsCOMPtr
<nsIDocShell
> targetRootDS
= do_QueryInterface(targetRoot
);
3085 OriginAttributes targetOA
=
3086 static_cast<nsDocShell
*>(targetDS
.get())->GetOriginAttributes();
3087 OriginAttributes accessingOA
=
3088 static_cast<nsDocShell
*>(accessingDS
.get())->GetOriginAttributes();
3090 // When the first party isolation is on, the top-level docShell may not have
3091 // the firstPartyDomain in its originAttributes, but its document will have
3092 // it. So we get the firstPartyDomain from the nodePrincipal of the document
3093 // before we compare the originAttributes.
3094 if (OriginAttributes::IsFirstPartyEnabled()) {
3095 if (aAccessingItem
->ItemType() == nsIDocShellTreeItem::typeContent
&&
3096 (accessingDS
== accessingRootDS
|| accessingDS
->GetIsMozBrowser())) {
3098 nsCOMPtr
<nsIDocument
> accessingDoc
= aAccessingItem
->GetDocument();
3101 nsCOMPtr
<nsIPrincipal
> accessingPrincipal
= accessingDoc
->NodePrincipal();
3103 accessingOA
.mFirstPartyDomain
=
3104 accessingPrincipal
->OriginAttributesRef().mFirstPartyDomain
;
3108 if (aTargetItem
->ItemType() == nsIDocShellTreeItem::typeContent
&&
3109 (targetDS
== targetRootDS
|| targetDS
->GetIsMozBrowser())) {
3111 nsCOMPtr
<nsIDocument
> targetDoc
= aAccessingItem
->GetDocument();
3114 nsCOMPtr
<nsIPrincipal
> targetPrincipal
= targetDoc
->NodePrincipal();
3116 targetOA
.mFirstPartyDomain
=
3117 targetPrincipal
->OriginAttributesRef().mFirstPartyDomain
;
3122 if (targetOA
!= accessingOA
) {
3126 // A private document can't access a non-private one, and vice versa.
3127 if (static_cast<nsDocShell
*>(targetDS
.get())->UsePrivateBrowsing() !=
3128 static_cast<nsDocShell
*>(accessingDS
.get())->UsePrivateBrowsing()) {
3132 if (aTargetItem
== accessingRoot
) {
3133 // A frame can navigate its root.
3137 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
3138 nsCOMPtr
<nsIDocShellTreeItem
> target
= aTargetItem
;
3140 if (ValidateOrigin(aAccessingItem
, target
)) {
3144 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
3145 target
->GetSameTypeParent(getter_AddRefs(parent
));
3146 parent
.swap(target
);
3149 if (aTargetItem
!= targetRoot
) {
3150 // target is a subframe, not in accessor's frame hierarchy, and all its
3151 // ancestors have origins different from that of the accessor. Don't
3156 if (!aConsiderOpener
) {
3161 nsCOMPtr
<nsPIDOMWindowOuter
> targetWindow
= aTargetItem
->GetWindow();
3162 if (!targetWindow
) {
3163 NS_ERROR("This should not happen, really");
3167 nsCOMPtr
<mozIDOMWindowProxy
> targetOpener
= targetWindow
->GetOpener();
3168 nsCOMPtr
<nsIWebNavigation
> openerWebNav(do_GetInterface(targetOpener
));
3169 nsCOMPtr
<nsIDocShellTreeItem
> openerItem(do_QueryInterface(openerWebNav
));
3175 return CanAccessItem(openerItem
, aAccessingItem
, false);
3179 ItemIsActive(nsIDocShellTreeItem
* aItem
)
3181 if (nsCOMPtr
<nsPIDOMWindowOuter
> window
= aItem
->GetWindow()) {
3182 auto* win
= nsGlobalWindowOuter::Cast(window
);
3183 if (!win
->GetClosedOuter()) {
3192 nsDocShell::FindItemWithName(const nsAString
& aName
,
3193 nsIDocShellTreeItem
* aRequestor
,
3194 nsIDocShellTreeItem
* aOriginalRequestor
,
3196 nsIDocShellTreeItem
** aResult
)
3198 NS_ENSURE_ARG_POINTER(aResult
);
3200 // If we don't find one, we return NS_OK and a null result
3203 if (aName
.IsEmpty()) {
3208 // If aRequestor is not null we don't need to check special names, so
3209 // just hand straight off to the search by actual name function.
3210 return DoFindItemWithName(aName
, aRequestor
, aOriginalRequestor
,
3211 aSkipTabGroup
, aResult
);
3213 // This is the entry point into the target-finding algorithm. Check
3214 // for special names. This should only be done once, hence the check
3215 // for a null aRequestor.
3217 nsCOMPtr
<nsIDocShellTreeItem
> foundItem
;
3218 if (aName
.LowerCaseEqualsLiteral("_self")) {
3220 } else if (aName
.LowerCaseEqualsLiteral("_blank")) {
3221 // Just return null. Caller must handle creating a new window with
3222 // a blank name himself.
3224 } else if (aName
.LowerCaseEqualsLiteral("_parent")) {
3225 GetSameTypeParent(getter_AddRefs(foundItem
));
3229 } else if (aName
.LowerCaseEqualsLiteral("_top")) {
3230 GetSameTypeRootTreeItem(getter_AddRefs(foundItem
));
3231 NS_ASSERTION(foundItem
, "Must have this; worst case it's us!");
3233 // Do the search for item by an actual name.
3234 DoFindItemWithName(aName
, aRequestor
, aOriginalRequestor
,
3235 aSkipTabGroup
, getter_AddRefs(foundItem
));
3238 if (foundItem
&& !CanAccessItem(foundItem
, aOriginalRequestor
)) {
3239 foundItem
= nullptr;
3242 // DoFindItemWithName only returns active items and we don't check if
3243 // the item is active for the special cases.
3245 foundItem
.swap(*aResult
);
3252 nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
3253 // Chrome docshells must not have a private browsing OriginAttribute
3254 // Content docshells must maintain the equality:
3255 // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
3256 if (mItemType
== typeChrome
) {
3257 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
== 0);
3259 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
== mPrivateBrowsingId
);
3264 nsDocShell::DoFindItemWithName(const nsAString
& aName
,
3265 nsIDocShellTreeItem
* aRequestor
,
3266 nsIDocShellTreeItem
* aOriginalRequestor
,
3268 nsIDocShellTreeItem
** aResult
)
3270 // First we check our name.
3271 if (mName
.Equals(aName
) && ItemIsActive(this) &&
3272 CanAccessItem(this, aOriginalRequestor
)) {
3273 NS_ADDREF(*aResult
= this);
3277 // Second we check our children making sure not to ask a child if
3278 // it is the aRequestor.
3282 FindChildWithName(aName
, true, true, aRequestor
, aOriginalRequestor
,
3284 NS_ASSERTION(NS_SUCCEEDED(rv
),
3285 "FindChildWithName should not be failing here.");
3290 // Third if we have a parent and it isn't the requestor then we
3291 // should ask it to do the search. If it is the requestor we
3292 // should just stop here and let the parent do the rest. If we
3293 // don't have a parent, then we should ask the
3294 // docShellTreeOwner to do the search.
3295 nsCOMPtr
<nsIDocShellTreeItem
> parentAsTreeItem
=
3296 do_QueryInterface(GetAsSupports(mParent
));
3297 if (parentAsTreeItem
) {
3298 if (parentAsTreeItem
== aRequestor
) {
3302 // If we have a same-type parent, respecting browser and app boundaries.
3303 // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344 are fixed.
3304 if (!GetIsMozBrowser() && parentAsTreeItem
->ItemType() == mItemType
) {
3305 return parentAsTreeItem
->FindItemWithName(
3307 static_cast<nsIDocShellTreeItem
*>(this),
3309 /* aSkipTabGroup = */ false,
3314 // If we have a null parent or the parent is not of the same type, we need to
3315 // give up on finding it in our tree, and start looking in our TabGroup.
3316 nsCOMPtr
<nsPIDOMWindowOuter
> window
= GetWindow();
3317 if (window
&& !aSkipTabGroup
) {
3318 RefPtr
<mozilla::dom::TabGroup
> tabGroup
= window
->TabGroup();
3319 tabGroup
->FindItemWithName(aName
, aRequestor
, aOriginalRequestor
, aResult
);
3326 nsDocShell::IsSandboxedFrom(nsIDocShell
* aTargetDocShell
)
3328 // If no target then not sandboxed.
3329 if (!aTargetDocShell
) {
3333 // We cannot be sandboxed from ourselves.
3334 if (aTargetDocShell
== this) {
3338 // Default the sandbox flags to our flags, so that if we can't retrieve the
3339 // active document, we will still enforce our own.
3340 uint32_t sandboxFlags
= mSandboxFlags
;
3341 if (mContentViewer
) {
3342 nsCOMPtr
<nsIDocument
> doc
= mContentViewer
->GetDocument();
3344 sandboxFlags
= doc
->GetSandboxFlags();
3348 // If no flags, we are not sandboxed at all.
3349 if (!sandboxFlags
) {
3353 // If aTargetDocShell has an ancestor, it is not top level.
3354 nsCOMPtr
<nsIDocShellTreeItem
> ancestorOfTarget
;
3355 aTargetDocShell
->GetSameTypeParent(getter_AddRefs(ancestorOfTarget
));
3356 if (ancestorOfTarget
) {
3358 // We are not sandboxed if we are an ancestor of target.
3359 if (ancestorOfTarget
== this) {
3362 nsCOMPtr
<nsIDocShellTreeItem
> tempTreeItem
;
3363 ancestorOfTarget
->GetSameTypeParent(getter_AddRefs(tempTreeItem
));
3364 tempTreeItem
.swap(ancestorOfTarget
);
3365 } while (ancestorOfTarget
);
3367 // Otherwise, we are sandboxed from aTargetDocShell.
3371 // aTargetDocShell is top level, are we the "one permitted sandboxed
3372 // navigator", i.e. did we open aTargetDocShell?
3373 nsCOMPtr
<nsIDocShell
> permittedNavigator
;
3374 aTargetDocShell
->GetOnePermittedSandboxedNavigator(
3375 getter_AddRefs(permittedNavigator
));
3376 if (permittedNavigator
== this) {
3380 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
3382 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION
)) {
3383 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
3384 GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem
));
3385 if (SameCOMIdentity(aTargetDocShell
, rootTreeItem
)) {
3390 // Otherwise, we are sandboxed from aTargetDocShell.
3395 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner
** aTreeOwner
)
3397 NS_ENSURE_ARG_POINTER(aTreeOwner
);
3399 *aTreeOwner
= mTreeOwner
;
3400 NS_IF_ADDREF(*aTreeOwner
);
3405 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
)
3407 if (mIsBeingDestroyed
&& aTreeOwner
) {
3408 return NS_ERROR_FAILURE
;
3411 // Don't automatically set the progress based on the tree owner for frames
3413 nsCOMPtr
<nsIWebProgress
> webProgress
=
3414 do_QueryInterface(GetAsSupports(this));
3417 nsCOMPtr
<nsIWebProgressListener
> oldListener
=
3418 do_QueryInterface(mTreeOwner
);
3419 nsCOMPtr
<nsIWebProgressListener
> newListener
=
3420 do_QueryInterface(aTreeOwner
);
3423 webProgress
->RemoveProgressListener(oldListener
);
3427 webProgress
->AddProgressListener(newListener
,
3428 nsIWebProgress::NOTIFY_ALL
);
3433 mTreeOwner
= aTreeOwner
; // Weak reference per API
3435 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
3436 while (iter
.HasMore()) {
3437 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryObject(iter
.GetNext());
3438 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
3440 if (child
->ItemType() == mItemType
) {
3441 child
->SetTreeOwner(aTreeOwner
);
3445 // Our tree owner has changed. Recompute scriptability.
3447 // Note that this is near-redundant with the recomputation in
3448 // SetDocLoaderParent(), but not so for the root DocShell, where the call to
3449 // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
3450 // and we never set another parent. Given that this is neither expensive nor
3451 // performance-critical, let's be safe and unconditionally recompute this
3452 // state whenever dependent state changes.
3453 RecomputeCanExecuteScripts();
3459 nsDocShell::SetChildOffset(int32_t aChildOffset
)
3461 mChildOffset
= aChildOffset
;
3466 nsDocShell::GetChildOffset(int32_t* aChildOffset
)
3468 *aChildOffset
= mChildOffset
;
3473 nsDocShell::GetHistoryID(nsID
** aID
)
3475 *aID
= mHistoryID
.Clone();
3480 nsDocShell::HistoryID()
3486 nsDocShell::GetIsInUnload(bool* aIsInUnload
)
3488 *aIsInUnload
= mFiredUnloadEvent
;
3493 nsDocShell::GetChildCount(int32_t* aChildCount
)
3495 NS_ENSURE_ARG_POINTER(aChildCount
);
3496 *aChildCount
= mChildList
.Length();
3501 nsDocShell::AddChild(nsIDocShellTreeItem
* aChild
)
3503 NS_ENSURE_ARG_POINTER(aChild
);
3505 RefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
3506 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
3508 // Make sure we're not creating a loop in the docshell tree
3509 nsDocLoader
* ancestor
= this;
3511 if (childAsDocLoader
== ancestor
) {
3512 return NS_ERROR_ILLEGAL_VALUE
;
3514 ancestor
= ancestor
->GetParent();
3517 // Make sure to remove the child from its current parent.
3518 nsDocLoader
* childsParent
= childAsDocLoader
->GetParent();
3520 nsresult rv
= childsParent
->RemoveChildLoader(childAsDocLoader
);
3521 NS_ENSURE_SUCCESS(rv
, rv
);
3524 // Make sure to clear the treeowner in case this child is a different type
3526 aChild
->SetTreeOwner(nullptr);
3528 nsresult res
= AddChildLoader(childAsDocLoader
);
3529 NS_ENSURE_SUCCESS(res
, res
);
3530 NS_ASSERTION(!mChildList
.IsEmpty(),
3531 "child list must not be empty after a successful add");
3533 nsCOMPtr
<nsIDocShell
> childDocShell
= do_QueryInterface(aChild
);
3534 bool dynamic
= false;
3535 childDocShell
->GetCreatedDynamically(&dynamic
);
3537 nsCOMPtr
<nsISHEntry
> currentSH
;
3539 GetCurrentSHEntry(getter_AddRefs(currentSH
), &oshe
);
3541 currentSH
->HasDynamicallyAddedChild(&dynamic
);
3544 childDocShell
->SetChildOffset(dynamic
? -1 : mChildList
.Length() - 1);
3546 /* Set the child's global history if the parent has one */
3547 if (mUseGlobalHistory
) {
3548 childDocShell
->SetUseGlobalHistory(true);
3551 if (aChild
->ItemType() != mItemType
) {
3555 aChild
->SetTreeOwner(mTreeOwner
);
3557 nsCOMPtr
<nsIDocShell
> childAsDocShell(do_QueryInterface(aChild
));
3558 if (!childAsDocShell
) {
3562 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3564 // Now take this document's charset and set the child's parentCharset field
3565 // to it. We'll later use that field, in the loading process, for the
3566 // charset choosing algorithm.
3567 // If we fail, at any point, we just return NS_OK.
3568 // This code has some performance impact. But this will be reduced when
3569 // the current charset will finally be stored as an Atom, avoiding the
3570 // alias resolution extra look-up.
3572 // we are NOT going to propagate the charset is this Chrome's docshell
3573 if (mItemType
== nsIDocShellTreeItem::typeChrome
) {
3577 // get the parent's current charset
3578 if (!mContentViewer
) {
3581 nsIDocument
* doc
= mContentViewer
->GetDocument();
3586 bool isWyciwyg
= false;
3589 // Check if the url is wyciwyg
3590 mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
3594 // If this docshell is loaded from a wyciwyg: URI, don't
3595 // advertise our charset since it does not in any way reflect
3596 // the actual source charset, which is what we're trying to
3599 const Encoding
* parentCS
= doc
->GetDocumentCharacterSet();
3600 int32_t charsetSource
= doc
->GetDocumentCharacterSetSource();
3601 // set the child's parentCharset
3602 childAsDocShell
->SetParentCharset(parentCS
,
3604 doc
->NodePrincipal());
3607 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
3608 // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3614 nsDocShell::RemoveChild(nsIDocShellTreeItem
* aChild
)
3616 NS_ENSURE_ARG_POINTER(aChild
);
3618 RefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
3619 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
3621 nsresult rv
= RemoveChildLoader(childAsDocLoader
);
3622 NS_ENSURE_SUCCESS(rv
, rv
);
3624 aChild
->SetTreeOwner(nullptr);
3626 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader
);
3630 nsDocShell::GetChildAt(int32_t aIndex
, nsIDocShellTreeItem
** aChild
)
3632 NS_ENSURE_ARG_POINTER(aChild
);
3636 NS_WARNING("Negative index passed to GetChildAt");
3637 } else if (static_cast<uint32_t>(aIndex
) >= mChildList
.Length()) {
3638 NS_WARNING("Too large an index passed to GetChildAt");
3642 nsIDocumentLoader
* child
= ChildAt(aIndex
);
3643 NS_ENSURE_TRUE(child
, NS_ERROR_UNEXPECTED
);
3645 return CallQueryInterface(child
, aChild
);
3649 nsDocShell::FindChildWithName(const nsAString
& aName
,
3650 bool aRecurse
, bool aSameType
,
3651 nsIDocShellTreeItem
* aRequestor
,
3652 nsIDocShellTreeItem
* aOriginalRequestor
,
3653 nsIDocShellTreeItem
** aResult
)
3655 NS_ENSURE_ARG_POINTER(aResult
);
3657 // if we don't find one, we return NS_OK and a null result
3660 if (aName
.IsEmpty()) {
3664 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
3665 while (iter
.HasMore()) {
3666 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryObject(iter
.GetNext());
3667 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
3668 int32_t childType
= child
->ItemType();
3670 if (aSameType
&& (childType
!= mItemType
)) {
3674 bool childNameEquals
= false;
3675 child
->NameEquals(aName
, &childNameEquals
);
3676 if (childNameEquals
&& ItemIsActive(child
) &&
3677 CanAccessItem(child
, aOriginalRequestor
)) {
3678 child
.swap(*aResult
);
3682 // Only ask it to check children if it is same type
3683 if (childType
!= mItemType
) {
3687 // Only ask the child if it isn't the requestor
3688 if (aRecurse
&& (aRequestor
!= child
)) {
3689 // See if child contains the shell with the given name
3693 child
->FindChildWithName(aName
, true, aSameType
,
3694 static_cast<nsIDocShellTreeItem
*>(this),
3695 aOriginalRequestor
, aResult
);
3696 NS_ASSERTION(NS_SUCCEEDED(rv
), "FindChildWithName should not fail here");
3707 nsDocShell::GetChildSHEntry(int32_t aChildOffset
, nsISHEntry
** aResult
)
3709 nsresult rv
= NS_OK
;
3711 NS_ENSURE_ARG_POINTER(aResult
);
3714 // A nsISHEntry for a child is *only* available when the parent is in
3715 // the progress of loading a document too...
3718 /* Before looking for the subframe's url, check
3719 * the expiration status of the parent. If the parent
3720 * has expired from cache, then subframes will not be
3721 * loaded from history in certain situations.
3723 bool parentExpired
= false;
3724 mLSHE
->GetExpirationStatus(&parentExpired
);
3726 /* Get the parent's Load Type so that it can be set on the child too.
3727 * By default give a loadHistory value
3729 uint32_t loadType
= nsIDocShellLoadInfo::loadHistory
;
3730 mLSHE
->GetLoadType(&loadType
);
3731 // If the user did a shift-reload on this frameset page,
3732 // we don't want to load the subframes from history.
3733 if (loadType
== nsIDocShellLoadInfo::loadReloadBypassCache
||
3734 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxy
||
3735 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
||
3736 loadType
== nsIDocShellLoadInfo::loadRefresh
) {
3740 /* If the user pressed reload and the parent frame has expired
3741 * from cache, we do not want to load the child frame from history.
3743 if (parentExpired
&& (loadType
== nsIDocShellLoadInfo::loadReloadNormal
)) {
3744 // The parent has expired. Return null.
3749 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
));
3751 // Get the child subframe from session history.
3752 rv
= container
->GetChildAt(aChildOffset
, aResult
);
3754 (*aResult
)->SetLoadType(loadType
);
3762 nsDocShell::AddChildSHEntry(nsISHEntry
* aCloneRef
, nsISHEntry
* aNewEntry
,
3763 int32_t aChildOffset
, uint32_t aLoadType
,
3764 bool aCloneChildren
)
3766 nsresult rv
= NS_OK
;
3768 if (mLSHE
&& aLoadType
!= LOAD_PUSHSTATE
) {
3769 /* You get here if you are currently building a
3770 * hierarchy ie.,you just visited a frameset page
3772 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
, &rv
));
3774 if (NS_FAILED(container
->ReplaceChild(aNewEntry
))) {
3775 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3778 } else if (!aCloneRef
) {
3779 /* This is an initial load in some subframe. Just append it if we can */
3780 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mOSHE
, &rv
));
3782 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3785 rv
= AddChildSHEntryInternal(aCloneRef
, aNewEntry
, aChildOffset
,
3786 aLoadType
, aCloneChildren
);
3792 nsDocShell::AddChildSHEntryInternal(nsISHEntry
* aCloneRef
,
3793 nsISHEntry
* aNewEntry
,
3794 int32_t aChildOffset
,
3796 bool aCloneChildren
)
3798 nsresult rv
= NS_OK
;
3799 if (mSessionHistory
) {
3800 /* You are currently in the rootDocShell.
3801 * You will get here when a subframe has a new url
3802 * to load and you have walked up the tree all the
3803 * way to the top to clone the current SHEntry hierarchy
3804 * and replace the subframe where a new url was loaded with
3807 nsCOMPtr
<nsISHEntry
> currentHE
;
3808 int32_t index
= mSessionHistory
->Index();
3810 return NS_ERROR_FAILURE
;
3813 rv
= mSessionHistory
->LegacySHistory()->GetEntryAtIndex(
3814 index
, false, getter_AddRefs(currentHE
));
3815 NS_ENSURE_TRUE(currentHE
, NS_ERROR_FAILURE
);
3817 nsCOMPtr
<nsISHEntry
> currentEntry(do_QueryInterface(currentHE
));
3819 uint32_t cloneID
= 0;
3820 nsCOMPtr
<nsISHEntry
> nextEntry
;
3821 aCloneRef
->GetID(&cloneID
);
3822 rv
= nsSHistory::CloneAndReplace(currentEntry
, this, cloneID
,
3823 aNewEntry
, aCloneChildren
, getter_AddRefs(nextEntry
));
3825 if (NS_SUCCEEDED(rv
)) {
3826 rv
= mSessionHistory
->LegacySHistoryInternal()->AddEntry(nextEntry
, true);
3830 /* Just pass this along */
3831 nsCOMPtr
<nsIDocShell
> parent
=
3832 do_QueryInterface(GetAsSupports(mParent
), &rv
);
3834 rv
= static_cast<nsDocShell
*>(parent
.get())->AddChildSHEntryInternal(
3835 aCloneRef
, aNewEntry
, aChildOffset
, aLoadType
, aCloneChildren
);
3842 nsDocShell::AddChildSHEntryToParent(nsISHEntry
* aNewEntry
, int32_t aChildOffset
,
3843 bool aCloneChildren
)
3845 /* You will get here when you are in a subframe and
3846 * a new url has been loaded on you.
3847 * The mOSHE in this subframe will be the previous url's
3848 * mOSHE. This mOSHE will be used as the identification
3849 * for this subframe in the CloneAndReplace function.
3852 // In this case, we will end up calling AddEntry, which increases the
3853 // current index by 1
3854 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
3856 mPreviousTransIndex
= rootSH
->Index();
3860 nsCOMPtr
<nsIDocShell
> parent
= do_QueryInterface(GetAsSupports(mParent
), &rv
);
3862 rv
= parent
->AddChildSHEntry(mOSHE
, aNewEntry
, aChildOffset
, mLoadType
,
3867 mLoadedTransIndex
= rootSH
->Index();
3868 #ifdef DEBUG_PAGE_CACHE
3869 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
3878 nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory
)
3880 mUseGlobalHistory
= aUseGlobalHistory
;
3881 if (!aUseGlobalHistory
) {
3885 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
3886 return history
? NS_OK
: NS_ERROR_FAILURE
;
3890 nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory
)
3892 *aUseGlobalHistory
= mUseGlobalHistory
;
3897 nsDocShell::RemoveFromSessionHistory()
3899 nsCOMPtr
<nsIDocShellTreeItem
> root
;
3900 GetSameTypeRootTreeItem(getter_AddRefs(root
));
3901 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav
= do_QueryInterface(root
);
3902 if (!rootAsWebnav
) {
3905 RefPtr
<ChildSHistory
> sessionHistory
= rootAsWebnav
->GetSessionHistory();
3906 if (!sessionHistory
) {
3909 int32_t index
= sessionHistory
->Index();
3910 AutoTArray
<nsID
, 16> ids({mHistoryID
});
3911 sessionHistory
->LegacySHistoryInternal()->RemoveEntries(ids
, index
);
3916 nsDocShell::SetCreatedDynamically(bool aDynamic
)
3918 mDynamicallyCreated
= aDynamic
;
3923 nsDocShell::GetCreatedDynamically(bool* aDynamic
)
3925 *aDynamic
= mDynamicallyCreated
;
3930 nsDocShell::GetCurrentSHEntry(nsISHEntry
** aEntry
, bool* aOSHE
)
3935 NS_ADDREF(*aEntry
= mLSHE
);
3937 NS_ADDREF(*aEntry
= mOSHE
);
3943 nsIScriptGlobalObject
*
3944 nsDocShell::GetScriptGlobalObject()
3946 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
3947 return mScriptGlobal
;
3951 nsDocShell::GetDocument()
3953 NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
3954 return mContentViewer
->GetDocument();
3958 nsDocShell::GetWindow()
3960 if (NS_FAILED(EnsureScriptEnvironment())) {
3963 return mScriptGlobal
->AsOuter();
3967 nsDocShell::SetDeviceSizeIsPageSize(bool aValue
)
3969 if (mDeviceSizeIsPageSize
!= aValue
) {
3970 mDeviceSizeIsPageSize
= aValue
;
3971 RefPtr
<nsPresContext
> presContext
;
3972 GetPresContext(getter_AddRefs(presContext
));
3974 presContext
->MediaFeatureValuesChanged({
3975 MediaFeatureChangeReason::DeviceSizeIsPageSizeChange
});
3982 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue
)
3984 *aValue
= mDeviceSizeIsPageSize
;
3989 nsDocShell::ClearFrameHistory(nsISHEntry
* aEntry
)
3991 nsCOMPtr
<nsISHContainer
> shcontainer
= do_QueryInterface(aEntry
);
3992 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
3993 if (!rootSH
|| !shcontainer
) {
3998 shcontainer
->GetChildCount(&count
);
3999 AutoTArray
<nsID
, 16> ids
;
4000 for (int32_t i
= 0; i
< count
; ++i
) {
4001 nsCOMPtr
<nsISHEntry
> child
;
4002 shcontainer
->GetChildAt(i
, getter_AddRefs(child
));
4004 ids
.AppendElement(child
->DocshellID());
4007 int32_t index
= rootSH
->Index();
4008 rootSH
->LegacySHistoryInternal()->RemoveEntries(ids
, index
);
4011 //-------------------------------------
4012 //-- Helper Method for Print discovery
4013 //-------------------------------------
4015 nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog
)
4017 if (mIsPrintingOrPP
&& aDisplayErrorDialog
) {
4018 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE
, nullptr, nullptr, nullptr);
4021 return mIsPrintingOrPP
;
4025 nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog
,
4026 bool aCheckIfUnloadFired
)
4028 bool isAllowed
= !IsPrintingOrPP(aDisplayPrintErrorDialog
) &&
4029 (!aCheckIfUnloadFired
|| !mFiredUnloadEvent
);
4033 if (!mContentViewer
) {
4036 bool firingBeforeUnload
;
4037 mContentViewer
->GetBeforeUnloadFiring(&firingBeforeUnload
);
4038 return !firingBeforeUnload
;
4041 //*****************************************************************************
4042 // nsDocShell::nsIWebNavigation
4043 //*****************************************************************************
4046 nsDocShell::GetCanGoBack(bool* aCanGoBack
)
4048 *aCanGoBack
= false;
4049 if (!IsNavigationAllowed(false)) {
4050 return NS_OK
; // JS may not handle returning of an error code
4052 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4054 *aCanGoBack
= rootSH
->CanGo(-1);
4057 return NS_ERROR_FAILURE
;
4061 nsDocShell::GetCanGoForward(bool* aCanGoForward
)
4063 *aCanGoForward
= false;
4064 if (!IsNavigationAllowed(false)) {
4065 return NS_OK
; // JS may not handle returning of an error code
4067 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4069 *aCanGoForward
= rootSH
->CanGo(1);
4072 return NS_ERROR_FAILURE
;
4076 nsDocShell::GoBack()
4078 if (!IsNavigationAllowed()) {
4079 return NS_OK
; // JS may not handle returning of an error code
4081 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4082 NS_ENSURE_TRUE(rootSH
, NS_ERROR_FAILURE
);
4085 return rv
.StealNSResult();
4089 nsDocShell::GoForward()
4091 if (!IsNavigationAllowed()) {
4092 return NS_OK
; // JS may not handle returning of an error code
4094 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4095 NS_ENSURE_TRUE(rootSH
, NS_ERROR_FAILURE
);
4098 return rv
.StealNSResult();
4101 // XXX(nika): We may want to stop exposing this API in the child process? Going
4102 // to a specific index from multiple different processes could definitely race.
4104 nsDocShell::GotoIndex(int32_t aIndex
)
4106 if (!IsNavigationAllowed()) {
4107 return NS_OK
; // JS may not handle returning of an error code
4109 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4110 NS_ENSURE_TRUE(rootSH
, NS_ERROR_FAILURE
);
4111 return rootSH
->LegacySHistoryWebNav()->GotoIndex(aIndex
);
4115 nsDocShell::LoadURI(const char16_t
* aURI
,
4116 uint32_t aLoadFlags
,
4117 nsIURI
* aReferringURI
,
4118 nsIInputStream
* aPostStream
,
4119 nsIInputStream
* aHeaderStream
,
4120 nsIPrincipal
* aTriggeringPrincipal
)
4122 return LoadURIWithOptions(aURI
, aLoadFlags
, aReferringURI
,
4123 RP_Unset
, aPostStream
,
4124 aHeaderStream
, nullptr, aTriggeringPrincipal
);
4128 nsDocShell::LoadURIWithOptions(const char16_t
* aURI
,
4129 uint32_t aLoadFlags
,
4130 nsIURI
* aReferringURI
,
4131 uint32_t aReferrerPolicy
,
4132 nsIInputStream
* aPostStream
,
4133 nsIInputStream
* aHeaderStream
,
4135 nsIPrincipal
* aTriggeringPrincipal
)
4137 NS_ASSERTION((aLoadFlags
& 0xf) == 0, "Unexpected flags");
4139 if (!IsNavigationAllowed()) {
4140 return NS_OK
; // JS may not handle returning of an error code
4142 nsCOMPtr
<nsIURI
> uri
;
4143 nsCOMPtr
<nsIInputStream
> postStream(aPostStream
);
4144 nsresult rv
= NS_OK
;
4146 // Create a URI from our string; if that succeeds, we want to
4147 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
4150 NS_ConvertUTF16toUTF8
uriString(aURI
);
4151 // Cleanup the empty spaces that might be on each end.
4152 uriString
.Trim(" ");
4153 // Eliminate embedded newlines, which single-line text fields now allow:
4154 uriString
.StripCRLF();
4155 NS_ENSURE_TRUE(!uriString
.IsEmpty(), NS_ERROR_FAILURE
);
4157 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
);
4159 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
4162 nsCOMPtr
<nsIURIFixupInfo
> fixupInfo
;
4164 // Call the fixup object. This will clobber the rv from NS_NewURI
4165 // above, but that's fine with us. Note that we need to do this even
4166 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
4167 // (things like view-source:mozilla.org for example).
4168 uint32_t fixupFlags
= 0;
4169 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
4170 fixupFlags
|= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
;
4172 if (aLoadFlags
& LOAD_FLAGS_FIXUP_SCHEME_TYPOS
) {
4173 fixupFlags
|= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS
;
4175 nsCOMPtr
<nsIInputStream
> fixupStream
;
4176 rv
= sURIFixup
->GetFixupURIInfo(uriString
, fixupFlags
,
4177 getter_AddRefs(fixupStream
),
4178 getter_AddRefs(fixupInfo
));
4180 if (NS_SUCCEEDED(rv
)) {
4181 fixupInfo
->GetPreferredURI(getter_AddRefs(uri
));
4182 fixupInfo
->SetConsumer(GetAsSupports(this));
4186 // GetFixupURIInfo only returns a post data stream if it succeeded
4187 // and changed the URI, in which case we should override the
4188 // passed-in post data.
4189 postStream
= fixupStream
;
4192 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
4193 nsCOMPtr
<nsIObserverService
> serv
= services::GetObserverService();
4195 serv
->NotifyObservers(fixupInfo
, "keyword-uri-fixup", aURI
);
4199 // else no fixup service so just use the URI we created and see
4202 if (NS_ERROR_MALFORMED_URI
== rv
) {
4203 if (DisplayLoadError(rv
, uri
, aURI
, nullptr) &&
4204 (aLoadFlags
& LOAD_FLAGS_ERROR_LOAD_CHANGES_RV
) != 0) {
4205 return NS_ERROR_LOAD_SHOWED_ERRORPAGE
;
4209 if (NS_FAILED(rv
) || !uri
) {
4210 return NS_ERROR_FAILURE
;
4213 PopupControlState popupState
;
4214 if (aLoadFlags
& LOAD_FLAGS_ALLOW_POPUPS
) {
4215 popupState
= openAllowed
;
4216 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_POPUPS
;
4218 popupState
= openOverridden
;
4220 nsAutoPopupStatePusher
statePusher(popupState
);
4222 bool forceAllowDataURI
=
4223 aLoadFlags
& LOAD_FLAGS_FORCE_ALLOW_DATA_URI
;
4225 // Don't pass certain flags that aren't needed and end up confusing
4226 // ConvertLoadTypeToDocShellInfoLoadType. We do need to ensure that they are
4227 // passed to LoadURI though, since it uses them.
4228 uint32_t extraFlags
= (aLoadFlags
& EXTRA_LOAD_FLAGS
);
4229 aLoadFlags
&= ~EXTRA_LOAD_FLAGS
;
4231 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
4232 rv
= CreateLoadInfo(getter_AddRefs(loadInfo
));
4233 if (NS_FAILED(rv
)) {
4238 * If the user "Disables Protection on This Page", we have to make sure to
4239 * remember the users decision when opening links in child tabs [Bug 906190]
4242 if (aLoadFlags
& LOAD_FLAGS_ALLOW_MIXED_CONTENT
) {
4243 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT
, aLoadFlags
);
4245 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
4248 loadInfo
->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(loadType
));
4249 loadInfo
->SetPostDataStream(postStream
);
4250 loadInfo
->SetReferrer(aReferringURI
);
4251 loadInfo
->SetReferrerPolicy(aReferrerPolicy
);
4252 loadInfo
->SetHeadersStream(aHeaderStream
);
4253 loadInfo
->SetBaseURI(aBaseURI
);
4254 loadInfo
->SetTriggeringPrincipal(aTriggeringPrincipal
);
4255 loadInfo
->SetForceAllowDataURI(forceAllowDataURI
);
4258 nsAutoString searchProvider
, keyword
;
4259 fixupInfo
->GetKeywordProviderName(searchProvider
);
4260 fixupInfo
->GetKeywordAsSent(keyword
);
4261 MaybeNotifyKeywordSearchLoading(searchProvider
, keyword
);
4264 rv
= LoadURI(uri
, loadInfo
, extraFlags
, true);
4266 // Save URI string in case it's needed later when
4267 // sending to search engine service in EndPageLoad()
4268 mOriginalUriString
= uriString
;
4274 nsDocShell::DisplayLoadError(nsresult aError
, nsIURI
* aURI
,
4275 const char16_t
* aURL
,
4276 nsIChannel
* aFailedChannel
,
4277 bool* aDisplayedErrorPage
)
4279 *aDisplayedErrorPage
= false;
4280 // Get prompt and string bundle servcies
4281 nsCOMPtr
<nsIPrompt
> prompter
;
4282 nsCOMPtr
<nsIStringBundle
> stringBundle
;
4283 GetPromptAndStringBundle(getter_AddRefs(prompter
),
4284 getter_AddRefs(stringBundle
));
4286 NS_ENSURE_TRUE(stringBundle
, NS_ERROR_FAILURE
);
4287 NS_ENSURE_TRUE(prompter
, NS_ERROR_FAILURE
);
4289 const char* error
= nullptr;
4290 // The key used to select the appropriate error message from the properties file.
4291 const char* errorDescriptionID
= nullptr;
4292 const uint32_t kMaxFormatStrArgs
= 3;
4293 nsAutoString formatStrs
[kMaxFormatStrArgs
];
4294 uint32_t formatStrCount
= 0;
4295 bool addHostPort
= false;
4296 nsresult rv
= NS_OK
;
4297 nsAutoString messageStr
;
4298 nsAutoCString cssClass
;
4299 nsAutoCString errorPage
;
4301 errorPage
.AssignLiteral("neterror");
4303 // Turn the error code into a human readable error message.
4304 if (NS_ERROR_UNKNOWN_PROTOCOL
== aError
) {
4305 NS_ENSURE_ARG_POINTER(aURI
);
4307 // Extract the schemes into a comma delimited list.
4308 nsAutoCString scheme
;
4309 aURI
->GetScheme(scheme
);
4310 CopyASCIItoUTF16(scheme
, formatStrs
[0]);
4311 nsCOMPtr
<nsINestedURI
> nestedURI
= do_QueryInterface(aURI
);
4313 nsCOMPtr
<nsIURI
> tempURI
;
4315 rv2
= nestedURI
->GetInnerURI(getter_AddRefs(tempURI
));
4316 if (NS_SUCCEEDED(rv2
) && tempURI
) {
4317 tempURI
->GetScheme(scheme
);
4318 formatStrs
[0].AppendLiteral(", ");
4319 AppendASCIItoUTF16(scheme
, formatStrs
[0]);
4321 nestedURI
= do_QueryInterface(tempURI
);
4324 error
= "unknownProtocolFound";
4325 } else if (NS_ERROR_FILE_NOT_FOUND
== aError
) {
4326 NS_ENSURE_ARG_POINTER(aURI
);
4327 error
= "fileNotFound";
4328 } else if (NS_ERROR_FILE_ACCESS_DENIED
== aError
) {
4329 NS_ENSURE_ARG_POINTER(aURI
);
4330 error
= "fileAccessDenied";
4331 } else if (NS_ERROR_UNKNOWN_HOST
== aError
) {
4332 NS_ENSURE_ARG_POINTER(aURI
);
4335 nsCOMPtr
<nsIURI
> innermostURI
= NS_GetInnermostURI(aURI
);
4336 innermostURI
->GetHost(host
);
4337 CopyUTF8toUTF16(host
, formatStrs
[0]);
4339 errorDescriptionID
= "dnsNotFound2";
4340 error
= "dnsNotFound";
4341 } else if (NS_ERROR_CONNECTION_REFUSED
== aError
) {
4342 NS_ENSURE_ARG_POINTER(aURI
);
4344 error
= "connectionFailure";
4345 } else if (NS_ERROR_NET_INTERRUPT
== aError
) {
4346 NS_ENSURE_ARG_POINTER(aURI
);
4348 error
= "netInterrupt";
4349 } else if (NS_ERROR_NET_TIMEOUT
== aError
) {
4350 NS_ENSURE_ARG_POINTER(aURI
);
4353 aURI
->GetHost(host
);
4354 CopyUTF8toUTF16(host
, formatStrs
[0]);
4356 error
= "netTimeout";
4357 } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION
== aError
||
4358 NS_ERROR_CSP_FORM_ACTION_VIOLATION
== aError
) {
4360 cssClass
.AssignLiteral("neterror");
4361 error
= "cspBlocked";
4362 } else if (NS_ERROR_GET_MODULE(aError
) == NS_ERROR_MODULE_SECURITY
) {
4363 nsCOMPtr
<nsINSSErrorsService
> nsserr
=
4364 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID
);
4366 uint32_t errorClass
;
4367 if (!nsserr
|| NS_FAILED(nsserr
->GetErrorClass(aError
, &errorClass
))) {
4368 errorClass
= nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL
;
4371 nsCOMPtr
<nsISupports
> securityInfo
;
4372 nsCOMPtr
<nsITransportSecurityInfo
> tsi
;
4373 if (aFailedChannel
) {
4374 aFailedChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
4376 tsi
= do_QueryInterface(securityInfo
);
4378 uint32_t securityState
;
4379 tsi
->GetSecurityState(&securityState
);
4380 if (securityState
& nsIWebProgressListener::STATE_USES_SSL_3
) {
4381 error
= "sslv3Used";
4383 } else if (securityState
& nsIWebProgressListener::STATE_USES_WEAK_CRYPTO
) {
4384 error
= "weakCryptoUsed";
4388 // No channel, let's obtain the generic error message
4390 nsserr
->GetErrorMessage(aError
, messageStr
);
4393 // We don't have a message string here anymore but DisplayLoadError
4394 // requires a non-empty messageStr.
4395 messageStr
.Truncate();
4396 messageStr
.AssignLiteral(u
" ");
4397 if (errorClass
== nsINSSErrorsService::ERROR_CLASS_BAD_CERT
) {
4398 error
= "nssBadCert";
4400 // If this is an HTTP Strict Transport Security host or a pinned host
4401 // and the certificate is bad, don't allow overrides (RFC 6797 section
4402 // 12.1, HPKP draft spec section 2.6).
4404 UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE
: 0;
4405 bool isStsHost
= false;
4406 bool isPinnedHost
= false;
4407 if (XRE_IsParentProcess()) {
4408 nsCOMPtr
<nsISiteSecurityService
> sss
=
4409 do_GetService(NS_SSSERVICE_CONTRACTID
, &rv
);
4410 NS_ENSURE_SUCCESS(rv
, rv
);
4411 rv
= sss
->IsSecureURI(nsISiteSecurityService::HEADER_HSTS
, aURI
,
4412 flags
, mOriginAttributes
, nullptr, nullptr,
4414 NS_ENSURE_SUCCESS(rv
, rv
);
4415 rv
= sss
->IsSecureURI(nsISiteSecurityService::HEADER_HPKP
, aURI
,
4416 flags
, mOriginAttributes
, nullptr, nullptr,
4418 NS_ENSURE_SUCCESS(rv
, rv
);
4420 mozilla::dom::ContentChild
* cc
=
4421 mozilla::dom::ContentChild::GetSingleton();
4422 mozilla::ipc::URIParams uri
;
4423 SerializeURI(aURI
, uri
);
4424 cc
->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS
, uri
, flags
,
4425 mOriginAttributes
, &isStsHost
);
4426 cc
->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP
, uri
, flags
,
4427 mOriginAttributes
, &isPinnedHost
);
4430 if (Preferences::GetBool(
4431 "browser.xul.error_pages.expert_bad_cert", false)) {
4432 cssClass
.AssignLiteral("expertBadCert");
4435 // HSTS/pinning takes precedence over the expert bad cert pref. We
4436 // never want to show the "Add Exception" button for these sites.
4437 // In the future we should differentiate between an HSTS host and a
4438 // pinned host and display a more informative message to the user.
4439 if (isStsHost
|| isPinnedHost
) {
4440 cssClass
.AssignLiteral("badStsCert");
4445 // measuring STS separately allows us to measure click through
4447 bucketId
= nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS
;
4449 bucketId
= nsISecurityUITelemetry::WARNING_BAD_CERT_TOP
;
4452 // See if an alternate cert error page is registered
4453 nsAutoCString alternateErrorPage
;
4455 Preferences::GetCString("security.alternate_certificate_error_page",
4456 alternateErrorPage
);
4457 if (NS_SUCCEEDED(rv
)) {
4458 errorPage
.Assign(alternateErrorPage
);
4461 if (!IsFrame() && errorPage
.EqualsIgnoreCase("certerror")) {
4462 Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI
, bucketId
);
4465 error
= "nssFailure2";
4467 } else if (NS_ERROR_PHISHING_URI
== aError
||
4468 NS_ERROR_MALWARE_URI
== aError
||
4469 NS_ERROR_UNWANTED_URI
== aError
||
4470 NS_ERROR_HARMFUL_URI
== aError
) {
4472 aURI
->GetHost(host
);
4473 CopyUTF8toUTF16(host
, formatStrs
[0]);
4476 // Malware and phishing detectors may want to use an alternate error
4477 // page, but if the pref's not set, we'll fall back on the standard page
4478 nsAutoCString alternateErrorPage
;
4479 nsresult rv
= Preferences::GetCString("urlclassifier.alternate_error_page",
4480 alternateErrorPage
);
4481 if (NS_SUCCEEDED(rv
)) {
4482 errorPage
.Assign(alternateErrorPage
);
4486 bool sendTelemetry
= false;
4487 if (NS_ERROR_PHISHING_URI
== aError
) {
4488 sendTelemetry
= true;
4489 error
= "deceptiveBlocked";
4490 bucketId
= IsFrame() ? IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_FRAME
4491 : IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_TOP
;
4492 } else if (NS_ERROR_MALWARE_URI
== aError
) {
4493 sendTelemetry
= true;
4494 error
= "malwareBlocked";
4495 bucketId
= IsFrame() ? IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_FRAME
4496 : IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_TOP
;
4497 } else if (NS_ERROR_UNWANTED_URI
== aError
) {
4498 sendTelemetry
= true;
4499 error
= "unwantedBlocked";
4500 bucketId
= IsFrame() ? IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_FRAME
4501 : IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_TOP
;
4502 } else if (NS_ERROR_HARMFUL_URI
== aError
) {
4503 sendTelemetry
= true;
4504 error
= "harmfulBlocked";
4505 bucketId
= IsFrame() ? IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_FRAME
4506 : IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_TOP
;
4509 if (sendTelemetry
&& errorPage
.EqualsIgnoreCase("blocked")) {
4510 Telemetry::Accumulate(Telemetry::URLCLASSIFIER_UI_EVENTS
, bucketId
);
4513 cssClass
.AssignLiteral("blacklist");
4514 } else if (NS_ERROR_CONTENT_CRASHED
== aError
) {
4515 errorPage
.AssignLiteral("tabcrashed");
4516 error
= "tabcrashed";
4518 nsCOMPtr
<EventTarget
> handler
= mChromeEventHandler
;
4520 nsCOMPtr
<Element
> element
= do_QueryInterface(handler
);
4521 element
->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr
);
4524 // DisplayLoadError requires a non-empty messageStr to proceed and call
4525 // LoadErrorPage. If the page doesn't have a title, we will use a blank
4526 // space which will be trimmed and thus treated as empty by the front-end.
4527 if (messageStr
.IsEmpty()) {
4528 messageStr
.AssignLiteral(u
" ");
4530 } else if (NS_ERROR_BUILDID_MISMATCH
== aError
) {
4531 errorPage
.AssignLiteral("restartrequired");
4532 error
= "restartrequired";
4534 // DisplayLoadError requires a non-empty messageStr to proceed and call
4535 // LoadErrorPage. If the page doesn't have a title, we will use a blank
4536 // space which will be trimmed and thus treated as empty by the front-end.
4537 if (messageStr
.IsEmpty()) {
4538 messageStr
.AssignLiteral(u
" ");
4541 // Errors requiring simple formatting
4543 case NS_ERROR_MALFORMED_URI
:
4545 error
= "malformedURI";
4546 errorDescriptionID
= "malformedURI2";
4548 case NS_ERROR_REDIRECT_LOOP
:
4549 // Doc failed to load because the server generated too many redirects
4550 error
= "redirectLoop";
4552 case NS_ERROR_UNKNOWN_SOCKET_TYPE
:
4553 // Doc failed to load because PSM is not installed
4554 error
= "unknownSocketType";
4556 case NS_ERROR_NET_RESET
:
4557 // Doc failed to load because the server kept reseting the connection
4558 // before we could read any data from it
4561 case NS_ERROR_DOCUMENT_NOT_CACHED
:
4562 // Doc failed to load because the cache does not contain a copy of
4564 error
= "notCached";
4566 case NS_ERROR_OFFLINE
:
4567 // Doc failed to load because we are offline.
4568 error
= "netOffline";
4570 case NS_ERROR_DOCUMENT_IS_PRINTMODE
:
4571 // Doc navigation attempted while Printing or Print Preview
4572 error
= "isprinting";
4574 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED
:
4575 // Port blocked for security reasons
4577 error
= "deniedPortAccess";
4579 case NS_ERROR_UNKNOWN_PROXY_HOST
:
4580 // Proxy hostname could not be resolved.
4581 error
= "proxyResolveFailure";
4583 case NS_ERROR_PROXY_CONNECTION_REFUSED
:
4584 // Proxy connection was refused.
4585 error
= "proxyConnectFailure";
4587 case NS_ERROR_INVALID_CONTENT_ENCODING
:
4588 // Bad Content Encoding.
4589 error
= "contentEncodingError";
4591 case NS_ERROR_REMOTE_XUL
:
4592 error
= "remoteXUL";
4594 case NS_ERROR_UNSAFE_CONTENT_TYPE
:
4595 // Channel refused to load from an unrecognized content type.
4596 error
= "unsafeContentType";
4598 case NS_ERROR_CORRUPTED_CONTENT
:
4599 // Broken Content Detected. e.g. Content-MD5 check failure.
4600 error
= "corruptedContentErrorv2";
4602 case NS_ERROR_INTERCEPTION_FAILED
:
4603 // ServiceWorker intercepted request, but something went wrong.
4604 error
= "corruptedContentErrorv2";
4606 case NS_ERROR_NET_INADEQUATE_SECURITY
:
4607 // Server negotiated bad TLS for HTTP/2.
4608 error
= "inadequateSecurityError";
4611 case NS_ERROR_BLOCKED_BY_POLICY
:
4612 // Page blocked by policy
4613 error
= "blockedByPolicy";
4620 // Test if the error should be displayed
4625 if (!errorDescriptionID
) {
4626 errorDescriptionID
= error
;
4629 // Test if the error needs to be formatted
4630 if (!messageStr
.IsEmpty()) {
4631 // already obtained message
4634 // Build up the host:port string.
4635 nsAutoCString hostport
;
4637 aURI
->GetHostPort(hostport
);
4639 hostport
.Assign('?');
4641 CopyUTF8toUTF16(hostport
, formatStrs
[formatStrCount
++]);
4645 rv
= NS_ERROR_NOT_AVAILABLE
;
4647 // displaying "file://" is aesthetically unpleasing and could even be
4648 // confusing to the user
4649 bool isFileURI
= false;
4650 rv
= aURI
->SchemeIs("file", &isFileURI
);
4651 if (NS_SUCCEEDED(rv
) && isFileURI
) {
4652 aURI
->GetPathQueryRef(spec
);
4654 aURI
->GetSpec(spec
);
4657 nsCOMPtr
<nsITextToSubURI
> textToSubURI(
4658 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
));
4659 if (NS_SUCCEEDED(rv
)) {
4660 rv
= textToSubURI
->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), spec
,
4661 formatStrs
[formatStrCount
]);
4666 if (NS_FAILED(rv
)) {
4667 CopyUTF8toUTF16(spec
, formatStrs
[formatStrCount
]);
4672 const char16_t
* strs
[kMaxFormatStrArgs
];
4673 for (uint32_t i
= 0; i
< formatStrCount
; i
++) {
4674 strs
[i
] = formatStrs
[i
].get();
4677 rv
= stringBundle
->FormatStringFromName(errorDescriptionID
, strs
, formatStrCount
, str
);
4678 NS_ENSURE_SUCCESS(rv
, rv
);
4679 messageStr
.Assign(str
.get());
4682 // Display the error as a page or an alert prompt
4683 NS_ENSURE_FALSE(messageStr
.IsEmpty(), NS_ERROR_FAILURE
);
4685 if (NS_ERROR_NET_INTERRUPT
== aError
|| NS_ERROR_NET_RESET
== aError
) {
4686 bool isSecureURI
= false;
4687 rv
= aURI
->SchemeIs("https", &isSecureURI
);
4688 if (NS_SUCCEEDED(rv
) && isSecureURI
) {
4689 // Maybe TLS intolerant. Treat this as an SSL error.
4690 error
= "nssFailure2";
4694 if (UseErrorPages()) {
4695 // Display an error page
4696 nsresult loadedPage
= LoadErrorPage(aURI
, aURL
, errorPage
.get(),
4697 error
, messageStr
.get(),
4698 cssClass
.get(), aFailedChannel
);
4699 *aDisplayedErrorPage
= NS_SUCCEEDED(loadedPage
);
4701 // The prompter reqires that our private window has a document (or it
4702 // asserts). Satisfy that assertion now since GetDoc will force
4703 // creation of one if it hasn't already been created.
4704 if (mScriptGlobal
) {
4705 Unused
<< mScriptGlobal
->GetDoc();
4708 // Display a message box
4709 prompter
->Alert(nullptr, messageStr
.get());
4715 #define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride"
4718 nsDocShell::LoadErrorPage(nsIURI
* aURI
, const char16_t
* aURL
,
4719 const char* aErrorPage
,
4720 const char* aErrorType
,
4721 const char16_t
* aDescription
,
4722 const char* aCSSClass
,
4723 nsIChannel
* aFailedChannel
)
4725 MOZ_ASSERT(!mIsBeingDestroyed
);
4728 if (MOZ_LOG_TEST(gDocShellLog
, LogLevel::Debug
)) {
4729 nsAutoCString chanName
;
4730 if (aFailedChannel
) {
4731 aFailedChannel
->GetName(chanName
);
4733 chanName
.AssignLiteral("<no channel>");
4736 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
4737 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
4738 aURI
? aURI
->GetSpecOrDefault().get() : "",
4739 NS_ConvertUTF16toUTF8(aURL
).get(),
4743 mFailedChannel
= aFailedChannel
;
4745 mFailedLoadType
= mLoadType
;
4748 // Abandon mLSHE's BFCache entry and create a new one. This way, if
4749 // we go back or forward to another SHEntry with the same doc
4750 // identifier, the error page won't persist.
4751 mLSHE
->AbandonBFCacheEntry();
4756 nsresult rv
= aURI
->GetSpec(url
);
4757 NS_ENSURE_SUCCESS(rv
, rv
);
4759 CopyUTF16toUTF8(aURL
, url
);
4761 return NS_ERROR_INVALID_POINTER
;
4764 // Create a URL to pass all the error information through to the page.
4767 #define SAFE_ESCAPE(output, input, params) \
4768 if (NS_WARN_IF(!NS_Escape(input, output, params))) { \
4769 return NS_ERROR_OUT_OF_MEMORY; \
4772 nsCString escapedUrl
, escapedError
, escapedDescription
,
4774 SAFE_ESCAPE(escapedUrl
, url
, url_Path
);
4775 SAFE_ESCAPE(escapedError
, nsDependentCString(aErrorType
), url_Path
);
4776 SAFE_ESCAPE(escapedDescription
,
4777 NS_ConvertUTF16toUTF8(aDescription
), url_Path
);
4779 nsCString
cssClass(aCSSClass
);
4780 SAFE_ESCAPE(escapedCSSClass
, cssClass
, url_Path
);
4782 nsCString
errorPageUrl("about:");
4783 errorPageUrl
.AppendASCII(aErrorPage
);
4784 errorPageUrl
.AppendLiteral("?e=");
4786 errorPageUrl
.AppendASCII(escapedError
.get());
4787 errorPageUrl
.AppendLiteral("&u=");
4788 errorPageUrl
.AppendASCII(escapedUrl
.get());
4789 if ((strcmp(aErrorPage
, "blocked") == 0) &&
4790 Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE
, true)) {
4791 errorPageUrl
.AppendLiteral("&o=1");
4793 if (!escapedCSSClass
.IsEmpty()) {
4794 errorPageUrl
.AppendLiteral("&s=");
4795 errorPageUrl
.AppendASCII(escapedCSSClass
.get());
4797 errorPageUrl
.AppendLiteral("&c=UTF-8");
4799 nsAutoCString
frameType(FrameTypeToString(mFrameType
));
4800 errorPageUrl
.AppendLiteral("&f=");
4801 errorPageUrl
.AppendASCII(frameType
.get());
4803 nsCOMPtr
<nsICaptivePortalService
> cps
= do_GetService(NS_CAPTIVEPORTAL_CID
);
4805 if (cps
&& NS_SUCCEEDED(cps
->GetState(&cpsState
)) &&
4806 cpsState
== nsICaptivePortalService::LOCKED_PORTAL
) {
4807 errorPageUrl
.AppendLiteral("&captive=true");
4810 // netError.xhtml's getDescription only handles the "d" parameter at the
4811 // end of the URL, so append it last.
4812 errorPageUrl
.AppendLiteral("&d=");
4813 errorPageUrl
.AppendASCII(escapedDescription
.get());
4815 nsCOMPtr
<nsIURI
> errorPageURI
;
4816 nsresult rv
= NS_NewURI(getter_AddRefs(errorPageURI
), errorPageUrl
);
4817 NS_ENSURE_SUCCESS(rv
, rv
);
4819 return InternalLoad(errorPageURI
, nullptr, Nothing(), false, nullptr, RP_Unset
,
4820 nsContentUtils::GetSystemPrincipal(), nullptr,
4821 INTERNAL_LOAD_FLAGS_NONE
, EmptyString(),
4822 nullptr, VoidString(), nullptr, nullptr,
4823 LOAD_ERROR_PAGE
, nullptr, true, VoidString(), this,
4824 nullptr, nullptr, nullptr);
4828 nsDocShell::Reload(uint32_t aReloadFlags
)
4830 if (!IsNavigationAllowed()) {
4831 return NS_OK
; // JS may not handle returning of an error code
4834 NS_ASSERTION(((aReloadFlags
& 0xf) == 0),
4835 "Reload command not updated to use load flags!");
4836 NS_ASSERTION((aReloadFlags
& EXTRA_LOAD_FLAGS
) == 0,
4837 "Don't pass these flags to Reload");
4839 uint32_t loadType
= MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL
, aReloadFlags
);
4840 NS_ENSURE_TRUE(IsValidLoadType(loadType
), NS_ERROR_INVALID_ARG
);
4842 // Send notifications to the HistoryListener if any, about the impending
4844 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
4845 bool canReload
= true;
4847 rootSH
->LegacySHistoryInternal()
4848 ->NotifyOnHistoryReload(mCurrentURI
, aReloadFlags
, &canReload
);
4855 /* If you change this part of code, make sure bug 45297 does not re-occur */
4857 rv
= LoadHistoryEntry(mOSHE
, loadType
);
4858 } else if (mLSHE
) { // In case a reload happened before the current load is done
4859 rv
= LoadHistoryEntry(mLSHE
, loadType
);
4861 nsCOMPtr
<nsIDocument
> doc(GetDocument());
4867 // Do not inherit owner from document
4868 uint32_t flags
= INTERNAL_LOAD_FLAGS_NONE
;
4869 nsAutoString srcdoc
;
4870 nsCOMPtr
<nsIURI
> baseURI
;
4871 nsCOMPtr
<nsIURI
> originalURI
;
4872 nsCOMPtr
<nsIURI
> resultPrincipalURI
;
4873 bool loadReplace
= false;
4875 nsIPrincipal
* triggeringPrincipal
= doc
->NodePrincipal();
4876 nsAutoString contentTypeHint
;
4877 doc
->GetContentType(contentTypeHint
);
4879 if (doc
->IsSrcdocDocument()) {
4880 doc
->GetSrcdocData(srcdoc
);
4881 flags
|= INTERNAL_LOAD_FLAGS_IS_SRCDOC
;
4882 baseURI
= doc
->GetBaseURI();
4884 nsCOMPtr
<nsIChannel
> chan
= doc
->GetChannel();
4887 chan
->GetLoadFlags(&loadFlags
);
4888 loadReplace
= loadFlags
& nsIChannel::LOAD_REPLACE
;
4889 nsCOMPtr
<nsIHttpChannel
> httpChan(do_QueryInterface(chan
));
4891 httpChan
->GetOriginalURI(getter_AddRefs(originalURI
));
4894 nsCOMPtr
<nsILoadInfo
> loadInfo
= chan
->GetLoadInfo();
4896 loadInfo
->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI
));
4900 MOZ_ASSERT(triggeringPrincipal
, "Need a valid triggeringPrincipal");
4902 // Stack variables to ensure changes to the member variables don't affect to
4904 nsCOMPtr
<nsIURI
> currentURI
= mCurrentURI
;
4905 nsCOMPtr
<nsIURI
> referrerURI
= mReferrerURI
;
4906 uint32_t referrerPolicy
= mReferrerPolicy
;
4908 // Reload always rewrites result principal URI.
4909 Maybe
<nsCOMPtr
<nsIURI
>> emplacedResultPrincipalURI
;
4910 emplacedResultPrincipalURI
.emplace(std::move(resultPrincipalURI
));
4911 rv
= InternalLoad(currentURI
,
4913 emplacedResultPrincipalURI
,
4917 triggeringPrincipal
,
4918 triggeringPrincipal
,
4920 EmptyString(), // No window target
4921 NS_LossyConvertUTF16toASCII(contentTypeHint
).get(),
4922 VoidString(), // No forced download
4923 nullptr, // No post data
4924 nullptr, // No headers data
4925 loadType
, // Load type
4926 nullptr, // No SHEntry
4928 srcdoc
, // srcdoc argument for iframe
4929 this, // For reloads we are the source
4931 nullptr, // No nsIDocShell
4932 nullptr); // No nsIRequest
4939 nsDocShell::Stop(uint32_t aStopFlags
)
4941 // Revoke any pending event related to content viewer restoration
4942 mRestorePresentationEvent
.Revoke();
4944 if (mLoadType
== LOAD_ERROR_PAGE
) {
4946 // Since error page loads never unset mLSHE, do so now
4947 SetHistoryEntry(&mOSHE
, mLSHE
);
4948 SetHistoryEntry(&mLSHE
, nullptr);
4951 mFailedChannel
= nullptr;
4952 mFailedURI
= nullptr;
4955 if (nsIWebNavigation::STOP_CONTENT
& aStopFlags
) {
4956 // Stop the document loading
4957 if (mContentViewer
) {
4958 nsCOMPtr
<nsIContentViewer
> cv
= mContentViewer
;
4963 if (nsIWebNavigation::STOP_NETWORK
& aStopFlags
) {
4964 // Suspend any timers that were set for this loader. We'll clear
4965 // them out for good in CreateContentViewer.
4966 if (mRefreshURIList
) {
4967 SuspendRefreshURIs();
4968 mSavedRefreshURIList
.swap(mRefreshURIList
);
4969 mRefreshURIList
= nullptr;
4972 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4973 // just call Stop() on us as an nsIDocumentLoader... We need fewer
4978 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
4979 while (iter
.HasMore()) {
4980 nsCOMPtr
<nsIWebNavigation
> shellAsNav(do_QueryObject(iter
.GetNext()));
4982 shellAsNav
->Stop(aStopFlags
);
4990 nsDocShell::GetDocument(nsIDocument
** aDocument
)
4992 NS_ENSURE_ARG_POINTER(aDocument
);
4993 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE
);
4995 nsCOMPtr
<nsIDocument
> doc
= mContentViewer
->GetDocument();
4997 return NS_ERROR_NOT_AVAILABLE
;
5000 doc
.forget(aDocument
);
5005 nsDocShell::GetCurrentURI(nsIURI
** aURI
)
5007 NS_ENSURE_ARG_POINTER(aURI
);
5009 nsCOMPtr
<nsIURI
> uri
= mCurrentURI
;
5015 nsDocShell::GetReferringURI(nsIURI
** aURI
)
5017 NS_ENSURE_ARG_POINTER(aURI
);
5019 *aURI
= mReferrerURI
;
5020 NS_IF_ADDREF(*aURI
);
5026 nsDocShell::InitSessionHistory()
5028 MOZ_ASSERT(!mIsBeingDestroyed
);
5030 // Make sure that we are the root DocShell, and set a handle to root docshell
5031 // in the session history.
5032 nsCOMPtr
<nsIDocShellTreeItem
> root
;
5033 GetSameTypeRootTreeItem(getter_AddRefs(root
));
5035 return NS_ERROR_FAILURE
;
5038 mSessionHistory
= new ChildSHistory(this);
5043 nsDocShell::GetSessionHistoryXPCOM(nsISupports
** aSessionHistory
)
5045 NS_ENSURE_ARG_POINTER(aSessionHistory
);
5046 RefPtr
<ChildSHistory
> shistory
= mSessionHistory
;
5047 shistory
.forget(aSessionHistory
);
5051 //*****************************************************************************
5052 // nsDocShell::nsIWebPageDescriptor
5053 //*****************************************************************************
5056 nsDocShell::LoadPage(nsISupports
* aPageDescriptor
, uint32_t aDisplayType
)
5058 nsCOMPtr
<nsISHEntry
> shEntryIn(do_QueryInterface(aPageDescriptor
));
5060 // Currently, the opaque 'page descriptor' is an nsISHEntry...
5062 return NS_ERROR_INVALID_POINTER
;
5065 // Now clone shEntryIn, since we might end up modifying it later on, and we
5066 // want a page descriptor to be reusable.
5067 nsCOMPtr
<nsISHEntry
> shEntry
;
5068 nsresult rv
= shEntryIn
->Clone(getter_AddRefs(shEntry
));
5069 NS_ENSURE_SUCCESS(rv
, rv
);
5071 // Give our cloned shEntry a new bfcache entry so this load is independent
5072 // of all other loads. (This is important, in particular, for bugs 582795
5074 rv
= shEntry
->AbandonBFCacheEntry();
5075 NS_ENSURE_SUCCESS(rv
, rv
);
5078 // load the page as view-source
5080 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE
== aDisplayType
) {
5081 nsCOMPtr
<nsIURI
> oldUri
, newUri
;
5082 nsCString spec
, newSpec
;
5084 // Create a new view-source URI and replace the original.
5085 rv
= shEntry
->GetURI(getter_AddRefs(oldUri
));
5086 if (NS_FAILED(rv
)) {
5090 oldUri
->GetSpec(spec
);
5091 newSpec
.AppendLiteral("view-source:");
5092 newSpec
.Append(spec
);
5094 rv
= NS_NewURI(getter_AddRefs(newUri
), newSpec
);
5095 if (NS_FAILED(rv
)) {
5098 shEntry
->SetURI(newUri
);
5099 shEntry
->SetOriginalURI(nullptr);
5100 shEntry
->SetResultPrincipalURI(nullptr);
5101 // shEntry's current triggering principal is whoever loaded that page initially.
5102 // But now we're doing another load of the page, via an API that is only exposed
5103 // to system code. The triggering principal for this load should be the system
5105 shEntry
->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
5108 rv
= LoadHistoryEntry(shEntry
, LOAD_HISTORY
);
5113 nsDocShell::GetCurrentDescriptor(nsISupports
** aPageDescriptor
)
5115 MOZ_ASSERT(aPageDescriptor
, "Null out param?");
5117 *aPageDescriptor
= nullptr;
5119 nsISHEntry
* src
= mOSHE
? mOSHE
: mLSHE
;
5121 nsCOMPtr
<nsISHEntry
> dest
;
5123 nsresult rv
= src
->Clone(getter_AddRefs(dest
));
5124 if (NS_FAILED(rv
)) {
5128 // null out inappropriate cloned attributes...
5129 dest
->SetParent(nullptr);
5130 dest
->SetIsSubFrame(false);
5132 return CallQueryInterface(dest
, aPageDescriptor
);
5135 return NS_ERROR_NOT_AVAILABLE
;
5138 //*****************************************************************************
5139 // nsDocShell::nsIBaseWindow
5140 //*****************************************************************************
5143 nsDocShell::InitWindow(nativeWindow aParentNativeWindow
,
5144 nsIWidget
* aParentWidget
, int32_t aX
, int32_t aY
,
5145 int32_t aWidth
, int32_t aHeight
)
5147 SetParentWidget(aParentWidget
);
5148 SetPositionAndSize(aX
, aY
, aWidth
, aHeight
, 0);
5154 nsDocShell::Create()
5157 // We've already been created
5161 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
5162 "Unexpected item type in docshell");
5164 NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE
);
5167 if (gValidateOrigin
== 0xffffffff) {
5168 // Check pref to see if we should prevent frameset spoofing
5170 Preferences::GetBool("browser.frame.validate_origin", true);
5173 // Should we use XUL error pages instead of alerts if possible?
5175 Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages
);
5177 if (!gAddedPreferencesVarCache
) {
5178 Preferences::AddBoolVarCache(&sUseErrorPages
,
5179 "browser.xul.error_pages.enabled",
5181 gAddedPreferencesVarCache
= true;
5184 mDisableMetaRefreshWhenInactive
=
5185 Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
5186 mDisableMetaRefreshWhenInactive
);
5188 mDeviceSizeIsPageSize
=
5189 Preferences::GetBool("docshell.device_size_is_page_size",
5190 mDeviceSizeIsPageSize
);
5192 nsCOMPtr
<nsIObserverService
> serv
= services::GetObserverService();
5194 const char* msg
= mItemType
== typeContent
?
5195 NS_WEBNAVIGATION_CREATE
: NS_CHROME_WEBNAVIGATION_CREATE
;
5196 serv
->NotifyObservers(GetAsSupports(this), msg
, nullptr);
5203 nsDocShell::Destroy()
5205 // XXX: We allow this function to be called just once. If you are going to
5206 // reset new variables in this function, please make sure the variables will
5207 // never be re-initialized. Adding assertions to check |mIsBeingDestroyed|
5208 // in the setter functions for the variables would be enough.
5209 if (mIsBeingDestroyed
) {
5210 return NS_ERROR_DOCSHELL_DYING
;
5213 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
5214 "Unexpected item type in docshell");
5216 AssertOriginAttributesMatchPrivateBrowsing();
5218 nsCOMPtr
<nsIObserverService
> serv
= services::GetObserverService();
5220 const char* msg
= mItemType
== typeContent
?
5221 NS_WEBNAVIGATION_DESTROY
: NS_CHROME_WEBNAVIGATION_DESTROY
;
5222 serv
->NotifyObservers(GetAsSupports(this), msg
, nullptr);
5225 mIsBeingDestroyed
= true;
5227 // Brak the cycle with the initial client, if present.
5228 mInitialClientSource
.reset();
5230 // Make sure we don't record profile timeline markers anymore
5231 SetRecordProfileTimelineMarkers(false);
5233 // Remove our pref observers
5234 if (mObserveErrorPages
) {
5235 mObserveErrorPages
= false;
5238 // Make sure to blow away our mLoadingURI just in case. No loads
5239 // from inside this pagehide.
5240 mLoadingURI
= nullptr;
5242 // Fire unload event before we blow anything away.
5243 (void)FirePageHideNotification(true);
5245 // Clear pointers to any detached nsEditorData that's lying
5246 // around in shistory entries. Breaks cycle. See bug 430921.
5248 mOSHE
->SetEditorData(nullptr);
5251 mLSHE
->SetEditorData(nullptr);
5254 // Note: mContentListener can be null if Init() failed and we're being
5255 // called from the destructor.
5256 if (mContentListener
) {
5257 mContentListener
->DropDocShellReference();
5258 mContentListener
->SetParentContentListener(nullptr);
5259 // Note that we do NOT set mContentListener to null here; that
5260 // way if someone tries to do a load in us after this point
5261 // the nsDSURIContentListener will block it. All of which
5262 // means that we should do this before calling Stop(), of
5266 // Stop any URLs that are currently being loaded...
5267 Stop(nsIWebNavigation::STOP_ALL
);
5269 mEditorData
= nullptr;
5271 // Save the state of the current document, before destroying the window.
5272 // This is needed to capture the state of a frameset when the new document
5273 // causes the frameset to be destroyed...
5274 PersistLayoutHistoryState();
5276 // Remove this docshell from its parent's child list
5277 nsCOMPtr
<nsIDocShellTreeItem
> docShellParentAsItem
=
5278 do_QueryInterface(GetAsSupports(mParent
));
5279 if (docShellParentAsItem
) {
5280 docShellParentAsItem
->RemoveChild(this);
5283 if (mContentViewer
) {
5284 mContentViewer
->Close(nullptr);
5285 mContentViewer
->Destroy();
5286 mContentViewer
= nullptr;
5289 nsDocLoader::Destroy();
5291 mParentWidget
= nullptr;
5292 mCurrentURI
= nullptr;
5294 if (mScriptGlobal
) {
5295 mScriptGlobal
->DetachFromDocShell();
5296 mScriptGlobal
= nullptr;
5299 if (mSessionHistory
) {
5300 // We want to destroy these content viewers now rather than
5301 // letting their destruction wait for the session history
5302 // entries to get garbage collected. (Bug 488394)
5303 mSessionHistory
->EvictLocalContentViewers();
5304 mSessionHistory
= nullptr;
5307 SetTreeOwner(nullptr);
5309 mOnePermittedSandboxedNavigator
= nullptr;
5311 // required to break ref cycle
5312 mSecurityUI
= nullptr;
5314 // Cancel any timers that were set for this docshell; this is needed
5315 // to break the cycle between us and the timers.
5316 CancelRefreshURITimers();
5318 if (UsePrivateBrowsing()) {
5319 mPrivateBrowsingId
= 0;
5320 mOriginAttributes
.SyncAttributesWithPrivateBrowsing(false);
5321 if (mAffectPrivateSessionLifetime
) {
5322 DecreasePrivateDocShellCount();
5330 nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale
)
5332 if (mParentWidget
) {
5333 *aScale
= mParentWidget
->GetDefaultScale().scale
;
5337 nsCOMPtr
<nsIBaseWindow
> ownerWindow(do_QueryInterface(mTreeOwner
));
5339 return ownerWindow
->GetUnscaledDevicePixelsPerCSSPixel(aScale
);
5347 nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale
)
5349 if (mParentWidget
) {
5350 *aScale
= mParentWidget
->GetDesktopToDeviceScale().scale
;
5354 nsCOMPtr
<nsIBaseWindow
> ownerWindow(do_QueryInterface(mTreeOwner
));
5356 return ownerWindow
->GetDevicePixelsPerDesktopPixel(aScale
);
5364 nsDocShell::SetPosition(int32_t aX
, int32_t aY
)
5366 mBounds
.MoveTo(aX
, aY
);
5368 if (mContentViewer
) {
5369 NS_ENSURE_SUCCESS(mContentViewer
->Move(aX
, aY
), NS_ERROR_FAILURE
);
5376 nsDocShell::SetPositionDesktopPix(int32_t aX
, int32_t aY
)
5378 nsCOMPtr
<nsIBaseWindow
> ownerWindow(do_QueryInterface(mTreeOwner
));
5380 return ownerWindow
->SetPositionDesktopPix(aX
, aY
);
5384 GetDevicePixelsPerDesktopPixel(&scale
);
5385 return SetPosition(NSToIntRound(aX
* scale
), NSToIntRound(aY
* scale
));
5389 nsDocShell::GetPosition(int32_t* aX
, int32_t* aY
)
5391 return GetPositionAndSize(aX
, aY
, nullptr, nullptr);
5395 nsDocShell::SetSize(int32_t aWidth
, int32_t aHeight
, bool aRepaint
)
5397 int32_t x
= 0, y
= 0;
5398 GetPosition(&x
, &y
);
5399 return SetPositionAndSize(x
, y
, aWidth
, aHeight
,
5400 aRepaint
? nsIBaseWindow::eRepaint
: 0);
5404 nsDocShell::GetSize(int32_t* aWidth
, int32_t* aHeight
)
5406 return GetPositionAndSize(nullptr, nullptr, aWidth
, aHeight
);
5410 nsDocShell::SetPositionAndSize(int32_t aX
, int32_t aY
, int32_t aWidth
,
5411 int32_t aHeight
, uint32_t aFlags
)
5413 mBounds
.SetRect(aX
, aY
, aWidth
, aHeight
);
5415 // Hold strong ref, since SetBounds can make us null out mContentViewer
5416 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
5418 uint32_t cvflags
= (aFlags
& nsIBaseWindow::eDelayResize
) ?
5419 nsIContentViewer::eDelayResize
: 0;
5420 // XXX Border figured in here or is that handled elsewhere?
5421 nsresult rv
= viewer
->SetBoundsWithFlags(mBounds
, cvflags
);
5422 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
5429 nsDocShell::GetPositionAndSize(int32_t* aX
, int32_t* aY
, int32_t* aWidth
,
5432 if (mParentWidget
) {
5433 // ensure size is up-to-date if window has changed resolution
5434 LayoutDeviceIntRect r
= mParentWidget
->GetClientBounds();
5435 SetPositionAndSize(mBounds
.X(), mBounds
.Y(), r
.Width(), r
.Height(), 0);
5438 // We should really consider just getting this information from
5439 // our window instead of duplicating the storage and code...
5440 if (aWidth
|| aHeight
) {
5441 // Caller wants to know our size; make sure to give them up to
5442 // date information.
5443 nsCOMPtr
<nsIDocument
> doc(do_GetInterface(GetAsSupports(mParent
)));
5445 doc
->FlushPendingNotifications(FlushType::Layout
);
5449 DoGetPositionAndSize(aX
, aY
, aWidth
, aHeight
);
5454 nsDocShell::DoGetPositionAndSize(int32_t* aX
, int32_t* aY
, int32_t* aWidth
,
5464 *aWidth
= mBounds
.Width();
5467 *aHeight
= mBounds
.Height();
5472 nsDocShell::Repaint(bool aForce
)
5474 nsCOMPtr
<nsIPresShell
> presShell
= GetPresShell();
5475 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
5477 nsViewManager
* viewManager
= presShell
->GetViewManager();
5478 NS_ENSURE_TRUE(viewManager
, NS_ERROR_FAILURE
);
5480 viewManager
->InvalidateAllViews();
5485 nsDocShell::GetParentWidget(nsIWidget
** aParentWidget
)
5487 NS_ENSURE_ARG_POINTER(aParentWidget
);
5489 *aParentWidget
= mParentWidget
;
5490 NS_IF_ADDREF(*aParentWidget
);
5496 nsDocShell::SetParentWidget(nsIWidget
* aParentWidget
)
5498 MOZ_ASSERT(!mIsBeingDestroyed
);
5499 mParentWidget
= aParentWidget
;
5505 nsDocShell::GetParentNativeWindow(nativeWindow
* aParentNativeWindow
)
5507 NS_ENSURE_ARG_POINTER(aParentNativeWindow
);
5509 if (mParentWidget
) {
5510 *aParentNativeWindow
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
5512 *aParentNativeWindow
= nullptr;
5519 nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow
)
5521 return NS_ERROR_NOT_IMPLEMENTED
;
5525 nsDocShell::GetNativeHandle(nsAString
& aNativeHandle
)
5527 // the nativeHandle should be accessed from nsIXULWindow
5528 return NS_ERROR_NOT_IMPLEMENTED
;
5532 nsDocShell::GetVisibility(bool* aVisibility
)
5534 NS_ENSURE_ARG_POINTER(aVisibility
);
5536 *aVisibility
= false;
5538 if (!mContentViewer
) {
5542 nsCOMPtr
<nsIPresShell
> presShell
= GetPresShell();
5547 // get the view manager
5548 nsViewManager
* vm
= presShell
->GetViewManager();
5549 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
5551 // get the root view
5552 nsView
* view
= vm
->GetRootView(); // views are not ref counted
5553 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
5555 // if our root view is hidden, we are not visible
5556 if (view
->GetVisibility() == nsViewVisibility_kHide
) {
5560 // otherwise, we must walk up the document and view trees checking
5561 // for a hidden view, unless we're an off screen browser, which
5562 // would make this test meaningless.
5564 RefPtr
<nsDocShell
> docShell
= this;
5565 RefPtr
<nsDocShell
> parentItem
= docShell
->GetParentDocshell();
5566 while (parentItem
) {
5567 presShell
= docShell
->GetPresShell();
5569 nsCOMPtr
<nsIPresShell
> pPresShell
= parentItem
->GetPresShell();
5571 // Null-check for crash in bug 267804
5573 MOZ_ASSERT_UNREACHABLE("parent docshell has null pres shell");
5577 vm
= presShell
->GetViewManager();
5579 view
= vm
->GetRootView();
5583 view
= view
->GetParent(); // anonymous inner view
5585 view
= view
->GetParent(); // subdocumentframe's view
5589 nsIFrame
* frame
= view
? view
->GetFrame() : nullptr;
5590 bool isDocShellOffScreen
= false;
5591 docShell
->GetIsOffScreenBrowser(&isDocShellOffScreen
);
5593 !frame
->IsVisibleConsideringAncestors(
5594 nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY
) &&
5595 !isDocShellOffScreen
) {
5599 docShell
= parentItem
;
5600 parentItem
= docShell
->GetParentDocshell();
5603 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
5604 if (!treeOwnerAsWin
) {
5605 *aVisibility
= true;
5609 // Check with the tree owner as well to give embedders a chance to
5610 // expose visibility as well.
5611 return treeOwnerAsWin
->GetVisibility(aVisibility
);
5615 nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen
)
5617 mIsOffScreenBrowser
= aIsOffScreen
;
5622 nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen
)
5624 *aIsOffScreen
= mIsOffScreenBrowser
;
5629 nsDocShell::SetIsActive(bool aIsActive
)
5631 // We disallow setting active on chrome docshells.
5632 if (mItemType
== nsIDocShellTreeItem::typeChrome
) {
5633 return NS_ERROR_INVALID_ARG
;
5636 // Keep track ourselves.
5637 mIsActive
= aIsActive
;
5639 // Tell the PresShell about it.
5640 nsCOMPtr
<nsIPresShell
> pshell
= GetPresShell();
5642 pshell
->SetIsActive(aIsActive
);
5645 // Tell the window about it
5646 if (mScriptGlobal
) {
5647 mScriptGlobal
->SetIsBackground(!aIsActive
);
5648 if (nsCOMPtr
<nsIDocument
> doc
= mScriptGlobal
->GetExtantDoc()) {
5649 // Update orientation when the top-level browsing context becomes active.
5651 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
5652 GetSameTypeParent(getter_AddRefs(parent
));
5654 // We only care about the top-level browsing context.
5655 uint16_t orientation
= OrientationLock();
5656 ScreenOrientation::UpdateActiveOrientationLock(orientation
);
5660 doc
->PostVisibilityUpdateEvent();
5664 // Tell the nsDOMNavigationTiming about it
5665 RefPtr
<nsDOMNavigationTiming
> timing
= mTiming
;
5666 if (!timing
&& mContentViewer
) {
5667 nsIDocument
* doc
= mContentViewer
->GetDocument();
5669 timing
= doc
->GetNavigationTiming();
5673 timing
->NotifyDocShellStateChanged(
5674 aIsActive
? nsDOMNavigationTiming::DocShellState::eActive
5675 : nsDOMNavigationTiming::DocShellState::eInactive
);
5678 // Recursively tell all of our children, but don't tell <iframe mozbrowser>
5679 // children; they handle their state separately.
5680 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
5681 while (iter
.HasMore()) {
5682 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryObject(iter
.GetNext());
5687 if (!docshell
->GetIsMozBrowser()) {
5688 docshell
->SetIsActive(aIsActive
);
5692 // Restart or stop meta refresh timers if necessary
5693 if (mDisableMetaRefreshWhenInactive
) {
5695 ResumeRefreshURIs();
5697 SuspendRefreshURIs();
5705 nsDocShell::GetIsActive(bool* aIsActive
)
5707 *aIsActive
= mIsActive
;
5712 nsDocShell::SetIsAppTab(bool aIsAppTab
)
5714 mIsAppTab
= aIsAppTab
;
5719 nsDocShell::GetIsAppTab(bool* aIsAppTab
)
5721 *aIsAppTab
= mIsAppTab
;
5726 nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags
)
5728 mSandboxFlags
= aSandboxFlags
;
5733 nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags
)
5735 *aSandboxFlags
= mSandboxFlags
;
5740 nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell
* aSandboxedNavigator
)
5742 if (mOnePermittedSandboxedNavigator
) {
5743 NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
5747 MOZ_ASSERT(!mIsBeingDestroyed
);
5749 mOnePermittedSandboxedNavigator
= do_GetWeakReference(aSandboxedNavigator
);
5750 NS_ASSERTION(mOnePermittedSandboxedNavigator
,
5751 "One Permitted Sandboxed Navigator must support weak references.");
5757 nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell
** aSandboxedNavigator
)
5759 NS_ENSURE_ARG_POINTER(aSandboxedNavigator
);
5760 nsCOMPtr
<nsIDocShell
> permittedNavigator
=
5761 do_QueryReferent(mOnePermittedSandboxedNavigator
);
5762 permittedNavigator
.forget(aSandboxedNavigator
);
5767 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags
)
5769 mDefaultLoadFlags
= aDefaultLoadFlags
;
5771 // Tell the load group to set these flags all requests in the group
5773 mLoadGroup
->SetDefaultLoadFlags(aDefaultLoadFlags
);
5775 NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
5778 // Recursively tell all of our children. We *do not* skip
5779 // <iframe mozbrowser> children - if someone sticks custom flags in this
5780 // docShell then they too get the same flags.
5781 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
5782 while (iter
.HasMore()) {
5783 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryObject(iter
.GetNext());
5787 docshell
->SetDefaultLoadFlags(aDefaultLoadFlags
);
5793 nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags
)
5795 *aDefaultLoadFlags
= mDefaultLoadFlags
;
5800 nsDocShell::SetMixedContentChannel(nsIChannel
* aMixedContentChannel
)
5803 // if the channel is non-null
5804 if (aMixedContentChannel
) {
5805 // Get the root docshell.
5806 nsCOMPtr
<nsIDocShellTreeItem
> root
;
5807 GetSameTypeRootTreeItem(getter_AddRefs(root
));
5808 NS_WARNING_ASSERTION(root
.get() == static_cast<nsIDocShellTreeItem
*>(this),
5809 "Setting mMixedContentChannel on a docshell that is "
5810 "not the root docshell");
5813 mMixedContentChannel
= aMixedContentChannel
;
5818 nsDocShell::GetFailedChannel(nsIChannel
** aFailedChannel
)
5820 NS_ENSURE_ARG_POINTER(aFailedChannel
);
5821 nsIDocument
* doc
= GetDocument();
5823 *aFailedChannel
= nullptr;
5826 NS_IF_ADDREF(*aFailedChannel
= doc
->GetFailedChannel());
5831 nsDocShell::GetMixedContentChannel(nsIChannel
** aMixedContentChannel
)
5833 NS_ENSURE_ARG_POINTER(aMixedContentChannel
);
5834 NS_IF_ADDREF(*aMixedContentChannel
= mMixedContentChannel
);
5839 nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection
,
5840 bool* aAllowMixedContent
,
5841 bool* aIsRootDocShell
)
5843 *aRootHasSecureConnection
= true;
5844 *aAllowMixedContent
= false;
5845 *aIsRootDocShell
= false;
5847 nsCOMPtr
<nsIDocShellTreeItem
> sameTypeRoot
;
5848 GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot
));
5849 NS_ASSERTION(sameTypeRoot
,
5850 "No document shell root tree item from document shell tree item!");
5852 sameTypeRoot
.get() == static_cast<nsIDocShellTreeItem
*>(this);
5854 // now get the document from sameTypeRoot
5855 nsCOMPtr
<nsIDocument
> rootDoc
= sameTypeRoot
->GetDocument();
5857 nsCOMPtr
<nsIPrincipal
> rootPrincipal
= rootDoc
->NodePrincipal();
5859 // For things with system principal (e.g. scratchpad) there is no uri
5860 // aRootHasSecureConnection should be false.
5861 nsCOMPtr
<nsIURI
> rootUri
;
5862 if (nsContentUtils::IsSystemPrincipal(rootPrincipal
) ||
5863 NS_FAILED(rootPrincipal
->GetURI(getter_AddRefs(rootUri
))) || !rootUri
||
5864 NS_FAILED(rootUri
->SchemeIs("https", aRootHasSecureConnection
))) {
5865 *aRootHasSecureConnection
= false;
5868 // Check the root doc's channel against the root docShell's
5869 // mMixedContentChannel to see if they are the same. If they are the same,
5870 // the user has overriden the block.
5871 nsCOMPtr
<nsIDocShell
> rootDocShell
= do_QueryInterface(sameTypeRoot
);
5872 nsCOMPtr
<nsIChannel
> mixedChannel
;
5873 rootDocShell
->GetMixedContentChannel(getter_AddRefs(mixedChannel
));
5874 *aAllowMixedContent
=
5875 mixedChannel
&& (mixedChannel
== rootDoc
->GetChannel());
5882 nsDocShell::SetVisibility(bool aVisibility
)
5884 // Show()/Hide() may change mContentViewer.
5885 nsCOMPtr
<nsIContentViewer
> cv
= mContentViewer
;
5899 nsDocShell::GetEnabled(bool* aEnabled
)
5901 NS_ENSURE_ARG_POINTER(aEnabled
);
5903 return NS_ERROR_NOT_IMPLEMENTED
;
5907 nsDocShell::SetEnabled(bool aEnabled
)
5909 return NS_ERROR_NOT_IMPLEMENTED
;
5913 nsDocShell::SetFocus()
5919 nsDocShell::GetMainWidget(nsIWidget
** aMainWidget
)
5921 // We don't create our own widget, so simply return the parent one.
5922 return GetParentWidget(aMainWidget
);
5926 nsDocShell::GetTitle(nsAString
& aTitle
)
5933 nsDocShell::SetTitle(const nsAString
& aTitle
)
5935 // Store local title
5938 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
5939 GetSameTypeParent(getter_AddRefs(parent
));
5941 // When title is set on the top object it should then be passed to the
5944 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
5945 if (treeOwnerAsWin
) {
5946 treeOwnerAsWin
->SetTitle(aTitle
);
5950 AssertOriginAttributesMatchPrivateBrowsing();
5951 if (mCurrentURI
&& mLoadType
!= LOAD_ERROR_PAGE
) {
5952 UpdateGlobalHistoryTitle(mCurrentURI
);
5955 // Update SessionHistory with the document's title.
5956 if (mOSHE
&& mLoadType
!= LOAD_BYPASS_HISTORY
&&
5957 mLoadType
!= LOAD_ERROR_PAGE
) {
5958 mOSHE
->SetTitle(mTitle
);
5965 nsDocShell::GetCurScrollPos(int32_t aScrollOrientation
, int32_t* aCurPos
)
5967 NS_ENSURE_ARG_POINTER(aCurPos
);
5969 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5971 return NS_ERROR_FAILURE
;
5974 nsPoint pt
= sf
->GetScrollPosition();
5976 switch (aScrollOrientation
) {
5977 case ScrollOrientation_X
:
5981 case ScrollOrientation_Y
:
5986 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG
);
5991 nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos
,
5992 int32_t aCurVerticalPos
)
5994 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5995 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5997 nsIScrollableFrame::ScrollMode scrollMode
= nsIScrollableFrame::INSTANT
;
5998 if (sf
->GetScrollbarStyles().mScrollBehavior
==
5999 NS_STYLE_SCROLL_BEHAVIOR_SMOOTH
) {
6000 scrollMode
= nsIScrollableFrame::SMOOTH_MSD
;
6003 sf
->ScrollTo(nsPoint(aCurHorizontalPos
, aCurVerticalPos
), scrollMode
);
6007 //*****************************************************************************
6008 // nsDocShell::nsIScrollable
6009 //*****************************************************************************
6012 nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation
,
6013 int32_t* aScrollbarPref
)
6015 NS_ENSURE_ARG_POINTER(aScrollbarPref
);
6016 switch (aScrollOrientation
) {
6017 case ScrollOrientation_X
:
6018 *aScrollbarPref
= mDefaultScrollbarPref
.x
;
6021 case ScrollOrientation_Y
:
6022 *aScrollbarPref
= mDefaultScrollbarPref
.y
;
6026 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG
);
6028 return NS_ERROR_FAILURE
;
6032 nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation
,
6033 int32_t aScrollbarPref
)
6035 switch (aScrollOrientation
) {
6036 case ScrollOrientation_X
:
6037 mDefaultScrollbarPref
.x
= aScrollbarPref
;
6040 case ScrollOrientation_Y
:
6041 mDefaultScrollbarPref
.y
= aScrollbarPref
;
6045 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG
);
6047 return NS_ERROR_FAILURE
;
6051 nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible
,
6052 bool* aHorizontalVisible
)
6054 nsIScrollableFrame
* sf
= GetRootScrollFrame();
6055 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
6057 uint32_t scrollbarVisibility
= sf
->GetScrollbarVisibility();
6058 if (aVerticalVisible
) {
6060 (scrollbarVisibility
& nsIScrollableFrame::VERTICAL
) != 0;
6062 if (aHorizontalVisible
) {
6063 *aHorizontalVisible
=
6064 (scrollbarVisibility
& nsIScrollableFrame::HORIZONTAL
) != 0;
6070 //*****************************************************************************
6071 // nsDocShell::nsITextScroll
6072 //*****************************************************************************
6075 nsDocShell::ScrollByLines(int32_t aNumLines
)
6077 nsIScrollableFrame
* sf
= GetRootScrollFrame();
6078 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
6080 sf
->ScrollBy(nsIntPoint(0, aNumLines
), nsIScrollableFrame::LINES
,
6081 nsIScrollableFrame::SMOOTH
);
6086 nsDocShell::ScrollByPages(int32_t aNumPages
)
6088 nsIScrollableFrame
* sf
= GetRootScrollFrame();
6089 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
6091 sf
->ScrollBy(nsIntPoint(0, aNumPages
), nsIScrollableFrame::PAGES
,
6092 nsIScrollableFrame::SMOOTH
);
6096 //*****************************************************************************
6097 // nsDocShell::nsIRefreshURI
6098 //*****************************************************************************
6101 nsDocShell::RefreshURI(nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
6102 int32_t aDelay
, bool aRepeat
,
6105 MOZ_ASSERT(!mIsBeingDestroyed
);
6107 NS_ENSURE_ARG(aURI
);
6109 /* Check if Meta refresh/redirects are permitted. Some
6110 * embedded applications may not want to do this.
6111 * Must do this before sending out NOTIFY_REFRESH events
6112 * because listeners may have side effects (e.g. displaying a
6113 * button to manually trigger the refresh later).
6115 bool allowRedirects
= true;
6116 GetAllowMetaRedirects(&allowRedirects
);
6117 if (!allowRedirects
) {
6121 // If any web progress listeners are listening for NOTIFY_REFRESH events,
6122 // give them a chance to block this refresh.
6124 nsresult rv
= aURI
->Equals(mCurrentURI
, &sameURI
);
6125 if (NS_FAILED(rv
)) {
6128 if (!RefreshAttempted(this, aURI
, aDelay
, sameURI
)) {
6132 nsCOMPtr
<nsITimerCallback
> refreshTimer
=
6133 new nsRefreshTimer(this, aURI
, aPrincipal
, aDelay
, aRepeat
, aMetaRefresh
);
6135 uint32_t busyFlags
= 0;
6136 GetBusyFlags(&busyFlags
);
6138 if (!mRefreshURIList
) {
6139 mRefreshURIList
= nsArray::Create();
6142 if (busyFlags
& BUSY_FLAGS_BUSY
|| (!mIsActive
&& mDisableMetaRefreshWhenInactive
)) {
6143 // We don't want to create the timer right now. Instead queue up the request
6144 // and trigger the timer in EndPageLoad() or whenever we become active.
6145 mRefreshURIList
->AppendElement(refreshTimer
);
6147 // There is no page loading going on right now. Create the
6148 // timer and fire it right away.
6149 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
6150 NS_ENSURE_TRUE(win
, NS_ERROR_FAILURE
);
6152 nsCOMPtr
<nsITimer
> timer
;
6154 NS_NewTimerWithCallback(refreshTimer
, aDelay
, nsITimer::TYPE_ONE_SHOT
,
6155 win
->TabGroup()->EventTargetFor(TaskCategory::Network
)));
6157 mRefreshURIList
->AppendElement(timer
); // owning timer ref
6163 nsDocShell::ForceRefreshURIFromTimer(nsIURI
* aURI
,
6164 nsIPrincipal
* aPrincipal
,
6169 MOZ_ASSERT(aTimer
, "Must have a timer here");
6171 // Remove aTimer from mRefreshURIList if needed
6172 if (mRefreshURIList
) {
6174 mRefreshURIList
->GetLength(&n
);
6176 for (uint32_t i
= 0; i
< n
; ++i
) {
6177 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
6178 if (timer
== aTimer
) {
6179 mRefreshURIList
->RemoveElementAt(i
);
6185 return ForceRefreshURI(aURI
, aPrincipal
, aDelay
, aMetaRefresh
);
6189 nsDocShell::ForceRefreshURI(nsIURI
* aURI
, nsIPrincipal
* aPrincipal
, int32_t aDelay
, bool aMetaRefresh
)
6191 NS_ENSURE_ARG(aURI
);
6193 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
6194 CreateLoadInfo(getter_AddRefs(loadInfo
));
6195 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
6197 /* We do need to pass in a referrer, but we don't want it to
6198 * be sent to the server.
6200 loadInfo
->SetSendReferrer(false);
6202 /* for most refreshes the current URI is an appropriate
6205 loadInfo
->SetReferrer(mCurrentURI
);
6207 // Set the triggering pricipal to aPrincipal if available, or current
6208 // document's principal otherwise.
6209 nsCOMPtr
<nsIPrincipal
> principal
= aPrincipal
;
6211 nsCOMPtr
<nsIDocument
> doc
= GetDocument();
6213 return NS_ERROR_FAILURE
;
6215 principal
= doc
->NodePrincipal();
6217 loadInfo
->SetTriggeringPrincipal(principal
);
6218 loadInfo
->SetPrincipalIsExplicit(true);
6220 /* Check if this META refresh causes a redirection
6223 bool equalUri
= false;
6224 nsresult rv
= aURI
->Equals(mCurrentURI
, &equalUri
);
6225 if (NS_SUCCEEDED(rv
) && (!equalUri
) && aMetaRefresh
&&
6226 aDelay
<= REFRESH_REDIRECT_TIMER
) {
6227 /* It is a META refresh based redirection within the threshold time
6228 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
6229 * Pass a REPLACE flag to LoadURI().
6231 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace
);
6233 /* for redirects we mimic HTTP, which passes the
6236 nsCOMPtr
<nsIURI
> internalReferrer
;
6237 GetReferringURI(getter_AddRefs(internalReferrer
));
6238 if (internalReferrer
) {
6239 loadInfo
->SetReferrer(internalReferrer
);
6242 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadRefresh
);
6246 * LoadURI(...) will cancel all refresh timers... This causes the
6247 * Timer and its refreshData instance to be released...
6249 LoadURI(aURI
, loadInfo
, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL
, true);
6255 nsDocShell::SetupRefreshURIFromHeader(nsIURI
* aBaseURI
,
6256 nsIPrincipal
* aPrincipal
,
6257 const nsACString
& aHeader
)
6259 // Refresh headers are parsed with the following format in mind
6260 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
6261 // By the time we are here, the following is true:
6262 // header = "REFRESH"
6263 // content = "5; URL=http://uri" // note the URL attribute is
6264 // optional, if it is absent, the currently loaded url is used.
6265 // Also note that the seconds and URL separator can be either
6266 // a ';' or a ','. The ',' separator should be illegal but CNN
6269 // We need to handle the following strings, where
6270 // - X is a set of digits
6271 // - URI is either a relative or absolute URI
6273 // Note that URI should start with "url=" but we allow omission
6276 // empty string. use the currently loaded URI
6277 // and refresh immediately.
6278 // "X" || "X;" || "X,"
6279 // Refresh the currently loaded URI in X seconds.
6280 // "X; URI" || "X, URI"
6281 // Refresh using URI as the destination in X seconds.
6282 // "URI" || "; URI" || ", URI"
6283 // Refresh immediately using URI as the destination.
6285 // Currently, anything immediately following the URI, if
6286 // separated by any char in the set "'\"\t\r\n " will be
6287 // ignored. So "10; url=go.html ; foo=bar" will work,
6288 // and so will "10; url='go.html'; foo=bar". However,
6289 // "10; url=go.html; foo=bar" will result in the uri
6290 // "go.html;" since ';' and ',' are valid uri characters.
6292 // Note that we need to remove any tokens wrapping the URI.
6293 // These tokens currently include spaces, double and single
6296 // when done, seconds is 0 or the given number of seconds
6297 // uriAttrib is empty or the URI specified
6298 MOZ_ASSERT(aPrincipal
);
6300 nsAutoCString uriAttrib
;
6301 int32_t seconds
= 0;
6302 bool specifiesSeconds
= false;
6304 nsACString::const_iterator iter
, tokenStart
, doneIterating
;
6306 aHeader
.BeginReading(iter
);
6307 aHeader
.EndReading(doneIterating
);
6309 // skip leading whitespace
6310 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
)) {
6316 // skip leading + and -
6317 if (iter
!= doneIterating
&& (*iter
== '-' || *iter
== '+')) {
6322 while (iter
!= doneIterating
&& (*iter
>= '0' && *iter
<= '9')) {
6323 seconds
= seconds
* 10 + (*iter
- '0');
6324 specifiesSeconds
= true;
6328 if (iter
!= doneIterating
) {
6329 // if we started with a '-', number is negative
6330 if (*tokenStart
== '-') {
6334 // skip to next ';' or ','
6335 nsACString::const_iterator iterAfterDigit
= iter
;
6336 while (iter
!= doneIterating
&& !(*iter
== ';' || *iter
== ',')) {
6337 if (specifiesSeconds
) {
6338 // Non-whitespace characters here mean that the string is
6339 // malformed but tolerate sites that specify a decimal point,
6340 // even though meta refresh only works on whole seconds.
6341 if (iter
== iterAfterDigit
&&
6342 !nsCRT::IsAsciiSpace(*iter
) && *iter
!= '.') {
6343 // The characters between the seconds and the next
6344 // section are just garbage!
6345 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
6346 // Just ignore this redirect.
6347 return NS_ERROR_FAILURE
;
6348 } else if (nsCRT::IsAsciiSpace(*iter
)) {
6349 // We've had at least one whitespace so tolerate the mistake
6350 // and drop through.
6351 // e.g. content="10 foo"
6359 // skip any remaining whitespace
6360 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
)) {
6365 if (iter
!= doneIterating
&& (*iter
== ';' || *iter
== ',')) {
6370 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
)) {
6375 // possible start of URI
6378 // skip "url = " to real start of URI
6379 if (iter
!= doneIterating
&& (*iter
== 'u' || *iter
== 'U')) {
6381 if (iter
!= doneIterating
&& (*iter
== 'r' || *iter
== 'R')) {
6383 if (iter
!= doneIterating
&& (*iter
== 'l' || *iter
== 'L')) {
6387 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
)) {
6391 if (iter
!= doneIterating
&& *iter
== '=') {
6395 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
)) {
6399 // found real start of URI
6406 // skip a leading '"' or '\''.
6408 bool isQuotedURI
= false;
6409 if (tokenStart
!= doneIterating
&&
6410 (*tokenStart
== '"' || *tokenStart
== '\'')) {
6415 // set iter to start of URI
6418 // tokenStart here points to the beginning of URI
6420 // grab the rest of the URI
6421 while (iter
!= doneIterating
) {
6422 if (isQuotedURI
&& (*iter
== '"' || *iter
== '\'')) {
6428 // move iter one back if the last character is a '"' or '\''
6429 if (iter
!= tokenStart
&& isQuotedURI
) {
6431 if (!(*iter
== '"' || *iter
== '\'')) {
6436 // URI is whatever's contained from tokenStart to iter.
6437 // note: if tokenStart == doneIterating, so is iter.
6439 nsresult rv
= NS_OK
;
6441 nsCOMPtr
<nsIURI
> uri
;
6442 bool specifiesURI
= false;
6443 if (tokenStart
== iter
) {
6446 uriAttrib
= Substring(tokenStart
, iter
);
6447 // NS_NewURI takes care of any whitespace surrounding the URL
6448 rv
= NS_NewURI(getter_AddRefs(uri
), uriAttrib
, nullptr, aBaseURI
);
6449 specifiesURI
= true;
6452 // No URI or seconds were specified
6453 if (!specifiesSeconds
&& !specifiesURI
) {
6454 // Do nothing because the alternative is to spin around in a refresh
6456 return NS_ERROR_FAILURE
;
6459 if (NS_SUCCEEDED(rv
)) {
6460 nsCOMPtr
<nsIScriptSecurityManager
> securityManager(
6461 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
6462 if (NS_SUCCEEDED(rv
)) {
6463 rv
= securityManager
->CheckLoadURIWithPrincipal(
6465 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
);
6467 if (NS_SUCCEEDED(rv
)) {
6469 rv
= NS_URIChainHasFlags(
6470 uri
, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT
, &isjs
);
6471 NS_ENSURE_SUCCESS(rv
, rv
);
6474 return NS_ERROR_FAILURE
;
6478 if (NS_SUCCEEDED(rv
)) {
6479 // Since we can't travel back in time yet, just pretend
6480 // negative numbers do nothing at all.
6482 return NS_ERROR_FAILURE
;
6485 rv
= RefreshURI(uri
, aPrincipal
, seconds
* 1000, false, true);
6493 nsDocShell::SetupRefreshURI(nsIChannel
* aChannel
)
6496 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
, &rv
));
6497 if (NS_SUCCEEDED(rv
)) {
6498 nsAutoCString refreshHeader
;
6499 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
6502 if (!refreshHeader
.IsEmpty()) {
6503 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
6504 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
6505 NS_ENSURE_SUCCESS(rv
, rv
);
6507 nsCOMPtr
<nsIPrincipal
> principal
;
6508 rv
= secMan
->GetChannelResultPrincipal(aChannel
,
6509 getter_AddRefs(principal
));
6510 NS_ENSURE_SUCCESS(rv
, rv
);
6512 SetupReferrerFromChannel(aChannel
);
6513 rv
= SetupRefreshURIFromHeader(mCurrentURI
, principal
, refreshHeader
);
6514 if (NS_SUCCEEDED(rv
)) {
6515 return NS_REFRESHURI_HEADER_FOUND
;
6523 DoCancelRefreshURITimers(nsIMutableArray
* aTimerList
)
6530 aTimerList
->GetLength(&n
);
6533 nsCOMPtr
<nsITimer
> timer(do_QueryElementAt(aTimerList
, --n
));
6535 aTimerList
->RemoveElementAt(n
); // bye bye owning timer ref
6544 nsDocShell::CancelRefreshURITimers()
6546 DoCancelRefreshURITimers(mRefreshURIList
);
6547 DoCancelRefreshURITimers(mSavedRefreshURIList
);
6548 mRefreshURIList
= nullptr;
6549 mSavedRefreshURIList
= nullptr;
6555 nsDocShell::GetRefreshPending(bool* aResult
)
6557 if (!mRefreshURIList
) {
6563 nsresult rv
= mRefreshURIList
->GetLength(&count
);
6564 if (NS_SUCCEEDED(rv
)) {
6565 *aResult
= (count
!= 0);
6571 nsDocShell::SuspendRefreshURIs()
6573 if (mRefreshURIList
) {
6575 mRefreshURIList
->GetLength(&n
);
6577 for (uint32_t i
= 0; i
< n
; ++i
) {
6578 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
6580 continue; // this must be a nsRefreshURI already
6583 // Replace this timer object with a nsRefreshTimer object.
6584 nsCOMPtr
<nsITimerCallback
> callback
;
6585 timer
->GetCallback(getter_AddRefs(callback
));
6589 nsCOMPtr
<nsITimerCallback
> rt
= do_QueryInterface(callback
);
6591 "RefreshURIList timer callbacks should only be RefreshTimer objects");
6593 mRefreshURIList
->ReplaceElementAt(rt
, i
);
6597 // Suspend refresh URIs for our child shells as well.
6598 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
6599 while (iter
.HasMore()) {
6600 nsCOMPtr
<nsIDocShell
> shell
= do_QueryObject(iter
.GetNext());
6602 shell
->SuspendRefreshURIs();
6610 nsDocShell::ResumeRefreshURIs()
6612 RefreshURIFromQueue();
6614 // Resume refresh URIs for our child shells as well.
6615 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
6616 while (iter
.HasMore()) {
6617 nsCOMPtr
<nsIDocShell
> shell
= do_QueryObject(iter
.GetNext());
6619 shell
->ResumeRefreshURIs();
6627 nsDocShell::RefreshURIFromQueue()
6629 if (!mRefreshURIList
) {
6633 mRefreshURIList
->GetLength(&n
);
6636 nsCOMPtr
<nsITimerCallback
> refreshInfo
=
6637 do_QueryElementAt(mRefreshURIList
, --n
);
6640 // This is the nsRefreshTimer object, waiting to be
6641 // setup in a timer object and fired.
6642 // Create the timer and trigger it.
6644 static_cast<nsRefreshTimer
*>(
6645 static_cast<nsITimerCallback
*>(refreshInfo
))->GetDelay();
6646 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
6648 nsCOMPtr
<nsITimer
> timer
;
6649 NS_NewTimerWithCallback(getter_AddRefs(timer
),
6650 refreshInfo
, delay
, nsITimer::TYPE_ONE_SHOT
,
6651 win
->TabGroup()->EventTargetFor(TaskCategory::Network
));
6654 // Replace the nsRefreshTimer element in the queue with
6655 // its corresponding timer object, so that in case another
6656 // load comes through before the timer can go off, the timer will
6657 // get cancelled in CancelRefreshURITimer()
6658 mRefreshURIList
->ReplaceElementAt(timer
, n
);
6668 nsDocShell::Embed(nsIContentViewer
* aContentViewer
,
6669 const char* aCommand
, nsISupports
* aExtraInfo
)
6671 // Save the LayoutHistoryState of the previous document, before
6672 // setting up new document
6673 PersistLayoutHistoryState();
6675 nsresult rv
= SetupNewViewer(aContentViewer
);
6676 NS_ENSURE_SUCCESS(rv
, rv
);
6678 // If we are loading a wyciwyg url from history, change the base URI for
6679 // the document to the original http url that created the document.write().
6680 // This makes sure that all relative urls in a document.written page loaded
6681 // via history work properly.
6683 (mLoadType
& LOAD_CMD_HISTORY
||
6684 mLoadType
== LOAD_RELOAD_NORMAL
||
6685 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
||
6686 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE
||
6687 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE
)) {
6688 bool isWyciwyg
= false;
6689 // Check if the url is wyciwyg
6690 rv
= mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
6691 if (isWyciwyg
&& NS_SUCCEEDED(rv
)) {
6692 SetBaseUrlForWyciwyg(aContentViewer
);
6695 // XXX What if SetupNewViewer fails?
6697 // Restore the editing state, if it's stored in session history.
6698 if (mLSHE
->HasDetachedEditor()) {
6699 ReattachEditorToWindow(mLSHE
);
6701 // Set history.state
6702 SetDocCurrentStateObj(mLSHE
);
6704 SetHistoryEntry(&mOSHE
, mLSHE
);
6707 bool updateHistory
= true;
6709 // Determine if this type of load should update history
6710 switch (mLoadType
) {
6711 case LOAD_NORMAL_REPLACE
:
6712 case LOAD_STOP_CONTENT_AND_REPLACE
:
6713 case LOAD_RELOAD_BYPASS_CACHE
:
6714 case LOAD_RELOAD_BYPASS_PROXY
:
6715 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
6716 case LOAD_REPLACE_BYPASS_CACHE
:
6717 updateHistory
= false;
6723 if (!updateHistory
) {
6724 SetLayoutHistoryState(nullptr);
6731 //*****************************************************************************
6732 // nsDocShell::nsIWebProgressListener
6733 //*****************************************************************************
6736 nsDocShell::OnProgressChange(nsIWebProgress
* aProgress
,
6737 nsIRequest
* aRequest
,
6738 int32_t aCurSelfProgress
,
6739 int32_t aMaxSelfProgress
,
6740 int32_t aCurTotalProgress
,
6741 int32_t aMaxTotalProgress
)
6747 nsDocShell::OnStateChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
6748 uint32_t aStateFlags
, nsresult aStatus
)
6750 if ((~aStateFlags
& (STATE_START
| STATE_IS_NETWORK
)) == 0) {
6751 // Save timing statistics.
6752 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
6753 nsCOMPtr
<nsIURI
> uri
;
6754 channel
->GetURI(getter_AddRefs(uri
));
6756 uri
->GetAsciiSpec(aURI
);
6758 nsCOMPtr
<nsIWyciwygChannel
> wcwgChannel(do_QueryInterface(aRequest
));
6759 nsCOMPtr
<nsIWebProgress
> webProgress
=
6760 do_QueryInterface(GetAsSupports(this));
6762 // We don't update navigation timing for wyciwyg channels
6763 if (this == aProgress
&& !wcwgChannel
) {
6764 mozilla::Unused
<< MaybeInitTiming();
6765 mTiming
->NotifyFetchStart(uri
,
6766 ConvertLoadTypeToNavigationType(mLoadType
));
6769 // Was the wyciwyg document loaded on this docshell?
6770 if (wcwgChannel
&& !mLSHE
&& (mItemType
== typeContent
) &&
6771 aProgress
== webProgress
.get()) {
6772 bool equalUri
= true;
6773 // Store the wyciwyg url in session history, only if it is
6774 // being loaded fresh for the first time. We don't want
6775 // multiple entries for successive loads
6777 NS_SUCCEEDED(uri
->Equals(mCurrentURI
, &equalUri
)) &&
6779 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
6780 GetSameTypeParent(getter_AddRefs(parentAsItem
));
6781 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
6782 bool inOnLoadHandler
= false;
6784 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
6786 if (inOnLoadHandler
) {
6787 // We're handling parent's load event listener, which causes
6788 // document.write in a subdocument.
6789 // Need to clear the session history for all child
6790 // docshells so that we can handle them like they would
6791 // all be added dynamically.
6792 nsCOMPtr
<nsIDocShell
> parent
= do_QueryInterface(parentAsItem
);
6795 nsCOMPtr
<nsISHEntry
> entry
;
6796 parent
->GetCurrentSHEntry(getter_AddRefs(entry
), &oshe
);
6797 static_cast<nsDocShell
*>(parent
.get())->ClearFrameHistory(entry
);
6801 // This is a document.write(). Get the made-up url
6802 // from the channel and store it in session history.
6803 // Pass false for aCloneChildren, since we're creating
6805 AddToSessionHistory(uri
, wcwgChannel
, nullptr, nullptr, false,
6806 getter_AddRefs(mLSHE
));
6807 SetCurrentURI(uri
, aRequest
, true, 0);
6808 // Save history state of the previous page
6809 PersistLayoutHistoryState();
6810 // We'll never get an Embed() for this load, so just go ahead
6811 // and SetHistoryEntry now.
6812 SetHistoryEntry(&mOSHE
, mLSHE
);
6815 // Page has begun to load
6816 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_BEFORE_PAGE_LOAD
;
6818 if ((aStateFlags
& STATE_RESTORING
) == 0) {
6819 // Show the progress cursor if the pref is set
6820 if (nsContentUtils::UseActivityCursor()) {
6821 nsCOMPtr
<nsIWidget
> mainWidget
;
6822 GetMainWidget(getter_AddRefs(mainWidget
));
6824 mainWidget
->SetCursor(eCursor_spinning
);
6828 } else if ((~aStateFlags
& (STATE_TRANSFERRING
| STATE_IS_DOCUMENT
)) == 0) {
6830 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_PAGE_LOADING
;
6831 } else if ((aStateFlags
& STATE_STOP
) && (aStateFlags
& STATE_IS_NETWORK
)) {
6832 // Page has finished loading
6833 mBusyFlags
= BUSY_FLAGS_NONE
;
6835 // Hide the progress cursor if the pref is set
6836 if (nsContentUtils::UseActivityCursor()) {
6837 nsCOMPtr
<nsIWidget
> mainWidget
;
6838 GetMainWidget(getter_AddRefs(mainWidget
));
6840 mainWidget
->SetCursor(eCursor_standard
);
6844 if ((~aStateFlags
& (STATE_IS_DOCUMENT
| STATE_STOP
)) == 0) {
6845 nsCOMPtr
<nsIWebProgress
> webProgress
=
6846 do_QueryInterface(GetAsSupports(this));
6847 // Is the document stop notification for this document?
6848 if (aProgress
== webProgress
.get()) {
6849 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
6850 EndPageLoad(aProgress
, channel
, aStatus
);
6853 // note that redirect state changes will go through here as well, but it
6854 // is better to handle those in OnRedirectStateChange where more
6855 // information is available.
6860 nsDocShell::OnLocationChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
6861 nsIURI
* aURI
, uint32_t aFlags
)
6863 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
6868 nsDocShell::OnRedirectStateChange(nsIChannel
* aOldChannel
,
6869 nsIChannel
* aNewChannel
,
6870 uint32_t aRedirectFlags
,
6871 uint32_t aStateFlags
)
6873 NS_ASSERTION(aStateFlags
& STATE_REDIRECTING
,
6874 "Calling OnRedirectStateChange when there is no redirect");
6876 // If mixed content is allowed for the old channel, we forward
6877 // the permission to the new channel if it has the same origin
6879 if (mMixedContentChannel
&& mMixedContentChannel
== aOldChannel
) {
6880 nsresult rv
= nsContentUtils::CheckSameOrigin(mMixedContentChannel
, aNewChannel
);
6881 if (NS_SUCCEEDED(rv
)) {
6882 SetMixedContentChannel(aNewChannel
); // Same origin: forward permission.
6884 SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel.
6888 if (!(aStateFlags
& STATE_IS_DOCUMENT
)) {
6889 return; // not a toplevel document
6892 nsCOMPtr
<nsIURI
> oldURI
, newURI
;
6893 aOldChannel
->GetURI(getter_AddRefs(oldURI
));
6894 aNewChannel
->GetURI(getter_AddRefs(newURI
));
6895 if (!oldURI
|| !newURI
) {
6899 // Below a URI visit is saved (see AddURIVisit method doc).
6900 // The visit chain looks something like:
6904 // (redirect to =>) Site N + 1 (we are here!)
6906 // Get N - 1 and transition type
6907 nsCOMPtr
<nsIURI
> previousURI
;
6908 uint32_t previousFlags
= 0;
6909 ExtractLastVisit(aOldChannel
, getter_AddRefs(previousURI
), &previousFlags
);
6911 if (aRedirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
||
6912 ChannelIsPost(aOldChannel
)) {
6913 // 1. Internal redirects are ignored because they are specific to the
6914 // channel implementation.
6915 // 2. POSTs are not saved by global history.
6917 // Regardless, we need to propagate the previous visit to the new
6919 SaveLastVisit(aNewChannel
, previousURI
, previousFlags
);
6921 nsCOMPtr
<nsIURI
> referrer
;
6922 // Treat referrer as null if there is an error getting it.
6923 (void)NS_GetReferrerFromChannel(aOldChannel
, getter_AddRefs(referrer
));
6925 // Get the HTTP response code, if available.
6926 uint32_t responseStatus
= 0;
6927 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aOldChannel
);
6929 Unused
<< httpChannel
->GetResponseStatus(&responseStatus
);
6932 // Add visit N -1 => N
6933 AddURIVisit(oldURI
, referrer
, previousURI
, previousFlags
, responseStatus
);
6935 // Since N + 1 could be the final destination, we will not save N => N + 1
6936 // here. OnNewURI will do that, so we will cache it.
6937 SaveLastVisit(aNewChannel
, oldURI
, aRedirectFlags
);
6940 // check if the new load should go through the application cache.
6941 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
6942 do_QueryInterface(aNewChannel
);
6943 if (appCacheChannel
) {
6944 if (GeckoProcessType_Default
!= XRE_GetProcessType()) {
6945 // Permission will be checked in the parent process.
6946 appCacheChannel
->SetChooseApplicationCache(true);
6948 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
6949 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
6952 nsCOMPtr
<nsIPrincipal
> principal
;
6953 secMan
->GetDocShellCodebasePrincipal(newURI
, this,
6954 getter_AddRefs(principal
));
6955 appCacheChannel
->SetChooseApplicationCache(
6956 NS_ShouldCheckAppCache(principal
));
6961 if (!(aRedirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
) &&
6962 mLoadType
& (LOAD_CMD_RELOAD
| LOAD_CMD_HISTORY
)) {
6963 mLoadType
= LOAD_NORMAL_REPLACE
;
6964 SetHistoryEntry(&mLSHE
, nullptr);
6969 nsDocShell::OnStatusChange(nsIWebProgress
* aWebProgress
,
6970 nsIRequest
* aRequest
,
6971 nsresult aStatus
, const char16_t
* aMessage
)
6973 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
6978 nsDocShell::OnSecurityChange(nsIWebProgress
* aWebProgress
,
6979 nsIRequest
* aRequest
, uint32_t aState
)
6981 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
6986 nsDocShell::EndPageLoad(nsIWebProgress
* aProgress
,
6987 nsIChannel
* aChannel
, nsresult aStatus
)
6990 return NS_ERROR_NULL_POINTER
;
6993 // Make sure to discard the initial client if we never created the initial
6994 // about:blank document. Do this before possibly returning from the method
6996 mInitialClientSource
.reset();
6998 nsCOMPtr
<nsIConsoleReportCollector
> reporter
= do_QueryInterface(aChannel
);
7000 nsCOMPtr
<nsILoadGroup
> loadGroup
;
7001 aChannel
->GetLoadGroup(getter_AddRefs(loadGroup
));
7003 reporter
->FlushConsoleReports(loadGroup
);
7005 reporter
->FlushConsoleReports(GetDocument());
7009 nsCOMPtr
<nsIURI
> url
;
7010 nsresult rv
= aChannel
->GetURI(getter_AddRefs(url
));
7011 if (NS_FAILED(rv
)) {
7015 nsCOMPtr
<nsITimedChannel
> timingChannel
= do_QueryInterface(aChannel
);
7016 if (timingChannel
) {
7017 TimeStamp channelCreationTime
;
7018 rv
= timingChannel
->GetChannelCreation(&channelCreationTime
);
7019 if (NS_SUCCEEDED(rv
) && !channelCreationTime
.IsNull()) {
7020 Telemetry::AccumulateTimeDelta(Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME
,
7021 channelCreationTime
);
7022 nsCOMPtr
<nsPILoadGroupInternal
> internalLoadGroup
=
7023 do_QueryInterface(mLoadGroup
);
7024 if (internalLoadGroup
) {
7025 internalLoadGroup
->OnEndPageLoad(aChannel
);
7030 // Timing is picked up by the window, we don't need it anymore
7033 // clean up reload state for meta charset
7034 if (eCharsetReloadRequested
== mCharsetReloadState
) {
7035 mCharsetReloadState
= eCharsetReloadStopOrigional
;
7037 mCharsetReloadState
= eCharsetReloadInit
;
7040 // Save a pointer to the currently-loading history entry.
7041 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
7042 // entry further down in this method.
7043 nsCOMPtr
<nsISHEntry
> loadingSHE
= mLSHE
;
7044 mozilla::Unused
<< loadingSHE
; // XXX: Not sure if we need this anymore
7047 // one of many safeguards that prevent death and destruction if
7048 // someone is so very very rude as to bring this window down
7049 // during this load handler.
7051 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
7053 // Notify the ContentViewer that the Document has finished loading. This
7054 // will cause any OnLoad(...) and PopState(...) handlers to fire.
7055 if (!mEODForCurrentDocument
&& mContentViewer
) {
7056 mIsExecutingOnLoadHandler
= true;
7057 mContentViewer
->LoadComplete(aStatus
);
7058 mIsExecutingOnLoadHandler
= false;
7060 mEODForCurrentDocument
= true;
7062 // If all documents have completed their loading
7063 // favor native event dispatch priorities
7065 if (--gNumberOfDocumentsLoading
== 0) {
7066 // Hint to use normal native event dispatch priorities
7067 FavorPerformanceHint(false);
7070 /* Check if the httpChannel has any cache-control related response headers,
7071 * like no-store, no-cache. If so, update SHEntry so that
7072 * when a user goes back/forward to this page, we appropriately do
7073 * form value restoration or load from server.
7075 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
7077 // HttpChannel could be hiding underneath a Multipart channel.
7078 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
7082 // figure out if SH should be saving layout state.
7083 bool discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
7084 if (mLSHE
&& discardLayoutState
&& (mLoadType
& LOAD_CMD_NORMAL
) &&
7085 (mLoadType
!= LOAD_BYPASS_HISTORY
) && (mLoadType
!= LOAD_ERROR_PAGE
)) {
7086 mLSHE
->SetSaveLayoutStateFlag(false);
7090 // Clear mLSHE after calling the onLoadHandlers. This way, if the
7091 // onLoadHandler tries to load something different in
7092 // itself or one of its children, we can deal with it appropriately.
7094 mLSHE
->SetLoadType(nsIDocShellLoadInfo::loadHistory
);
7096 // Clear the mLSHE reference to indicate document loading is done one
7098 SetHistoryEntry(&mLSHE
, nullptr);
7100 // if there's a refresh header in the channel, this method
7101 // will set it up for us.
7102 if (mIsActive
|| !mDisableMetaRefreshWhenInactive
)
7103 RefreshURIFromQueue();
7105 // Test whether this is the top frame or a subframe
7106 bool isTopFrame
= true;
7107 nsCOMPtr
<nsIDocShellTreeItem
> targetParentTreeItem
;
7108 rv
= GetSameTypeParent(getter_AddRefs(targetParentTreeItem
));
7109 if (NS_SUCCEEDED(rv
) && targetParentTreeItem
) {
7114 // If the page load failed, then deal with the error condition...
7115 // Errors are handled as follows:
7116 // 1. Check to see if it's a file not found error or bad content
7118 // 2. Send the URI to a keyword server (if enabled)
7119 // 3. If the error was DNS failure, then add www and .com to the URI
7120 // (if appropriate).
7121 // 4. Throw an error dialog box...
7123 if (url
&& NS_FAILED(aStatus
)) {
7124 if (aStatus
== NS_ERROR_FILE_NOT_FOUND
||
7125 aStatus
== NS_ERROR_FILE_ACCESS_DENIED
||
7126 aStatus
== NS_ERROR_CORRUPTED_CONTENT
||
7127 aStatus
== NS_ERROR_INVALID_CONTENT_ENCODING
) {
7128 DisplayLoadError(aStatus
, url
, nullptr, aChannel
);
7132 // Handle iframe document not loading error because source was
7133 // a tracking URL. We make a note of this iframe node by including
7134 // it in a dedicated array of blocked tracking nodes under its parent
7135 // document. (document of parent window of blocked document)
7136 if (isTopFrame
== false && aStatus
== NS_ERROR_TRACKING_URI
) {
7137 // frameElement is our nsIContent to be annotated
7138 RefPtr
<Element
> frameElement
;
7139 nsPIDOMWindowOuter
* thisWindow
= GetWindow();
7144 frameElement
= thisWindow
->GetFrameElement();
7145 if (!frameElement
) {
7150 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
7151 GetSameTypeParent(getter_AddRefs(parentItem
));
7156 nsCOMPtr
<nsIDocument
> parentDoc
;
7157 parentDoc
= parentItem
->GetDocument();
7162 parentDoc
->AddBlockedTrackingNode(frameElement
);
7169 // Try and make an alternative URI from the old one
7171 nsCOMPtr
<nsIURI
> newURI
;
7172 nsCOMPtr
<nsIInputStream
> newPostData
;
7174 nsAutoCString oldSpec
;
7175 url
->GetSpec(oldSpec
);
7178 // First try keyword fixup
7180 nsAutoString keywordProviderName
, keywordAsSent
;
7181 if (aStatus
== NS_ERROR_UNKNOWN_HOST
&& mAllowKeywordFixup
) {
7182 bool keywordsEnabled
= Preferences::GetBool("keyword.enabled", false);
7187 nsAutoCString scheme
;
7188 url
->GetScheme(scheme
);
7190 int32_t dotLoc
= host
.FindChar('.');
7192 // we should only perform a keyword search under the following
7194 // (0) Pref keyword.enabled is true
7195 // (1) the url scheme is http (or https)
7196 // (2) the url does not have a protocol scheme
7197 // If we don't enforce such a policy, then we end up doing
7198 // keyword searchs on urls we don't intend like imap, file,
7199 // mailbox, etc. This could lead to a security problem where we
7200 // send data to the keyword server that we shouldn't be.
7201 // Someone needs to clean up keywords in general so we can
7202 // determine on a per url basis if we want keywords
7203 // enabled...this is just a bandaid...
7204 if (keywordsEnabled
&& !scheme
.IsEmpty() &&
7205 (scheme
.Find("http") != 0)) {
7206 keywordsEnabled
= false;
7209 if (keywordsEnabled
&& (kNotFound
== dotLoc
)) {
7210 nsCOMPtr
<nsIURIFixupInfo
> info
;
7211 // only send non-qualified hosts to the keyword server
7212 if (!mOriginalUriString
.IsEmpty()) {
7213 sURIFixup
->KeywordToURI(mOriginalUriString
,
7214 getter_AddRefs(newPostData
),
7215 getter_AddRefs(info
));
7218 // If this string was passed through nsStandardURL by
7219 // chance, then it may have been converted from UTF-8 to
7220 // ACE, which would result in a completely bogus keyword
7221 // query. Here we try to recover the original Unicode
7222 // value, but this is not 100% correct since the value may
7223 // have been normalized per the IDN normalization rules.
7225 // Since we don't have access to the exact original string
7226 // that was entered by the user, this will just have to do.
7228 nsAutoCString utf8Host
;
7229 nsCOMPtr
<nsIIDNService
> idnSrv
=
7230 do_GetService(NS_IDNSERVICE_CONTRACTID
);
7232 NS_SUCCEEDED(idnSrv
->IsACE(host
, &isACE
)) && isACE
&&
7233 NS_SUCCEEDED(idnSrv
->ConvertACEtoUTF8(host
, utf8Host
))) {
7234 sURIFixup
->KeywordToURI(utf8Host
,
7235 getter_AddRefs(newPostData
),
7236 getter_AddRefs(info
));
7238 sURIFixup
->KeywordToURI(host
,
7239 getter_AddRefs(newPostData
),
7240 getter_AddRefs(info
));
7244 info
->GetPreferredURI(getter_AddRefs(newURI
));
7246 info
->GetKeywordAsSent(keywordAsSent
);
7247 info
->GetKeywordProviderName(keywordProviderName
);
7249 } // end keywordsEnabled
7253 // Now try change the address, e.g. turn http://foo into
7254 // http://www.foo.com
7256 if (aStatus
== NS_ERROR_UNKNOWN_HOST
||
7257 aStatus
== NS_ERROR_NET_RESET
) {
7258 bool doCreateAlternate
= true;
7260 // Skip fixup for anything except a normal document load
7261 // operation on the topframe.
7263 if (mLoadType
!= LOAD_NORMAL
|| !isTopFrame
) {
7264 doCreateAlternate
= false;
7266 // Test if keyword lookup produced a new URI or not
7268 bool sameURI
= false;
7269 url
->Equals(newURI
, &sameURI
);
7271 // Keyword lookup made a new URI so no need to try
7272 // an alternate one.
7273 doCreateAlternate
= false;
7277 if (doCreateAlternate
) {
7278 // Skip doing this if our channel was redirected, because we
7279 // shouldn't be guessing things about the post-redirect URI.
7280 nsLoadFlags loadFlags
= 0;
7281 if (NS_FAILED(aChannel
->GetLoadFlags(&loadFlags
)) ||
7282 (loadFlags
& nsIChannel::LOAD_REPLACE
)) {
7283 doCreateAlternate
= false;
7287 if (doCreateAlternate
) {
7289 newPostData
= nullptr;
7290 keywordProviderName
.Truncate();
7291 keywordAsSent
.Truncate();
7292 sURIFixup
->CreateFixupURI(oldSpec
,
7293 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
,
7294 getter_AddRefs(newPostData
),
7295 getter_AddRefs(newURI
));
7299 // Did we make a new URI that is different to the old one? If so
7303 // Make sure the new URI is different from the old one,
7304 // otherwise there's little point trying to load it again.
7305 bool sameURI
= false;
7306 url
->Equals(newURI
, &sameURI
);
7308 nsAutoCString newSpec
;
7309 newURI
->GetSpec(newSpec
);
7310 NS_ConvertUTF8toUTF16
newSpecW(newSpec
);
7312 // This notification is meant for Firefox Health Report so it
7313 // can increment counts from the search engine
7314 MaybeNotifyKeywordSearchLoading(keywordProviderName
, keywordAsSent
);
7316 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->GetLoadInfo();
7317 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
= loadInfo
7318 ? loadInfo
->TriggeringPrincipal()
7319 : nsContentUtils::GetSystemPrincipal();
7320 return LoadURI(newSpecW
.get(), // URI string
7321 LOAD_FLAGS_NONE
, // Load flags
7322 nullptr, // Referring URI
7323 newPostData
, // Post data stream
7324 nullptr, // Headers stream
7325 triggeringPrincipal
); // TriggeringPrincipal
7330 // Well, fixup didn't work :-(
7331 // It is time to throw an error dialog box, and be done with it...
7333 // Errors to be shown only on top-level frames
7334 if ((aStatus
== NS_ERROR_UNKNOWN_HOST
||
7335 aStatus
== NS_ERROR_CONNECTION_REFUSED
||
7336 aStatus
== NS_ERROR_UNKNOWN_PROXY_HOST
||
7337 aStatus
== NS_ERROR_PROXY_CONNECTION_REFUSED
||
7338 aStatus
== NS_ERROR_BLOCKED_BY_POLICY
) &&
7339 (isTopFrame
|| UseErrorPages())) {
7340 DisplayLoadError(aStatus
, url
, nullptr, aChannel
);
7341 } else if (aStatus
== NS_ERROR_NET_TIMEOUT
||
7342 aStatus
== NS_ERROR_REDIRECT_LOOP
||
7343 aStatus
== NS_ERROR_UNKNOWN_SOCKET_TYPE
||
7344 aStatus
== NS_ERROR_NET_INTERRUPT
||
7345 aStatus
== NS_ERROR_NET_RESET
||
7346 aStatus
== NS_ERROR_OFFLINE
||
7347 aStatus
== NS_ERROR_MALWARE_URI
||
7348 aStatus
== NS_ERROR_PHISHING_URI
||
7349 aStatus
== NS_ERROR_UNWANTED_URI
||
7350 aStatus
== NS_ERROR_HARMFUL_URI
||
7351 aStatus
== NS_ERROR_UNSAFE_CONTENT_TYPE
||
7352 aStatus
== NS_ERROR_REMOTE_XUL
||
7353 aStatus
== NS_ERROR_INTERCEPTION_FAILED
||
7354 aStatus
== NS_ERROR_NET_INADEQUATE_SECURITY
||
7355 NS_ERROR_GET_MODULE(aStatus
) == NS_ERROR_MODULE_SECURITY
) {
7356 // Errors to be shown for any frame
7357 DisplayLoadError(aStatus
, url
, nullptr, aChannel
);
7358 } else if (aStatus
== NS_ERROR_DOCUMENT_NOT_CACHED
) {
7359 // Non-caching channels will simply return NS_ERROR_OFFLINE.
7360 // Caching channels would have to look at their flags to work
7361 // out which error to return. Or we can fix up the error here.
7362 if (!(mLoadType
& LOAD_CMD_HISTORY
)) {
7363 aStatus
= NS_ERROR_OFFLINE
;
7365 DisplayLoadError(aStatus
, url
, nullptr, aChannel
);
7367 } else if (url
&& NS_SUCCEEDED(aStatus
)) {
7368 // If we have a host
7369 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->GetLoadInfo();
7371 PredictorLearnRedirect(url
, aChannel
, loadInfo
->GetOriginAttributes());
7378 //*****************************************************************************
7379 // nsDocShell: Content Viewer Management
7380 //*****************************************************************************
7383 nsDocShell::EnsureContentViewer()
7385 if (mContentViewer
) {
7388 if (mIsBeingDestroyed
) {
7389 return NS_ERROR_FAILURE
;
7392 nsCOMPtr
<nsIURI
> baseURI
;
7393 nsIPrincipal
* principal
= GetInheritedPrincipal(false);
7394 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
7395 GetSameTypeParent(getter_AddRefs(parentItem
));
7397 if (nsCOMPtr
<nsPIDOMWindowOuter
> domWin
= GetWindow()) {
7398 nsCOMPtr
<Element
> parentElement
= domWin
->GetFrameElementInternal();
7399 if (parentElement
) {
7400 baseURI
= parentElement
->GetBaseURI();
7405 nsresult rv
= CreateAboutBlankContentViewer(principal
, baseURI
);
7407 NS_ENSURE_STATE(mContentViewer
);
7409 if (NS_SUCCEEDED(rv
)) {
7410 nsCOMPtr
<nsIDocument
> doc(GetDocument());
7412 "Should have doc if CreateAboutBlankContentViewer "
7415 doc
->SetIsInitialDocument(true);
7417 // Documents created using EnsureContentViewer may be transient
7418 // placeholders created by framescripts before content has a chance to
7419 // load. In some cases, window.open(..., "noopener") will create such a
7420 // document (in a new TabGroup) and then synchronously tear it down, firing
7421 // a "pagehide" event. Doing so violates our assertions about
7422 // DocGroups. It's easier to silence the assertion here than to avoid
7423 // creating the extra document.
7424 doc
->IgnoreDocGroupMismatches();
7431 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
,
7433 bool aTryToSaveOldPresentation
,
7434 bool aCheckPermitUnload
)
7436 nsCOMPtr
<nsIDocument
> blankDoc
;
7437 nsCOMPtr
<nsIContentViewer
> viewer
;
7438 nsresult rv
= NS_ERROR_FAILURE
;
7440 /* mCreatingDocument should never be true at this point. However, it's
7441 a theoretical possibility. We want to know about it and make it stop,
7442 and this sounds like a job for an assertion. */
7443 NS_ASSERTION(!mCreatingDocument
,
7444 "infinite(?) loop creating document averted");
7445 if (mCreatingDocument
) {
7446 return NS_ERROR_FAILURE
;
7449 // mContentViewer->PermitUnload may release |this| docshell.
7450 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
7452 AutoRestore
<bool> creatingDocument(mCreatingDocument
);
7453 mCreatingDocument
= true;
7455 if (aPrincipal
&& !nsContentUtils::IsSystemPrincipal(aPrincipal
) &&
7456 mItemType
!= typeChrome
) {
7457 MOZ_ASSERT(aPrincipal
->OriginAttributesRef() == mOriginAttributes
);
7460 // Make sure timing is created. But first record whether we had it
7461 // already, so we don't clobber the timing for an in-progress load.
7462 bool hadTiming
= mTiming
;
7463 bool toBeReset
= MaybeInitTiming();
7464 if (mContentViewer
) {
7465 if (aCheckPermitUnload
) {
7466 // We've got a content viewer already. Make sure the user
7467 // permits us to discard the current document and replace it
7468 // with about:blank. And also ensure we fire the unload events
7469 // in the current document.
7471 // Unload gets fired first for
7472 // document loaded from the session history.
7473 mTiming
->NotifyBeforeUnload();
7476 rv
= mContentViewer
->PermitUnload(&okToUnload
);
7478 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
7479 // The user chose not to unload the page, interrupt the load.
7480 MaybeResetInitTiming(toBeReset
);
7481 return NS_ERROR_FAILURE
;
7484 mTiming
->NotifyUnloadAccepted(mCurrentURI
);
7488 mSavingOldViewer
= aTryToSaveOldPresentation
&&
7489 CanSavePresentation(LOAD_NORMAL
, nullptr, nullptr);
7491 // Make sure to blow away our mLoadingURI just in case. No loads
7492 // from inside this pagehide.
7493 mLoadingURI
= nullptr;
7495 // Stop any in-progress loading, so that we don't accidentally trigger any
7496 // PageShow notifications from Embed() interrupting our loading below.
7499 // Notify the current document that it is about to be unloaded!!
7501 // It is important to fire the unload() notification *before* any state
7502 // is changed within the DocShell - otherwise, javascript will get the
7503 // wrong information :-(
7505 (void)FirePageHideNotification(!mSavingOldViewer
);
7506 // pagehide notification might destroy this docshell.
7507 if (mIsBeingDestroyed
) {
7508 return NS_ERROR_DOCSHELL_DYING
;
7512 // Now make sure we don't think we're in the middle of firing unload after
7513 // this point. This will make us fire unload when the about:blank document
7514 // unloads... but that's ok, more or less. Would be nice if it fired load
7516 mFiredUnloadEvent
= false;
7518 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory
=
7519 nsContentUtils::FindInternalContentViewer(NS_LITERAL_CSTRING("text/html"));
7522 nsCOMPtr
<nsIPrincipal
> principal
;
7523 if (mSandboxFlags
& SANDBOXED_ORIGIN
) {
7525 principal
= NullPrincipal::CreateWithInheritedAttributes(aPrincipal
);
7527 principal
= NullPrincipal::CreateWithInheritedAttributes(this);
7530 principal
= aPrincipal
;
7533 MaybeCreateInitialClientSource(principal
);
7535 // generate (about:blank) document to load
7536 blankDoc
= nsContentDLF::CreateBlankDocument(mLoadGroup
, principal
, this);
7538 // Hack: set the base URI manually, since this document never
7539 // got Reset() with a channel.
7540 blankDoc
->SetBaseURI(aBaseURI
);
7542 // Copy our sandbox flags to the document. These are immutable
7543 // after being set here.
7544 blankDoc
->SetSandboxFlags(mSandboxFlags
);
7546 // create a content viewer for us and the new document
7547 docFactory
->CreateInstanceForDocument(
7548 NS_ISUPPORTS_CAST(nsIDocShell
*, this), blankDoc
, "view",
7549 getter_AddRefs(viewer
));
7553 viewer
->SetContainer(this);
7554 rv
= Embed(viewer
, "", 0);
7555 NS_ENSURE_SUCCESS(rv
, rv
);
7557 SetCurrentURI(blankDoc
->GetDocumentURI(), nullptr, true, 0);
7558 rv
= mIsBeingDestroyed
? NS_ERROR_NOT_AVAILABLE
: NS_OK
;
7563 // The transient about:blank viewer doesn't have a session history entry.
7564 SetHistoryEntry(&mOSHE
, nullptr);
7566 // Clear out our mTiming like we would in EndPageLoad, if we didn't
7567 // have one before entering this function.
7570 mBlankTiming
= true;
7577 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
)
7579 return CreateAboutBlankContentViewer(aPrincipal
, nullptr);
7583 nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
)
7585 return CreateAboutBlankContentViewer(aPrincipal
, nullptr, true, false);
7589 nsDocShell::CanSavePresentation(uint32_t aLoadType
,
7590 nsIRequest
* aNewRequest
,
7591 nsIDocument
* aNewDocument
)
7594 return false; // no entry to save into
7597 nsCOMPtr
<nsIContentViewer
> viewer
;
7598 mOSHE
->GetContentViewer(getter_AddRefs(viewer
));
7600 NS_WARNING("mOSHE already has a content viewer!");
7604 // Only save presentation for "normal" loads and link loads. Anything else
7605 // probably wants to refetch the page, so caching the old presentation
7606 // would be incorrect.
7607 if (aLoadType
!= LOAD_NORMAL
&&
7608 aLoadType
!= LOAD_HISTORY
&&
7609 aLoadType
!= LOAD_LINK
&&
7610 aLoadType
!= LOAD_STOP_CONTENT
&&
7611 aLoadType
!= LOAD_STOP_CONTENT_AND_REPLACE
&&
7612 aLoadType
!= LOAD_ERROR_PAGE
) {
7616 // If the session history entry has the saveLayoutState flag set to false,
7617 // then we should not cache the presentation.
7619 mOSHE
->GetSaveLayoutStateFlag(&canSaveState
);
7620 if (!canSaveState
) {
7624 // If the document is not done loading, don't cache it.
7625 if (!mScriptGlobal
|| mScriptGlobal
->IsLoading()) {
7629 if (mScriptGlobal
->WouldReuseInnerWindow(aNewDocument
)) {
7633 // Avoid doing the work of saving the presentation state in the case where
7634 // the content viewer cache is disabled.
7635 if (nsSHistory::GetMaxTotalViewers() == 0) {
7639 // Don't cache the content viewer if we're in a subframe.
7640 nsCOMPtr
<nsIDocShellTreeItem
> root
;
7641 GetSameTypeParent(getter_AddRefs(root
));
7642 if (root
&& root
!= this) {
7643 return false; // this is a subframe load
7646 // If the document does not want its presentation cached, then don't.
7647 nsCOMPtr
<nsIDocument
> doc
= mScriptGlobal
->GetExtantDoc();
7648 return doc
&& doc
->CanSavePresentation(aNewRequest
);
7652 nsDocShell::ReattachEditorToWindow(nsISHEntry
* aSHEntry
)
7654 MOZ_ASSERT(!mIsBeingDestroyed
);
7656 NS_ASSERTION(!mEditorData
,
7657 "Why reattach an editor when we already have one?");
7658 NS_ASSERTION(aSHEntry
&& aSHEntry
->HasDetachedEditor(),
7659 "Reattaching when there's not a detached editor.");
7661 if (mEditorData
|| !aSHEntry
) {
7665 mEditorData
= aSHEntry
->ForgetEditorData();
7670 mEditorData
->ReattachToWindow(this);
7671 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to reattach editing session");
7676 nsDocShell::DetachEditorFromWindow()
7678 if (!mEditorData
|| mEditorData
->WaitingForLoad()) {
7679 // If there's nothing to detach, or if the editor data is actually set
7680 // up for the _new_ page that's coming in, don't detach.
7684 NS_ASSERTION(!mOSHE
|| !mOSHE
->HasDetachedEditor(),
7685 "Detaching editor when it's already detached.");
7687 nsresult res
= mEditorData
->DetachFromWindow();
7688 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to detach editor");
7690 if (NS_SUCCEEDED(res
)) {
7691 // Make mOSHE hold the owning ref to the editor data.
7693 MOZ_ASSERT(!mIsBeingDestroyed
|| !mOSHE
->HasDetachedEditor(),
7694 "We should not set the editor data again once after we "
7695 "detached the editor data during destroying this docshell");
7696 mOSHE
->SetEditorData(mEditorData
.forget());
7698 mEditorData
= nullptr;
7705 GetEditable(&isEditable
);
7706 NS_ASSERTION(!isEditable
,
7707 "Window is still editable after detaching editor.");
7713 nsDocShell::CaptureState()
7715 if (!mOSHE
|| mOSHE
== mLSHE
) {
7716 // No entry to save into, or we're replacing the existing entry.
7717 return NS_ERROR_FAILURE
;
7720 if (!mScriptGlobal
) {
7721 return NS_ERROR_FAILURE
;
7724 nsCOMPtr
<nsISupports
> windowState
= mScriptGlobal
->SaveWindowState();
7725 NS_ENSURE_TRUE(windowState
, NS_ERROR_FAILURE
);
7727 #ifdef DEBUG_PAGE_CACHE
7728 nsCOMPtr
<nsIURI
> uri
;
7729 mOSHE
->GetURI(getter_AddRefs(uri
));
7734 printf("Saving presentation into session history\n");
7735 printf(" SH URI: %s\n", spec
.get());
7738 nsresult rv
= mOSHE
->SetWindowState(windowState
);
7739 NS_ENSURE_SUCCESS(rv
, rv
);
7741 // Suspend refresh URIs and save off the timer queue
7742 rv
= mOSHE
->SetRefreshURIList(mSavedRefreshURIList
);
7743 NS_ENSURE_SUCCESS(rv
, rv
);
7745 // Capture the current content viewer bounds.
7746 if (mContentViewer
) {
7748 mContentViewer
->GetBounds(bounds
);
7749 rv
= mOSHE
->SetViewerBounds(bounds
);
7750 NS_ENSURE_SUCCESS(rv
, rv
);
7753 // Capture the docshell hierarchy.
7754 mOSHE
->ClearChildShells();
7756 uint32_t childCount
= mChildList
.Length();
7757 for (uint32_t i
= 0; i
< childCount
; ++i
) {
7758 nsCOMPtr
<nsIDocShellTreeItem
> childShell
= do_QueryInterface(ChildAt(i
));
7759 NS_ASSERTION(childShell
, "null child shell");
7761 mOSHE
->AddChildShell(childShell
);
7768 nsDocShell::RestorePresentationEvent::Run()
7770 if (mDocShell
&& NS_FAILED(mDocShell
->RestoreFromHistory())) {
7771 NS_WARNING("RestoreFromHistory failed");
7777 nsDocShell::BeginRestore(nsIContentViewer
* aContentViewer
, bool aTop
)
7780 if (!aContentViewer
) {
7781 rv
= EnsureContentViewer();
7782 NS_ENSURE_SUCCESS(rv
, rv
);
7784 aContentViewer
= mContentViewer
;
7787 // Dispatch events for restoring the presentation. We try to simulate
7788 // the progress notifications loading the document would cause, so we add
7789 // the document's channel to the loadgroup to initiate stateChange
7792 nsCOMPtr
<nsIDocument
> doc
= aContentViewer
->GetDocument();
7794 nsIChannel
* channel
= doc
->GetChannel();
7796 mEODForCurrentDocument
= false;
7797 mIsRestoringDocument
= true;
7798 mLoadGroup
->AddRequest(channel
, nullptr);
7799 mIsRestoringDocument
= false;
7804 // This point corresponds to us having gotten OnStartRequest or
7805 // STATE_START, so do the same thing that CreateContentViewer does at
7806 // this point to ensure that unload/pagehide events for this document
7807 // will fire when it's unloaded again.
7808 mFiredUnloadEvent
= false;
7810 // For non-top frames, there is no notion of making sure that the
7811 // previous document is in the domwindow when STATE_START notifications
7812 // happen. We can just call BeginRestore for all of the child shells
7814 rv
= BeginRestoreChildren();
7815 NS_ENSURE_SUCCESS(rv
, rv
);
7822 nsDocShell::BeginRestoreChildren()
7824 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
7825 while (iter
.HasMore()) {
7826 nsCOMPtr
<nsIDocShell
> child
= do_QueryObject(iter
.GetNext());
7828 nsresult rv
= child
->BeginRestore(nullptr, false);
7829 NS_ENSURE_SUCCESS(rv
, rv
);
7836 nsDocShell::FinishRestore()
7838 // First we call finishRestore() on our children. In the simulated load,
7839 // all of the child frames finish loading before the main document.
7841 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
7842 while (iter
.HasMore()) {
7843 nsCOMPtr
<nsIDocShell
> child
= do_QueryObject(iter
.GetNext());
7845 child
->FinishRestore();
7849 if (mOSHE
&& mOSHE
->HasDetachedEditor()) {
7850 ReattachEditorToWindow(mOSHE
);
7853 nsCOMPtr
<nsIDocument
> doc
= GetDocument();
7855 // Finally, we remove the request from the loadgroup. This will
7856 // cause onStateChange(STATE_STOP) to fire, which will fire the
7857 // pageshow event to the chrome.
7859 nsIChannel
* channel
= doc
->GetChannel();
7861 mIsRestoringDocument
= true;
7862 mLoadGroup
->RemoveRequest(channel
, nullptr, NS_OK
);
7863 mIsRestoringDocument
= false;
7871 nsDocShell::GetRestoringDocument(bool* aRestoring
)
7873 *aRestoring
= mIsRestoringDocument
;
7878 nsDocShell::RestorePresentation(nsISHEntry
* aSHEntry
, bool* aRestoring
)
7880 MOZ_ASSERT(!mIsBeingDestroyed
);
7882 NS_ASSERTION(mLoadType
& LOAD_CMD_HISTORY
,
7883 "RestorePresentation should only be called for history loads");
7885 nsCOMPtr
<nsIContentViewer
> viewer
;
7886 aSHEntry
->GetContentViewer(getter_AddRefs(viewer
));
7888 #ifdef DEBUG_PAGE_CACHE
7889 nsCOMPtr
<nsIURI
> uri
;
7890 aSHEntry
->GetURI(getter_AddRefs(uri
));
7898 *aRestoring
= false;
7901 #ifdef DEBUG_PAGE_CACHE
7902 printf("no saved presentation for uri: %s\n", spec
.get());
7907 // We need to make sure the content viewer's container is this docshell.
7908 // In subframe navigation, it's possible for the docshell that the
7909 // content viewer was originally loaded into to be replaced with a
7910 // different one. We don't currently support restoring the presentation
7913 nsCOMPtr
<nsIDocShell
> container
;
7914 viewer
->GetContainer(getter_AddRefs(container
));
7915 if (!::SameCOMIdentity(container
, GetAsSupports(this))) {
7916 #ifdef DEBUG_PAGE_CACHE
7917 printf("No valid container, clearing presentation\n");
7919 aSHEntry
->SetContentViewer(nullptr);
7920 return NS_ERROR_FAILURE
;
7923 NS_ASSERTION(mContentViewer
!= viewer
, "Restoring existing presentation");
7925 #ifdef DEBUG_PAGE_CACHE
7926 printf("restoring presentation from session history: %s\n", spec
.get());
7929 SetHistoryEntry(&mLSHE
, aSHEntry
);
7931 // Post an event that will remove the request after we've returned
7932 // to the event loop. This mimics the way it is called by nsIChannel
7935 // Revoke any pending restore (just in case)
7936 NS_ASSERTION(!mRestorePresentationEvent
.IsPending(),
7937 "should only have one RestorePresentationEvent");
7938 mRestorePresentationEvent
.Revoke();
7940 RefPtr
<RestorePresentationEvent
> evt
= new RestorePresentationEvent(this);
7941 nsresult rv
= DispatchToTabGroup(TaskCategory::Other
,
7942 RefPtr
<RestorePresentationEvent
>(evt
).forget());
7943 if (NS_SUCCEEDED(rv
)) {
7944 mRestorePresentationEvent
= evt
.get();
7945 // The rest of the restore processing will happen on our event
7954 class MOZ_STACK_CLASS PresentationEventForgetter
7957 explicit PresentationEventForgetter(
7958 nsRevocableEventPtr
<nsDocShell::RestorePresentationEvent
>&
7959 aRestorePresentationEvent
)
7960 : mRestorePresentationEvent(aRestorePresentationEvent
)
7961 , mEvent(aRestorePresentationEvent
.get())
7965 ~PresentationEventForgetter()
7972 if (mRestorePresentationEvent
.get() == mEvent
) {
7973 mRestorePresentationEvent
.Forget();
7979 nsRevocableEventPtr
<nsDocShell::RestorePresentationEvent
>&
7980 mRestorePresentationEvent
;
7981 RefPtr
<nsDocShell::RestorePresentationEvent
> mEvent
;
7987 nsDocShell::SandboxFlagsImplyCookies(const uint32_t &aSandboxFlags
)
7989 return (aSandboxFlags
& (SANDBOXED_ORIGIN
| SANDBOXED_SCRIPTS
)) == 0;
7993 nsDocShell::RestoreFromHistory()
7995 MOZ_ASSERT(mRestorePresentationEvent
.IsPending());
7996 PresentationEventForgetter
forgetter(mRestorePresentationEvent
);
7998 // This section of code follows the same ordering as CreateContentViewer.
8000 return NS_ERROR_FAILURE
;
8003 nsCOMPtr
<nsIContentViewer
> viewer
;
8004 mLSHE
->GetContentViewer(getter_AddRefs(viewer
));
8006 return NS_ERROR_FAILURE
;
8009 if (mSavingOldViewer
) {
8010 // We determined that it was safe to cache the document presentation
8011 // at the time we initiated the new load. We need to check whether
8012 // it's still safe to do so, since there may have been DOM mutations
8013 // or new requests initiated.
8014 nsCOMPtr
<nsIDocument
> doc
= viewer
->GetDocument();
8015 nsIRequest
* request
= nullptr;
8017 request
= doc
->GetChannel();
8019 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
8022 nsCOMPtr
<nsIContentViewer
> oldCv(mContentViewer
);
8023 nsCOMPtr
<nsIContentViewer
> newCv(viewer
);
8024 int32_t minFontSize
= 0;
8025 float textZoom
= 1.0f
;
8026 float pageZoom
= 1.0f
;
8027 float overrideDPPX
= 0.0f
;
8029 bool styleDisabled
= false;
8030 if (oldCv
&& newCv
) {
8031 oldCv
->GetMinFontSize(&minFontSize
);
8032 oldCv
->GetTextZoom(&textZoom
);
8033 oldCv
->GetFullZoom(&pageZoom
);
8034 oldCv
->GetOverrideDPPX(&overrideDPPX
);
8035 oldCv
->GetAuthorStyleDisabled(&styleDisabled
);
8038 // Protect against mLSHE going away via a load triggered from
8039 // pagehide or unload.
8040 nsCOMPtr
<nsISHEntry
> origLSHE
= mLSHE
;
8042 // Make sure to blow away our mLoadingURI just in case. No loads
8043 // from inside this pagehide.
8044 mLoadingURI
= nullptr;
8046 // Notify the old content viewer that it's being hidden.
8047 FirePageHideNotification(!mSavingOldViewer
);
8048 // pagehide notification might destroy this docshell.
8049 if (mIsBeingDestroyed
) {
8050 return NS_ERROR_DOCSHELL_DYING
;
8053 // If mLSHE was changed as a result of the pagehide event, then
8054 // something else was loaded. Don't finish restoring.
8055 if (mLSHE
!= origLSHE
) {
8059 // Add the request to our load group. We do this before swapping out
8060 // the content viewers so that consumers of STATE_START can access
8061 // the old document. We only deal with the toplevel load at this time --
8062 // to be consistent with normal document loading, subframes cannot start
8063 // loading until after data arrives, which is after STATE_START completes.
8065 RefPtr
<RestorePresentationEvent
> currentPresentationRestoration
=
8066 mRestorePresentationEvent
.get();
8068 // Make sure we're still restoring the same presentation.
8069 // If we aren't, docshell is in process doing another load already.
8070 NS_ENSURE_STATE(currentPresentationRestoration
==
8071 mRestorePresentationEvent
.get());
8072 BeginRestore(viewer
, true);
8073 NS_ENSURE_STATE(currentPresentationRestoration
==
8074 mRestorePresentationEvent
.get());
8077 // Set mFiredUnloadEvent = false so that the unload handler for the
8078 // *new* document will fire.
8079 mFiredUnloadEvent
= false;
8081 mURIResultedInDocument
= true;
8082 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
8084 mPreviousTransIndex
= rootSH
->Index();
8085 rootSH
->LegacySHistoryInternal()->UpdateIndex();
8086 mLoadedTransIndex
= rootSH
->Index();
8087 #ifdef DEBUG_PAGE_CACHE
8088 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
8093 // Rather than call Embed(), we will retrieve the viewer from the session
8094 // history entry and swap it in.
8095 // XXX can we refactor this so that we can just call Embed()?
8096 PersistLayoutHistoryState();
8098 if (mContentViewer
) {
8099 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
8101 mOSHE
->SyncPresentationState();
8103 mSavingOldViewer
= false;
8107 mSavedRefreshURIList
= nullptr;
8109 // In cases where we use a transient about:blank viewer between loads,
8110 // we never show the transient viewer, so _its_ previous viewer is never
8111 // unhooked from the view hierarchy. Destroy any such previous viewer now,
8112 // before we grab the root view sibling, so that we don't grab a view
8113 // that's about to go away.
8115 if (mContentViewer
) {
8116 nsCOMPtr
<nsIContentViewer
> previousViewer
;
8117 mContentViewer
->GetPreviousViewer(getter_AddRefs(previousViewer
));
8118 if (previousViewer
) {
8119 mContentViewer
->SetPreviousViewer(nullptr);
8120 previousViewer
->Destroy();
8124 // Save off the root view's parent and sibling so that we can insert the
8125 // new content viewer's root view at the same position. Also save the
8126 // bounds of the root view's widget.
8128 nsView
* rootViewSibling
= nullptr;
8129 nsView
* rootViewParent
= nullptr;
8130 nsIntRect
newBounds(0, 0, 0, 0);
8132 nsCOMPtr
<nsIPresShell
> oldPresShell
= GetPresShell();
8134 nsViewManager
* vm
= oldPresShell
->GetViewManager();
8136 nsView
* oldRootView
= vm
->GetRootView();
8139 rootViewSibling
= oldRootView
->GetNextSibling();
8140 rootViewParent
= oldRootView
->GetParent();
8142 mContentViewer
->GetBounds(newBounds
);
8147 nsCOMPtr
<nsIContent
> container
;
8148 nsCOMPtr
<nsIDocument
> sibling
;
8149 if (rootViewParent
&& rootViewParent
->GetParent()) {
8150 nsIFrame
* frame
= rootViewParent
->GetParent()->GetFrame();
8151 container
= frame
? frame
->GetContent() : nullptr;
8153 if (rootViewSibling
) {
8154 nsIFrame
* frame
= rootViewSibling
->GetFrame();
8156 frame
? frame
->PresShell()->GetDocument() : nullptr;
8159 // Transfer ownership to mContentViewer. By ensuring that either the
8160 // docshell or the session history, but not both, have references to the
8161 // content viewer, we prevent the viewer from being torn down after
8162 // Destroy() is called.
8164 if (mContentViewer
) {
8165 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nullptr);
8166 viewer
->SetPreviousViewer(mContentViewer
);
8168 if (mOSHE
&& (!mContentViewer
|| !mSavingOldViewer
)) {
8169 // We don't plan to save a viewer in mOSHE; tell it to drop
8170 // any other state it's holding.
8171 mOSHE
->SyncPresentationState();
8174 // Order the mContentViewer setup just like Embed does.
8175 mContentViewer
= nullptr;
8177 // Now that we're about to switch documents, forget all of our children.
8178 // Note that we cached them as needed up in CaptureState above.
8181 mContentViewer
.swap(viewer
);
8183 // Grab all of the related presentation from the SHEntry now.
8184 // Clearing the viewer from the SHEntry will clear all of this state.
8185 nsCOMPtr
<nsISupports
> windowState
;
8186 mLSHE
->GetWindowState(getter_AddRefs(windowState
));
8187 mLSHE
->SetWindowState(nullptr);
8190 mLSHE
->GetSticky(&sticky
);
8192 nsCOMPtr
<nsIDocument
> document
= mContentViewer
->GetDocument();
8194 nsCOMArray
<nsIDocShellTreeItem
> childShells
;
8196 nsCOMPtr
<nsIDocShellTreeItem
> child
;
8197 while (NS_SUCCEEDED(mLSHE
->ChildShellAt(i
++, getter_AddRefs(child
))) &&
8199 childShells
.AppendObject(child
);
8202 // get the previous content viewer size
8203 nsIntRect
oldBounds(0, 0, 0, 0);
8204 mLSHE
->GetViewerBounds(oldBounds
);
8206 // Restore the refresh URI list. The refresh timers will be restarted
8207 // when EndPageLoad() is called.
8208 nsCOMPtr
<nsIMutableArray
> refreshURIList
;
8209 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIList
));
8211 // Reattach to the window object.
8212 mIsRestoringDocument
= true; // for MediaDocument::BecomeInteractive
8213 rv
= mContentViewer
->Open(windowState
, mLSHE
);
8214 mIsRestoringDocument
= false;
8216 // Hack to keep nsDocShellEditorData alive across the
8217 // SetContentViewer(nullptr) call below.
8218 nsAutoPtr
<nsDocShellEditorData
> data(mLSHE
->ForgetEditorData());
8220 // Now remove it from the cached presentation.
8221 mLSHE
->SetContentViewer(nullptr);
8222 mEODForCurrentDocument
= false;
8224 mLSHE
->SetEditorData(data
.forget());
8228 nsCOMPtr
<nsIMutableArray
> refreshURIs
;
8229 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIs
));
8230 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
8231 mLSHE
->ChildShellAt(0, getter_AddRefs(childShell
));
8232 NS_ASSERTION(!refreshURIs
&& !childShell
,
8233 "SHEntry should have cleared presentation state");
8237 // Restore the sticky state of the viewer. The viewer has set this state
8238 // on the history entry in Destroy() just before marking itself non-sticky,
8239 // to avoid teardown of the presentation.
8240 mContentViewer
->SetSticky(sticky
);
8242 NS_ENSURE_SUCCESS(rv
, rv
);
8244 // mLSHE is now our currently-loaded document.
8245 SetHistoryEntry(&mOSHE
, mLSHE
);
8247 // XXX special wyciwyg handling in Embed()?
8249 // We aren't going to restore any items from the LayoutHistoryState,
8250 // but we don't want them to stay around in case the page is reloaded.
8251 SetLayoutHistoryState(nullptr);
8253 // This is the end of our Embed() replacement
8255 mSavingOldViewer
= false;
8256 mEODForCurrentDocument
= false;
8258 // Tell the event loop to favor plevents over user events, see comments
8259 // in CreateContentViewer.
8260 if (++gNumberOfDocumentsLoading
== 1) {
8261 FavorPerformanceHint(true);
8264 if (oldCv
&& newCv
) {
8265 newCv
->SetMinFontSize(minFontSize
);
8266 newCv
->SetTextZoom(textZoom
);
8267 newCv
->SetFullZoom(pageZoom
);
8268 newCv
->SetOverrideDPPX(overrideDPPX
);
8269 newCv
->SetAuthorStyleDisabled(styleDisabled
);
8273 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
8275 nsCOMPtr
<nsIDocument
> d
= parent
->GetDocument();
8277 if (d
->EventHandlingSuppressed()) {
8278 document
->SuppressEventHandling(d
->EventHandlingSuppressed());
8283 // Use the uri from the mLSHE we had when we entered this function
8284 // (which need not match the document's URI if anchors are involved),
8285 // since that's the history entry we're loading. Note that if we use
8286 // origLSHE we don't have to worry about whether the entry in question
8287 // is still mLSHE or whether it's now mOSHE.
8288 nsCOMPtr
<nsIURI
> uri
;
8289 origLSHE
->GetURI(getter_AddRefs(uri
));
8290 SetCurrentURI(uri
, document
->GetChannel(), true, 0);
8293 // This is the end of our CreateContentViewer() replacement.
8294 // Now we simulate a load. First, we restore the state of the javascript
8296 nsCOMPtr
<nsPIDOMWindowOuter
> privWin
= GetWindow();
8297 NS_ASSERTION(privWin
, "could not get nsPIDOMWindow interface");
8299 // Now, dispatch a title change event which would happen as the
8300 // <head> is parsed.
8301 document
->NotifyPossibleTitleChange(false);
8303 // Now we simulate appending child docshells for subframes.
8304 for (i
= 0; i
< childShells
.Count(); ++i
) {
8305 nsIDocShellTreeItem
* childItem
= childShells
.ObjectAt(i
);
8306 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(childItem
);
8308 // Make sure to not clobber the state of the child. Since AddChild
8309 // always clobbers it, save it off first.
8311 childShell
->GetAllowPlugins(&allowPlugins
);
8313 bool allowJavascript
;
8314 childShell
->GetAllowJavascript(&allowJavascript
);
8316 bool allowRedirects
;
8317 childShell
->GetAllowMetaRedirects(&allowRedirects
);
8319 bool allowSubframes
;
8320 childShell
->GetAllowSubframes(&allowSubframes
);
8323 childShell
->GetAllowImages(&allowImages
);
8325 bool allowMedia
= childShell
->GetAllowMedia();
8327 bool allowDNSPrefetch
;
8328 childShell
->GetAllowDNSPrefetch(&allowDNSPrefetch
);
8330 bool allowContentRetargeting
= childShell
->GetAllowContentRetargeting();
8331 bool allowContentRetargetingOnChildren
=
8332 childShell
->GetAllowContentRetargetingOnChildren();
8334 uint32_t defaultLoadFlags
;
8335 childShell
->GetDefaultLoadFlags(&defaultLoadFlags
);
8337 // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
8338 // the child inherits our state. Among other things, this means that the
8339 // child inherits our mIsActive mPrivateBrowsingId, which is what we want.
8340 AddChild(childItem
);
8342 childShell
->SetAllowPlugins(allowPlugins
);
8343 childShell
->SetAllowJavascript(allowJavascript
);
8344 childShell
->SetAllowMetaRedirects(allowRedirects
);
8345 childShell
->SetAllowSubframes(allowSubframes
);
8346 childShell
->SetAllowImages(allowImages
);
8347 childShell
->SetAllowMedia(allowMedia
);
8348 childShell
->SetAllowDNSPrefetch(allowDNSPrefetch
);
8349 childShell
->SetAllowContentRetargeting(allowContentRetargeting
);
8350 childShell
->SetAllowContentRetargetingOnChildren(
8351 allowContentRetargetingOnChildren
);
8352 childShell
->SetDefaultLoadFlags(defaultLoadFlags
);
8354 rv
= childShell
->BeginRestore(nullptr, false);
8355 NS_ENSURE_SUCCESS(rv
, rv
);
8358 // Make sure to restore the window state after adding the child shells back
8359 // to the tree. This is necessary for Thaw() and Resume() to propagate
8361 rv
= privWin
->RestoreWindowState(windowState
);
8362 NS_ENSURE_SUCCESS(rv
, rv
);
8364 nsCOMPtr
<nsIPresShell
> shell
= GetPresShell();
8366 // We may be displayed on a different monitor (or in a different
8367 // HiDPI mode) than when we got into the history list. So we need
8368 // to check if this has happened. See bug 838239.
8370 // Because the prescontext normally handles resolution changes via
8371 // a runnable (see nsPresContext::UIResolutionChanged), its device
8372 // context won't be -immediately- updated as a result of calling
8373 // shell->BackingScaleFactorChanged().
8375 // But we depend on that device context when adjusting the view size
8376 // via mContentViewer->SetBounds(newBounds) below. So we need to
8377 // explicitly tell it to check for changed resolution here.
8378 if (shell
&& shell
->GetPresContext()->DeviceContext()->CheckDPIChange()) {
8379 shell
->BackingScaleFactorChanged();
8382 nsViewManager
* newVM
= shell
? shell
->GetViewManager() : nullptr;
8383 nsView
* newRootView
= newVM
? newVM
->GetRootView() : nullptr;
8385 // Insert the new root view at the correct location in the view tree.
8387 nsSubDocumentFrame
* subDocFrame
=
8388 do_QueryFrame(container
->GetPrimaryFrame());
8389 rootViewParent
= subDocFrame
? subDocFrame
->EnsureInnerView() : nullptr;
8391 rootViewParent
= nullptr;
8394 sibling
->GetShell() &&
8395 sibling
->GetShell()->GetViewManager()) {
8396 rootViewSibling
= sibling
->GetShell()->GetViewManager()->GetRootView();
8398 rootViewSibling
= nullptr;
8400 if (rootViewParent
&& newRootView
&&
8401 newRootView
->GetParent() != rootViewParent
) {
8402 nsViewManager
* parentVM
= rootViewParent
->GetViewManager();
8404 // InsertChild(parent, child, sib, true) inserts the child after
8405 // sib in content order, which is before sib in view order. BUT
8406 // when sib is null it inserts at the end of the the document
8407 // order, i.e., first in view order. But when oldRootSibling is
8408 // null, the old root as at the end of the view list --- last in
8409 // content order --- and we want to call InsertChild(parent, child,
8410 // nullptr, false) in that case.
8411 parentVM
->InsertChild(rootViewParent
, newRootView
,
8413 rootViewSibling
? true : false);
8415 NS_ASSERTION(newRootView
->GetNextSibling() == rootViewSibling
,
8416 "error in InsertChild");
8420 nsCOMPtr
<nsPIDOMWindowInner
> privWinInner
= privWin
->GetCurrentInnerWindow();
8422 // If parent is suspended, increase suspension count.
8423 // This can't be done as early as event suppression since this
8424 // depends on docshell tree.
8425 privWinInner
->SyncStateFromParentWindow();
8427 // Now that all of the child docshells have been put into place, we can
8428 // restart the timers for the window and all of the child frames.
8429 privWinInner
->Resume();
8431 // Restore the refresh URI list. The refresh timers will be restarted
8432 // when EndPageLoad() is called.
8433 mRefreshURIList
= refreshURIList
;
8435 // Meta-refresh timers have been restarted for this shell, but not
8436 // for our children. Walk the child shells and restart their timers.
8437 nsTObserverArray
<nsDocLoader
*>::ForwardIterator
iter(mChildList
);
8438 while (iter
.HasMore()) {
8439 nsCOMPtr
<nsIDocShell
> child
= do_QueryObject(iter
.GetNext());
8441 child
->ResumeRefreshURIs();
8445 // Make sure this presentation is the same size as the previous
8446 // presentation. If this is not the same size we showed it at last time,
8447 // then we need to resize the widget.
8449 // XXXbryner This interacts poorly with Firefox's infobar. If the old
8450 // presentation had the infobar visible, then we will resize the new
8451 // presentation to that smaller size. However, firing the locationchanged
8452 // event will hide the infobar, which will immediately resize the window
8453 // back to the larger size. A future optimization might be to restore
8454 // the presentation at the "wrong" size, then fire the locationchanged
8455 // event and check whether the docshell's new size is the same as the
8456 // cached viewer size (skipping the resize if they are equal).
8459 if (!newBounds
.IsEmpty() && !newBounds
.IsEqualEdges(oldBounds
)) {
8460 #ifdef DEBUG_PAGE_CACHE
8461 printf("resize widget(%d, %d, %d, %d)\n", newBounds
.x
,
8462 newBounds
.y
, newBounds
.width
, newBounds
.height
);
8464 mContentViewer
->SetBounds(newBounds
);
8466 nsIScrollableFrame
* rootScrollFrame
=
8467 shell
->GetRootScrollFrameAsScrollable();
8468 if (rootScrollFrame
) {
8469 rootScrollFrame
->PostScrolledAreaEventForCurrentArea();
8474 // The FinishRestore call below can kill these, null them out so we don't
8475 // have invalid pointer lying around.
8476 newRootView
= rootViewSibling
= rootViewParent
= nullptr;
8479 // Simulate the completion of the load.
8480 nsDocShell::FinishRestore();
8482 // Restart plugins, and paint the content.
8487 return privWin
->FireDelayedDOMEvents();
8491 nsDocShell::CreateContentViewer(const nsACString
& aContentType
,
8492 nsIRequest
* aRequest
,
8493 nsIStreamListener
** aContentHandler
)
8495 *aContentHandler
= nullptr;
8497 if (!mTreeOwner
|| mIsBeingDestroyed
) {
8498 // If we don't have a tree owner, then we're in the process of being
8499 // destroyed. Rather than continue trying to load something, just give up.
8500 return NS_ERROR_DOCSHELL_DYING
;
8503 // Can we check the content type of the current content viewer
8504 // and reuse it without destroying it and re-creating it?
8506 NS_ASSERTION(mLoadGroup
, "Someone ignored return from Init()?");
8508 // Instantiate the content viewer object
8509 nsCOMPtr
<nsIContentViewer
> viewer
;
8510 nsresult rv
= NewContentViewerObj(aContentType
, aRequest
, mLoadGroup
,
8511 aContentHandler
, getter_AddRefs(viewer
));
8513 if (NS_FAILED(rv
)) {
8517 // Notify the current document that it is about to be unloaded!!
8519 // It is important to fire the unload() notification *before* any state
8520 // is changed within the DocShell - otherwise, javascript will get the
8521 // wrong information :-(
8524 if (mSavingOldViewer
) {
8525 // We determined that it was safe to cache the document presentation
8526 // at the time we initiated the new load. We need to check whether
8527 // it's still safe to do so, since there may have been DOM mutations
8528 // or new requests initiated.
8529 nsCOMPtr
<nsIDocument
> doc
= viewer
->GetDocument();
8530 mSavingOldViewer
= CanSavePresentation(mLoadType
, aRequest
, doc
);
8533 NS_ASSERTION(!mLoadingURI
, "Re-entering unload?");
8535 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(aRequest
);
8536 if (aOpenedChannel
) {
8537 aOpenedChannel
->GetURI(getter_AddRefs(mLoadingURI
));
8539 FirePageHideNotification(!mSavingOldViewer
);
8540 if (mIsBeingDestroyed
) {
8541 // Force to stop the newly created orphaned viewer.
8543 return NS_ERROR_DOCSHELL_DYING
;
8545 mLoadingURI
= nullptr;
8547 // Set mFiredUnloadEvent = false so that the unload handler for the
8548 // *new* document will fire.
8549 mFiredUnloadEvent
= false;
8551 // we've created a new document so go ahead and call
8552 // OnLoadingSite(), but don't fire OnLocationChange()
8553 // notifications before we've called Embed(). See bug 284993.
8554 mURIResultedInDocument
= true;
8555 bool errorOnLocationChangeNeeded
= false;
8556 nsCOMPtr
<nsIChannel
> failedChannel
= mFailedChannel
;
8557 nsCOMPtr
<nsIURI
> failedURI
;
8559 if (mLoadType
== LOAD_ERROR_PAGE
) {
8560 // We need to set the SH entry and our current URI here and not
8561 // at the moment we load the page. We want the same behavior
8562 // of Stop() as for a normal page load. See bug 514232 for details.
8564 // Revert mLoadType to load type to state the page load failed,
8565 // following function calls need it.
8566 mLoadType
= mFailedLoadType
;
8569 nsIDocument
* doc
= viewer
->GetDocument();
8571 doc
->SetFailedChannel(failedChannel
);
8574 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
8575 if (failedChannel
) {
8576 // Make sure we have a URI to set currentURI.
8577 NS_GetFinalChannelURI(failedChannel
, getter_AddRefs(failedURI
));
8580 // if there is no failed channel we have to explicitly provide
8581 // a triggeringPrincipal for the history entry.
8582 triggeringPrincipal
= nsContentUtils::GetSystemPrincipal();
8586 failedURI
= mFailedURI
;
8589 // We need a URI object to store a session history entry, so make up a URI
8590 NS_NewURI(getter_AddRefs(failedURI
), "about:blank");
8593 // When we don't have failedURI, something wrong will happen. See
8595 MOZ_ASSERT(failedURI
, "We don't have a URI for history APIs.");
8597 mFailedChannel
= nullptr;
8598 mFailedURI
= nullptr;
8600 // Create an shistory entry for the old load.
8602 errorOnLocationChangeNeeded
= OnNewURI(
8603 failedURI
, failedChannel
, triggeringPrincipal
,
8604 nullptr, mLoadType
, false, false, false);
8607 // Be sure to have a correct mLSHE, it may have been cleared by
8608 // EndPageLoad. See bug 302115.
8609 if (mSessionHistory
&& !mLSHE
) {
8611 mSessionHistory
->LegacySHistory()->GetRequestedIndex(&idx
);
8613 idx
= mSessionHistory
->Index();
8615 mSessionHistory
->LegacySHistory()->
8616 GetEntryAtIndex(idx
, false, getter_AddRefs(mLSHE
));
8619 mLoadType
= LOAD_ERROR_PAGE
;
8622 bool onLocationChangeNeeded
= OnLoadingSite(aOpenedChannel
, false);
8624 // let's try resetting the load group if we need to...
8625 nsCOMPtr
<nsILoadGroup
> currentLoadGroup
;
8627 aOpenedChannel
->GetLoadGroup(getter_AddRefs(currentLoadGroup
)),
8630 if (currentLoadGroup
!= mLoadGroup
) {
8631 nsLoadFlags loadFlags
= 0;
8633 // Cancel any URIs that are currently loading...
8634 // XXX: Need to do this eventually Stop();
8636 // Retarget the document to this loadgroup...
8638 /* First attach the channel to the right loadgroup
8639 * and then remove from the old loadgroup. This
8640 * puts the notifications in the right order and
8641 * we don't null-out mLSHE in OnStateChange() for
8642 * all redirected urls
8644 aOpenedChannel
->SetLoadGroup(mLoadGroup
);
8646 // Mark the channel as being a document URI...
8647 aOpenedChannel
->GetLoadFlags(&loadFlags
);
8648 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
;
8649 if (SandboxFlagsImplyCookies(mSandboxFlags
)) {
8650 loadFlags
|= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE
;
8653 aOpenedChannel
->SetLoadFlags(loadFlags
);
8655 mLoadGroup
->AddRequest(aRequest
, nullptr);
8656 if (currentLoadGroup
) {
8657 currentLoadGroup
->RemoveRequest(aRequest
, nullptr, NS_BINDING_RETARGETED
);
8660 // Update the notification callbacks, so that progress and
8661 // status information are sent to the right docshell...
8662 aOpenedChannel
->SetNotificationCallbacks(this);
8665 NS_ENSURE_SUCCESS(Embed(viewer
, "", nullptr), NS_ERROR_FAILURE
);
8667 mSavedRefreshURIList
= nullptr;
8668 mSavingOldViewer
= false;
8669 mEODForCurrentDocument
= false;
8671 // if this document is part of a multipart document,
8672 // the ID can be used to distinguish it from the other parts.
8673 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(aRequest
));
8674 if (multiPartChannel
) {
8675 nsCOMPtr
<nsIPresShell
> shell
= GetPresShell();
8676 if (NS_SUCCEEDED(rv
) && shell
) {
8677 nsIDocument
* doc
= shell
->GetDocument();
8680 multiPartChannel
->GetPartID(&partID
);
8681 doc
->SetPartID(partID
);
8686 // Give hint to native plevent dispatch mechanism. If a document
8687 // is loading the native plevent dispatch mechanism should favor
8688 // performance over normal native event dispatch priorities.
8689 if (++gNumberOfDocumentsLoading
== 1) {
8690 // Hint to favor performance for the plevent notification mechanism.
8691 // We want the pages to load as fast as possible even if its means
8692 // native messages might be starved.
8693 FavorPerformanceHint(true);
8696 if (errorOnLocationChangeNeeded
){
8697 FireOnLocationChange(this, failedChannel
, failedURI
,
8698 LOCATION_CHANGE_ERROR_PAGE
);
8699 } else if (onLocationChangeNeeded
) {
8700 FireOnLocationChange(this, aRequest
, mCurrentURI
, 0);
8707 nsDocShell::NewContentViewerObj(const nsACString
& aContentType
,
8708 nsIRequest
* aRequest
, nsILoadGroup
* aLoadGroup
,
8709 nsIStreamListener
** aContentHandler
,
8710 nsIContentViewer
** aViewer
)
8712 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(aRequest
);
8714 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
=
8715 nsContentUtils::FindInternalContentViewer(aContentType
);
8716 if (!docLoaderFactory
) {
8717 return NS_ERROR_FAILURE
;
8720 // Now create an instance of the content viewer nsLayoutDLF makes the
8721 // determination if it should be a "view-source" instead of "view"
8722 nsresult rv
= docLoaderFactory
->CreateInstance("view",
8724 aLoadGroup
, aContentType
,
8729 NS_ENSURE_SUCCESS(rv
, rv
);
8731 (*aViewer
)->SetContainer(this);
8736 nsDocShell::SetupNewViewer(nsIContentViewer
* aNewViewer
)
8738 MOZ_ASSERT(!mIsBeingDestroyed
);
8741 // Copy content viewer state from previous or parent content viewer.
8743 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
8745 // Do NOT to maintain a reference to the old content viewer outside
8746 // of this "copying" block, or it will not be destroyed until the end of
8747 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
8749 // In this block of code, if we get an error result, we return it
8750 // but if we get a null pointer, that's perfectly legal for parent
8751 // and parentContentViewer.
8759 // This will get the size from the current content viewer or from the
8761 DoGetPositionAndSize(&x
, &y
, &cx
, &cy
);
8763 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
8764 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem
)),
8766 nsCOMPtr
<nsIDocShell
> parent(do_QueryInterface(parentAsItem
));
8768 const Encoding
* forceCharset
= nullptr;
8769 const Encoding
* hintCharset
= nullptr;
8770 int32_t hintCharsetSource
;
8771 int32_t minFontSize
;
8776 // |newMUDV| also serves as a flag to set the data from the above vars
8777 nsCOMPtr
<nsIContentViewer
> newCv
;
8779 if (mContentViewer
|| parent
) {
8780 nsCOMPtr
<nsIContentViewer
> oldCv
;
8781 if (mContentViewer
) {
8782 // Get any interesting state from old content viewer
8783 // XXX: it would be far better to just reuse the document viewer ,
8784 // since we know we're just displaying the same document as before
8785 oldCv
= mContentViewer
;
8787 // Tell the old content viewer to hibernate in session history when
8790 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
8792 mOSHE
->SyncPresentationState();
8794 mSavingOldViewer
= false;
8797 // No old content viewer, so get state from parent's content viewer
8798 parent
->GetContentViewer(getter_AddRefs(oldCv
));
8804 forceCharset
= oldCv
->GetForceCharset();
8805 hintCharset
= oldCv
->GetHintCharset();
8806 NS_ENSURE_SUCCESS(oldCv
->GetHintCharacterSetSource(&hintCharsetSource
),
8808 NS_ENSURE_SUCCESS(oldCv
->GetMinFontSize(&minFontSize
),
8810 NS_ENSURE_SUCCESS(oldCv
->GetTextZoom(&textZoom
),
8812 NS_ENSURE_SUCCESS(oldCv
->GetFullZoom(&pageZoom
),
8814 NS_ENSURE_SUCCESS(oldCv
->GetOverrideDPPX(&overrideDPPX
),
8816 NS_ENSURE_SUCCESS(oldCv
->GetAuthorStyleDisabled(&styleDisabled
),
8822 nscolor bgcolor
= NS_RGBA(0, 0, 0, 0);
8823 bool isActive
= false;
8824 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
8825 nsCOMPtr
<nsIContentViewer
> contentViewer
= mContentViewer
;
8826 if (contentViewer
) {
8827 // Stop any activity that may be happening in the old document before
8829 contentViewer
->Stop();
8831 // Try to extract the canvas background color from the old
8832 // presentation shell, so we can use it for the next document.
8833 nsCOMPtr
<nsIPresShell
> shell
;
8834 contentViewer
->GetPresShell(getter_AddRefs(shell
));
8837 bgcolor
= shell
->GetCanvasBackground();
8838 isActive
= shell
->IsActive();
8841 contentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nullptr);
8842 aNewViewer
->SetPreviousViewer(contentViewer
);
8844 if (mOSHE
&& (!mContentViewer
|| !mSavingOldViewer
)) {
8845 // We don't plan to save a viewer in mOSHE; tell it to drop
8846 // any other state it's holding.
8847 mOSHE
->SyncPresentationState();
8850 mContentViewer
= nullptr;
8852 // Now that we're about to switch documents, forget all of our children.
8853 // Note that we cached them as needed up in CaptureState above.
8856 mContentViewer
= aNewViewer
;
8858 nsCOMPtr
<nsIWidget
> widget
;
8859 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget
)), NS_ERROR_FAILURE
);
8861 nsIntRect
bounds(x
, y
, cx
, cy
);
8863 mContentViewer
->SetNavigationTiming(mTiming
);
8865 if (NS_FAILED(mContentViewer
->Init(widget
, bounds
))) {
8866 mContentViewer
= nullptr;
8867 NS_WARNING("ContentViewer Initialization failed");
8868 return NS_ERROR_FAILURE
;
8871 // If we have old state to copy, set the old state onto the new content
8874 newCv
->SetForceCharset(forceCharset
);
8875 newCv
->SetHintCharset(hintCharset
);
8876 NS_ENSURE_SUCCESS(newCv
->SetHintCharacterSetSource(hintCharsetSource
),
8878 NS_ENSURE_SUCCESS(newCv
->SetMinFontSize(minFontSize
),
8880 NS_ENSURE_SUCCESS(newCv
->SetTextZoom(textZoom
),
8882 NS_ENSURE_SUCCESS(newCv
->SetFullZoom(pageZoom
),
8884 NS_ENSURE_SUCCESS(newCv
->SetOverrideDPPX(overrideDPPX
),
8886 NS_ENSURE_SUCCESS(newCv
->SetAuthorStyleDisabled(styleDisabled
),
8890 // Stuff the bgcolor from the old pres shell into the new
8891 // pres shell. This improves page load continuity.
8892 nsCOMPtr
<nsIPresShell
> shell
;
8893 mContentViewer
->GetPresShell(getter_AddRefs(shell
));
8896 shell
->SetCanvasBackground(bgcolor
);
8898 shell
->SetIsActive(isActive
);
8902 // XXX: It looks like the LayoutState gets restored again in Embed()
8903 // right after the call to SetupNewViewer(...)
8905 // We don't show the mContentViewer yet, since we want to draw the old page
8906 // until we have enough of the new page to show. Just return with the new
8907 // viewer still set to hidden.
8913 nsDocShell::SetDocCurrentStateObj(nsISHEntry
* aShEntry
)
8915 NS_ENSURE_STATE(mContentViewer
);
8916 nsCOMPtr
<nsIDocument
> document
= GetDocument();
8917 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
8919 nsCOMPtr
<nsIStructuredCloneContainer
> scContainer
;
8921 nsresult rv
= aShEntry
->GetStateData(getter_AddRefs(scContainer
));
8922 NS_ENSURE_SUCCESS(rv
, rv
);
8924 // If aShEntry is null, just set the document's state object to null.
8927 // It's OK for scContainer too be null here; that just means there's no
8928 // state data associated with this history entry.
8929 document
->SetStateObject(scContainer
);
8935 nsDocShell::CheckLoadingPermissions()
8937 // This method checks whether the caller may load content into
8938 // this docshell. Even though we've done our best to hide windows
8939 // from code that doesn't have the right to access them, it's
8940 // still possible for an evil site to open a window and access
8941 // frames in the new window through window.frames[] (which is
8942 // allAccess for historic reasons), so we still need to do this
8944 nsresult rv
= NS_OK
;
8946 if (!gValidateOrigin
|| !IsFrame()) {
8947 // Origin validation was turned off, or we're not a frame.
8948 // Permit all loads.
8953 // Note - The check for a current JSContext here isn't necessarily sensical.
8954 // It's just designed to preserve the old semantics during a mass-conversion
8956 if (!nsContentUtils::GetCurrentJSContext()) {
8960 // Check if the caller is from the same origin as this docshell,
8961 // or any of its ancestors.
8962 nsCOMPtr
<nsIDocShellTreeItem
> item(this);
8964 nsCOMPtr
<nsIScriptGlobalObject
> sgo
= do_GetInterface(item
);
8965 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(sgo
));
8968 if (!sop
|| !(p
= sop
->GetPrincipal())) {
8969 return NS_ERROR_UNEXPECTED
;
8972 if (nsContentUtils::SubjectPrincipal()->Subsumes(p
)) {
8973 // Same origin, permit load
8977 nsCOMPtr
<nsIDocShellTreeItem
> tmp
;
8978 item
->GetSameTypeParent(getter_AddRefs(tmp
));
8982 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
8985 //*****************************************************************************
8986 // nsDocShell: Site Loading
8987 //*****************************************************************************
8990 nsDocShell::CopyFavicon(nsIURI
* aOldURI
,
8992 nsIPrincipal
* aLoadingPrincipal
,
8993 bool aInPrivateBrowsing
)
8995 if (XRE_IsContentProcess()) {
8996 dom::ContentChild
* contentChild
= dom::ContentChild::GetSingleton();
8998 mozilla::ipc::URIParams oldURI
, newURI
;
8999 SerializeURI(aOldURI
, oldURI
);
9000 SerializeURI(aNewURI
, newURI
);
9001 contentChild
->SendCopyFavicon(oldURI
, newURI
,
9002 IPC::Principal(aLoadingPrincipal
),
9003 aInPrivateBrowsing
);
9009 nsCOMPtr
<nsIFaviconService
> favSvc
=
9010 do_GetService("@mozilla.org/browser/favicon-service;1");
9012 favSvc
->CopyFavicons(aOldURI
, aNewURI
,
9013 aInPrivateBrowsing
? nsIFaviconService::FAVICON_LOAD_PRIVATE
9014 : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE
, nullptr);
9019 class InternalLoadEvent
: public Runnable
9022 InternalLoadEvent(nsDocShell
* aDocShell
,
9024 nsIURI
* aOriginalURI
,
9025 Maybe
<nsCOMPtr
<nsIURI
>> const& aResultPrincipalURI
,
9027 nsIURI
* aReferrer
, uint32_t aReferrerPolicy
,
9028 nsIPrincipal
* aTriggeringPrincipal
,
9029 nsIPrincipal
* aPrincipalToInherit
,
9031 const char* aTypeHint
,
9032 nsIInputStream
* aPostData
,
9033 nsIInputStream
* aHeadersData
,
9035 nsISHEntry
* aSHEntry
,
9037 const nsAString
& aSrcdoc
,
9038 nsIDocShell
* aSourceDocShell
,
9040 : mozilla::Runnable("InternalLoadEvent")
9042 , mDocShell(aDocShell
)
9044 , mOriginalURI(aOriginalURI
)
9045 , mResultPrincipalURI(aResultPrincipalURI
)
9046 , mLoadReplace(aLoadReplace
)
9047 , mReferrer(aReferrer
)
9048 , mReferrerPolicy(aReferrerPolicy
)
9049 , mTriggeringPrincipal(aTriggeringPrincipal
)
9050 , mPrincipalToInherit(aPrincipalToInherit
)
9051 , mPostData(aPostData
)
9052 , mHeadersData(aHeadersData
)
9053 , mSHEntry(aSHEntry
)
9055 , mLoadType(aLoadType
)
9056 , mFirstParty(aFirstParty
)
9057 , mSourceDocShell(aSourceDocShell
)
9058 , mBaseURI(aBaseURI
)
9060 // Make sure to keep null things null as needed
9062 mTypeHint
= aTypeHint
;
9064 mTypeHint
.SetIsVoid(true);
9071 return mDocShell
->InternalLoad(mURI
, mOriginalURI
, mResultPrincipalURI
,
9075 mTriggeringPrincipal
, mPrincipalToInherit
,
9076 mFlags
, EmptyString(),
9077 mTypeHint
.IsVoid() ? nullptr
9079 VoidString(), mPostData
,
9080 mHeadersData
, mLoadType
, mSHEntry
,
9081 mFirstParty
, mSrcdoc
, mSourceDocShell
,
9087 nsCString mTypeHint
;
9090 RefPtr
<nsDocShell
> mDocShell
;
9091 nsCOMPtr
<nsIURI
> mURI
;
9092 nsCOMPtr
<nsIURI
> mOriginalURI
;
9093 Maybe
<nsCOMPtr
<nsIURI
>> mResultPrincipalURI
;
9095 nsCOMPtr
<nsIURI
> mReferrer
;
9096 uint32_t mReferrerPolicy
;
9097 nsCOMPtr
<nsIPrincipal
> mTriggeringPrincipal
;
9098 nsCOMPtr
<nsIPrincipal
> mPrincipalToInherit
;
9099 nsCOMPtr
<nsIInputStream
> mPostData
;
9100 nsCOMPtr
<nsIInputStream
> mHeadersData
;
9101 nsCOMPtr
<nsISHEntry
> mSHEntry
;
9105 nsCOMPtr
<nsIDocShell
> mSourceDocShell
;
9106 nsCOMPtr
<nsIURI
> mBaseURI
;
9110 * Returns true if we started an asynchronous load (i.e., from the network), but
9111 * the document we're loading there hasn't yet become this docshell's active
9114 * When JustStartedNetworkLoad is true, you should be careful about modifying
9115 * mLoadType and mLSHE. These are both set when the asynchronous load first
9116 * starts, and the load expects that, when it eventually runs InternalLoad,
9117 * mLoadType and mLSHE will have their original values.
9120 nsDocShell::JustStartedNetworkLoad()
9122 return mDocumentRequest
&& mDocumentRequest
!= GetCurrentDocChannel();
9126 nsDocShell::CreatePrincipalFromReferrer(nsIURI
* aReferrer
,
9127 nsIPrincipal
** aResult
)
9129 nsCOMPtr
<nsIPrincipal
> prin
=
9130 BasePrincipal::CreateCodebasePrincipal(aReferrer
, mOriginAttributes
);
9131 prin
.forget(aResult
);
9133 return *aResult
? NS_OK
: NS_ERROR_FAILURE
;
9137 nsDocShell::InternalLoad(nsIURI
* aURI
,
9138 nsIURI
* aOriginalURI
,
9139 Maybe
<nsCOMPtr
<nsIURI
>> const& aResultPrincipalURI
,
9142 uint32_t aReferrerPolicy
,
9143 nsIPrincipal
* aTriggeringPrincipal
,
9144 nsIPrincipal
* aPrincipalToInherit
,
9146 const nsAString
& aWindowTarget
,
9147 const char* aTypeHint
,
9148 const nsAString
& aFileName
,
9149 nsIInputStream
* aPostData
,
9150 nsIInputStream
* aHeadersData
,
9152 nsISHEntry
* aSHEntry
,
9154 const nsAString
& aSrcdoc
,
9155 nsIDocShell
* aSourceDocShell
,
9157 nsIDocShell
** aDocShell
,
9158 nsIRequest
** aRequest
)
9160 MOZ_ASSERT(aTriggeringPrincipal
, "need a valid TriggeringPrincipal");
9162 nsresult rv
= NS_OK
;
9163 mOriginalUriString
.Truncate();
9165 MOZ_LOG(gDocShellLeakLog
, LogLevel::Debug
,
9166 ("DOCSHELL %p InternalLoad %s\n",
9167 this, aURI
? aURI
->GetSpecOrDefault().get() : ""));
9168 // Initialize aDocShell/aRequest
9170 *aDocShell
= nullptr;
9173 *aRequest
= nullptr;
9177 return NS_ERROR_NULL_POINTER
;
9180 NS_ENSURE_TRUE(IsValidLoadType(aLoadType
), NS_ERROR_INVALID_ARG
);
9182 NS_ENSURE_TRUE(!mIsBeingDestroyed
, NS_ERROR_NOT_AVAILABLE
);
9184 rv
= EnsureScriptEnvironment();
9185 if (NS_FAILED(rv
)) {
9189 // wyciwyg urls can only be loaded through history. Any normal load of
9190 // wyciwyg through docshell is illegal. Disallow such loads.
9191 if (aLoadType
& LOAD_CMD_NORMAL
) {
9192 bool isWyciwyg
= false;
9193 rv
= aURI
->SchemeIs("wyciwyg", &isWyciwyg
);
9194 if ((isWyciwyg
&& NS_SUCCEEDED(rv
)) || NS_FAILED(rv
)) {
9195 return NS_ERROR_FAILURE
;
9199 bool isJavaScript
= false;
9200 if (NS_FAILED(aURI
->SchemeIs("javascript", &isJavaScript
))) {
9201 isJavaScript
= false;
9204 bool isTargetTopLevelDocShell
= false;
9205 nsCOMPtr
<nsIDocShell
> targetDocShell
;
9206 if (!aWindowTarget
.IsEmpty()) {
9207 // Locate the target DocShell.
9208 nsCOMPtr
<nsIDocShellTreeItem
> targetItem
;
9209 // Only _self, _parent, and _top are supported in noopener case. But we
9210 // have to be careful to not apply that to the noreferrer case. See bug
9212 bool allowNamedTarget
= !(aFlags
& INTERNAL_LOAD_FLAGS_NO_OPENER
) ||
9213 (aFlags
& INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
);
9214 if (allowNamedTarget
||
9215 aWindowTarget
.LowerCaseEqualsLiteral("_self") ||
9216 aWindowTarget
.LowerCaseEqualsLiteral("_parent") ||
9217 aWindowTarget
.LowerCaseEqualsLiteral("_top")) {
9218 rv
= FindItemWithName(aWindowTarget
, nullptr, this, false,
9219 getter_AddRefs(targetItem
));
9220 NS_ENSURE_SUCCESS(rv
, rv
);
9223 targetDocShell
= do_QueryInterface(targetItem
);
9224 if (targetDocShell
) {
9225 // If the targetDocShell and the rootDocShell are the same, then the
9226 // targetDocShell is the top level document and hence we should
9227 // consider this TYPE_DOCUMENT
9231 // 2. target="_parent", where this docshell is in the 2nd level of
9233 nsCOMPtr
<nsIDocShellTreeItem
> sameTypeRoot
;
9234 targetDocShell
->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot
));
9235 NS_ASSERTION(sameTypeRoot
,
9236 "No document shell root tree item from targetDocShell!");
9237 nsCOMPtr
<nsIDocShell
> rootShell
= do_QueryInterface(sameTypeRoot
);
9238 NS_ASSERTION(rootShell
,
9239 "No root docshell from document shell root tree item.");
9240 isTargetTopLevelDocShell
= targetDocShell
== rootShell
;
9242 // If the targetDocShell doesn't exist, then this is a new docShell
9243 // and we should consider this a TYPE_DOCUMENT load
9245 // For example, when target="_blank"
9246 isTargetTopLevelDocShell
= true;
9250 // The contentType will be INTERNAL_(I)FRAME if:
9251 // 1. This docshell is for iframe.
9252 // 2. AND aWindowTarget is not a new window, nor a top-level window.
9254 // This variable will be used when we call NS_CheckContentLoadPolicy, and
9255 // later when we call DoURILoad.
9256 uint32_t contentType
;
9257 if (IsFrame() && !isTargetTopLevelDocShell
) {
9258 nsCOMPtr
<Element
> requestingElement
=
9259 mScriptGlobal
->AsOuter()->GetFrameElementInternal();
9260 if (requestingElement
) {
9261 contentType
= requestingElement
->IsHTMLElement(nsGkAtoms::iframe
) ?
9262 nsIContentPolicy::TYPE_INTERNAL_IFRAME
: nsIContentPolicy::TYPE_INTERNAL_FRAME
;
9264 // If we have lost our frame element by now, just assume we're
9265 // an iframe since that's more common.
9266 contentType
= nsIContentPolicy::TYPE_INTERNAL_IFRAME
;
9269 contentType
= nsIContentPolicy::TYPE_DOCUMENT
;
9270 isTargetTopLevelDocShell
= true;
9273 // If there's no targetDocShell, that means we are about to create a new
9274 // window (or aWindowTarget is empty). Perform a content policy check before
9275 // creating the window. Please note for all other docshell loads
9276 // content policy checks are performed within the contentSecurityManager
9277 // when the channel is about to be openend.
9278 if (!targetDocShell
&& !aWindowTarget
.IsEmpty()) {
9279 MOZ_ASSERT(contentType
== nsIContentPolicy::TYPE_DOCUMENT
,
9280 "opening a new window requires type to be TYPE_DOCUMENT");
9282 nsISupports
* requestingContext
= nullptr;
9283 if (XRE_IsContentProcess()) {
9284 // In e10s the child process doesn't have access to the element that
9285 // contains the browsing context (because that element is in the chrome
9286 // process). So we just pass mScriptGlobal.
9287 requestingContext
= ToSupports(mScriptGlobal
);
9289 // This is for loading non-e10s tabs and toplevel windows of various
9291 // For the toplevel window cases, requestingElement will be null.
9292 nsCOMPtr
<Element
> requestingElement
=
9293 mScriptGlobal
->AsOuter()->GetFrameElementInternal();
9294 requestingContext
= requestingElement
;
9297 // Ideally we should use the same loadinfo as within DoURILoad which
9298 // should match this one when both are applicable.
9299 nsCOMPtr
<nsPIDOMWindowOuter
> loadingWindow
= mScriptGlobal
->AsOuter();
9300 nsCOMPtr
<nsILoadInfo
> secCheckLoadInfo
=
9301 new LoadInfo(loadingWindow
,
9302 aTriggeringPrincipal
,
9304 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
);
9306 // Since Content Policy checks are performed within docShell as well as
9307 // the ContentSecurityManager we need a reliable way to let certain
9308 // nsIContentPolicy consumers ignore duplicate calls.
9309 secCheckLoadInfo
->SetSkipContentPolicyCheckForWebRequest(true);
9311 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
9312 rv
= NS_CheckContentLoadPolicy(aURI
,
9314 EmptyCString(), // mime guess
9317 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
9318 if (NS_SUCCEEDED(rv
) && shouldLoad
== nsIContentPolicy::REJECT_TYPE
) {
9319 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
9322 return NS_ERROR_CONTENT_BLOCKED
;
9326 nsCOMPtr
<nsIPrincipal
> principalToInherit
= aPrincipalToInherit
;
9328 // Get a principal from the current document if necessary. Note that we only
9329 // do this for URIs that inherit a security context and local file URIs;
9330 // in particular we do NOT do this for about:blank. This way, random
9331 // about:blank loads that have no principal (which basically means they were
9332 // done by someone from chrome manually messing with our nsIWebNavigation
9333 // or by C++ setting document.location) don't get a funky principal. If
9334 // callers want something interesting to happen with the about:blank
9335 // principal in this case, they should pass aPrincipalToInherit in.
9339 // One more twist: Don't inherit the principal for external loads.
9340 if (aLoadType
!= LOAD_NORMAL_EXTERNAL
&& !principalToInherit
&&
9341 (aFlags
& INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL
) &&
9342 NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI
,
9345 principalToInherit
= GetInheritedPrincipal(true);
9349 nsIDocument
* doc
= mContentViewer
? mContentViewer
->GetDocument()
9352 const bool isDocumentAuxSandboxed
= doc
&&
9353 (doc
->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION
);
9355 if (aURI
&& mLoadURIDelegate
&&
9356 (!targetDocShell
|| targetDocShell
== static_cast<nsIDocShell
*>(this))) {
9357 // Dispatch only load requests for the current or a new window to the
9358 // delegate, e.g., to allow for GeckoView apps to handle the load event
9359 // outside of Gecko.
9360 const int where
= (aWindowTarget
.IsEmpty() || targetDocShell
)
9361 ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
9362 : nsIBrowserDOMWindow::OPEN_NEWWINDOW
;
9364 if (where
== nsIBrowserDOMWindow::OPEN_NEWWINDOW
&& isDocumentAuxSandboxed
) {
9365 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
9368 bool loadURIHandled
= false;
9369 rv
= mLoadURIDelegate
->LoadURI(aURI
, where
, aFlags
, aTriggeringPrincipal
,
9371 if (NS_SUCCEEDED(rv
) && loadURIHandled
) {
9372 // The request has been handled, nothing to do here.
9378 // Resolve the window target before going any further...
9379 // If the load has been targeted to another DocShell, then transfer the
9382 if (!aWindowTarget
.IsEmpty()) {
9383 // We've already done our owner-inheriting. Mask out that bit, so we
9384 // don't try inheriting an owner from the target window if we came up
9385 // with a null owner above.
9386 aFlags
= aFlags
& ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL
;
9388 bool isNewWindow
= false;
9389 if (!targetDocShell
) {
9390 // If the docshell's document is sandboxed, only open a new window
9391 // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
9392 // (i.e. if allow-popups is specified)
9393 NS_ENSURE_TRUE(mContentViewer
, NS_ERROR_FAILURE
);
9394 if (isDocumentAuxSandboxed
) {
9395 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
9398 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
9399 NS_ENSURE_TRUE(win
, NS_ERROR_NOT_AVAILABLE
);
9401 nsCOMPtr
<nsPIDOMWindowOuter
> newWin
;
9404 aURI
->GetSpec(spec
);
9406 // If we are a noopener load, we just hand the whole thing over to our
9408 if (aFlags
& INTERNAL_LOAD_FLAGS_NO_OPENER
) {
9409 // Various asserts that we know to hold because NO_OPENER loads can only
9410 // happen for links.
9411 MOZ_ASSERT(!aLoadReplace
);
9412 MOZ_ASSERT(aPrincipalToInherit
== aTriggeringPrincipal
);
9413 MOZ_ASSERT((aFlags
& ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED
) ==
9414 INTERNAL_LOAD_FLAGS_NO_OPENER
||
9415 (aFlags
& ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED
) ==
9416 (INTERNAL_LOAD_FLAGS_NO_OPENER
|
9417 INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
));
9418 MOZ_ASSERT(!aPostData
);
9419 MOZ_ASSERT(!aHeadersData
);
9420 // If OnLinkClickSync was invoked inside the onload handler, the load
9421 // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
9423 MOZ_ASSERT(aLoadType
== LOAD_LINK
||
9424 aLoadType
== LOAD_NORMAL_REPLACE
);
9425 MOZ_ASSERT(!aSHEntry
);
9426 MOZ_ASSERT(aFirstParty
); // Windowwatcher will assume this.
9428 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
9429 rv
= CreateLoadInfo(getter_AddRefs(loadInfo
));
9430 if (NS_FAILED(rv
)) {
9434 // Set up our loadinfo so it will do the load as much like we would have
9436 loadInfo
->SetReferrer(aReferrer
);
9437 loadInfo
->SetReferrerPolicy(aReferrerPolicy
);
9438 loadInfo
->SetSendReferrer(!(aFlags
&
9439 INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
));
9440 loadInfo
->SetOriginalURI(aOriginalURI
);
9441 SetMaybeResultPrincipalURI(loadInfo
, aResultPrincipalURI
);
9442 loadInfo
->SetLoadReplace(aLoadReplace
);
9443 loadInfo
->SetTriggeringPrincipal(aTriggeringPrincipal
);
9444 loadInfo
->SetInheritPrincipal(
9445 aFlags
& INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL
);
9446 // Explicit principal because we do not want any guesses as to what the
9447 // principal to inherit is: it should be aTriggeringPrincipal.
9448 loadInfo
->SetPrincipalIsExplicit(true);
9449 loadInfo
->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(LOAD_LINK
));
9450 loadInfo
->SetForceAllowDataURI(aFlags
& INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI
);
9452 rv
= win
->Open(NS_ConvertUTF8toUTF16(spec
),
9453 aWindowTarget
, // window name
9454 EmptyString(), // Features
9456 true, // aForceNoOpener
9457 getter_AddRefs(newWin
));
9458 MOZ_ASSERT(!newWin
);
9462 rv
= win
->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec
),
9463 aWindowTarget
, // window name
9464 EmptyString(), // Features
9465 getter_AddRefs(newWin
));
9467 // In some cases the Open call doesn't actually result in a new
9468 // window being opened. We can detect these cases by examining the
9469 // document in |newWin|, if any.
9470 nsCOMPtr
<nsPIDOMWindowOuter
> piNewWin
= do_QueryInterface(newWin
);
9472 nsCOMPtr
<nsIDocument
> newDoc
= piNewWin
->GetExtantDoc();
9473 if (!newDoc
|| newDoc
->IsInitialDocument()) {
9475 aFlags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
9479 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(newWin
);
9480 targetDocShell
= do_QueryInterface(webNav
);
9484 // Transfer the load to the target DocShell... Pass nullptr as the
9485 // window target name from to prevent recursive retargeting!
9487 if (NS_SUCCEEDED(rv
) && targetDocShell
) {
9488 rv
= targetDocShell
->InternalLoad(aURI
,
9490 aResultPrincipalURI
,
9494 aTriggeringPrincipal
,
9497 EmptyString(), // No window target
9499 VoidString(), // No forced download
9510 if (rv
== NS_ERROR_NO_CONTENT
) {
9511 // XXXbz except we never reach this code!
9514 // At this point, a new window has been created, but the
9515 // URI did not have any data associated with it...
9517 // So, the best we can do, is to tear down the new window
9518 // that was just created!
9520 if (nsCOMPtr
<nsPIDOMWindowOuter
> domWin
= targetDocShell
->GetWindow()) {
9525 // NS_ERROR_NO_CONTENT should not be returned to the
9526 // caller... This is an internal error code indicating that
9527 // the URI had no data associated with it - probably a
9528 // helper-app style protocol (ie. mailto://)
9531 } else if (isNewWindow
) {
9532 // XXX: Once new windows are created hidden, the new
9533 // window will need to be made visible... For now,
9537 if (NS_SUCCEEDED(rv
)) {
9538 // Switch to target tab if we're currently focused window.
9539 // Take loadDivertedInBackground into account so the behavior would be
9540 // the same as how the tab first opened.
9541 bool isTargetActive
= false;
9542 targetDocShell
->GetIsActive(&isTargetActive
);
9543 nsCOMPtr
<nsPIDOMWindowOuter
> domWin
= targetDocShell
->GetWindow();
9544 if (mIsActive
&& !isTargetActive
&& domWin
&&
9545 !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) {
9546 if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin
))) {
9547 return NS_ERROR_FAILURE
;
9553 // Else we ran out of memory, or were a popup and got blocked,
9560 // Load is being targetted at this docshell so return an error if the
9561 // docshell is in the process of being destroyed.
9563 if (mIsBeingDestroyed
) {
9564 return NS_ERROR_FAILURE
;
9567 NS_ENSURE_STATE(!HasUnloadedParent());
9569 rv
= CheckLoadingPermissions();
9570 if (NS_FAILED(rv
)) {
9574 if (mFiredUnloadEvent
) {
9575 if (IsOKToLoadURI(aURI
)) {
9576 MOZ_ASSERT(aWindowTarget
.IsEmpty(),
9577 "Shouldn't have a window target here!");
9579 // If this is a replace load, make whatever load triggered
9580 // the unload event also a replace load, so we don't
9581 // create extra history entries.
9582 if (LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
9583 mLoadType
= LOAD_NORMAL_REPLACE
;
9586 // Do this asynchronously
9587 nsCOMPtr
<nsIRunnable
> ev
=
9588 new InternalLoadEvent(this, aURI
, aOriginalURI
, aResultPrincipalURI
,
9589 aLoadReplace
, aReferrer
, aReferrerPolicy
,
9590 aTriggeringPrincipal
, principalToInherit
,
9591 aFlags
, aTypeHint
, aPostData
,
9592 aHeadersData
, aLoadType
, aSHEntry
, aFirstParty
,
9593 aSrcdoc
, aSourceDocShell
, aBaseURI
);
9594 return DispatchToTabGroup(TaskCategory::Other
, ev
.forget());
9597 // Just ignore this load attempt
9601 // If a source docshell has been passed, check to see if we are sandboxed
9602 // from it as the result of an iframe or CSP sandbox.
9603 if (aSourceDocShell
&& aSourceDocShell
->IsSandboxedFrom(this)) {
9604 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
9607 // If this docshell is owned by a frameloader, make sure to cancel
9608 // possible frameloader initialization before loading a new page.
9609 nsCOMPtr
<nsIDocShellTreeItem
> parent
= GetParentDocshell();
9611 nsCOMPtr
<nsIDocument
> doc
= parent
->GetDocument();
9613 doc
->TryCancelFrameLoaderInitialization(this);
9617 bool loadFromExternal
= false;
9619 // Before going any further vet loads initiated by external programs.
9620 if (aLoadType
== LOAD_NORMAL_EXTERNAL
) {
9621 loadFromExternal
= true;
9622 // Disallow external chrome: loads targetted at content windows
9623 bool isChrome
= false;
9624 if (NS_SUCCEEDED(aURI
->SchemeIs("chrome", &isChrome
)) && isChrome
) {
9625 NS_WARNING("blocked external chrome: url -- use '--chrome' option");
9626 return NS_ERROR_FAILURE
;
9629 // clear the decks to prevent context bleed-through (bug 298255)
9630 rv
= CreateAboutBlankContentViewer(nullptr, nullptr);
9631 if (NS_FAILED(rv
)) {
9632 return NS_ERROR_FAILURE
;
9635 // reset loadType so we don't have to add lots of tests for
9636 // LOAD_NORMAL_EXTERNAL after this point
9637 aLoadType
= LOAD_NORMAL
;
9640 mAllowKeywordFixup
=
9641 (aFlags
& INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) != 0;
9642 mURIResultedInDocument
= false; // reset the clock...
9644 if (aLoadType
== LOAD_NORMAL
||
9645 aLoadType
== LOAD_STOP_CONTENT
||
9646 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) ||
9647 aLoadType
== LOAD_HISTORY
||
9648 aLoadType
== LOAD_LINK
) {
9649 nsCOMPtr
<nsIURI
> currentURI
= mCurrentURI
;
9651 nsAutoCString curHash
, newHash
;
9652 bool curURIHasRef
= false, newURIHasRef
= false;
9654 nsresult rvURINew
= aURI
->GetRef(newHash
);
9655 if (NS_SUCCEEDED(rvURINew
)) {
9656 rvURINew
= aURI
->GetHasRef(&newURIHasRef
);
9659 bool sameExceptHashes
= false;
9660 if (currentURI
&& NS_SUCCEEDED(rvURINew
)) {
9661 nsresult rvURIOld
= currentURI
->GetRef(curHash
);
9662 if (NS_SUCCEEDED(rvURIOld
)) {
9663 rvURIOld
= currentURI
->GetHasRef(&curURIHasRef
);
9665 if (NS_SUCCEEDED(rvURIOld
)) {
9666 if (NS_FAILED(currentURI
->EqualsExceptRef(aURI
, &sameExceptHashes
))) {
9667 sameExceptHashes
= false;
9672 if (!sameExceptHashes
&& sURIFixup
&& currentURI
&&
9673 NS_SUCCEEDED(rvURINew
)) {
9674 // Maybe aURI came from the exposable form of currentURI?
9675 nsCOMPtr
<nsIURI
> currentExposableURI
;
9676 rv
= sURIFixup
->CreateExposableURI(currentURI
,
9677 getter_AddRefs(currentExposableURI
));
9678 NS_ENSURE_SUCCESS(rv
, rv
);
9679 nsresult rvURIOld
= currentExposableURI
->GetRef(curHash
);
9680 if (NS_SUCCEEDED(rvURIOld
)) {
9681 rvURIOld
= currentExposableURI
->GetHasRef(&curURIHasRef
);
9683 if (NS_SUCCEEDED(rvURIOld
)) {
9684 if (NS_FAILED(currentExposableURI
->EqualsExceptRef(aURI
, &sameExceptHashes
))) {
9685 sameExceptHashes
= false;
9690 bool historyNavBetweenSameDoc
= false;
9691 if (mOSHE
&& aSHEntry
) {
9692 // We're doing a history load.
9694 mOSHE
->SharesDocumentWith(aSHEntry
, &historyNavBetweenSameDoc
);
9697 if (historyNavBetweenSameDoc
) {
9698 nsCOMPtr
<nsIInputStream
> currentPostData
;
9699 mOSHE
->GetPostData(getter_AddRefs(currentPostData
));
9700 NS_ASSERTION(currentPostData
== aPostData
,
9701 "Different POST data for entries for the same page?");
9706 // A short-circuited load happens when we navigate between two SHEntries
9707 // for the same document. We do a short-circuited load under two
9708 // circumstances. Either
9710 // a) we're navigating between two different SHEntries which share a
9713 // b) we're navigating to a new shentry whose URI differs from the
9714 // current URI only in its hash, the new hash is non-empty, and
9715 // we're not doing a POST.
9717 // The restriction tha the SHEntries in (a) must be different ensures
9718 // that history.go(0) and the like trigger full refreshes, rather than
9719 // short-circuited loads.
9720 bool doShortCircuitedLoad
=
9721 (historyNavBetweenSameDoc
&& mOSHE
!= aSHEntry
) ||
9722 (!aSHEntry
&& !aPostData
&&
9723 sameExceptHashes
&& newURIHasRef
);
9725 if (doShortCircuitedLoad
) {
9726 // Save the position of the scrollers.
9727 nscoord cx
= 0, cy
= 0;
9728 GetCurScrollPos(ScrollOrientation_X
, &cx
);
9729 GetCurScrollPos(ScrollOrientation_Y
, &cy
);
9731 // Reset mLoadType to its original value once we exit this block,
9732 // because this short-circuited load might have started after a
9733 // normal, network load, and we don't want to clobber its load type.
9735 AutoRestore
<uint32_t> loadTypeResetter(mLoadType
);
9737 // If a non-short-circuit load (i.e., a network load) is pending,
9738 // make this a replacement load, so that we don't add a SHEntry here
9739 // and the network load goes into the SHEntry it expects to.
9740 if (JustStartedNetworkLoad() && (aLoadType
& LOAD_CMD_NORMAL
)) {
9741 mLoadType
= LOAD_NORMAL_REPLACE
;
9743 mLoadType
= aLoadType
;
9746 mURIResultedInDocument
= true;
9748 nsCOMPtr
<nsISHEntry
> oldLSHE
= mLSHE
;
9750 /* we need to assign mLSHE to aSHEntry right here, so that on History
9751 * loads, SetCurrentURI() called from OnNewURI() will send proper
9752 * onLocationChange() notifications to the browser to update
9753 * back/forward buttons.
9755 SetHistoryEntry(&mLSHE
, aSHEntry
);
9757 // Set the doc's URI according to the new history entry's URI.
9758 nsCOMPtr
<nsIDocument
> doc
= GetDocument();
9759 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
9760 doc
->SetDocumentURI(aURI
);
9762 /* This is a anchor traversal with in the same page.
9763 * call OnNewURI() so that, this traversal will be
9764 * recorded in session and global history.
9766 nsCOMPtr
<nsIPrincipal
> newURITriggeringPrincipal
, newURIPrincipalToInherit
;
9768 mOSHE
->GetTriggeringPrincipal(getter_AddRefs(newURITriggeringPrincipal
));
9769 mOSHE
->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit
));
9771 newURITriggeringPrincipal
= aTriggeringPrincipal
;
9772 newURIPrincipalToInherit
= doc
->NodePrincipal();
9774 // Pass true for aCloneSHChildren, since we're not
9775 // changing documents here, so all of our subframes are
9776 // still relevant to the new session history entry.
9778 // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
9779 // flag on firing onLocationChange(...).
9780 // Anyway, aCloneSHChildren param is simply reflecting
9781 // doShortCircuitedLoad in this scope.
9782 OnNewURI(aURI
, nullptr, newURITriggeringPrincipal
, newURIPrincipalToInherit
,
9783 mLoadType
, true, true, true);
9785 nsCOMPtr
<nsIInputStream
> postData
;
9786 uint32_t cacheKey
= 0;
9788 bool scrollRestorationIsManual
= false;
9790 /* save current position of scroller(s) (bug 59774) */
9791 mOSHE
->SetScrollPosition(cx
, cy
);
9792 mOSHE
->GetScrollRestorationIsManual(&scrollRestorationIsManual
);
9793 // Get the postdata and page ident from the current page, if
9794 // the new load is being done via normal means. Note that
9795 // "normal means" can be checked for just by checking for
9796 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
9797 // above -- it filters out some LOAD_CMD_NORMAL cases that we
9798 // wouldn't want here.
9799 if (aLoadType
& LOAD_CMD_NORMAL
) {
9800 mOSHE
->GetPostData(getter_AddRefs(postData
));
9801 mOSHE
->GetCacheKey(&cacheKey
);
9803 // Link our new SHEntry to the old SHEntry's back/forward
9804 // cache data, since the two SHEntries correspond to the
9808 // If we're not doing a history load, scroll restoration
9809 // should be inherited from the previous session history entry.
9810 mLSHE
->SetScrollRestorationIsManual(scrollRestorationIsManual
);
9812 mLSHE
->AdoptBFCacheEntry(mOSHE
);
9817 // If we're doing a history load, use its scroll restoration state.
9819 aSHEntry
->GetScrollRestorationIsManual(&scrollRestorationIsManual
);
9822 /* Assign mOSHE to mLSHE. This will either be a new entry created
9823 * by OnNewURI() for normal loads or aSHEntry for history loads.
9826 SetHistoryEntry(&mOSHE
, mLSHE
);
9827 // Save the postData obtained from the previous page
9828 // in to the session history entry created for the
9829 // anchor page, so that any history load of the anchor
9830 // page will restore the appropriate postData.
9832 mOSHE
->SetPostData(postData
);
9835 // Make sure we won't just repost without hitting the
9837 if (cacheKey
!= 0) {
9838 mOSHE
->SetCacheKey(cacheKey
);
9842 /* Restore the original LSHE if we were loading something
9843 * while short-circuited load was initiated.
9845 SetHistoryEntry(&mLSHE
, oldLSHE
);
9846 /* Set the title for the SH entry for this target url. so that
9847 * SH menus in go/back/forward buttons won't be empty for this.
9849 if (mSessionHistory
) {
9850 int32_t index
= mSessionHistory
->Index();
9851 nsCOMPtr
<nsISHEntry
> shEntry
;
9852 mSessionHistory
->LegacySHistory()->GetEntryAtIndex(
9853 index
, false, getter_AddRefs(shEntry
));
9854 NS_ENSURE_TRUE(shEntry
, NS_ERROR_FAILURE
);
9855 shEntry
->SetTitle(mTitle
);
9858 /* Set the title for the Global History entry for this anchor url.
9860 UpdateGlobalHistoryTitle(aURI
);
9862 SetDocCurrentStateObj(mOSHE
);
9864 // Inform the favicon service that the favicon for oldURI also
9866 CopyFavicon(currentURI
, aURI
, doc
->NodePrincipal(), UsePrivateBrowsing());
9868 RefPtr
<nsGlobalWindowOuter
> scriptGlobal
= mScriptGlobal
;
9869 RefPtr
<nsGlobalWindowInner
> win
= scriptGlobal
?
9870 scriptGlobal
->GetCurrentInnerWindowInternal() : nullptr;
9872 // ScrollToAnchor doesn't necessarily cause us to scroll the window;
9873 // the function decides whether a scroll is appropriate based on the
9874 // arguments it receives. But even if we don't end up scrolling,
9875 // ScrollToAnchor performs other important tasks, such as informing
9876 // the presShell that we have a new hash. See bug 680257.
9877 rv
= ScrollToAnchor(curURIHasRef
, newURIHasRef
, newHash
, aLoadType
);
9878 NS_ENSURE_SUCCESS(rv
, rv
);
9880 /* restore previous position of scroller(s), if we're moving
9881 * back in history (bug 59774)
9885 bool needsScrollPosUpdate
= false;
9886 if (mOSHE
&& (aLoadType
== LOAD_HISTORY
||
9887 aLoadType
== LOAD_RELOAD_NORMAL
) &&
9888 !scrollRestorationIsManual
) {
9889 needsScrollPosUpdate
= true;
9890 mOSHE
->GetScrollPosition(&bx
, &by
);
9893 // Dispatch the popstate and hashchange events, as appropriate.
9895 // The event dispatch below can cause us to re-enter script and
9896 // destroy the docshell, nulling out mScriptGlobal. Hold a stack
9897 // reference to avoid null derefs. See bug 914521.
9899 // Fire a hashchange event URIs differ, and only in their hashes.
9900 bool doHashchange
= sameExceptHashes
&&
9901 (curURIHasRef
!= newURIHasRef
|| !curHash
.Equals(newHash
));
9903 if (historyNavBetweenSameDoc
|| doHashchange
) {
9904 win
->DispatchSyncPopState();
9907 if (needsScrollPosUpdate
&& win
->AsInner()->HasActiveDocument()) {
9908 SetCurScrollPosEx(bx
, by
);
9912 // Note that currentURI hasn't changed because it's on the
9913 // stack, so we can just use it directly as the old URI.
9914 win
->DispatchAsyncHashchange(currentURI
, aURI
);
9922 // mContentViewer->PermitUnload can destroy |this| docShell, which
9923 // causes the next call of CanSavePresentation to crash.
9924 // Hold onto |this| until we return, to prevent a crash from happening.
9926 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
9928 // Don't init timing for javascript:, since it generally doesn't
9929 // actually start a load or anything. If it does, we'll init
9930 // timing then, from OnStateChange.
9932 // XXXbz mTiming should know what channel it's for, so we don't
9933 // need this hackery.
9934 bool toBeReset
= false;
9935 if (!isJavaScript
) {
9936 toBeReset
= MaybeInitTiming();
9938 bool timeBeforeUnload
= aFileName
.IsVoid();
9939 if (mTiming
&& timeBeforeUnload
) {
9940 mTiming
->NotifyBeforeUnload();
9942 // Check if the page doesn't want to be unloaded. The javascript:
9943 // protocol handler deals with this for javascript: URLs.
9944 if (!isJavaScript
&& aFileName
.IsVoid() && mContentViewer
) {
9946 rv
= mContentViewer
->PermitUnload(&okToUnload
);
9948 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
9949 // The user chose not to unload the page, interrupt the
9951 MaybeResetInitTiming(toBeReset
);
9956 if (mTiming
&& timeBeforeUnload
) {
9957 mTiming
->NotifyUnloadAccepted(mCurrentURI
);
9960 // Check if the webbrowser chrome wants the load to proceed; this can be
9961 // used to cancel attempts to load URIs in the wrong process.
9962 nsCOMPtr
<nsIWebBrowserChrome3
> browserChrome3
= do_GetInterface(mTreeOwner
);
9963 if (browserChrome3
) {
9965 rv
= browserChrome3
->ShouldLoadURI(this, aURI
, aReferrer
, !!aPostData
,
9966 aTriggeringPrincipal
, &shouldLoad
);
9967 if (NS_SUCCEEDED(rv
) && !shouldLoad
) {
9972 // Whenever a top-level browsing context is navigated, the user agent MUST
9973 // lock the orientation of the document to the document's default
9974 // orientation. We don't explicitly check for a top-level browsing context
9975 // here because orientation is only set on top-level browsing contexts.
9976 if (OrientationLock() != eScreenOrientation_None
) {
9978 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
9979 GetSameTypeParent(getter_AddRefs(parent
));
9980 MOZ_ASSERT(!parent
);
9982 SetOrientationLock(eScreenOrientation_None
);
9984 ScreenOrientation::UpdateActiveOrientationLock(eScreenOrientation_None
);
9988 // Check for saving the presentation here, before calling Stop().
9989 // This is necessary so that we can catch any pending requests.
9990 // Since the new request has not been created yet, we pass null for the
9991 // new request parameter.
9992 // Also pass nullptr for the document, since it doesn't affect the return
9993 // value for our purposes here.
9994 bool savePresentation
= CanSavePresentation(aLoadType
, nullptr, nullptr);
9996 // Don't stop current network activity for javascript: URL's since
9997 // they might not result in any data, and thus nothing should be
9998 // stopped in those cases. In the case where they do result in
9999 // data, the javascript: URL channel takes care of stopping
10000 // current network activity.
10001 if (!isJavaScript
&& aFileName
.IsVoid()) {
10002 // Stop any current network activity.
10003 // Also stop content if this is a zombie doc. otherwise
10004 // the onload will be delayed by other loads initiated in the
10005 // background by the first document that
10006 // didn't fully load before the next load was initiated.
10007 // If not a zombie, don't stop content until data
10008 // starts arriving from the new URI...
10010 nsCOMPtr
<nsIContentViewer
> zombieViewer
;
10011 if (mContentViewer
) {
10012 mContentViewer
->GetPreviousViewer(getter_AddRefs(zombieViewer
));
10015 if (zombieViewer
||
10016 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_STOP_CONTENT
)) {
10017 rv
= Stop(nsIWebNavigation::STOP_ALL
);
10019 rv
= Stop(nsIWebNavigation::STOP_NETWORK
);
10022 if (NS_FAILED(rv
)) {
10027 mLoadType
= aLoadType
;
10029 // mLSHE should be assigned to aSHEntry, only after Stop() has
10030 // been called. But when loading an error page, do not clear the
10031 // mLSHE for the real page.
10032 if (mLoadType
!= LOAD_ERROR_PAGE
) {
10033 SetHistoryEntry(&mLSHE
, aSHEntry
);
10035 // We're making history navigation or a reload. Make sure our history ID
10036 // points to the same ID as SHEntry's docshell ID.
10037 mHistoryID
= aSHEntry
->DocshellID();
10041 mSavingOldViewer
= savePresentation
;
10043 // If we have a saved content viewer in history, restore and show it now.
10044 if (aSHEntry
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
10045 // It's possible that the previous viewer of mContentViewer is the
10046 // viewer that will end up in aSHEntry when it gets closed. If that's
10047 // the case, we need to go ahead and force it into its shentry so we
10049 if (mContentViewer
) {
10050 nsCOMPtr
<nsIContentViewer
> prevViewer
;
10051 mContentViewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
10054 nsCOMPtr
<nsIContentViewer
> prevPrevViewer
;
10055 prevViewer
->GetPreviousViewer(getter_AddRefs(prevPrevViewer
));
10056 NS_ASSERTION(!prevPrevViewer
, "Should never have viewer chain here");
10058 nsCOMPtr
<nsISHEntry
> viewerEntry
;
10059 prevViewer
->GetHistoryEntry(getter_AddRefs(viewerEntry
));
10060 if (viewerEntry
== aSHEntry
) {
10061 // Make sure this viewer ends up in the right place
10062 mContentViewer
->SetPreviousViewer(nullptr);
10063 prevViewer
->Destroy();
10067 nsCOMPtr
<nsISHEntry
> oldEntry
= mOSHE
;
10069 rv
= RestorePresentation(aSHEntry
, &restoring
);
10074 // We failed to restore the presentation, so clean up.
10075 // Both the old and new history entries could potentially be in
10076 // an inconsistent state.
10077 if (NS_FAILED(rv
)) {
10079 oldEntry
->SyncPresentationState();
10082 aSHEntry
->SyncPresentationState();
10086 nsAutoString srcdoc
;
10087 if (aFlags
& INTERNAL_LOAD_FLAGS_IS_SRCDOC
) {
10090 srcdoc
= VoidString();
10093 bool isTopLevelDoc
= mItemType
== typeContent
&&
10094 (isTargetTopLevelDocShell
||
10095 GetIsMozBrowser());
10097 OriginAttributes attrs
= GetOriginAttributes();
10098 attrs
.SetFirstPartyDomain(isTopLevelDoc
, aURI
);
10100 PredictorLearn(aURI
, nullptr,
10101 nsINetworkPredictor::LEARN_LOAD_TOPLEVEL
, attrs
);
10102 PredictorPredict(aURI
, nullptr,
10103 nsINetworkPredictor::PREDICT_LOAD
, attrs
, nullptr);
10105 nsCOMPtr
<nsIRequest
> req
;
10106 rv
= DoURILoad(aURI
, aOriginalURI
, aResultPrincipalURI
, aLoadReplace
,
10108 (aFlags
& INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI
),
10109 (aFlags
& INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC
),
10111 !(aFlags
& INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
),
10113 aTriggeringPrincipal
, principalToInherit
, aTypeHint
,
10114 aFileName
, aPostData
, aHeadersData
,
10115 aFirstParty
, aDocShell
, getter_AddRefs(req
),
10116 (aFlags
& INTERNAL_LOAD_FLAGS_FIRST_LOAD
) != 0,
10117 (aFlags
& INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
) != 0,
10118 (aFlags
& INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
) != 0,
10119 srcdoc
, aBaseURI
, contentType
);
10120 if (req
&& aRequest
) {
10121 NS_ADDREF(*aRequest
= req
);
10124 if (NS_FAILED(rv
)) {
10125 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(req
));
10126 if (DisplayLoadError(rv
, aURI
, nullptr, chan
) &&
10127 (aFlags
& LOAD_FLAGS_ERROR_LOAD_CHANGES_RV
) != 0) {
10128 return NS_ERROR_LOAD_SHOWED_ERRORPAGE
;
10136 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument
)
10138 nsCOMPtr
<nsIDocument
> document
;
10139 bool inheritedFromCurrent
= false;
10141 if (aConsiderCurrentDocument
&& mContentViewer
) {
10142 document
= mContentViewer
->GetDocument();
10143 inheritedFromCurrent
= true;
10147 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
10148 GetSameTypeParent(getter_AddRefs(parentItem
));
10150 document
= parentItem
->GetDocument();
10155 if (!aConsiderCurrentDocument
) {
10159 // Make sure we end up with _something_ as the principal no matter
10160 // what.If this fails, we'll just get a null docViewer and bail.
10161 EnsureContentViewer();
10162 if (!mContentViewer
) {
10165 document
= mContentViewer
->GetDocument();
10168 //-- Get the document's principal
10170 nsIPrincipal
* docPrincipal
= document
->NodePrincipal();
10172 // Don't allow loads in typeContent docShells to inherit the system
10173 // principal from existing documents.
10174 if (inheritedFromCurrent
&&
10175 mItemType
== typeContent
&&
10176 nsContentUtils::IsSystemPrincipal(docPrincipal
)) {
10180 return docPrincipal
;
10186 // CSPs upgrade-insecure-requests directive applies to same origin top level
10187 // navigations. Using the SOP would return false for the case when an https
10188 // page triggers and http page to load, even though that http page would be
10189 // upgraded to https later. Hence we have to use that custom function instead
10190 // of simply calling aTriggeringPrincipal->Equals(aResultPrincipal).
10192 IsConsideredSameOriginForUIR(nsIPrincipal
* aTriggeringPrincipal
,
10193 nsIPrincipal
* aResultPrincipal
)
10195 MOZ_ASSERT(aTriggeringPrincipal
);
10196 MOZ_ASSERT(aResultPrincipal
);
10198 // we only have to make sure that the following truth table holds:
10199 // aTriggeringPrincipal | aResultPrincipal | Result
10200 // ----------------------------------------------------------------
10201 // http://example.com/foo.html | http://example.com/bar.html | true
10202 // https://example.com/foo.html | https://example.com/bar.html | true
10203 // https://example.com/foo.html | http://example.com/bar.html | true
10204 if (aTriggeringPrincipal
->Equals(aResultPrincipal
)) {
10208 if (!aResultPrincipal
->GetIsCodebasePrincipal()) {
10212 nsCOMPtr
<nsIURI
> resultURI
;
10213 nsresult rv
= aResultPrincipal
->GetURI(getter_AddRefs(resultURI
));
10214 NS_ENSURE_SUCCESS(rv
, false);
10216 nsAutoCString resultScheme
;
10217 rv
= resultURI
->GetScheme(resultScheme
);
10218 NS_ENSURE_SUCCESS(rv
, false);
10219 if (!resultScheme
.EqualsLiteral("http")) {
10223 nsAutoCString tmpResultSpec
;
10224 rv
= resultURI
->GetSpec(tmpResultSpec
);
10225 NS_ENSURE_SUCCESS(rv
, false);
10226 // replace http with https
10227 tmpResultSpec
.ReplaceLiteral(0, 4, "https");
10229 nsCOMPtr
<nsIURI
> tmpResultURI
;
10230 rv
= NS_NewURI(getter_AddRefs(tmpResultURI
), tmpResultSpec
);
10231 NS_ENSURE_SUCCESS(rv
, false);
10233 mozilla::OriginAttributes tmpOA
=
10234 BasePrincipal::Cast(aResultPrincipal
)->OriginAttributesRef();
10236 nsCOMPtr
<nsIPrincipal
> tmpResultPrincipal
=
10237 BasePrincipal::CreateCodebasePrincipal(tmpResultURI
, tmpOA
);
10239 return aTriggeringPrincipal
->Equals(tmpResultPrincipal
);
10243 nsDocShell::DoURILoad(nsIURI
* aURI
,
10244 nsIURI
* aOriginalURI
,
10245 Maybe
<nsCOMPtr
<nsIURI
>> const& aResultPrincipalURI
,
10247 bool aLoadFromExternal
,
10248 bool aForceAllowDataURI
,
10249 bool aOriginalFrameSrc
,
10250 nsIURI
* aReferrerURI
,
10251 bool aSendReferrer
,
10252 uint32_t aReferrerPolicy
,
10253 nsIPrincipal
* aTriggeringPrincipal
,
10254 nsIPrincipal
* aPrincipalToInherit
,
10255 const char* aTypeHint
,
10256 const nsAString
& aFileName
,
10257 nsIInputStream
* aPostData
,
10258 nsIInputStream
* aHeadersData
,
10260 nsIDocShell
** aDocShell
,
10261 nsIRequest
** aRequest
,
10262 bool aIsNewWindowTarget
,
10263 bool aBypassClassifier
,
10264 bool aForceAllowCookies
,
10265 const nsAString
& aSrcdoc
,
10267 nsContentPolicyType aContentPolicyType
)
10269 // Double-check that we're still around to load this URI.
10270 if (mIsBeingDestroyed
) {
10271 // Return NS_OK despite not doing anything to avoid throwing exceptions from
10272 // nsLocation::SetHref if the unload handler of the existing page tears us
10278 nsCOMPtr
<nsIURILoader
> uriLoader
= do_GetService(NS_URI_LOADER_CONTRACTID
, &rv
);
10279 if (NS_FAILED(rv
)) {
10285 MOZ_ASSERT(aContentPolicyType
== nsIContentPolicy::TYPE_INTERNAL_IFRAME
||
10286 aContentPolicyType
== nsIContentPolicy::TYPE_INTERNAL_FRAME
,
10287 "DoURILoad thinks this is a frame and InternalLoad does not");
10289 // Only allow view-source scheme in top-level docshells. view-source is
10290 // the only scheme to which this applies at the moment due to potential
10291 // timing attacks to read data from cross-origin iframes. If this widens
10292 // we should add a protocol flag for whether the scheme is allowed in
10293 // frames and use something like nsNetUtil::NS_URIChainHasFlags.
10294 nsCOMPtr
<nsIURI
> tempURI
= aURI
;
10295 nsCOMPtr
<nsINestedURI
> nestedURI
= do_QueryInterface(tempURI
);
10296 while (nestedURI
) {
10297 // view-source should always be an nsINestedURI, loop and check the
10298 // scheme on this and all inner URIs that are also nested URIs.
10299 bool isViewSource
= false;
10300 rv
= tempURI
->SchemeIs("view-source", &isViewSource
);
10301 if (NS_FAILED(rv
) || isViewSource
) {
10302 return NS_ERROR_UNKNOWN_PROTOCOL
;
10304 nestedURI
->GetInnerURI(getter_AddRefs(tempURI
));
10305 nestedURI
= do_QueryInterface(tempURI
);
10308 MOZ_ASSERT(aContentPolicyType
== nsIContentPolicy::TYPE_DOCUMENT
,
10309 "DoURILoad thinks this is a document and InternalLoad does not");
10312 // open a channel for the url
10313 nsCOMPtr
<nsIChannel
> channel
;
10315 bool isSrcdoc
= !aSrcdoc
.IsVoid();
10317 // There are two cases we care about:
10318 // * Top-level load: In this case, loadingNode is null, but loadingWindow
10319 // is our mScriptGlobal. We pass null for loadingPrincipal in this case.
10320 // * Subframe load: loadingWindow is null, but loadingNode is the frame
10321 // element for the load. loadingPrincipal is the NodePrincipal of the frame
10323 nsCOMPtr
<nsINode
> loadingNode
;
10324 nsCOMPtr
<nsPIDOMWindowOuter
> loadingWindow
;
10325 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
;
10326 nsCOMPtr
<nsISupports
> topLevelLoadingContext
;
10328 if (aContentPolicyType
== nsIContentPolicy::TYPE_DOCUMENT
) {
10329 loadingNode
= nullptr;
10330 loadingPrincipal
= nullptr;
10331 loadingWindow
= mScriptGlobal
->AsOuter();
10332 if (XRE_IsContentProcess()) {
10333 // In e10s the child process doesn't have access to the element that
10334 // contains the browsing context (because that element is in the chrome
10336 nsCOMPtr
<nsITabChild
> tabChild
= GetTabChild();
10337 topLevelLoadingContext
= ToSupports(tabChild
);
10339 // This is for loading non-e10s tabs and toplevel windows of various
10341 // For the toplevel window cases, requestingElement will be null.
10342 nsCOMPtr
<Element
> requestingElement
=
10343 loadingWindow
->GetFrameElementInternal();
10344 topLevelLoadingContext
= requestingElement
;
10347 loadingWindow
= nullptr;
10348 loadingNode
= mScriptGlobal
->AsOuter()->GetFrameElementInternal();
10350 // If we have a loading node, then use that as our loadingPrincipal.
10351 loadingPrincipal
= loadingNode
->NodePrincipal();
10353 // Get the docshell type for requestingElement.
10354 nsCOMPtr
<nsIDocument
> requestingDoc
= loadingNode
->OwnerDoc();
10355 nsCOMPtr
<nsIDocShell
> elementDocShell
= requestingDoc
->GetDocShell();
10356 // requestingElement docshell type = current docshell type.
10357 MOZ_ASSERT(mItemType
== elementDocShell
->ItemType(),
10358 "subframes should have the same docshell type as their parent");
10361 // If this isn't a top-level load and mScriptGlobal's frame element is
10362 // null, then the element got removed from the DOM while we were trying
10363 // to load this resource. This docshell is scheduled for destruction
10364 // already, so bail out here.
10369 // Getting the right triggeringPrincipal needs to be updated and is only
10370 // ready for use once bug 1182569 landed. Until then, we cannot rely on
10371 // the triggeringPrincipal for TYPE_DOCUMENT loads.
10372 MOZ_ASSERT(aTriggeringPrincipal
, "Need a valid triggeringPrincipal");
10374 bool isSandBoxed
= mSandboxFlags
& SANDBOXED_ORIGIN
;
10376 // We want to inherit aPrincipalToInherit when:
10377 // 1. ChannelShouldInheritPrincipal returns true.
10378 // 2. aURI is not data: URI, or data: URI is not configured as unique opaque
10380 bool inheritAttrs
= false, inheritPrincipal
= false;
10382 if (aPrincipalToInherit
) {
10383 inheritAttrs
= nsContentUtils::ChannelShouldInheritPrincipal(
10384 aPrincipalToInherit
,
10386 true, // aInheritForAboutBlank
10390 bool isURIUniqueOrigin
= nsIOService::IsDataURIUniqueOpaqueOrigin() &&
10391 NS_SUCCEEDED(aURI
->SchemeIs("data", &isData
)) &&
10393 inheritPrincipal
= inheritAttrs
&& !isURIUniqueOrigin
;
10396 nsLoadFlags loadFlags
= mDefaultLoadFlags
;
10397 nsSecurityFlags securityFlags
=
10398 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
;
10401 // tag first party URL loads
10402 loadFlags
|= nsIChannel::LOAD_INITIAL_DOCUMENT_URI
;
10405 if (mLoadType
== LOAD_ERROR_PAGE
) {
10406 // Error pages are LOAD_BACKGROUND
10407 loadFlags
|= nsIChannel::LOAD_BACKGROUND
;
10408 securityFlags
|= nsILoadInfo::SEC_LOAD_ERROR_PAGE
;
10411 if (inheritPrincipal
) {
10412 securityFlags
|= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL
;
10415 securityFlags
|= nsILoadInfo::SEC_SANDBOXED
;
10418 nsCOMPtr
<nsILoadInfo
> loadInfo
=
10419 (aContentPolicyType
== nsIContentPolicy::TYPE_DOCUMENT
) ?
10420 new LoadInfo(loadingWindow
, aTriggeringPrincipal
, topLevelLoadingContext
,
10422 new LoadInfo(loadingPrincipal
, aTriggeringPrincipal
, loadingNode
,
10423 securityFlags
, aContentPolicyType
);
10425 if (aPrincipalToInherit
) {
10426 loadInfo
->SetPrincipalToInherit(aPrincipalToInherit
);
10428 loadInfo
->SetLoadTriggeredFromExternal(aLoadFromExternal
);
10429 loadInfo
->SetForceAllowDataURI(aForceAllowDataURI
);
10430 loadInfo
->SetOriginalFrameSrcLoad(aOriginalFrameSrc
);
10432 // We have to do this in case our OriginAttributes are different from the
10433 // OriginAttributes of the parent document. Or in case there isn't a
10434 // parent document.
10435 bool isTopLevelDoc
= mItemType
== typeContent
&&
10436 (aContentPolicyType
== nsIContentPolicy::TYPE_DOCUMENT
||
10437 GetIsMozBrowser());
10439 OriginAttributes attrs
;
10441 // Inherit origin attributes from aPrincipalToInherit if inheritAttrs is true.
10442 // Otherwise we just use the origin attributes from docshell.
10443 if (inheritAttrs
) {
10444 MOZ_ASSERT(aPrincipalToInherit
, "We should have aPrincipalToInherit here.");
10445 attrs
= aPrincipalToInherit
->OriginAttributesRef();
10446 // If firstPartyIsolation is not enabled, then PrincipalToInherit should
10447 // have the same origin attributes with docshell.
10448 MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(), attrs
== GetOriginAttributes());
10450 attrs
= GetOriginAttributes();
10451 attrs
.SetFirstPartyDomain(isTopLevelDoc
, aURI
);
10454 rv
= loadInfo
->SetOriginAttributes(attrs
);
10455 if (NS_WARN_IF(NS_FAILED(rv
))) {
10459 // Document loads should set the reload flag on the channel so that it
10460 // can be exposed on the service worker FetchEvent.
10461 rv
= loadInfo
->SetIsDocshellReload(mLoadType
& LOAD_CMD_RELOAD
);
10462 NS_ENSURE_SUCCESS(rv
, rv
);
10465 rv
= NS_NewChannelInternal(getter_AddRefs(channel
),
10468 nullptr, // PerformanceStorage
10469 nullptr, // loadGroup
10470 static_cast<nsIInterfaceRequestor
*>(this),
10473 if (NS_FAILED(rv
)) {
10474 if (rv
== NS_ERROR_UNKNOWN_PROTOCOL
) {
10475 // This is a uri with a protocol scheme we don't know how
10476 // to handle. Embedders might still be interested in
10477 // handling the load, though, so we fire a notification
10478 // before throwing the load away.
10479 bool abort
= false;
10480 nsresult rv2
= mContentListener
->OnStartURIOpen(aURI
, &abort
);
10481 if (NS_SUCCEEDED(rv2
) && abort
) {
10482 // Hey, they're handling the load for us! How convenient!
10490 nsCOMPtr
<nsIViewSourceChannel
> vsc
= do_QueryInterface(channel
);
10492 rv
= vsc
->SetBaseURI(aBaseURI
);
10493 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10497 nsAutoCString scheme
;
10498 rv
= aURI
->GetScheme(scheme
);
10499 NS_ENSURE_SUCCESS(rv
, rv
);
10501 aURI
->SchemeIs("view-source", &isViewSource
);
10503 if (isViewSource
) {
10504 nsViewSourceHandler
* vsh
= nsViewSourceHandler::GetInstance();
10505 NS_ENSURE_TRUE(vsh
, NS_ERROR_FAILURE
);
10507 rv
= vsh
->NewSrcdocChannel(aURI
, aBaseURI
, aSrcdoc
,
10508 loadInfo
, getter_AddRefs(channel
));
10510 rv
= NS_NewInputStreamChannelInternal(getter_AddRefs(channel
),
10513 NS_LITERAL_CSTRING("text/html"),
10516 NS_ENSURE_SUCCESS(rv
, rv
);
10517 nsCOMPtr
<nsIInputStreamChannel
> isc
= do_QueryInterface(channel
);
10519 isc
->SetBaseURI(aBaseURI
);
10523 // Navigational requests that are same origin need to be upgraded in case
10524 // upgrade-insecure-requests is present. Please note that in that case
10525 // the triggeringPrincipal is holding the CSP that potentially
10526 // holds upgrade-insecure-requests.
10527 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
10528 aTriggeringPrincipal
->GetCsp(getter_AddRefs(csp
));
10530 bool upgradeInsecureRequests
= false;
10531 csp
->GetUpgradeInsecureRequests(&upgradeInsecureRequests
);
10532 if (upgradeInsecureRequests
) {
10533 // only upgrade if the navigation is same origin
10534 nsCOMPtr
<nsIPrincipal
> resultPrincipal
;
10535 rv
= nsContentUtils::GetSecurityManager()->
10536 GetChannelResultPrincipal(channel
,
10537 getter_AddRefs(resultPrincipal
));
10538 NS_ENSURE_SUCCESS(rv
, rv
);
10539 if (IsConsideredSameOriginForUIR(aTriggeringPrincipal
, resultPrincipal
)) {
10540 static_cast<LoadInfo
*>(loadInfo
.get())->SetUpgradeInsecureRequests();
10546 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
10547 do_QueryInterface(channel
);
10548 if (appCacheChannel
) {
10549 // Any document load should not inherit application cache.
10550 appCacheChannel
->SetInheritApplicationCache(false);
10552 // Loads with the correct permissions should check for a matching
10553 // application cache.
10554 if (GeckoProcessType_Default
!= XRE_GetProcessType()) {
10555 // Permission will be checked in the parent process
10556 appCacheChannel
->SetChooseApplicationCache(true);
10558 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
10559 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
10562 nsCOMPtr
<nsIPrincipal
> principal
;
10563 secMan
->GetDocShellCodebasePrincipal(aURI
, this,
10564 getter_AddRefs(principal
));
10565 appCacheChannel
->SetChooseApplicationCache(
10566 NS_ShouldCheckAppCache(principal
));
10571 // Make sure to give the caller a channel if we managed to create one
10572 // This is important for correct error page/session history interaction
10574 NS_ADDREF(*aRequest
= channel
);
10577 if (aOriginalURI
) {
10578 channel
->SetOriginalURI(aOriginalURI
);
10579 // The LOAD_REPLACE flag and its handling here will be removed as part
10580 // of bug 1319110. For now preserve its restoration here to not break
10581 // any code expecting it being set specially on redirected channels.
10582 // If the flag has originally been set to change result of
10583 // NS_GetFinalChannelURI it won't have any effect and also won't cause
10585 if (aLoadReplace
) {
10586 uint32_t loadFlags
;
10587 channel
->GetLoadFlags(&loadFlags
);
10588 NS_ENSURE_SUCCESS(rv
, rv
);
10589 channel
->SetLoadFlags(loadFlags
| nsIChannel::LOAD_REPLACE
);
10592 channel
->SetOriginalURI(aURI
);
10595 if (aResultPrincipalURI
) {
10596 // Unconditionally override, we want the replay to be equal to what has
10598 loadInfo
->SetResultPrincipalURI(aResultPrincipalURI
.ref());
10601 if (aTypeHint
&& *aTypeHint
) {
10602 channel
->SetContentType(nsDependentCString(aTypeHint
));
10603 mContentTypeHint
= aTypeHint
;
10605 mContentTypeHint
.Truncate();
10608 if (!aFileName
.IsVoid()) {
10609 rv
= channel
->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT
);
10610 NS_ENSURE_SUCCESS(rv
, rv
);
10611 if (!aFileName
.IsEmpty()) {
10612 rv
= channel
->SetContentDispositionFilename(aFileName
);
10613 NS_ENSURE_SUCCESS(rv
, rv
);
10617 if (mLoadType
== LOAD_NORMAL_ALLOW_MIXED_CONTENT
||
10618 mLoadType
== LOAD_RELOAD_ALLOW_MIXED_CONTENT
) {
10619 rv
= SetMixedContentChannel(channel
);
10620 NS_ENSURE_SUCCESS(rv
, rv
);
10621 } else if (mMixedContentChannel
) {
10623 * If the user "Disables Protection on This Page", we call
10624 * SetMixedContentChannel for the first time, otherwise
10625 * mMixedContentChannel is still null.
10626 * Later, if the new channel passes a same orign check, we remember the
10627 * users decision by calling SetMixedContentChannel using the new channel.
10628 * This way, the user does not have to click the disable protection button
10629 * over and over for browsing the same site.
10631 rv
= nsContentUtils::CheckSameOrigin(mMixedContentChannel
, channel
);
10632 if (NS_FAILED(rv
) || NS_FAILED(SetMixedContentChannel(channel
))) {
10633 SetMixedContentChannel(nullptr);
10638 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
10639 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal(
10640 do_QueryInterface(channel
));
10641 if (httpChannelInternal
) {
10642 if (aForceAllowCookies
) {
10643 rv
= httpChannelInternal
->SetThirdPartyFlags(
10644 nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW
);
10645 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10648 rv
= httpChannelInternal
->SetDocumentURI(aURI
);
10649 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10651 rv
= httpChannelInternal
->SetDocumentURI(aReferrerURI
);
10652 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10654 rv
= httpChannelInternal
->SetRedirectMode(
10655 nsIHttpChannelInternal::REDIRECT_MODE_MANUAL
);
10656 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10659 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(channel
));
10661 // save true referrer for those who need it (e.g. xpinstall whitelisting)
10662 // Currently only http and ftp channels support this.
10663 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
10667 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel(do_QueryInterface(channel
));
10668 /* Get the cache Key from SH */
10669 uint32_t cacheKey
= 0;
10670 if (cacheChannel
) {
10672 mLSHE
->GetCacheKey(&cacheKey
);
10673 } else if (mOSHE
) { // for reload cases
10674 mOSHE
->GetCacheKey(&cacheKey
);
10678 // figure out if we need to set the post data stream on the channel...
10680 nsCOMPtr
<nsIFormPOSTActionChannel
> postChannel(do_QueryInterface(channel
));
10682 // XXX it's a bit of a hack to rewind the postdata stream here but
10683 // it has to be done in case the post data is being reused multiple
10685 nsCOMPtr
<nsISeekableStream
> postDataSeekable
=
10686 do_QueryInterface(aPostData
);
10687 if (postDataSeekable
) {
10688 rv
= postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
10689 NS_ENSURE_SUCCESS(rv
, rv
);
10692 // we really need to have a content type associated with this stream!!
10693 postChannel
->SetUploadStream(aPostData
, EmptyCString(), -1);
10696 /* If there is a valid postdata *and* it is a History Load,
10697 * set up the cache key on the channel, to retrieve the
10698 * data *only* from the cache. If it is a normal reload, the
10699 * cache is free to go to the server for updated postdata.
10701 if (cacheChannel
&& cacheKey
!= 0) {
10702 if (mLoadType
== LOAD_HISTORY
||
10703 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
10704 cacheChannel
->SetCacheKey(cacheKey
);
10705 uint32_t loadFlags
;
10706 if (NS_SUCCEEDED(channel
->GetLoadFlags(&loadFlags
))) {
10707 channel
->SetLoadFlags(
10708 loadFlags
| nsICachingChannel::LOAD_ONLY_FROM_CACHE
);
10710 } else if (mLoadType
== LOAD_RELOAD_NORMAL
) {
10711 cacheChannel
->SetCacheKey(cacheKey
);
10715 /* If there is no postdata, set the cache key on the channel, and
10716 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
10717 * will be free to get it from net if it is not found in cache.
10718 * New cache may use it creatively on CGI pages with GET
10719 * method and even on those that say "no-cache"
10721 if (mLoadType
== LOAD_HISTORY
||
10722 mLoadType
== LOAD_RELOAD_NORMAL
||
10723 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
||
10724 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE
||
10725 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE
) {
10726 if (cacheChannel
&& cacheKey
!= 0) {
10727 cacheChannel
->SetCacheKey(cacheKey
);
10733 if (aHeadersData
) {
10734 rv
= AddHeadersToChannel(aHeadersData
, httpChannel
);
10736 // Set the referrer explicitly
10737 if (aReferrerURI
&& aSendReferrer
) {
10738 // Referrer is currenly only set for link clicks here.
10739 rv
= httpChannel
->SetReferrerWithPolicy(aReferrerURI
, aReferrerPolicy
);
10740 MOZ_ASSERT(NS_SUCCEEDED(rv
));
10744 nsCOMPtr
<nsIScriptChannel
> scriptChannel
= do_QueryInterface(channel
);
10745 if (scriptChannel
) {
10746 // Allow execution against our context if the principals match
10747 scriptChannel
->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
10750 if (aIsNewWindowTarget
) {
10751 nsCOMPtr
<nsIWritablePropertyBag2
> props
= do_QueryInterface(channel
);
10753 props
->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
10758 nsCOMPtr
<nsITimedChannel
> timedChannel(do_QueryInterface(channel
));
10759 if (timedChannel
) {
10760 timedChannel
->SetTimingEnabled(true);
10762 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
10763 if (IsFrame() && win
) {
10764 nsCOMPtr
<Element
> frameElement
= win
->GetFrameElementInternal();
10765 if (frameElement
) {
10766 timedChannel
->SetInitiatorType(frameElement
->LocalName());
10771 // Mark the http channel as UrgentStart for top level document loading
10773 if (mIsActive
|| (mLoadType
& (LOAD_CMD_NORMAL
| LOAD_CMD_HISTORY
))) {
10774 if (httpChannel
&& isTopLevelDoc
) {
10775 nsCOMPtr
<nsIClassOfService
> cos(do_QueryInterface(channel
));
10777 cos
->AddClassFlags(nsIClassOfService::UrgentStart
);
10782 rv
= DoChannelLoad(channel
, uriLoader
, aBypassClassifier
);
10785 // If the channel load failed, we failed and nsIWebProgress just ain't
10788 if (NS_SUCCEEDED(rv
)) {
10791 NS_ADDREF(*aDocShell
);
10799 AppendSegmentToString(nsIInputStream
* aIn
,
10801 const char* aFromRawSegment
,
10802 uint32_t aToOffset
,
10804 uint32_t* aWriteCount
)
10806 // aFromSegment now contains aCount bytes of data.
10808 nsAutoCString
* buf
= static_cast<nsAutoCString
*>(aClosure
);
10809 buf
->Append(aFromRawSegment
, aCount
);
10811 // Indicate that we have consumed all of aFromSegment
10812 *aWriteCount
= aCount
;
10817 nsDocShell::AddHeadersToChannel(nsIInputStream
* aHeadersData
,
10818 nsIChannel
* aGenericChannel
)
10820 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aGenericChannel
);
10821 NS_ENSURE_STATE(httpChannel
);
10824 nsAutoCString headersString
;
10825 nsresult rv
= aHeadersData
->ReadSegments(AppendSegmentToString
,
10829 NS_ENSURE_SUCCESS(rv
, rv
);
10831 // used during the manipulation of the String from the InputStream
10832 nsAutoCString headerName
;
10833 nsAutoCString headerValue
;
10838 // Iterate over the headersString: for each "\r\n" delimited chunk,
10839 // add the value as a header to the nsIHttpChannel
10842 static const char kWhitespace
[] = "\b\t\r\n ";
10844 crlf
= headersString
.Find("\r\n");
10845 if (crlf
== kNotFound
) {
10849 const nsACString
& oneHeader
= StringHead(headersString
, crlf
);
10851 colon
= oneHeader
.FindChar(':');
10852 if (colon
== kNotFound
) {
10853 return NS_ERROR_UNEXPECTED
;
10856 headerName
= StringHead(oneHeader
, colon
);
10857 headerValue
= Substring(oneHeader
, colon
+ 1);
10859 headerName
.Trim(kWhitespace
);
10860 headerValue
.Trim(kWhitespace
);
10862 headersString
.Cut(0, crlf
+ 2);
10865 // FINALLY: we can set the header!
10868 rv
= httpChannel
->SetRequestHeader(headerName
, headerValue
, true);
10869 NS_ENSURE_SUCCESS(rv
, rv
);
10872 MOZ_ASSERT_UNREACHABLE("oops");
10873 return NS_ERROR_UNEXPECTED
;
10877 nsDocShell::DoChannelLoad(nsIChannel
* aChannel
,
10878 nsIURILoader
* aURILoader
,
10879 bool aBypassClassifier
)
10882 // Mark the channel as being a document URI and allow content sniffing...
10883 nsLoadFlags loadFlags
= 0;
10884 (void)aChannel
->GetLoadFlags(&loadFlags
);
10885 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
|
10886 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
;
10888 if (SandboxFlagsImplyCookies(mSandboxFlags
)) {
10889 loadFlags
|= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE
;
10891 // Load attributes depend on load type...
10892 switch (mLoadType
) {
10893 case LOAD_HISTORY
: {
10894 // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
10895 // push/replaceState (bug 669671).
10896 bool uriModified
= false;
10898 mLSHE
->GetURIWasModified(&uriModified
);
10901 if (!uriModified
) {
10902 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
10907 case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE
:
10908 case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE
:
10909 loadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
|
10910 nsIRequest::LOAD_FRESH_CONNECTION
;
10913 case LOAD_RELOAD_CHARSET_CHANGE
: {
10914 // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only want
10915 // to force cache load for this channel, not the whole loadGroup.
10916 nsCOMPtr
<nsICacheInfoChannel
> cachingChannel
= do_QueryInterface(aChannel
);
10917 if (cachingChannel
) {
10918 cachingChannel
->SetAllowStaleCacheContent(true);
10923 case LOAD_RELOAD_NORMAL
:
10925 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
10928 case LOAD_NORMAL_BYPASS_CACHE
:
10929 case LOAD_NORMAL_BYPASS_PROXY
:
10930 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
10931 case LOAD_NORMAL_ALLOW_MIXED_CONTENT
:
10932 case LOAD_RELOAD_BYPASS_CACHE
:
10933 case LOAD_RELOAD_BYPASS_PROXY
:
10934 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
10935 case LOAD_RELOAD_ALLOW_MIXED_CONTENT
:
10936 case LOAD_REPLACE_BYPASS_CACHE
:
10937 loadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
|
10938 nsIRequest::LOAD_FRESH_CONNECTION
;
10943 // Set cache checking flags
10944 switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
10946 loadFlags
|= nsIRequest::VALIDATE_ONCE_PER_SESSION
;
10949 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
10952 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
10958 if (!aBypassClassifier
) {
10959 loadFlags
|= nsIChannel::LOAD_CLASSIFY_URI
;
10962 // If the user pressed shift-reload, then do not allow ServiceWorker
10963 // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
10964 if (IsForceReloadType(mLoadType
)) {
10965 loadFlags
|= nsIChannel::LOAD_BYPASS_SERVICE_WORKER
;
10968 (void)aChannel
->SetLoadFlags(loadFlags
);
10970 uint32_t openFlags
= 0;
10971 if (mLoadType
== LOAD_LINK
) {
10972 openFlags
|= nsIURILoader::IS_CONTENT_PREFERRED
;
10974 if (!mAllowContentRetargeting
) {
10975 openFlags
|= nsIURILoader::DONT_RETARGET
;
10978 // If anything fails here, make sure to clear our initial ClientSource.
10979 auto cleanupInitialClient
= MakeScopeExit([&] {
10980 mInitialClientSource
.reset();
10983 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
10984 NS_ENSURE_TRUE(win
, NS_ERROR_FAILURE
);
10986 MaybeCreateInitialClientSource();
10988 // Since we are loading a document we need to make sure the proper reserved
10989 // and initial client data is stored on the nsILoadInfo. The
10990 // ClientChannelHelper does this and ensures that it is propagated properly
10991 // on redirects. We pass no reserved client here so that the helper will
10992 // create the reserved ClientSource if necessary.
10993 Maybe
<ClientInfo
> noReservedClient
;
10994 rv
= AddClientChannelHelper(aChannel
,
10995 std::move(noReservedClient
),
10996 GetInitialClientInfo(),
10997 win
->EventTargetFor(TaskCategory::Other
));
10998 NS_ENSURE_SUCCESS(rv
, rv
);
11000 rv
= aURILoader
->OpenURI(aChannel
, openFlags
, this);
11001 NS_ENSURE_SUCCESS(rv
, rv
);
11003 // We're about to load a new page and it may take time before necko
11004 // gives back any data, so main thread might have a chance to process a
11006 nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL
);
11008 // Success. Keep the initial ClientSource if it exists.
11009 cleanupInitialClient
.release();
11015 nsDocShell::ScrollToAnchor(bool aCurHasRef
, bool aNewHasRef
,
11016 nsACString
& aNewHash
, uint32_t aLoadType
)
11018 if (!mCurrentURI
) {
11022 nsCOMPtr
<nsIPresShell
> shell
= GetPresShell();
11024 // If we failed to get the shell, or if there is no shell,
11025 // nothing left to do here.
11029 nsIScrollableFrame
* rootScroll
= shell
->GetRootScrollFrameAsScrollable();
11031 rootScroll
->ClearDidHistoryRestore();
11034 // If we have no new anchor, we do not want to scroll, unless there is a
11035 // current anchor and we are doing a history load. So return if we have no
11036 // new anchor, and there is no current anchor or the load is not a history
11038 if ((!aCurHasRef
|| aLoadType
!= LOAD_HISTORY
) && !aNewHasRef
) {
11042 // Both the new and current URIs refer to the same page. We can now
11043 // browse to the hash stored in the new URI.
11045 if (!aNewHash
.IsEmpty()) {
11046 // anchor is there, but if it's a load from history,
11047 // we don't have any anchor jumping to do
11048 bool scroll
= aLoadType
!= LOAD_HISTORY
&&
11049 aLoadType
!= LOAD_RELOAD_NORMAL
;
11051 // We assume that the bytes are in UTF-8, as it says in the
11053 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
11055 // We try the UTF-8 string first, and then try the document's
11056 // charset (see below). If the string is not UTF-8,
11057 // conversion will fail and give us an empty Unicode string.
11058 // In that case, we should just fall through to using the
11060 nsresult rv
= NS_ERROR_FAILURE
;
11061 NS_ConvertUTF8toUTF16
uStr(aNewHash
);
11062 if (!uStr
.IsEmpty()) {
11063 rv
= shell
->GoToAnchor(uStr
, scroll
,
11064 nsIPresShell::SCROLL_SMOOTH_AUTO
);
11067 if (NS_FAILED(rv
)) {
11068 char* str
= ToNewCString(aNewHash
);
11070 return NS_ERROR_OUT_OF_MEMORY
;
11073 NS_ConvertUTF8toUTF16
utf16Str(str
);
11074 if (!utf16Str
.IsEmpty()) {
11075 rv
= shell
->GoToAnchor(utf16Str
, scroll
,
11076 nsIPresShell::SCROLL_SMOOTH_AUTO
);
11081 // Above will fail if the anchor name is not UTF-8. Need to
11082 // convert from document charset to unicode.
11083 if (NS_FAILED(rv
)) {
11084 // Get a document charset
11085 NS_ENSURE_TRUE(mContentViewer
, NS_ERROR_FAILURE
);
11086 nsIDocument
* doc
= mContentViewer
->GetDocument();
11087 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
11088 nsAutoCString charset
;
11089 doc
->GetDocumentCharacterSet()->Name(charset
);
11091 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
11092 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
11093 NS_ENSURE_SUCCESS(rv
, rv
);
11095 // Unescape and convert to unicode
11098 rv
= textToSubURI
->UnEscapeAndConvert(charset
, aNewHash
, uStr
);
11099 NS_ENSURE_SUCCESS(rv
, rv
);
11101 // Ignore return value of GoToAnchor, since it will return an error
11102 // if there is no such anchor in the document, which is actually a
11103 // success condition for us (we want to update the session history
11104 // with the new URI no matter whether we actually scrolled
11107 // When aNewHash contains "%00", unescaped string may be empty.
11108 // And GoToAnchor asserts if we ask it to scroll to an empty ref.
11109 shell
->GoToAnchor(uStr
, scroll
&& !uStr
.IsEmpty(),
11110 nsIPresShell::SCROLL_SMOOTH_AUTO
);
11113 // Tell the shell it's at an anchor, without scrolling.
11114 shell
->GoToAnchor(EmptyString(), false);
11116 // An empty anchor was found, but if it's a load from history,
11117 // we don't have to jump to the top of the page. Scrollbar
11118 // position will be restored by the caller, based on positions
11119 // stored in session history.
11120 if (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
) {
11123 // An empty anchor. Scroll to the top of the page. Ignore the
11124 // return value; failure to scroll here (e.g. if there is no
11125 // root scrollframe) is not grounds for canceling the load!
11126 SetCurScrollPosEx(0, 0);
11133 nsDocShell::SetupReferrerFromChannel(nsIChannel
* aChannel
)
11135 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
11137 nsCOMPtr
<nsIURI
> referrer
;
11138 nsresult rv
= httpChannel
->GetReferrer(getter_AddRefs(referrer
));
11139 if (NS_SUCCEEDED(rv
)) {
11140 SetReferrerURI(referrer
);
11142 uint32_t referrerPolicy
;
11143 rv
= httpChannel
->GetReferrerPolicy(&referrerPolicy
);
11144 if (NS_SUCCEEDED(rv
)) {
11145 SetReferrerPolicy(referrerPolicy
);
11151 nsDocShell::OnNewURI(nsIURI
* aURI
, nsIChannel
* aChannel
,
11152 nsIPrincipal
* aTriggeringPrincipal
,
11153 nsIPrincipal
* aPrincipalToInherit
,
11154 uint32_t aLoadType
, bool aFireOnLocationChange
,
11155 bool aAddToGlobalHistory
, bool aCloneSHChildren
)
11157 MOZ_ASSERT(aURI
, "uri is null");
11158 MOZ_ASSERT(!aChannel
|| !aTriggeringPrincipal
, "Shouldn't have both set");
11160 MOZ_ASSERT(!aPrincipalToInherit
|| (aPrincipalToInherit
&& aTriggeringPrincipal
));
11163 if (MOZ_LOG_TEST(gDocShellLog
, LogLevel::Debug
)) {
11164 nsAutoCString chanName
;
11166 aChannel
->GetName(chanName
);
11168 chanName
.AssignLiteral("<no channel>");
11171 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
11172 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
11173 this, aURI
->GetSpecOrDefault().get(), chanName
.get(), aLoadType
));
11177 bool equalUri
= false;
11179 // Get the post data and the HTTP response code from the channel.
11180 uint32_t responseStatus
= 0;
11181 nsCOMPtr
<nsIInputStream
> inputStream
;
11183 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
11185 // Check if the HTTPChannel is hiding under a multiPartChannel
11186 if (!httpChannel
) {
11187 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
11191 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
11192 if (uploadChannel
) {
11193 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
11196 // If the response status indicates an error, unlink this session
11197 // history entry from any entries sharing its document.
11198 nsresult rv
= httpChannel
->GetResponseStatus(&responseStatus
);
11199 if (mLSHE
&& NS_SUCCEEDED(rv
) && responseStatus
>= 400) {
11200 mLSHE
->AbandonBFCacheEntry();
11205 // Determine if this type of load should update history.
11206 bool updateGHistory
= !(aLoadType
== LOAD_BYPASS_HISTORY
||
11207 aLoadType
== LOAD_ERROR_PAGE
||
11208 aLoadType
& LOAD_CMD_HISTORY
);
11210 // We don't update session history on reload unless we're loading
11211 // an iframe in shift-reload case.
11212 bool updateSHistory
= updateGHistory
&&
11213 (!(aLoadType
& LOAD_CMD_RELOAD
) ||
11214 (IsForceReloadType(aLoadType
) && IsFrame()));
11216 // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
11217 // current frame or in the root docshell.
11218 RefPtr
<ChildSHistory
> rootSH
= mSessionHistory
;
11220 // Get the handle to SH from the root docshell
11221 rootSH
= GetRootSessionHistory();
11224 updateSHistory
= false;
11225 updateGHistory
= false; // XXX Why global history too?
11228 // Check if the url to be loaded is the same as the one already loaded.
11230 aURI
->Equals(mCurrentURI
, &equalUri
);
11234 bool shAvailable
= (rootSH
!= nullptr);
11236 // XXX This log message is almost useless because |updateSHistory|
11237 // and |updateGHistory| are not correct at this point.
11239 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
11240 (" shAvailable=%i updateSHistory=%i updateGHistory=%i"
11242 shAvailable
, updateSHistory
, updateGHistory
, equalUri
));
11244 if (shAvailable
&& mCurrentURI
&& !mOSHE
&& aLoadType
!= LOAD_ERROR_PAGE
) {
11245 // XXX mCurrentURI can be changed from any caller regardless what actual
11246 // loaded document is, so testing mCurrentURI isn't really a reliable way.
11247 // Session restore is one example which changes current URI in order to
11248 // show address before loading. See bug 1301399.
11249 NS_ASSERTION(NS_IsAboutBlank(mCurrentURI
),
11250 "no SHEntry for a non-transient viewer?");
11254 /* If the url to be loaded is the same as the one already there,
11255 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
11256 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
11257 * AddToSessionHistory() won't mess with the current SHEntry and
11258 * if this page has any frame children, it also will be handled
11259 * properly. see bug 83684
11261 * NB: If mOSHE is null but we have a current URI, then it means
11262 * that we must be at the transient about:blank content viewer
11263 * (asserted above) and we should let the normal load continue,
11264 * since there's nothing to replace.
11266 * XXX Hopefully changing the loadType at this time will not hurt
11267 * anywhere. The other way to take care of sequentially repeating
11268 * frameset pages is to add new methods to nsIDocShellTreeItem.
11269 * Hopefully I don't have to do that.
11273 (mLoadType
== LOAD_NORMAL
||
11274 mLoadType
== LOAD_LINK
||
11275 mLoadType
== LOAD_STOP_CONTENT
) &&
11277 mLoadType
= LOAD_NORMAL_REPLACE
;
11280 // If this is a refresh to the currently loaded url, we don't
11281 // have to update session or global history.
11282 if (mLoadType
== LOAD_REFRESH
&& !inputStream
&& equalUri
) {
11283 SetHistoryEntry(&mLSHE
, mOSHE
);
11286 /* If the user pressed shift-reload, cache will create a new cache key
11287 * for the page. Save the new cacheKey in Session History.
11290 if (aChannel
&& IsForceReloadType(aLoadType
)) {
11291 MOZ_ASSERT(!updateSHistory
|| IsFrame(),
11292 "We shouldn't be updating session history for forced"
11293 " reloads unless we're in a newly created iframe!");
11295 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel(do_QueryInterface(aChannel
));
11296 uint32_t cacheKey
= 0;
11297 // Get the Cache Key and store it in SH.
11298 if (cacheChannel
) {
11299 cacheChannel
->GetCacheKey(&cacheKey
);
11301 // If we already have a loading history entry, store the new cache key
11302 // in it. Otherwise, since we're doing a reload and won't be updating
11303 // our history entry, store the cache key in our current history entry.
11305 mLSHE
->SetCacheKey(cacheKey
);
11306 } else if (mOSHE
) {
11307 mOSHE
->SetCacheKey(cacheKey
);
11310 // Since we're force-reloading, clear all the sub frame history.
11311 ClearFrameHistory(mLSHE
);
11312 ClearFrameHistory(mOSHE
);
11315 // Clear subframe history on refresh.
11316 // XXX: history.go(0) won't go this path as aLoadType is LOAD_HISTORY in this
11317 // case. One should re-validate after bug 1331865 fixed.
11318 if (aLoadType
== LOAD_REFRESH
) {
11319 ClearFrameHistory(mLSHE
);
11320 ClearFrameHistory(mOSHE
);
11323 if (updateSHistory
) {
11324 // Update session history if necessary...
11325 if (!mLSHE
&& (mItemType
== typeContent
) && mURIResultedInDocument
) {
11326 /* This is a fresh page getting loaded for the first time
11327 *.Create a Entry for it and add it to SH, if this is the
11330 (void)AddToSessionHistory(aURI
, aChannel
, aTriggeringPrincipal
,
11331 aPrincipalToInherit
, aCloneSHChildren
,
11332 getter_AddRefs(mLSHE
));
11334 } else if (mSessionHistory
&& mLSHE
&& mURIResultedInDocument
) {
11335 // Even if we don't add anything to SHistory, ensure the current index
11336 // points to the same SHEntry as our mLSHE.
11338 mSessionHistory
->LegacySHistory()->GetRequestedIndex(&index
);
11340 index
= mSessionHistory
->Index();
11342 nsCOMPtr
<nsISHEntry
> currentSH
;
11343 mSessionHistory
->LegacySHistory()->GetEntryAtIndex(
11344 index
, false, getter_AddRefs(currentSH
));
11345 if (currentSH
!= mLSHE
) {
11346 mSessionHistory
->LegacySHistoryInternal()->ReplaceEntry(index
, mLSHE
);
11350 // If this is a POST request, we do not want to include this in global
11352 if (updateGHistory
&& aAddToGlobalHistory
&& !ChannelIsPost(aChannel
)) {
11353 nsCOMPtr
<nsIURI
> previousURI
;
11354 uint32_t previousFlags
= 0;
11356 if (aLoadType
& LOAD_CMD_RELOAD
) {
11357 // On a reload request, we don't set redirecting flags.
11358 previousURI
= aURI
;
11360 ExtractLastVisit(aChannel
, getter_AddRefs(previousURI
), &previousFlags
);
11363 // Note: We don't use |referrer| when our global history is
11364 // based on IHistory.
11365 nsCOMPtr
<nsIURI
> referrer
;
11366 // Treat referrer as null if there is an error getting it.
11367 (void)NS_GetReferrerFromChannel(aChannel
, getter_AddRefs(referrer
));
11369 AddURIVisit(aURI
, referrer
, previousURI
, previousFlags
, responseStatus
);
11372 // If this was a history load or a refresh, or it was a history load but
11373 // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index
11374 // in session history.
11376 ((mLoadType
& (LOAD_CMD_HISTORY
| LOAD_CMD_RELOAD
)) ||
11377 mLoadType
== LOAD_NORMAL_REPLACE
)) {
11378 mPreviousTransIndex
= rootSH
->Index();
11379 rootSH
->LegacySHistoryInternal()->UpdateIndex();
11380 mLoadedTransIndex
= rootSH
->Index();
11381 #ifdef DEBUG_PAGE_CACHE
11382 printf("Previous index: %d, Loaded index: %d\n\n",
11383 mPreviousTransIndex
, mLoadedTransIndex
);
11387 // aCloneSHChildren exactly means "we are not loading a new document".
11388 uint32_t locationFlags
=
11389 aCloneSHChildren
? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT
) : 0;
11391 bool onLocationChangeNeeded
= SetCurrentURI(aURI
, aChannel
,
11392 aFireOnLocationChange
,
11394 // Make sure to store the referrer from the channel, if any
11395 SetupReferrerFromChannel(aChannel
);
11396 return onLocationChangeNeeded
;
11400 nsDocShell::OnLoadingSite(nsIChannel
* aChannel
, bool aFireOnLocationChange
,
11401 bool aAddToGlobalHistory
)
11403 nsCOMPtr
<nsIURI
> uri
;
11404 // If this a redirect, use the final url (uri)
11405 // else use the original url
11407 // Note that this should match what documents do (see nsDocument::Reset).
11408 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
11409 NS_ENSURE_TRUE(uri
, false);
11411 // Pass false for aCloneSHChildren, since we're loading a new page here.
11412 return OnNewURI(uri
, aChannel
, nullptr, nullptr, mLoadType
, aFireOnLocationChange
,
11413 aAddToGlobalHistory
, false);
11417 nsDocShell::SetReferrerURI(nsIURI
* aURI
)
11419 mReferrerURI
= aURI
; // This assigment addrefs
11423 nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy
)
11425 mReferrerPolicy
= aReferrerPolicy
;
11428 //*****************************************************************************
11429 // nsDocShell: Session History
11430 //*****************************************************************************
11433 nsDocShell::AddState(JS::Handle
<JS::Value
> aData
, const nsAString
& aTitle
,
11434 const nsAString
& aURL
, bool aReplace
, JSContext
* aCx
)
11436 // Implements History.pushState and History.replaceState
11438 // Here's what we do, roughly in the order specified by HTML5:
11439 // 1. Serialize aData using structured clone.
11440 // 2. If the third argument is present,
11441 // a. Resolve the url, relative to the first script's base URL
11442 // b. If (a) fails, raise a SECURITY_ERR
11443 // c. Compare the resulting absolute URL to the document's address. If
11444 // any part of the URLs difer other than the <path>, <query>, and
11445 // <fragment> components, raise a SECURITY_ERR and abort.
11446 // 3. If !aReplace:
11447 // Remove from the session history all entries after the current entry,
11448 // as we would after a regular navigation, and save the current
11449 // entry's scroll position (bug 590573).
11450 // 4. As apropriate, either add a state object entry to the session history
11451 // after the current entry with the following properties, or modify the
11452 // current session history entry to set
11453 // a. cloned data as the state object,
11454 // b. if the third argument was present, the absolute URL found in
11456 // Also clear the new history entry's POST data (see bug 580069).
11457 // 5. If aReplace is false (i.e. we're doing a pushState instead of a
11458 // replaceState), notify bfcache that we've navigated to a new page.
11459 // 6. If the third argument is present, set the document's current address
11460 // to the absolute URL found in step 2.
11462 // It's important that this function not run arbitrary scripts after step 1
11463 // and before completing step 5. For example, if a script called
11464 // history.back() before we completed step 5, bfcache might destroy an
11465 // active content viewer. Since EvictOutOfRangeContentViewers at the end of
11466 // step 5 might run script, we can't just put a script blocker around the
11467 // critical section.
11469 // Note that we completely ignore the aTitle parameter.
11473 // Don't clobber the load type of an existing network load.
11474 AutoRestore
<uint32_t> loadTypeResetter(mLoadType
);
11476 // pushState effectively becomes replaceState when we've started a network
11477 // load but haven't adopted its document yet. This mirrors what we do with
11478 // changes to the hash at this stage of the game.
11479 if (JustStartedNetworkLoad()) {
11483 nsCOMPtr
<nsIDocument
> document
= GetDocument();
11484 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
11486 // Step 1: Serialize aData using structured clone.
11487 nsCOMPtr
<nsIStructuredCloneContainer
> scContainer
;
11489 // scContainer->Init might cause arbitrary JS to run, and this code might
11490 // navigate the page we're on, potentially to a different origin! (bug
11491 // 634834) To protect against this, we abort if our principal changes due
11492 // to the InitFromJSVal() call.
11494 nsCOMPtr
<nsIDocument
> origDocument
= GetDocument();
11495 if (!origDocument
) {
11496 return NS_ERROR_DOM_SECURITY_ERR
;
11498 nsCOMPtr
<nsIPrincipal
> origPrincipal
= origDocument
->NodePrincipal();
11500 scContainer
= new nsStructuredCloneContainer();
11501 rv
= scContainer
->InitFromJSVal(aData
, aCx
);
11502 NS_ENSURE_SUCCESS(rv
, rv
);
11504 nsCOMPtr
<nsIDocument
> newDocument
= GetDocument();
11505 if (!newDocument
) {
11506 return NS_ERROR_DOM_SECURITY_ERR
;
11508 nsCOMPtr
<nsIPrincipal
> newPrincipal
= newDocument
->NodePrincipal();
11510 bool principalsEqual
= false;
11511 origPrincipal
->Equals(newPrincipal
, &principalsEqual
);
11512 NS_ENSURE_TRUE(principalsEqual
, NS_ERROR_DOM_SECURITY_ERR
);
11515 // Check that the state object isn't too long.
11516 // Default max length: 640k bytes.
11517 int32_t maxStateObjSize
=
11518 Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
11519 if (maxStateObjSize
< 0) {
11520 maxStateObjSize
= 0;
11524 rv
= scContainer
->GetSerializedNBytes(&scSize
);
11525 NS_ENSURE_SUCCESS(rv
, rv
);
11527 NS_ENSURE_TRUE(scSize
<= (uint32_t)maxStateObjSize
, NS_ERROR_ILLEGAL_VALUE
);
11529 // Step 2: Resolve aURL
11530 bool equalURIs
= true;
11531 nsCOMPtr
<nsIURI
> currentURI
;
11532 if (sURIFixup
&& mCurrentURI
) {
11533 rv
= sURIFixup
->CreateExposableURI(mCurrentURI
, getter_AddRefs(currentURI
));
11534 NS_ENSURE_SUCCESS(rv
, rv
);
11536 currentURI
= mCurrentURI
;
11538 nsCOMPtr
<nsIURI
> oldURI
= currentURI
;
11539 nsCOMPtr
<nsIURI
> newURI
;
11540 if (aURL
.Length() == 0) {
11541 newURI
= currentURI
;
11543 // 2a: Resolve aURL relative to mURI
11545 nsIURI
* docBaseURI
= document
->GetDocBaseURI();
11547 return NS_ERROR_FAILURE
;
11550 nsAutoCString spec
;
11551 docBaseURI
->GetSpec(spec
);
11553 rv
= NS_NewURI(getter_AddRefs(newURI
), aURL
,
11554 document
->GetDocumentCharacterSet(), docBaseURI
);
11556 // 2b: If 2a fails, raise a SECURITY_ERR
11557 if (NS_FAILED(rv
)) {
11558 return NS_ERROR_DOM_SECURITY_ERR
;
11561 // 2c: Same-origin check.
11562 if (!nsContentUtils::URIIsLocalFile(newURI
)) {
11563 // In addition to checking that the security manager says that
11564 // the new URI has the same origin as our current URI, we also
11565 // check that the two URIs have the same userpass. (The
11566 // security manager says that |http://foo.com| and
11567 // |http://me@foo.com| have the same origin.) currentURI
11568 // won't contain the password part of the userpass, so this
11569 // means that it's never valid to specify a password in a
11570 // pushState or replaceState URI.
11572 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
11573 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
11574 NS_ENSURE_TRUE(secMan
, NS_ERROR_FAILURE
);
11576 // It's very important that we check that newURI is of the same
11577 // origin as currentURI, not docBaseURI, because a page can
11578 // set docBaseURI arbitrarily to any domain.
11579 nsAutoCString currentUserPass
, newUserPass
;
11580 NS_ENSURE_SUCCESS(currentURI
->GetUserPass(currentUserPass
),
11582 NS_ENSURE_SUCCESS(newURI
->GetUserPass(newUserPass
), NS_ERROR_FAILURE
);
11583 if (NS_FAILED(secMan
->CheckSameOriginURI(currentURI
, newURI
, true)) ||
11584 !currentUserPass
.Equals(newUserPass
)) {
11585 return NS_ERROR_DOM_SECURITY_ERR
;
11588 // It's a file:// URI
11589 nsCOMPtr
<nsIScriptObjectPrincipal
> docScriptObj
=
11590 do_QueryInterface(document
);
11592 if (!docScriptObj
) {
11593 return NS_ERROR_DOM_SECURITY_ERR
;
11596 nsCOMPtr
<nsIPrincipal
> principal
= docScriptObj
->GetPrincipal();
11599 NS_FAILED(principal
->CheckMayLoad(newURI
, true, false))) {
11600 return NS_ERROR_DOM_SECURITY_ERR
;
11605 currentURI
->Equals(newURI
, &equalURIs
);
11610 } // end of same-origin check
11612 // Step 3: Create a new entry in the session history. This will erase
11613 // all SHEntries after the new entry and make this entry the current
11614 // one. This operation may modify mOSHE, which we need later, so we
11615 // keep a reference here.
11616 NS_ENSURE_TRUE(mOSHE
, NS_ERROR_FAILURE
);
11617 nsCOMPtr
<nsISHEntry
> oldOSHE
= mOSHE
;
11619 mLoadType
= LOAD_PUSHSTATE
;
11621 nsCOMPtr
<nsISHEntry
> newSHEntry
;
11623 // Save the current scroll position (bug 590573).
11624 nscoord cx
= 0, cy
= 0;
11625 GetCurScrollPos(ScrollOrientation_X
, &cx
);
11626 GetCurScrollPos(ScrollOrientation_Y
, &cy
);
11627 mOSHE
->SetScrollPosition(cx
, cy
);
11629 bool scrollRestorationIsManual
= false;
11630 mOSHE
->GetScrollRestorationIsManual(&scrollRestorationIsManual
);
11632 // Since we're not changing which page we have loaded, pass
11633 // true for aCloneChildren.
11634 rv
= AddToSessionHistory(newURI
, nullptr,
11635 document
->NodePrincipal(), // triggeringPrincipal
11637 getter_AddRefs(newSHEntry
));
11638 NS_ENSURE_SUCCESS(rv
, rv
);
11640 NS_ENSURE_TRUE(newSHEntry
, NS_ERROR_FAILURE
);
11642 // Session history entries created by pushState inherit scroll restoration
11643 // mode from the current entry.
11644 newSHEntry
->SetScrollRestorationIsManual(scrollRestorationIsManual
);
11646 // Link the new SHEntry to the old SHEntry's BFCache entry, since the
11647 // two entries correspond to the same document.
11648 NS_ENSURE_SUCCESS(newSHEntry
->AdoptBFCacheEntry(oldOSHE
), NS_ERROR_FAILURE
);
11650 // Set the new SHEntry's title (bug 655273).
11652 mOSHE
->GetTitle(getter_Copies(title
));
11653 newSHEntry
->SetTitle(title
);
11655 // AddToSessionHistory may not modify mOSHE. In case it doesn't,
11656 // we'll just set mOSHE here.
11657 mOSHE
= newSHEntry
;
11660 newSHEntry
= mOSHE
;
11661 newSHEntry
->SetURI(newURI
);
11662 newSHEntry
->SetOriginalURI(newURI
);
11663 newSHEntry
->SetLoadReplace(false);
11666 // Step 4: Modify new/original session history entry and clear its POST
11667 // data, if there is any.
11668 newSHEntry
->SetStateData(scContainer
);
11669 newSHEntry
->SetPostData(nullptr);
11671 // If this push/replaceState changed the document's current URI and the new
11672 // URI differs from the old URI in more than the hash, or if the old
11673 // SHEntry's URI was modified in this way by a push/replaceState call
11674 // set URIWasModified to true for the current SHEntry (bug 669671).
11675 bool sameExceptHashes
= true, oldURIWasModified
= false;
11676 newURI
->EqualsExceptRef(currentURI
, &sameExceptHashes
);
11677 oldOSHE
->GetURIWasModified(&oldURIWasModified
);
11678 newSHEntry
->SetURIWasModified(!sameExceptHashes
|| oldURIWasModified
);
11680 // Step 5: If aReplace is false, indicating that we're doing a pushState
11681 // rather than a replaceState, notify bfcache that we've added a page to
11682 // the history so it can evict content viewers if appropriate. Otherwise
11683 // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
11685 RefPtr
<ChildSHistory
> rootSH
= GetRootSessionHistory();
11686 NS_ENSURE_TRUE(rootSH
, NS_ERROR_UNEXPECTED
);
11689 int32_t curIndex
= rootSH
->Index();
11690 if (curIndex
> -1) {
11691 rootSH
->LegacySHistoryInternal()->EvictOutOfRangeContentViewers(curIndex
);
11694 nsCOMPtr
<nsISHEntry
> rootSHEntry
= nsSHistory::GetRootSHEntry(newSHEntry
);
11696 int32_t index
= -1;
11697 rv
= rootSH
->LegacySHistory()->GetIndexOfEntry(rootSHEntry
, &index
);
11698 if (NS_SUCCEEDED(rv
) && index
> -1) {
11699 rootSH
->LegacySHistoryInternal()->ReplaceEntry(index
, rootSHEntry
);
11703 // Step 6: If the document's URI changed, update document's URI and update
11706 // We need to call FireOnLocationChange so that the browser's address bar
11707 // gets updated and the back button is enabled, but we only need to
11708 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
11709 // since SetCurrentURI will call FireOnLocationChange for us.
11711 // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
11712 // nullptr for aRequest param to FireOnLocationChange(...). Such an update
11713 // notification is allowed only when we know docshell is not loading a new
11714 // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
11715 // FireOnLocationChange(...) breaks security UI.
11717 document
->SetDocumentURI(newURI
);
11718 // We can't trust SetCurrentURI to do always fire locationchange events
11719 // when we expect it to, so we hack around that by doing it ourselves...
11720 SetCurrentURI(newURI
, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT
);
11721 if (mLoadType
!= LOAD_ERROR_PAGE
) {
11722 FireDummyOnLocationChange();
11725 AddURIVisit(newURI
, oldURI
, oldURI
, 0);
11727 // AddURIVisit doesn't set the title for the new URI in global history,
11728 // so do that here.
11729 UpdateGlobalHistoryTitle(newURI
);
11731 // Inform the favicon service that our old favicon applies to this new
11733 CopyFavicon(oldURI
, newURI
, document
->NodePrincipal(), UsePrivateBrowsing());
11735 FireDummyOnLocationChange();
11737 document
->SetStateObject(scContainer
);
11743 nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual
)
11745 *aIsManual
= false;
11747 mOSHE
->GetScrollRestorationIsManual(aIsManual
);
11754 nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual
)
11757 mOSHE
->SetScrollRestorationIsManual(aIsManual
);
11764 nsDocShell::ShouldAddToSessionHistory(nsIURI
* aURI
, nsIChannel
* aChannel
)
11766 // I believe none of the about: urls should go in the history. But then
11767 // that could just be me... If the intent is only deny about:blank then we
11768 // should just do a spec compare, rather than two gets of the scheme and
11769 // then the path. -Gagan
11773 rv
= aURI
->GetScheme(buf
);
11774 if (NS_FAILED(rv
)) {
11778 if (buf
.EqualsLiteral("about")) {
11779 rv
= aURI
->GetPathQueryRef(buf
);
11780 if (NS_FAILED(rv
)) {
11784 if (buf
.EqualsLiteral("blank")) {
11787 // We only want to add about:newtab if it's not privileged:
11788 if (buf
.EqualsLiteral("newtab")) {
11789 NS_ENSURE_TRUE(aChannel
, false);
11790 nsCOMPtr
<nsIPrincipal
> resultPrincipal
;
11791 rv
= nsContentUtils::GetSecurityManager()->
11792 GetChannelResultPrincipal(aChannel
,
11793 getter_AddRefs(resultPrincipal
));
11794 NS_ENSURE_SUCCESS(rv
, false);
11795 return !nsContentUtils::IsSystemPrincipal(resultPrincipal
);
11803 nsDocShell::AddToSessionHistory(nsIURI
* aURI
, nsIChannel
* aChannel
,
11804 nsIPrincipal
* aTriggeringPrincipal
,
11805 nsIPrincipal
* aPrincipalToInherit
,
11806 bool aCloneChildren
,
11807 nsISHEntry
** aNewEntry
)
11809 MOZ_ASSERT(aURI
, "uri is null");
11810 MOZ_ASSERT(!aChannel
|| !aTriggeringPrincipal
, "Shouldn't have both set");
11813 if (MOZ_LOG_TEST(gDocShellLog
, LogLevel::Debug
)) {
11814 nsAutoCString chanName
;
11816 aChannel
->GetName(chanName
);
11818 chanName
.AssignLiteral("<no channel>");
11821 MOZ_LOG(gDocShellLog
, LogLevel::Debug
,
11822 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
11823 this, aURI
->GetSpecOrDefault().get(), chanName
.get()));
11827 nsresult rv
= NS_OK
;
11828 nsCOMPtr
<nsISHEntry
> entry
;
11830 // Get a handle to the root docshell
11831 nsCOMPtr
<nsIDocShellTreeItem
> root
;
11832 GetSameTypeRootTreeItem(getter_AddRefs(root
));
11834 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
11835 * the existing SH entry in the page and replace the url and
11836 * other vitalities.
11838 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) &&
11839 root
!= static_cast<nsIDocShellTreeItem
*>(this)) {
11840 // This is a subframe
11842 nsCOMPtr
<nsISHContainer
> shContainer(do_QueryInterface(entry
));
11844 int32_t childCount
= 0;
11845 shContainer
->GetChildCount(&childCount
);
11846 // Remove all children of this entry
11847 for (int32_t i
= childCount
- 1; i
>= 0; i
--) {
11848 nsCOMPtr
<nsISHEntry
> child
;
11849 shContainer
->GetChildAt(i
, getter_AddRefs(child
));
11850 shContainer
->RemoveChild(child
);
11852 entry
->AbandonBFCacheEntry();
11856 // Create a new entry if necessary.
11858 entry
= do_CreateInstance(NS_SHENTRY_CONTRACTID
);
11861 return NS_ERROR_OUT_OF_MEMORY
;
11865 // Get the post data & referrer
11866 nsCOMPtr
<nsIInputStream
> inputStream
;
11867 nsCOMPtr
<nsIURI
> originalURI
;
11868 nsCOMPtr
<nsIURI
> resultPrincipalURI
;
11869 bool loadReplace
= false;
11870 nsCOMPtr
<nsIURI
> referrerURI
;
11871 uint32_t referrerPolicy
= RP_Unset
;
11872 uint32_t cacheKey
= 0;
11873 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
= aTriggeringPrincipal
;
11874 nsCOMPtr
<nsIPrincipal
> principalToInherit
= aPrincipalToInherit
;
11875 bool expired
= false;
11876 bool discardLayoutState
= false;
11877 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel
;
11879 cacheChannel
= do_QueryInterface(aChannel
);
11881 /* If there is a caching channel, get the Cache Key and store it
11884 if (cacheChannel
) {
11885 cacheChannel
->GetCacheKey(&cacheKey
);
11887 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
11889 // Check if the httpChannel is hiding under a multipartChannel
11890 if (!httpChannel
) {
11891 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
11894 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
11895 if (uploadChannel
) {
11896 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
11898 httpChannel
->GetOriginalURI(getter_AddRefs(originalURI
));
11899 uint32_t loadFlags
;
11900 aChannel
->GetLoadFlags(&loadFlags
);
11901 loadReplace
= loadFlags
& nsIChannel::LOAD_REPLACE
;
11902 rv
= httpChannel
->GetReferrer(getter_AddRefs(referrerURI
));
11903 MOZ_ASSERT(NS_SUCCEEDED(rv
));
11904 rv
= httpChannel
->GetReferrerPolicy(&referrerPolicy
);
11905 MOZ_ASSERT(NS_SUCCEEDED(rv
));
11907 discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
11910 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->GetLoadInfo();
11912 if (!triggeringPrincipal
) {
11913 triggeringPrincipal
= loadInfo
->TriggeringPrincipal();
11916 loadInfo
->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI
));
11918 // For now keep storing just the principal in the SHEntry.
11919 if (!principalToInherit
) {
11920 if (loadInfo
->GetLoadingSandboxed()) {
11921 if (loadInfo
->LoadingPrincipal()) {
11922 principalToInherit
= NullPrincipal::CreateWithInheritedAttributes(
11923 loadInfo
->LoadingPrincipal());
11925 // get the OriginAttributes
11926 OriginAttributes attrs
;
11927 loadInfo
->GetOriginAttributes(&attrs
);
11928 principalToInherit
= NullPrincipal::Create(attrs
);
11931 principalToInherit
= loadInfo
->PrincipalToInherit();
11937 // Title is set in nsDocShell::SetTitle()
11938 entry
->Create(aURI
, // uri
11939 EmptyString(), // Title
11940 inputStream
, // Post data stream
11941 nullptr, // LayoutHistory state
11942 cacheKey
, // CacheKey
11943 mContentTypeHint
, // Content-type
11944 triggeringPrincipal
, // Channel or provided principal
11945 principalToInherit
,
11947 mDynamicallyCreated
);
11949 entry
->SetOriginalURI(originalURI
);
11950 entry
->SetResultPrincipalURI(resultPrincipalURI
);
11951 entry
->SetLoadReplace(loadReplace
);
11952 entry
->SetReferrerURI(referrerURI
);
11953 entry
->SetReferrerPolicy(referrerPolicy
);
11954 nsCOMPtr
<nsIInputStreamChannel
> inStrmChan
= do_QueryInterface(aChannel
);
11956 bool isSrcdocChannel
;
11957 inStrmChan
->GetIsSrcdocChannel(&isSrcdocChannel
);
11958 if (isSrcdocChannel
) {
11959 nsAutoString srcdoc
;
11960 inStrmChan
->GetSrcdocData(srcdoc
);
11961 entry
->SetSrcdocData(srcdoc
);
11962 nsCOMPtr
<nsIURI
> baseURI
;
11963 inStrmChan
->GetBaseURI(getter_AddRefs(baseURI
));
11964 entry
->SetBaseURI(baseURI
);
11967 /* If cache got a 'no-store', ask SH not to store
11968 * HistoryLayoutState. By default, SH will set this
11969 * flag to true and save HistoryLayoutState.
11971 if (discardLayoutState
) {
11972 entry
->SetSaveLayoutStateFlag(false);
11974 if (cacheChannel
) {
11975 // Check if the page has expired from cache
11976 uint32_t expTime
= 0;
11977 cacheChannel
->GetCacheTokenExpirationTime(&expTime
);
11978 uint32_t now
= PRTimeToSeconds(PR_Now());
11979 if (expTime
<= now
) {
11984 entry
->SetExpirationStatus(true);
11987 if (root
== static_cast<nsIDocShellTreeItem
*>(this) && mSessionHistory
) {
11988 // If we need to clone our children onto the new session
11989 // history entry, do so now.
11990 if (aCloneChildren
&& mOSHE
) {
11992 mOSHE
->GetID(&cloneID
);
11993 nsCOMPtr
<nsISHEntry
> newEntry
;
11994 nsSHistory::CloneAndReplace(mOSHE
, this, cloneID
, entry
, true,
11995 getter_AddRefs(newEntry
));
11996 NS_ASSERTION(entry
== newEntry
,
11997 "The new session history should be in the new entry");
12000 // This is the root docshell
12001 bool addToSHistory
= !LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
);
12002 if (!addToSHistory
) {
12003 // Replace current entry in session history; If the requested index is
12004 // valid, it indicates the loading was triggered by a history load, and
12005 // we should replace the entry at requested index instead.
12007 mSessionHistory
->LegacySHistory()->GetRequestedIndex(&index
);
12009 index
= mSessionHistory
->Index();
12012 // Replace the current entry with the new entry
12014 rv
= mSessionHistory
->LegacySHistoryInternal()->ReplaceEntry(index
,
12017 // If we're trying to replace an inexistant shistory entry, append.
12018 addToSHistory
= true;
12022 if (addToSHistory
) {
12023 // Add to session history
12024 mPreviousTransIndex
= mSessionHistory
->Index();
12026 bool shouldPersist
= ShouldAddToSessionHistory(aURI
, aChannel
);
12027 rv
= mSessionHistory
->LegacySHistoryInternal()->AddEntry(
12028 entry
, shouldPersist
);
12029 mLoadedTransIndex
= mSessionHistory
->Index();
12030 #ifdef DEBUG_PAGE_CACHE
12031 printf("Previous index: %d, Loaded index: %d\n\n",
12032 mPreviousTransIndex
, mLoadedTransIndex
);
12036 // This is a subframe.
12037 if (!mOSHE
|| !LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
12038 rv
= AddChildSHEntryToParent(entry
, mChildOffset
, aCloneChildren
);
12042 // Return the new SH entry...
12044 *aNewEntry
= nullptr;
12045 if (NS_SUCCEEDED(rv
)) {
12046 entry
.forget(aNewEntry
);
12054 nsDocShell::LoadHistoryEntry(nsISHEntry
* aEntry
, uint32_t aLoadType
)
12056 if (!IsNavigationAllowed()) {
12060 nsCOMPtr
<nsIURI
> uri
;
12061 nsCOMPtr
<nsIURI
> originalURI
;
12062 nsCOMPtr
<nsIURI
> resultPrincipalURI
;
12063 bool loadReplace
= false;
12064 nsCOMPtr
<nsIInputStream
> postData
;
12065 nsCOMPtr
<nsIURI
> referrerURI
;
12066 uint32_t referrerPolicy
;
12067 nsAutoCString contentType
;
12068 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
12069 nsCOMPtr
<nsIPrincipal
> principalToInherit
;
12071 NS_ENSURE_TRUE(aEntry
, NS_ERROR_FAILURE
);
12073 NS_ENSURE_SUCCESS(aEntry
->GetURI(getter_AddRefs(uri
)), NS_ERROR_FAILURE
);
12074 NS_ENSURE_SUCCESS(aEntry
->GetOriginalURI(getter_AddRefs(originalURI
)),
12076 NS_ENSURE_SUCCESS(aEntry
->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI
)),
12078 NS_ENSURE_SUCCESS(aEntry
->GetLoadReplace(&loadReplace
),
12080 NS_ENSURE_SUCCESS(aEntry
->GetReferrerURI(getter_AddRefs(referrerURI
)),
12082 NS_ENSURE_SUCCESS(aEntry
->GetReferrerPolicy(&referrerPolicy
),
12084 NS_ENSURE_SUCCESS(aEntry
->GetPostData(getter_AddRefs(postData
)),
12086 NS_ENSURE_SUCCESS(aEntry
->GetContentType(contentType
), NS_ERROR_FAILURE
);
12087 NS_ENSURE_SUCCESS(aEntry
->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal
)),
12089 NS_ENSURE_SUCCESS(aEntry
->GetPrincipalToInherit(getter_AddRefs(principalToInherit
)),
12092 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
12093 // that's the only thing holding a ref to aEntry that will cause aEntry to
12094 // die while we're loading it. So hold a strong ref to aEntry here, just
12096 nsCOMPtr
<nsISHEntry
> kungFuDeathGrip(aEntry
);
12098 nsresult rv
= uri
->SchemeIs("javascript", &isJS
);
12099 if (NS_FAILED(rv
) || isJS
) {
12100 // We're loading a URL that will execute script from inside asyncOpen.
12101 // Replace the current document with about:blank now to prevent
12102 // anything from the current document from leaking into any JavaScript
12103 // code in the URL.
12104 // Don't cache the presentation if we're going to just reload the
12105 // current entry. Caching would lead to trying to save the different
12106 // content viewers in the same nsISHEntry object.
12107 rv
= CreateAboutBlankContentViewer(principalToInherit
, nullptr,
12110 if (NS_FAILED(rv
)) {
12111 // The creation of the intermittent about:blank content
12112 // viewer failed for some reason (potentially because the
12113 // user prevented it). Interrupt the history load.
12117 if (!triggeringPrincipal
) {
12118 // Ensure that we have a triggeringPrincipal. Otherwise javascript:
12119 // URIs will pick it up from the about:blank page we just loaded,
12120 // and we don't really want even that in this case.
12121 triggeringPrincipal
= NullPrincipal::CreateWithInheritedAttributes(this);
12125 /* If there is a valid postdata *and* the user pressed
12126 * reload or shift-reload, take user's permission before we
12127 * repost the data to the server.
12129 if ((aLoadType
& LOAD_CMD_RELOAD
) && postData
) {
12131 rv
= ConfirmRepost(&repost
);
12132 if (NS_FAILED(rv
)) {
12136 // If the user pressed cancel in the dialog, return. We're done here.
12138 return NS_BINDING_ABORTED
;
12142 // Do not inherit principal from document (security-critical!);
12143 uint32_t flags
= INTERNAL_LOAD_FLAGS_NONE
;
12145 nsAutoString srcdoc
;
12147 nsCOMPtr
<nsIURI
> baseURI
;
12148 aEntry
->GetIsSrcdocEntry(&isSrcdoc
);
12150 aEntry
->GetSrcdocData(srcdoc
);
12151 aEntry
->GetBaseURI(getter_AddRefs(baseURI
));
12152 flags
|= INTERNAL_LOAD_FLAGS_IS_SRCDOC
;
12154 srcdoc
= VoidString();
12157 // If there is no valid triggeringPrincipal, we deny the load
12158 MOZ_ASSERT(triggeringPrincipal
, "need a valid triggeringPrincipal to load from history");
12159 if (!triggeringPrincipal
) {
12160 return NS_ERROR_FAILURE
;
12163 // Passing nullptr as aSourceDocShell gives the same behaviour as before
12164 // aSourceDocShell was introduced. According to spec we should be passing
12165 // the source browsing context that was used when the history entry was
12166 // first created. bug 947716 has been created to address this issue.
12167 Maybe
<nsCOMPtr
<nsIURI
>> emplacedResultPrincipalURI
;
12168 emplacedResultPrincipalURI
.emplace(std::move(resultPrincipalURI
));
12169 rv
= InternalLoad(uri
,
12171 emplacedResultPrincipalURI
,
12175 triggeringPrincipal
,
12176 principalToInherit
,
12178 EmptyString(), // No window target
12179 contentType
.get(), // Type hint
12180 VoidString(), // No forced file download
12181 postData
, // Post data stream
12182 nullptr, // No headers stream
12183 aLoadType
, // Load type
12187 nullptr, // Source docshell, see comment above
12189 nullptr, // No nsIDocShell
12190 nullptr); // No nsIRequest
12195 nsDocShell::GetShouldSaveLayoutState(bool* aShould
)
12199 // Don't capture historystate and save it in history
12200 // if the page asked not to do so.
12201 mOSHE
->GetSaveLayoutStateFlag(aShould
);
12208 nsDocShell::PersistLayoutHistoryState()
12210 nsresult rv
= NS_OK
;
12213 bool scrollRestorationIsManual
= false;
12214 mOSHE
->GetScrollRestorationIsManual(&scrollRestorationIsManual
);
12216 nsCOMPtr
<nsIPresShell
> shell
= GetPresShell();
12217 nsCOMPtr
<nsILayoutHistoryState
> layoutState
;
12219 rv
= shell
->CaptureHistoryState(getter_AddRefs(layoutState
));
12220 } else if (scrollRestorationIsManual
) {
12221 // Even if we don't have layout anymore, we may want to reset the current
12222 // scroll state in layout history.
12223 GetLayoutHistoryState(getter_AddRefs(layoutState
));
12226 if (scrollRestorationIsManual
&& layoutState
) {
12227 layoutState
->ResetScrollState();
12235 nsDocShell::SwapHistoryEntries(nsISHEntry
* aOldEntry
, nsISHEntry
* aNewEntry
)
12237 if (aOldEntry
== mOSHE
) {
12241 if (aOldEntry
== mLSHE
) {
12247 nsDocShell::SetHistoryEntry(nsCOMPtr
<nsISHEntry
>* aPtr
, nsISHEntry
* aEntry
)
12249 // We need to sync up the docshell and session history trees for
12250 // subframe navigation. If the load was in a subframe, we forward up to
12251 // the root docshell, which will then recursively sync up all docshells
12252 // to their corresponding entries in the new session history tree.
12253 // If we don't do this, then we can cache a content viewer on the wrong
12254 // cloned entry, and subsequently restore it at the wrong time.
12256 nsISHEntry
* newRootEntry
= nsSHistory::GetRootSHEntry(aEntry
);
12257 if (newRootEntry
) {
12258 // newRootEntry is now the new root entry.
12259 // Find the old root entry as well.
12261 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
12262 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
12263 nsCOMPtr
<nsISHEntry
> oldRootEntry
= nsSHistory::GetRootSHEntry(*aPtr
);
12264 if (oldRootEntry
) {
12265 nsCOMPtr
<nsIDocShellTreeItem
> rootAsItem
;
12266 GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem
));
12267 nsCOMPtr
<nsIDocShell
> rootShell
= do_QueryInterface(rootAsItem
);
12268 if (rootShell
) { // if we're the root just set it, nothing to swap
12269 nsSHistory::SwapEntriesData data
= { this, newRootEntry
};
12270 nsIDocShell
* rootIDocShell
= static_cast<nsIDocShell
*>(rootShell
);
12271 nsDocShell
* rootDocShell
= static_cast<nsDocShell
*>(rootIDocShell
);
12276 nsSHistory::SetChildHistoryEntry(oldRootEntry
, rootDocShell
, 0, &data
);
12277 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetChildHistoryEntry failed");
12285 already_AddRefed
<ChildSHistory
>
12286 nsDocShell::GetRootSessionHistory()
12288 nsCOMPtr
<nsIDocShellTreeItem
> root
;
12289 nsresult rv
= GetSameTypeRootTreeItem(getter_AddRefs(root
));
12290 if (NS_WARN_IF(NS_FAILED(rv
))) {
12293 nsCOMPtr
<nsIWebNavigation
> webnav
= do_QueryInterface(root
);
12297 return webnav
->GetSessionHistory();
12301 nsDocShell::GetHttpChannel(nsIChannel
* aChannel
, nsIHttpChannel
** aReturn
)
12303 NS_ENSURE_ARG_POINTER(aReturn
);
12305 return NS_ERROR_FAILURE
;
12308 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(aChannel
));
12309 if (multiPartChannel
) {
12310 nsCOMPtr
<nsIChannel
> baseChannel
;
12311 multiPartChannel
->GetBaseChannel(getter_AddRefs(baseChannel
));
12312 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(baseChannel
));
12313 *aReturn
= httpChannel
;
12314 NS_IF_ADDREF(*aReturn
);
12320 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel
* aChannel
)
12322 // By default layout State will be saved.
12327 // figure out if SH should be saving layout state
12328 bool noStore
= false;
12329 Unused
<< aChannel
->IsNoStoreResponse(&noStore
);
12334 nsDocShell::GetEditor(nsIEditor
** aEditor
)
12336 NS_ENSURE_ARG_POINTER(aEditor
);
12337 RefPtr
<HTMLEditor
> htmlEditor
= GetHTMLEditorInternal();
12338 htmlEditor
.forget(aEditor
);
12343 nsDocShell::SetEditor(nsIEditor
* aEditor
)
12345 HTMLEditor
* htmlEditor
= aEditor
? aEditor
->AsHTMLEditor() : nullptr;
12346 // If TextEditor comes, throw an error.
12347 if (aEditor
&& !htmlEditor
) {
12348 return NS_ERROR_INVALID_ARG
;
12350 return SetHTMLEditorInternal(htmlEditor
);
12354 nsDocShell::GetHTMLEditorInternal()
12356 return mEditorData
? mEditorData
->GetHTMLEditor() : nullptr;
12360 nsDocShell::SetHTMLEditorInternal(HTMLEditor
* aHTMLEditor
)
12362 if (!aHTMLEditor
&& !mEditorData
) {
12366 nsresult rv
= EnsureEditorData();
12367 if (NS_FAILED(rv
)) {
12371 return mEditorData
->SetHTMLEditor(aHTMLEditor
);
12375 nsDocShell::GetEditable(bool* aEditable
)
12377 NS_ENSURE_ARG_POINTER(aEditable
);
12378 *aEditable
= mEditorData
&& mEditorData
->GetEditable();
12383 nsDocShell::GetHasEditingSession(bool* aHasEditingSession
)
12385 NS_ENSURE_ARG_POINTER(aHasEditingSession
);
12388 nsCOMPtr
<nsIEditingSession
> editingSession
;
12389 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
12390 *aHasEditingSession
= (editingSession
.get() != nullptr);
12392 *aHasEditingSession
= false;
12399 nsDocShell::MakeEditable(bool aInWaitForUriLoad
)
12401 nsresult rv
= EnsureEditorData();
12402 if (NS_FAILED(rv
)) {
12406 return mEditorData
->MakeEditable(aInWaitForUriLoad
);
12410 nsDocShell::ChannelIsPost(nsIChannel
* aChannel
)
12412 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
12413 if (!httpChannel
) {
12417 nsAutoCString method
;
12418 Unused
<< httpChannel
->GetRequestMethod(method
);
12419 return method
.EqualsLiteral("POST");
12423 nsDocShell::ExtractLastVisit(nsIChannel
* aChannel
,
12425 uint32_t* aChannelRedirectFlags
)
12427 nsCOMPtr
<nsIPropertyBag2
> props(do_QueryInterface(aChannel
));
12432 nsresult rv
= props
->GetPropertyAsInterface(
12433 NS_LITERAL_STRING("docshell.previousURI"),
12434 NS_GET_IID(nsIURI
),
12435 reinterpret_cast<void**>(aURI
));
12437 if (NS_FAILED(rv
)) {
12438 // There is no last visit for this channel, so this must be the first
12439 // link. Link the visit to the referrer of this request, if any.
12440 // Treat referrer as null if there is an error getting it.
12441 (void)NS_GetReferrerFromChannel(aChannel
, aURI
);
12443 rv
= props
->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12444 aChannelRedirectFlags
);
12446 NS_WARNING_ASSERTION(
12448 "Could not fetch previous flags, URI will be treated like referrer");
12453 nsDocShell::SaveLastVisit(nsIChannel
* aChannel
,
12455 uint32_t aChannelRedirectFlags
)
12457 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(aChannel
));
12458 if (!props
|| !aURI
) {
12462 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
12464 props
->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12465 aChannelRedirectFlags
);
12469 nsDocShell::AddURIVisit(nsIURI
* aURI
,
12470 nsIURI
* aReferrerURI
,
12471 nsIURI
* aPreviousURI
,
12472 uint32_t aChannelRedirectFlags
,
12473 uint32_t aResponseStatus
)
12475 MOZ_ASSERT(aURI
, "Visited URI is null!");
12476 MOZ_ASSERT(mLoadType
!= LOAD_ERROR_PAGE
&&
12477 mLoadType
!= LOAD_BYPASS_HISTORY
,
12478 "Do not add error or bypass pages to global history");
12480 // Only content-type docshells save URI visits. Also don't do
12481 // anything here if we're not supposed to use global history.
12482 if (mItemType
!= typeContent
|| !mUseGlobalHistory
|| UsePrivateBrowsing()) {
12486 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
12489 uint32_t visitURIFlags
= 0;
12492 visitURIFlags
|= IHistory::TOP_LEVEL
;
12495 if (aChannelRedirectFlags
& nsIChannelEventSink::REDIRECT_TEMPORARY
) {
12496 visitURIFlags
|= IHistory::REDIRECT_TEMPORARY
;
12497 } else if (aChannelRedirectFlags
& nsIChannelEventSink::REDIRECT_PERMANENT
) {
12498 visitURIFlags
|= IHistory::REDIRECT_PERMANENT
;
12500 MOZ_ASSERT(!aChannelRedirectFlags
,
12501 "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
12502 "if any flags in aChannelRedirectFlags is set.");
12505 if (aResponseStatus
>= 300 && aResponseStatus
< 400) {
12506 visitURIFlags
|= IHistory::REDIRECT_SOURCE
;
12507 if (aResponseStatus
== 301 || aResponseStatus
== 308) {
12508 visitURIFlags
|= IHistory::REDIRECT_SOURCE_PERMANENT
;
12511 // Errors 400-501 and 505 are considered unrecoverable, in the sense a
12512 // simple retry attempt by the user is unlikely to solve them.
12513 // 408 is special cased, since may actually indicate a temporary
12514 // connection problem.
12515 else if (aResponseStatus
!= 408 &&
12516 ((aResponseStatus
>= 400 && aResponseStatus
<= 501) ||
12517 aResponseStatus
== 505)) {
12518 visitURIFlags
|= IHistory::UNRECOVERABLE_ERROR
;
12521 (void)history
->VisitURI(aURI
, aPreviousURI
, visitURIFlags
);
12525 //*****************************************************************************
12526 // nsDocShell: Helper Routines
12527 //*****************************************************************************
12530 nsDocShell::SetLoadType(uint32_t aLoadType
)
12532 mLoadType
= aLoadType
;
12537 nsDocShell::GetLoadType(uint32_t* aLoadType
)
12539 *aLoadType
= mLoadType
;
12544 nsDocShell::ConfirmRepost(bool* aRepost
)
12546 nsCOMPtr
<nsIPrompt
> prompter
;
12547 CallGetInterface(this, static_cast<nsIPrompt
**>(getter_AddRefs(prompter
)));
12549 return NS_ERROR_NOT_AVAILABLE
;
12552 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
12553 mozilla::services::GetStringBundleService();
12554 if (!stringBundleService
) {
12555 return NS_ERROR_FAILURE
;
12558 nsCOMPtr
<nsIStringBundle
> appBundle
;
12559 nsresult rv
= stringBundleService
->CreateBundle(kAppstringsBundleURL
,
12560 getter_AddRefs(appBundle
));
12561 NS_ENSURE_SUCCESS(rv
, rv
);
12563 nsCOMPtr
<nsIStringBundle
> brandBundle
;
12564 rv
= stringBundleService
->CreateBundle(kBrandBundleURL
,
12565 getter_AddRefs(brandBundle
));
12566 NS_ENSURE_SUCCESS(rv
, rv
);
12568 NS_ASSERTION(prompter
&& brandBundle
&& appBundle
,
12569 "Unable to set up repost prompter.");
12571 nsAutoString brandName
;
12572 rv
= brandBundle
->GetStringFromName("brandShortName", brandName
);
12574 nsAutoString msgString
, button0Title
;
12575 if (NS_FAILED(rv
)) { // No brand, use the generic version.
12576 rv
= appBundle
->GetStringFromName("confirmRepostPrompt", msgString
);
12578 // Brand available - if the app has an override file with formatting, the
12579 // app name will be included. Without an override, the prompt will look
12580 // like the generic version.
12581 const char16_t
* formatStrings
[] = { brandName
.get() };
12582 rv
= appBundle
->FormatStringFromName("confirmRepostPrompt",
12584 ArrayLength(formatStrings
),
12587 if (NS_FAILED(rv
)) {
12591 rv
= appBundle
->GetStringFromName("resendButton.label", button0Title
);
12592 if (NS_FAILED(rv
)) {
12596 // Make the repost prompt tab modal to prevent malicious pages from locking
12597 // up the browser, see bug 1412559 for an example.
12598 if (nsCOMPtr
<nsIWritablePropertyBag2
> promptBag
= do_QueryInterface(prompter
)) {
12599 promptBag
->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
12602 int32_t buttonPressed
;
12603 // The actual value here is irrelevant, but we can't pass an invalid
12604 // bool through XPConnect.
12605 bool checkState
= false;
12606 rv
= prompter
->ConfirmEx(
12607 nullptr, msgString
.get(),
12608 (nsIPrompt::BUTTON_POS_0
* nsIPrompt::BUTTON_TITLE_IS_STRING
) +
12609 (nsIPrompt::BUTTON_POS_1
* nsIPrompt::BUTTON_TITLE_CANCEL
),
12610 button0Title
.get(), nullptr, nullptr, nullptr, &checkState
, &buttonPressed
);
12611 if (NS_FAILED(rv
)) {
12615 *aRepost
= (buttonPressed
== 0);
12620 nsDocShell::GetPromptAndStringBundle(nsIPrompt
** aPrompt
,
12621 nsIStringBundle
** aStringBundle
)
12623 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt
), (void**)aPrompt
),
12626 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
12627 mozilla::services::GetStringBundleService();
12628 NS_ENSURE_TRUE(stringBundleService
, NS_ERROR_FAILURE
);
12631 stringBundleService
->CreateBundle(kAppstringsBundleURL
, aStringBundle
),
12637 nsIScrollableFrame
*
12638 nsDocShell::GetRootScrollFrame()
12640 nsCOMPtr
<nsIPresShell
> shell
= GetPresShell();
12641 NS_ENSURE_TRUE(shell
, nullptr);
12643 return shell
->GetRootScrollFrameAsScrollable();
12647 nsDocShell::EnsureScriptEnvironment()
12649 if (mScriptGlobal
) {
12653 if (mIsBeingDestroyed
) {
12654 return NS_ERROR_NOT_AVAILABLE
;
12658 NS_ASSERTION(!mInEnsureScriptEnv
,
12659 "Infinite loop! Calling EnsureScriptEnvironment() from "
12660 "within EnsureScriptEnvironment()!");
12662 // Yeah, this isn't re-entrant safe, but that's ok since if we
12663 // re-enter this method, we'll infinitely loop...
12664 AutoRestore
<bool> boolSetter(mInEnsureScriptEnv
);
12665 mInEnsureScriptEnv
= true;
12668 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
12669 NS_ENSURE_TRUE(browserChrome
, NS_ERROR_NOT_AVAILABLE
);
12671 uint32_t chromeFlags
;
12672 browserChrome
->GetChromeFlags(&chromeFlags
);
12674 // If our window is modal and we're not opened as chrome, make
12675 // this window a modal content window.
12676 mScriptGlobal
= NS_NewScriptGlobalObject(mItemType
== typeChrome
);
12677 MOZ_ASSERT(mScriptGlobal
);
12679 mScriptGlobal
->SetDocShell(this);
12681 // Ensure the script object is set up to run script.
12682 return mScriptGlobal
->EnsureScriptEnvironment();
12686 nsDocShell::EnsureEditorData()
12688 MOZ_ASSERT(!mIsBeingDestroyed
);
12690 bool openDocHasDetachedEditor
= mOSHE
&& mOSHE
->HasDetachedEditor();
12691 if (!mEditorData
&& !mIsBeingDestroyed
&& !openDocHasDetachedEditor
) {
12692 // We shouldn't recreate the editor data if it already exists, or
12693 // we're shutting down, or we already have a detached editor data
12694 // stored in the session history. We should only have one editordata
12696 mEditorData
= new nsDocShellEditorData(this);
12699 return mEditorData
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
12703 nsDocShell::EnsureFind()
12707 mFind
= do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv
);
12708 if (NS_FAILED(rv
)) {
12713 // we promise that the nsIWebBrowserFind that we return has been set
12714 // up to point to the focused, or content window, so we have to
12715 // set that up each time.
12717 nsIScriptGlobalObject
* scriptGO
= GetScriptGlobalObject();
12718 NS_ENSURE_TRUE(scriptGO
, NS_ERROR_UNEXPECTED
);
12720 // default to our window
12721 nsCOMPtr
<nsPIDOMWindowOuter
> ourWindow
= do_QueryInterface(scriptGO
);
12722 nsCOMPtr
<nsPIDOMWindowOuter
> windowToSearch
;
12723 nsFocusManager::GetFocusedDescendant(ourWindow
,
12724 nsFocusManager::eIncludeAllDescendants
,
12725 getter_AddRefs(windowToSearch
));
12727 nsCOMPtr
<nsIWebBrowserFindInFrames
> findInFrames
= do_QueryInterface(mFind
);
12728 if (!findInFrames
) {
12729 return NS_ERROR_NO_INTERFACE
;
12732 rv
= findInFrames
->SetRootSearchFrame(ourWindow
);
12733 if (NS_FAILED(rv
)) {
12736 rv
= findInFrames
->SetCurrentSearchFrame(windowToSearch
);
12737 if (NS_FAILED(rv
)) {
12745 nsDocShell::IsFrame()
12747 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
12748 GetSameTypeParent(getter_AddRefs(parent
));
12753 nsDocShell::IsBeingDestroyed(bool* aDoomed
)
12755 NS_ENSURE_ARG(aDoomed
);
12756 *aDoomed
= mIsBeingDestroyed
;
12761 nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult
)
12763 NS_ENSURE_ARG(aResult
);
12764 *aResult
= mIsExecutingOnLoadHandler
;
12769 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState
** aLayoutHistoryState
)
12772 mOSHE
->GetLayoutHistoryState(aLayoutHistoryState
);
12778 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState
* aLayoutHistoryState
)
12781 mOSHE
->SetLayoutHistoryState(aLayoutHistoryState
);
12786 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
12787 nsIInterfaceRequestor
* aRequestor
)
12790 mWeakPtr
= do_GetWeakReference(aRequestor
);
12794 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
12796 mWeakPtr
= nullptr;
12799 NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy
, nsIInterfaceRequestor
)
12802 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID
& aIID
,
12805 NS_ENSURE_ARG_POINTER(aSink
);
12806 nsCOMPtr
<nsIInterfaceRequestor
> ifReq
= do_QueryReferent(mWeakPtr
);
12808 return ifReq
->GetInterface(aIID
, aSink
);
12811 return NS_NOINTERFACE
;
12815 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer
* aContentViewer
)
12817 if (!aContentViewer
) {
12818 return NS_ERROR_FAILURE
;
12821 nsCOMPtr
<nsIURI
> baseURI
;
12822 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
12825 rv
= sURIFixup
->CreateExposableURI(mCurrentURI
, getter_AddRefs(baseURI
));
12828 // Get the current document and set the base uri
12830 nsIDocument
* document
= aContentViewer
->GetDocument();
12832 document
->SetBaseURI(baseURI
);
12838 //*****************************************************************************
12839 // nsDocShell::nsIAuthPromptProvider
12840 //*****************************************************************************
12843 nsDocShell::GetAuthPrompt(uint32_t aPromptReason
, const nsIID
& aIID
,
12846 // a priority prompt request will override a false mAllowAuth setting
12847 bool priorityPrompt
= (aPromptReason
== PROMPT_PROXY
);
12849 if (!mAllowAuth
&& !priorityPrompt
) {
12850 return NS_ERROR_NOT_AVAILABLE
;
12853 // we're either allowing auth, or it's a proxy request
12855 nsCOMPtr
<nsIPromptFactory
> wwatch
=
12856 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
12857 NS_ENSURE_SUCCESS(rv
, rv
);
12859 rv
= EnsureScriptEnvironment();
12860 NS_ENSURE_SUCCESS(rv
, rv
);
12862 // Get the an auth prompter for our window so that the parenting
12863 // of the dialogs works as it should when using tabs.
12865 return wwatch
->GetPrompt(mScriptGlobal
->AsOuter(), aIID
,
12866 reinterpret_cast<void**>(aResult
));
12869 //*****************************************************************************
12870 // nsDocShell::nsILoadContext
12871 //*****************************************************************************
12874 nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy
** aWindow
)
12876 CallGetInterface(this, aWindow
);
12881 nsDocShell::GetTopWindow(mozIDOMWindowProxy
** aWindow
)
12883 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
12885 win
= win
->GetTop();
12887 win
.forget(aWindow
);
12892 nsDocShell::GetTopFrameElement(Element
** aElement
)
12894 *aElement
= nullptr;
12895 nsCOMPtr
<nsPIDOMWindowOuter
> win
= GetWindow();
12900 nsCOMPtr
<nsPIDOMWindowOuter
> top
= win
->GetScriptableTop();
12901 NS_ENSURE_TRUE(top
, NS_ERROR_FAILURE
);
12903 // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
12904 // inside <iframe mozbrowser>, we want to return the iframe, not null.
12905 // And we want to cross the content/chrome boundary.
12906 RefPtr
<Element
> elt
= top
->GetFrameElementInternal();
12907 elt
.forget(aElement
);
12912 nsDocShell::GetNestedFrameId(uint64_t* aId
)
12919 nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection
)
12921 *aUseTrackingProtection
= false;
12923 static bool sTPEnabled
= false;
12924 static bool sTPInPBEnabled
= false;
12925 static bool sPrefsInit
= false;
12929 Preferences::AddBoolVarCache(&sTPEnabled
,
12930 "privacy.trackingprotection.enabled", false);
12931 Preferences::AddBoolVarCache(&sTPInPBEnabled
,
12932 "privacy.trackingprotection.pbmode.enabled", false);
12935 if (mUseTrackingProtection
|| sTPEnabled
||
12936 (UsePrivateBrowsing() && sTPInPBEnabled
)) {
12937 *aUseTrackingProtection
= true;
12941 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
12943 return parent
->GetUseTrackingProtection(aUseTrackingProtection
);
12950 nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection
)
12952 mUseTrackingProtection
= aUseTrackingProtection
;
12957 nsDocShell::GetIsContent(bool* aIsContent
)
12959 *aIsContent
= (mItemType
== typeContent
);
12964 nsDocShell::IsOKToLoadURI(nsIURI
* aURI
)
12966 MOZ_ASSERT(aURI
, "Must have a URI!");
12968 if (!mFiredUnloadEvent
) {
12972 if (!mLoadingURI
) {
12976 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
12977 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
12979 NS_SUCCEEDED(secMan
->CheckSameOriginURI(aURI
, mLoadingURI
, false));
12983 // Routines for selection and clipboard
12986 nsDocShell::GetControllerForCommand(const char* aCommand
,
12987 nsIController
** aResult
)
12989 NS_ENSURE_ARG_POINTER(aResult
);
12990 *aResult
= nullptr;
12992 NS_ENSURE_TRUE(mScriptGlobal
, NS_ERROR_FAILURE
);
12994 nsCOMPtr
<nsPIWindowRoot
> root
= mScriptGlobal
->GetTopWindowRoot();
12995 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
12997 return root
->GetControllerForCommand(aCommand
, false /* for any window */,
13002 nsDocShell::IsCommandEnabled(const char* aCommand
, bool* aResult
)
13004 NS_ENSURE_ARG_POINTER(aResult
);
13007 nsresult rv
= NS_ERROR_FAILURE
;
13009 nsCOMPtr
<nsIController
> controller
;
13010 rv
= GetControllerForCommand(aCommand
, getter_AddRefs(controller
));
13012 rv
= controller
->IsCommandEnabled(aCommand
, aResult
);
13019 nsDocShell::DoCommand(const char* aCommand
)
13021 nsresult rv
= NS_ERROR_FAILURE
;
13023 nsCOMPtr
<nsIController
> controller
;
13024 rv
= GetControllerForCommand(aCommand
, getter_AddRefs(controller
));
13026 rv
= controller
->DoCommand(aCommand
);
13033 nsDocShell::DoCommandWithParams(const char* aCommand
, nsICommandParams
* aParams
)
13035 nsCOMPtr
<nsIController
> controller
;
13036 nsresult rv
= GetControllerForCommand(aCommand
, getter_AddRefs(controller
));
13037 if (NS_WARN_IF(NS_FAILED(rv
))) {
13041 nsCOMPtr
<nsICommandController
> commandController
=
13042 do_QueryInterface(controller
, &rv
);
13043 if (NS_WARN_IF(NS_FAILED(rv
))) {
13047 return commandController
->DoCommandWithParams(aCommand
, aParams
);
13051 nsDocShell::EnsureCommandHandler()
13053 if (!mCommandManager
) {
13054 nsCOMPtr
<nsPICommandUpdater
> commandUpdater
=
13055 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
13056 if (!commandUpdater
) {
13057 return NS_ERROR_OUT_OF_MEMORY
;
13060 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow
= GetWindow();
13061 nsresult rv
= commandUpdater
->Init(domWindow
);
13062 if (NS_SUCCEEDED(rv
)) {
13063 mCommandManager
= do_QueryInterface(commandUpdater
);
13067 return mCommandManager
? NS_OK
: NS_ERROR_FAILURE
;
13071 nsDocShell::CanCutSelection(bool* aResult
)
13073 return IsCommandEnabled("cmd_cut", aResult
);
13077 nsDocShell::CanCopySelection(bool* aResult
)
13079 return IsCommandEnabled("cmd_copy", aResult
);
13083 nsDocShell::CanCopyLinkLocation(bool* aResult
)
13085 return IsCommandEnabled("cmd_copyLink", aResult
);
13089 nsDocShell::CanCopyImageLocation(bool* aResult
)
13091 return IsCommandEnabled("cmd_copyImageLocation", aResult
);
13095 nsDocShell::CanCopyImageContents(bool* aResult
)
13097 return IsCommandEnabled("cmd_copyImageContents", aResult
);
13101 nsDocShell::CanPaste(bool* aResult
)
13103 return IsCommandEnabled("cmd_paste", aResult
);
13107 nsDocShell::CutSelection(void)
13109 return DoCommand("cmd_cut");
13113 nsDocShell::CopySelection(void)
13115 return DoCommand("cmd_copy");
13119 nsDocShell::CopyLinkLocation(void)
13121 return DoCommand("cmd_copyLink");
13125 nsDocShell::CopyImageLocation(void)
13127 return DoCommand("cmd_copyImageLocation");
13131 nsDocShell::CopyImageContents(void)
13133 return DoCommand("cmd_copyImageContents");
13137 nsDocShell::Paste(void)
13139 return DoCommand("cmd_paste");
13143 nsDocShell::SelectAll(void)
13145 return DoCommand("cmd_selectAll");
13151 // Collapses the current selection, insertion point ends up at beginning
13152 // of previous selection.
13155 nsDocShell::SelectNone(void)
13157 return DoCommand("cmd_selectNone");
13162 class OnLinkClickEvent
: public Runnable
13165 OnLinkClickEvent(nsDocShell
* aHandler
, nsIContent
* aContent
,
13167 const char16_t
* aTargetSpec
,
13168 const nsAString
& aFileName
,
13169 nsIInputStream
* aPostDataStream
,
13170 nsIInputStream
* aHeadersDataStream
,
13171 bool aNoOpenerImplied
,
13172 bool aIsUserTriggered
,
13174 nsIPrincipal
* aTriggeringPrincipal
);
13176 NS_IMETHOD
Run() override
13178 nsAutoPopupStatePusher
popupStatePusher(mPopupState
);
13180 // We need to set up an AutoJSAPI here for the following reason: When we do
13181 // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
13182 // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
13183 // So we need to fake things so that we don't look like native code as far
13184 // as LegacyIsCallerNativeCode() is concerned.
13186 if (mIsTrusted
|| jsapi
.Init(mContent
->OwnerDoc()->GetScopeObject())) {
13187 mHandler
->OnLinkClickSync(mContent
, mURI
,
13188 mTargetSpec
.get(), mFileName
,
13190 mHeadersDataStream
, mNoOpenerImplied
,
13191 nullptr, nullptr, mIsUserTriggered
,
13192 mTriggeringPrincipal
);
13198 RefPtr
<nsDocShell
> mHandler
;
13199 nsCOMPtr
<nsIURI
> mURI
;
13200 nsString mTargetSpec
;
13201 nsString mFileName
;
13202 nsCOMPtr
<nsIInputStream
> mPostDataStream
;
13203 nsCOMPtr
<nsIInputStream
> mHeadersDataStream
;
13204 nsCOMPtr
<nsIContent
> mContent
;
13205 PopupControlState mPopupState
;
13206 bool mNoOpenerImplied
;
13207 bool mIsUserTriggered
;
13209 nsCOMPtr
<nsIPrincipal
> mTriggeringPrincipal
;
13212 OnLinkClickEvent::OnLinkClickEvent(nsDocShell
* aHandler
,
13213 nsIContent
* aContent
,
13215 const char16_t
* aTargetSpec
,
13216 const nsAString
& aFileName
,
13217 nsIInputStream
* aPostDataStream
,
13218 nsIInputStream
* aHeadersDataStream
,
13219 bool aNoOpenerImplied
,
13220 bool aIsUserTriggered
,
13222 nsIPrincipal
* aTriggeringPrincipal
)
13223 : mozilla::Runnable("OnLinkClickEvent")
13224 , mHandler(aHandler
)
13226 , mTargetSpec(aTargetSpec
)
13227 , mFileName(aFileName
)
13228 , mPostDataStream(aPostDataStream
)
13229 , mHeadersDataStream(aHeadersDataStream
)
13230 , mContent(aContent
)
13231 , mPopupState(mHandler
->mScriptGlobal
->GetPopupControlState())
13232 , mNoOpenerImplied(aNoOpenerImplied
)
13233 , mIsUserTriggered(aIsUserTriggered
)
13234 , mIsTrusted(aIsTrusted
)
13235 , mTriggeringPrincipal(aTriggeringPrincipal
)
13240 nsDocShell::OnLinkClick(nsIContent
* aContent
,
13242 const char16_t
* aTargetSpec
,
13243 const nsAString
& aFileName
,
13244 nsIInputStream
* aPostDataStream
,
13245 nsIInputStream
* aHeadersDataStream
,
13246 bool aIsUserTriggered
,
13248 nsIPrincipal
* aTriggeringPrincipal
)
13250 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
13252 if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI
)) {
13256 // On history navigation through Back/Forward buttons, don't execute
13257 // automatic JavaScript redirection such as |anchorElement.click()| or
13258 // |formElement.submit()|.
13260 // XXX |formElement.submit()| bypasses this checkpoint because it calls
13261 // nsDocShell::OnLinkClickSync(...) instead.
13262 if (ShouldBlockLoadingForBackButton()) {
13266 if (aContent
->IsEditable()) {
13270 nsresult rv
= NS_ERROR_FAILURE
;
13271 nsAutoString target
;
13273 nsCOMPtr
<nsIWebBrowserChrome3
> browserChrome3
= do_GetInterface(mTreeOwner
);
13274 bool noOpenerImplied
= false;
13275 if (browserChrome3
) {
13276 nsAutoString
oldTarget(aTargetSpec
);
13277 rv
= browserChrome3
->OnBeforeLinkTraversal(oldTarget
, aURI
,
13278 aContent
, mIsAppTab
, target
);
13279 if (!oldTarget
.Equals(target
)) {
13280 noOpenerImplied
= true;
13284 if (NS_FAILED(rv
)) {
13285 target
= aTargetSpec
;
13288 nsCOMPtr
<nsIRunnable
> ev
=
13289 new OnLinkClickEvent(this, aContent
, aURI
, target
.get(), aFileName
,
13290 aPostDataStream
, aHeadersDataStream
, noOpenerImplied
,
13291 aIsUserTriggered
, aIsTrusted
, aTriggeringPrincipal
);
13292 return DispatchToTabGroup(TaskCategory::UI
, ev
.forget());
13296 IsElementAnchorOrArea(nsIContent
* aContent
)
13298 // Make sure we are dealing with either an <A> or <AREA> element in the HTML
13299 // or XHTML namespace.
13300 return aContent
->IsAnyOfHTMLElements(nsGkAtoms::a
, nsGkAtoms::area
);
13304 nsDocShell::OnLinkClickSync(nsIContent
* aContent
,
13306 const char16_t
* aTargetSpec
,
13307 const nsAString
& aFileName
,
13308 nsIInputStream
* aPostDataStream
,
13309 nsIInputStream
* aHeadersDataStream
,
13310 bool aNoOpenerImplied
,
13311 nsIDocShell
** aDocShell
,
13312 nsIRequest
** aRequest
,
13313 bool aIsUserTriggered
,
13314 nsIPrincipal
* aTriggeringPrincipal
)
13316 // Initialize the DocShell / Request
13318 *aDocShell
= nullptr;
13321 *aRequest
= nullptr;
13324 if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI
)) {
13328 // XXX When the linking node was HTMLFormElement, it is synchronous event.
13329 // That is, the caller of this method is not |OnLinkClickEvent::Run()|
13330 // but |HTMLFormElement::SubmitSubmission(...)|.
13331 if (aContent
->IsHTMLElement(nsGkAtoms::form
) &&
13332 ShouldBlockLoadingForBackButton()) {
13336 if (aContent
->IsEditable()) {
13341 // defer to an external protocol handler if necessary...
13342 nsCOMPtr
<nsIExternalProtocolService
> extProtService
=
13343 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
);
13344 if (extProtService
) {
13345 nsAutoCString scheme
;
13346 aURI
->GetScheme(scheme
);
13347 if (!scheme
.IsEmpty()) {
13348 // if the URL scheme does not correspond to an exposed protocol, then we
13349 // need to hand this link click over to the external protocol handler.
13352 extProtService
->IsExposedProtocol(scheme
.get(), &isExposed
);
13353 if (NS_SUCCEEDED(rv
) && !isExposed
) {
13354 return extProtService
->LoadURI(aURI
, this);
13360 uint32_t flags
= INTERNAL_LOAD_FLAGS_NONE
;
13361 if (IsElementAnchorOrArea(aContent
)) {
13362 MOZ_ASSERT(aContent
->IsHTMLElement());
13363 nsAutoString referrer
;
13364 aContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::rel
, referrer
);
13365 nsWhitespaceTokenizerTemplate
<nsContentUtils::IsHTMLWhitespace
> tok(referrer
);
13366 while (tok
.hasMoreTokens()) {
13367 const nsAString
& token
= tok
.nextToken();
13368 if (token
.LowerCaseEqualsLiteral("noreferrer")) {
13369 flags
|= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
|
13370 INTERNAL_LOAD_FLAGS_NO_OPENER
;
13371 // We now have all the flags we could possibly have, so just stop.
13374 if (token
.LowerCaseEqualsLiteral("noopener")) {
13375 flags
|= INTERNAL_LOAD_FLAGS_NO_OPENER
;
13378 if (aNoOpenerImplied
) {
13379 flags
|= INTERNAL_LOAD_FLAGS_NO_OPENER
;
13383 // Get the owner document of the link that was clicked, this will be
13384 // the document that the link is in, or the last document that the
13385 // link was in. From that document, we'll get the URI to use as the
13386 // referer, since the current URI in this docshell may be a
13387 // new document that we're in the process of loading.
13388 nsCOMPtr
<nsIDocument
> refererDoc
= aContent
->OwnerDoc();
13389 NS_ENSURE_TRUE(refererDoc
, NS_ERROR_UNEXPECTED
);
13391 // Now check that the refererDoc's inner window is the current inner
13392 // window for mScriptGlobal. If it's not, then we don't want to
13393 // follow this link.
13394 nsPIDOMWindowInner
* refererInner
= refererDoc
->GetInnerWindow();
13395 NS_ENSURE_TRUE(refererInner
, NS_ERROR_UNEXPECTED
);
13396 if (!mScriptGlobal
||
13397 mScriptGlobal
->AsOuter()->GetCurrentInnerWindow() != refererInner
) {
13398 // We're no longer the current inner window
13402 nsCOMPtr
<nsIURI
> referer
= refererDoc
->GetDocumentURI();
13403 uint32_t refererPolicy
= refererDoc
->GetReferrerPolicy();
13405 // get referrer attribute from clicked link and parse it
13406 // if per element referrer is enabled, the element referrer overrules
13407 // the document wide referrer
13408 if (IsElementAnchorOrArea(aContent
)) {
13409 net::ReferrerPolicy refPolEnum
=
13410 aContent
->AsElement()->GetReferrerPolicyAsEnum();
13411 if (refPolEnum
!= RP_Unset
) {
13412 refererPolicy
= refPolEnum
;
13416 // referer could be null here in some odd cases, but that's ok,
13417 // we'll just load the link w/o sending a referer in those cases.
13419 nsAutoString
target(aTargetSpec
);
13421 // If this is an anchor element, grab its type property to use as a hint
13422 nsAutoString typeHint
;
13423 RefPtr
<HTMLAnchorElement
> anchor
= HTMLAnchorElement::FromNode(aContent
);
13425 anchor
->GetType(typeHint
);
13426 NS_ConvertUTF16toUTF8
utf8Hint(typeHint
);
13427 nsAutoCString type
, dummy
;
13428 NS_ParseRequestContentType(utf8Hint
, type
, dummy
);
13429 CopyUTF8toUTF16(type
, typeHint
);
13432 // if the triggeringPrincipal is not passed explicitly, then we
13433 // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
13434 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
=
13435 aTriggeringPrincipal
? aTriggeringPrincipal
13436 : aContent
->NodePrincipal();
13438 // Link click (or form submission) can be triggered inside an onload handler,
13439 // and we don't want to add history entry in this case.
13440 bool inOnLoadHandler
= false;
13441 GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
13442 uint32_t loadType
= inOnLoadHandler
? LOAD_NORMAL_REPLACE
: LOAD_LINK
;
13444 if (aIsUserTriggered
) {
13445 flags
|= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED
;
13448 nsresult rv
= InternalLoad(aURI
, // New URI
13449 nullptr, // Original URI
13450 Nothing(), // Let the protocol handler assign it
13451 false, // LoadReplace
13452 referer
, // Referer URI
13453 refererPolicy
, // Referer policy
13454 triggeringPrincipal
,
13455 aContent
->NodePrincipal(),
13457 target
, // Window target
13458 NS_LossyConvertUTF16toASCII(typeHint
).get(),
13459 aFileName
, // Download as file
13460 aPostDataStream
, // Post data stream
13461 aHeadersDataStream
, // Headers stream
13462 loadType
, // Load type
13463 nullptr, // No SHEntry
13464 true, // first party site
13465 VoidString(), // No srcdoc
13466 this, // We are the source
13467 nullptr, // baseURI not needed
13468 aDocShell
, // DocShell out-param
13469 aRequest
); // Request out-param
13470 if (NS_SUCCEEDED(rv
)) {
13471 nsPingListener::DispatchPings(this, aContent
, aURI
, referer
, refererPolicy
);
13477 nsDocShell::OnOverLink(nsIContent
* aContent
,
13479 const char16_t
* aTargetSpec
)
13481 if (aContent
->IsEditable()) {
13485 nsCOMPtr
<nsIWebBrowserChrome2
> browserChrome2
= do_GetInterface(mTreeOwner
);
13486 nsresult rv
= NS_ERROR_FAILURE
;
13488 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
;
13489 if (!browserChrome2
) {
13490 browserChrome
= do_GetInterface(mTreeOwner
);
13491 if (!browserChrome
) {
13496 nsAutoCString spec
;
13497 rv
= aURI
->GetDisplaySpec(spec
);
13498 NS_ENSURE_SUCCESS(rv
, rv
);
13500 NS_ConvertUTF8toUTF16
uStr(spec
);
13502 PredictorPredict(aURI
, mCurrentURI
,
13503 nsINetworkPredictor::PREDICT_LINK
,
13504 aContent
->NodePrincipal()->OriginAttributesRef(),
13507 if (browserChrome2
) {
13508 rv
= browserChrome2
->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK
,
13511 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
, uStr
.get());
13517 nsDocShell::OnLeaveLink()
13519 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
13520 nsresult rv
= NS_ERROR_FAILURE
;
13522 if (browserChrome
) {
13523 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
,
13524 EmptyString().get());
13530 nsDocShell::ShouldBlockLoadingForBackButton()
13532 if (!(mLoadType
& LOAD_CMD_HISTORY
) ||
13533 EventStateManager::IsHandlingUserInput() ||
13534 !Preferences::GetBool("accessibility.blockjsredirection")) {
13538 bool canGoForward
= false;
13539 GetCanGoForward(&canGoForward
);
13540 return canGoForward
;
13544 nsDocShell::PluginsAllowedInCurrentDoc()
13547 if (!mContentViewer
) {
13551 nsIDocument
* doc
= mContentViewer
->GetDocument();
13556 return doc
->GetAllowPlugins();
13559 //----------------------------------------------------------------------
13560 // Web Shell Services API
13562 // This functions is only called when a new charset is detected in loading a
13563 // document. Its name should be changed to "CharsetReloadDocument"
13565 nsDocShell::ReloadDocument(const char* aCharset
, int32_t aSource
)
13567 // XXX hack. keep the aCharset and aSource wait to pick it up
13568 nsCOMPtr
<nsIContentViewer
> cv
;
13569 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv
)), NS_ERROR_FAILURE
);
13572 cv
->GetHintCharacterSetSource(&hint
);
13573 if (aSource
> hint
) {
13574 nsCString
charset(aCharset
);
13575 cv
->SetHintCharacterSet(charset
);
13576 cv
->SetHintCharacterSetSource(aSource
);
13577 if (eCharsetReloadRequested
!= mCharsetReloadState
) {
13578 mCharsetReloadState
= eCharsetReloadRequested
;
13579 switch (mLoadType
) {
13580 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
13581 return Reload(LOAD_FLAGS_CHARSET_CHANGE
|
13582 LOAD_FLAGS_BYPASS_CACHE
|
13583 LOAD_FLAGS_BYPASS_PROXY
);
13584 case LOAD_RELOAD_BYPASS_CACHE
:
13585 return Reload(LOAD_FLAGS_CHARSET_CHANGE
|
13586 LOAD_FLAGS_BYPASS_CACHE
);
13588 return Reload(LOAD_FLAGS_CHARSET_CHANGE
);
13593 // return failure if this request is not accepted due to mCharsetReloadState
13594 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
13598 nsDocShell::StopDocumentLoad(void)
13600 if (eCharsetReloadRequested
!= mCharsetReloadState
) {
13601 Stop(nsIWebNavigation::STOP_ALL
);
13604 // return failer if this request is not accepted due to mCharsetReloadState
13605 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
13609 nsDocShell::SetIsPrinting(bool aIsPrinting
)
13611 mIsPrintingOrPP
= aIsPrinting
;
13616 nsDocShell::GetPrintPreview(nsIWebBrowserPrint
** aPrintPreview
)
13618 *aPrintPreview
= nullptr;
13619 #if NS_PRINT_PREVIEW
13620 nsCOMPtr
<nsIDocumentViewerPrint
> print
= do_QueryInterface(mContentViewer
);
13621 if (!print
|| !print
->IsInitializedForPrintPreview()) {
13622 // XXX: Creating a brand new content viewer to host preview every
13623 // time we enter here seems overwork. We could skip ahead to where
13624 // we QI the mContentViewer if the current URI is either about:blank
13625 // or about:printpreview.
13626 Stop(nsIWebNavigation::STOP_ALL
);
13627 nsCOMPtr
<nsIPrincipal
> principal
= NullPrincipal::CreateWithInheritedAttributes(this);
13628 nsCOMPtr
<nsIURI
> uri
;
13629 NS_NewURI(getter_AddRefs(uri
), NS_LITERAL_CSTRING("about:printpreview"));
13630 nsresult rv
= CreateAboutBlankContentViewer(principal
, uri
);
13631 NS_ENSURE_SUCCESS(rv
, rv
);
13632 // Here we manually set current URI since we have just created a
13633 // brand new content viewer (about:blank) to host preview.
13634 SetCurrentURI(uri
, nullptr, true, 0);
13635 print
= do_QueryInterface(mContentViewer
);
13636 NS_ENSURE_STATE(print
);
13637 print
->InitializeForPrintPreview();
13639 nsCOMPtr
<nsIWebBrowserPrint
> result
= do_QueryInterface(print
);
13640 result
.forget(aPrintPreview
);
13643 return NS_ERROR_NOT_IMPLEMENTED
;
13648 unsigned long nsDocShell::gNumberOfDocShells
= 0;
13652 nsDocShell::GetCanExecuteScripts(bool* aResult
)
13654 *aResult
= mCanExecuteScripts
;
13658 /* [infallible] */ NS_IMETHODIMP
13659 nsDocShell::SetFrameType(uint32_t aFrameType
)
13661 mFrameType
= aFrameType
;
13665 /* [infallible] */ NS_IMETHODIMP
13666 nsDocShell::GetFrameType(uint32_t* aFrameType
)
13668 *aFrameType
= mFrameType
;
13672 /* [infallible] */ NS_IMETHODIMP
13673 nsDocShell::GetIsMozBrowser(bool* aIsMozBrowser
)
13675 *aIsMozBrowser
= (mFrameType
== FRAME_TYPE_BROWSER
);
13680 nsDocShell::GetInheritedFrameType()
13682 if (mFrameType
!= FRAME_TYPE_REGULAR
) {
13686 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
13687 GetSameTypeParent(getter_AddRefs(parentAsItem
));
13689 nsCOMPtr
<nsIDocShell
> parent
= do_QueryInterface(parentAsItem
);
13691 return FRAME_TYPE_REGULAR
;
13694 return static_cast<nsDocShell
*>(parent
.get())->GetInheritedFrameType();
13697 /* [infallible] */ NS_IMETHODIMP
13698 nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement
)
13700 bool result
= mFrameType
== FRAME_TYPE_BROWSER
&&
13701 mOriginAttributes
.mInIsolatedMozBrowser
;
13702 *aIsIsolatedMozBrowserElement
= result
;
13706 /* [infallible] */ NS_IMETHODIMP
13707 nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement
)
13709 MOZ_ASSERT(!mOriginAttributes
.mInIsolatedMozBrowser
||
13710 (GetInheritedFrameType() == FRAME_TYPE_BROWSER
),
13711 "Isolated mozbrowser should only be true inside browser frames");
13712 bool result
= (GetInheritedFrameType() == FRAME_TYPE_BROWSER
) &&
13713 mOriginAttributes
.mInIsolatedMozBrowser
;
13714 *aIsInIsolatedMozBrowserElement
= result
;
13718 /* [infallible] */ NS_IMETHODIMP
13719 nsDocShell::GetIsInMozBrowser(bool* aIsInMozBrowser
)
13721 *aIsInMozBrowser
= (GetInheritedFrameType() == FRAME_TYPE_BROWSER
);
13725 /* [infallible] */ NS_IMETHODIMP
13726 nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell
)
13728 *aIsTopLevelContentDocShell
= false;
13730 if (mItemType
== typeContent
) {
13731 nsCOMPtr
<nsIDocShellTreeItem
> root
;
13732 GetSameTypeRootTreeItem(getter_AddRefs(root
));
13733 *aIsTopLevelContentDocShell
= root
.get() == static_cast<nsIDocShellTreeItem
*>(this);
13739 // Implements nsILoadContext.originAttributes
13741 nsDocShell::GetScriptableOriginAttributes(JS::MutableHandle
<JS::Value
> aVal
)
13743 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
13746 return GetOriginAttributes(cx
, aVal
);
13749 // Implements nsIDocShell.GetOriginAttributes()
13751 nsDocShell::GetOriginAttributes(JSContext
* aCx
,
13752 JS::MutableHandle
<JS::Value
> aVal
)
13754 bool ok
= ToJSValue(aCx
, mOriginAttributes
, aVal
);
13755 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
13760 nsDocShell::CanSetOriginAttributes()
13762 MOZ_ASSERT(mChildList
.IsEmpty());
13763 if (!mChildList
.IsEmpty()) {
13767 // TODO: Bug 1273058 - mContentViewer should be null when setting origin
13769 if (mContentViewer
) {
13770 nsIDocument
* doc
= mContentViewer
->GetDocument();
13772 nsIURI
* uri
= doc
->GetDocumentURI();
13776 nsCString uriSpec
= uri
->GetSpecOrDefault();
13777 MOZ_ASSERT(uriSpec
.EqualsLiteral("about:blank"));
13778 if (!uriSpec
.EqualsLiteral("about:blank")) {
13788 nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal
* aPrincipal
,
13791 MOZ_ASSERT(aPrincipal
);
13794 if (UsePrivateBrowsing() || mSandboxFlags
) {
13798 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
13799 GetSameTypeParent(getter_AddRefs(parent
));
13800 nsPIDOMWindowOuter
* parentOuter
= parent
? parent
->GetWindow() : nullptr;
13801 nsPIDOMWindowInner
* parentInner
=
13802 parentOuter
? parentOuter
->GetCurrentInnerWindow() : nullptr;
13804 nsContentUtils::StorageAccess storage
=
13805 nsContentUtils::StorageAllowedForNewWindow(aPrincipal
, aURI
, parentInner
);
13807 return storage
== nsContentUtils::StorageAccess::eAllow
;
13811 nsDocShell::SetOriginAttributes(const OriginAttributes
& aAttrs
)
13813 MOZ_ASSERT(!mIsBeingDestroyed
);
13815 if (!CanSetOriginAttributes()) {
13816 return NS_ERROR_FAILURE
;
13819 AssertOriginAttributesMatchPrivateBrowsing();
13820 mOriginAttributes
= aAttrs
;
13822 bool isPrivate
= mOriginAttributes
.mPrivateBrowsingId
> 0;
13823 // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
13824 if (mItemType
== typeChrome
&& isPrivate
) {
13825 mOriginAttributes
.mPrivateBrowsingId
= 0;
13828 SetPrivateBrowsing(isPrivate
);
13829 AssertOriginAttributesMatchPrivateBrowsing();
13835 nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle
<JS::Value
> aOriginAttributes
)
13837 if (!aOriginAttributes
.isObject()) {
13838 return NS_ERROR_INVALID_ARG
;
13842 if (!jsapi
.Init(&aOriginAttributes
.toObject())) {
13843 return NS_ERROR_UNEXPECTED
;
13846 JSContext
* cx
= jsapi
.cx();
13847 if (NS_WARN_IF(!cx
)) {
13848 return NS_ERROR_FAILURE
;
13851 OriginAttributes attrs
;
13852 if (!aOriginAttributes
.isObject() || !attrs
.Init(cx
, aOriginAttributes
)) {
13853 return NS_ERROR_INVALID_ARG
;
13856 return SetOriginAttributes(attrs
);
13860 nsDocShell::SetOriginAttributes(JS::Handle
<JS::Value
> aOriginAttributes
,
13863 OriginAttributes attrs
;
13864 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
13865 return NS_ERROR_INVALID_ARG
;
13868 return SetOriginAttributes(attrs
);
13872 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut
)
13874 if (nsIPresShell
* presShell
= GetPresShell()) {
13875 *aOut
= presShell
->AsyncPanZoomEnabled();
13879 // If we don't have a presShell, fall back to the default platform value of
13880 // whether or not APZ is enabled.
13881 *aOut
= gfxPlatform::AsyncPanZoomEnabled();
13886 nsDocShell::HasUnloadedParent()
13888 RefPtr
<nsDocShell
> parent
= GetParentDocshell();
13890 bool inUnload
= false;
13891 parent
->GetIsInUnload(&inUnload
);
13895 parent
= parent
->GetParentDocshell();
13901 nsDocShell::UpdateGlobalHistoryTitle(nsIURI
* aURI
)
13903 if (mUseGlobalHistory
&& !UsePrivateBrowsing()) {
13904 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
13906 history
->SetURITitle(aURI
, mTitle
);
13912 nsDocShell::IsInvisible()
13918 nsDocShell::SetInvisible(bool aInvisible
)
13920 mInvisible
= aInvisible
;
13924 nsDocShell::SetOpener(nsITabParent
* aOpener
)
13926 mOpener
= do_GetWeakReference(aOpener
);
13930 nsDocShell::GetOpener()
13932 nsCOMPtr
<nsITabParent
> opener(do_QueryReferent(mOpener
));
13936 // The caller owns |aAsyncCause| here.
13938 nsDocShell::NotifyJSRunToCompletionStart(const char* aReason
,
13939 const char16_t
* aFunctionName
,
13940 const char16_t
* aFilename
,
13941 const uint32_t aLineNumber
,
13942 JS::Handle
<JS::Value
> aAsyncStack
,
13943 const char* aAsyncCause
)
13945 // If first start, mark interval start.
13946 if (mJSRunToCompletionDepth
== 0) {
13947 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
13948 if (timelines
&& timelines
->HasConsumer(this)) {
13949 timelines
->AddMarkerForDocShell(this,
13950 mozilla::MakeUnique
<JavascriptTimelineMarker
>(
13951 aReason
, aFunctionName
, aFilename
, aLineNumber
, MarkerTracingType::START
,
13952 aAsyncStack
, aAsyncCause
));
13956 mJSRunToCompletionDepth
++;
13960 nsDocShell::NotifyJSRunToCompletionStop()
13962 mJSRunToCompletionDepth
--;
13964 // If last stop, mark interval end.
13965 if (mJSRunToCompletionDepth
== 0) {
13966 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
13967 if (timelines
&& timelines
->HasConsumer(this)) {
13968 timelines
->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END
);
13974 nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString
& aProvider
,
13975 const nsString
& aKeyword
)
13977 if (aProvider
.IsEmpty()) {
13981 if (XRE_IsContentProcess()) {
13982 dom::ContentChild
* contentChild
= dom::ContentChild::GetSingleton();
13983 if (contentChild
) {
13984 contentChild
->SendNotifyKeywordSearchLoading(aProvider
, aKeyword
);
13989 #ifdef MOZ_TOOLKIT_SEARCH
13990 nsCOMPtr
<nsIBrowserSearchService
> searchSvc
=
13991 do_GetService("@mozilla.org/browser/search-service;1");
13993 nsCOMPtr
<nsISearchEngine
> searchEngine
;
13994 searchSvc
->GetEngineByName(aProvider
, getter_AddRefs(searchEngine
));
13995 if (searchEngine
) {
13996 nsCOMPtr
<nsIObserverService
> obsSvc
= services::GetObserverService();
13998 // Note that "keyword-search" refers to a search via the url
13999 // bar, not a bookmarks keyword search.
14000 obsSvc
->NotifyObservers(searchEngine
, "keyword-search", aKeyword
.get());
14008 nsDocShell::ShouldPrepareForIntercept(nsIURI
* aURI
, nsIChannel
* aChannel
,
14009 bool* aShouldIntercept
)
14011 return mInterceptController
->ShouldPrepareForIntercept(aURI
, aChannel
,
14016 nsDocShell::ChannelIntercepted(nsIInterceptedChannel
* aChannel
)
14018 return mInterceptController
->ChannelIntercepted(aChannel
);
14022 nsDocShell::InFrameSwap()
14024 RefPtr
<nsDocShell
> shell
= this;
14026 if (shell
->mInFrameSwap
) {
14029 shell
= shell
->GetParentDocshell();
14034 UniquePtr
<ClientSource
>
14035 nsDocShell::TakeInitialClientSource()
14037 return std::move(mInitialClientSource
);
14041 nsDocShell::IssueWarning(uint32_t aWarning
, bool aAsError
)
14043 if (mContentViewer
) {
14044 nsCOMPtr
<nsIDocument
> doc
= mContentViewer
->GetDocument();
14046 doc
->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning
), aAsError
);
14053 nsDocShell::GetEditingSession(nsIEditingSession
** aEditSession
)
14055 if (!NS_SUCCEEDED(EnsureEditorData())) {
14056 return NS_ERROR_FAILURE
;
14059 mEditorData
->GetEditingSession(aEditSession
);
14060 return *aEditSession
? NS_OK
: NS_ERROR_FAILURE
;
14064 nsDocShell::GetScriptableTabChild(nsITabChild
** aTabChild
)
14066 *aTabChild
= GetTabChild().take();
14067 return *aTabChild
? NS_OK
: NS_ERROR_FAILURE
;
14070 already_AddRefed
<nsITabChild
>
14071 nsDocShell::GetTabChild()
14073 nsCOMPtr
<nsIDocShellTreeOwner
> owner(mTreeOwner
);
14074 nsCOMPtr
<nsITabChild
> tc
= do_GetInterface(owner
);
14075 return tc
.forget();
14079 nsDocShell::GetCommandManager()
14081 NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
14082 return mCommandManager
;
14086 nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult
)
14088 MOZ_ASSERT(aResult
);
14090 nsPIDOMWindowOuter
* outer
= GetWindow();
14093 // If we are not toplevel then we are not the only toplevel window in the tab
14095 if (outer
->GetScriptableParentOrNull()) {
14100 // If we have any other toplevel windows in our tab group, then we are not the
14101 // only toplevel window in the tab group.
14102 nsTArray
<nsPIDOMWindowOuter
*> toplevelWindows
=
14103 outer
->TabGroup()->GetTopLevelWindows();
14104 if (toplevelWindows
.Length() > 1) {
14108 MOZ_ASSERT(toplevelWindows
.Length() == 1);
14109 MOZ_ASSERT(toplevelWindows
[0] == outer
);
14116 nsDocShell::GetAwaitingLargeAlloc(bool* aResult
)
14118 MOZ_ASSERT(aResult
);
14119 nsCOMPtr
<nsITabChild
> tabChild
= GetTabChild();
14124 *aResult
= static_cast<TabChild
*>(tabChild
.get())->IsAwaitingLargeAlloc();
14128 NS_IMETHODIMP_(void)
14129 nsDocShell::GetOriginAttributes(mozilla::OriginAttributes
& aAttrs
)
14131 aAttrs
= mOriginAttributes
;
14135 nsIDocShell::GetHTMLEditor()
14137 nsDocShell
* docShell
= static_cast<nsDocShell
*>(this);
14138 return docShell
->GetHTMLEditorInternal();
14142 nsIDocShell::SetHTMLEditor(HTMLEditor
* aHTMLEditor
)
14144 nsDocShell
* docShell
= static_cast<nsDocShell
*>(this);
14145 return docShell
->SetHTMLEditorInternal(aHTMLEditor
);
14149 nsDocShell::GetDisplayMode(uint32_t* aDisplayMode
)
14151 NS_ENSURE_ARG_POINTER(aDisplayMode
);
14152 *aDisplayMode
= mDisplayMode
;
14157 nsDocShell::SetDisplayMode(uint32_t aDisplayMode
)
14159 if (!(aDisplayMode
== nsIDocShell::DISPLAY_MODE_BROWSER
||
14160 aDisplayMode
== nsIDocShell::DISPLAY_MODE_STANDALONE
||
14161 aDisplayMode
== nsIDocShell::DISPLAY_MODE_FULLSCREEN
||
14162 aDisplayMode
== nsIDocShell::DISPLAY_MODE_MINIMAL_UI
)) {
14163 return NS_ERROR_INVALID_ARG
;
14166 if (aDisplayMode
!= mDisplayMode
) {
14167 mDisplayMode
= aDisplayMode
;
14169 RefPtr
<nsPresContext
> presContext
;
14170 if (NS_SUCCEEDED(GetPresContext(getter_AddRefs(presContext
)))) {
14171 presContext
->MediaFeatureValuesChangedAllDocuments({
14172 MediaFeatureChangeReason::DisplayModeChange
});
14180 nsDocShell::SetColorMatrix(float* aMatrix
, uint32_t aMatrixLen
)
14182 if (aMatrixLen
== 20) {
14183 mColorMatrix
.reset(new gfx::Matrix5x4());
14184 MOZ_ASSERT(aMatrixLen
* sizeof(*aMatrix
) == sizeof(mColorMatrix
->components
));
14185 memcpy(mColorMatrix
->components
, aMatrix
, sizeof(mColorMatrix
->components
));
14186 } else if (aMatrixLen
== 0) {
14187 mColorMatrix
.reset();
14189 return NS_ERROR_INVALID_ARG
;
14192 nsIPresShell
* presShell
= GetPresShell();
14194 return NS_ERROR_FAILURE
;
14197 nsIFrame
* frame
= presShell
->GetRootFrame();
14199 return NS_ERROR_FAILURE
;
14202 frame
->SchedulePaint();
14208 nsDocShell::GetColorMatrix(uint32_t* aMatrixLen
, float** aMatrix
)
14210 NS_ENSURE_ARG_POINTER(aMatrixLen
);
14213 NS_ENSURE_ARG_POINTER(aMatrix
);
14214 *aMatrix
= nullptr;
14216 if (mColorMatrix
) {
14217 *aMatrix
= (float*)moz_xmalloc(20 * sizeof(float));
14219 return NS_ERROR_OUT_OF_MEMORY
;
14222 MOZ_ASSERT(20 * sizeof(float) == sizeof(mColorMatrix
->components
));
14224 memcpy(*aMatrix
, mColorMatrix
->components
, 20 * sizeof(float));