Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/docshell/base/./../../../docshell/base/nsDocShell.cpp
Warning:line 3645, column 9
Value stored to 'error' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_docshell_base0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/docshell/base -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/docshell/base -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/docshell/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/docshell/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/docshell/shistory -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/bindings -I /root/firefox-clang/js/xpconnect/src -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/xul -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/netwerk/protocol/viewsource -I /root/firefox-clang/toolkit/components/browser -I /root/firefox-clang/toolkit/components/find -I /root/firefox-clang/tools/profiler -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-11-12-001017-1011516-1 -x c++ Unified_cpp_docshell_base0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsDocShell.h"
6
7#include <algorithm>
8#include "mozilla/CycleCollectedJSContext.h"
9#include "mozilla/dom/HTMLFormElement.h"
10
11#ifdef XP_WIN
12# include <process.h>
13# define getpid _getpid
14#else
15# include <unistd.h> // for getpid()
16#endif
17
18#include "nsDeviceContext.h"
19#include "mozilla/Attributes.h"
20#include "mozilla/AutoRestore.h"
21#include "mozilla/BasePrincipal.h"
22#include "mozilla/Casting.h"
23#include "mozilla/CheckedInt.h"
24#include "mozilla/Components.h"
25#include "mozilla/Encoding.h"
26#include "mozilla/EventStateManager.h"
27#include "mozilla/HTMLEditor.h"
28#include "mozilla/InputTaskManager.h"
29#include "mozilla/LoadInfo.h"
30#include "mozilla/Logging.h"
31#include "mozilla/MediaFeatureChange.h"
32#include "mozilla/Preferences.h"
33#include "mozilla/PresShell.h"
34#include "mozilla/SchedulerGroup.h"
35#include "mozilla/ScopeExit.h"
36#include "mozilla/ScrollContainerFrame.h"
37#include "mozilla/ScrollTypes.h"
38#include "mozilla/SimpleEnumerator.h"
39#include "mozilla/StaticPrefs_browser.h"
40#include "mozilla/StaticPrefs_docshell.h"
41#include "mozilla/StaticPrefs_dom.h"
42#include "mozilla/StaticPrefs_extensions.h"
43#include "mozilla/StaticPrefs_mathml.h"
44#include "mozilla/StaticPrefs_network.h"
45#include "mozilla/StaticPrefs_privacy.h"
46#include "mozilla/StaticPrefs_security.h"
47#include "mozilla/StaticPrefs_ui.h"
48#include "mozilla/StaticPrefs_fission.h"
49#include "mozilla/StartupTimeline.h"
50#include "mozilla/StorageAccess.h"
51#include "mozilla/StoragePrincipalHelper.h"
52#include "mozilla/Telemetry.h"
53
54#include "mozilla/WidgetUtils.h"
55
56#include "mozilla/dom/AutoEntryScript.h"
57#include "mozilla/dom/ChildProcessChannelListener.h"
58#include "mozilla/dom/ClientChannelHelper.h"
59#include "mozilla/dom/ClientHandle.h"
60#include "mozilla/dom/ClientInfo.h"
61#include "mozilla/dom/ClientManager.h"
62#include "mozilla/dom/ClientSource.h"
63#include "mozilla/dom/ContentChild.h"
64#include "mozilla/dom/ContentFrameMessageManager.h"
65#include "mozilla/dom/DocGroup.h"
66#include "mozilla/dom/Element.h"
67#include "mozilla/dom/FragmentDirective.h"
68#include "mozilla/dom/HTMLAnchorElement.h"
69#include "mozilla/dom/HTMLIFrameElement.h"
70#include "mozilla/dom/Navigation.h"
71#include "mozilla/dom/NavigationBinding.h"
72#include "mozilla/dom/NavigationHistoryEntry.h"
73#include "mozilla/dom/NavigationUtils.h"
74#include "mozilla/dom/PerformanceNavigation.h"
75#include "mozilla/dom/PermissionMessageUtils.h"
76#include "mozilla/dom/PolicyContainer.h"
77#include "mozilla/dom/PopupBlocker.h"
78#include "mozilla/dom/ScreenOrientation.h"
79#include "mozilla/dom/ScriptSettings.h"
80#include "mozilla/dom/ServiceWorkerInterceptController.h"
81#include "mozilla/dom/ServiceWorkerUtils.h"
82#include "mozilla/dom/SessionHistoryEntry.h"
83#include "mozilla/dom/SessionStorageManager.h"
84#include "mozilla/dom/SessionStoreChangeListener.h"
85#include "mozilla/dom/SessionStoreChild.h"
86#include "mozilla/dom/SessionStoreUtils.h"
87#include "mozilla/dom/TrustedTypeUtils.h"
88#include "mozilla/dom/TrustedTypesConstants.h"
89#include "mozilla/dom/BrowserChild.h"
90#include "mozilla/dom/ToJSValue.h"
91#include "mozilla/dom/UserActivation.h"
92#include "mozilla/dom/ChildSHistory.h"
93#include "mozilla/dom/nsCSPContext.h"
94#include "mozilla/dom/nsHTTPSOnlyUtils.h"
95#include "mozilla/dom/LoadURIOptionsBinding.h"
96#include "mozilla/dom/JSWindowActorChild.h"
97#include "mozilla/dom/DocumentBinding.h"
98#include "mozilla/glean/DocshellMetrics.h"
99#include "mozilla/ipc/ProtocolUtils.h"
100#include "mozilla/net/DocumentChannel.h"
101#include "mozilla/net/DocumentChannelChild.h"
102#include "mozilla/net/ParentChannelWrapper.h"
103#include "mozilla/net/UrlClassifierFeatureFactory.h"
104#include "ReferrerInfo.h"
105
106#include "nsIAuthPrompt.h"
107#include "nsIAuthPrompt2.h"
108#include "nsICachingChannel.h"
109#include "nsICaptivePortalService.h"
110#include "nsIChannel.h"
111#include "nsIChannelEventSink.h"
112#include "nsIClassifiedChannel.h"
113#include "nsIClassOfService.h"
114#include "nsIConsoleReportCollector.h"
115#include "nsIContent.h"
116#include "nsIContentInlines.h"
117#include "nsIContentSecurityPolicy.h"
118#include "nsIController.h"
119#include "nsIDocShellTreeItem.h"
120#include "nsIDocShellTreeOwner.h"
121#include "nsIDocumentViewer.h"
122#include "mozilla/dom/Document.h"
123#include "mozilla/dom/ViewTransition.h"
124#include "nsHTMLDocument.h"
125#include "nsIDocumentLoaderFactory.h"
126#include "nsIDOMWindow.h"
127#include "nsIEditingSession.h"
128#include "nsIEffectiveTLDService.h"
129#include "nsExternalHelperAppService.h"
130#include "nsIExternalProtocolService.h"
131#include "nsIFormPOSTActionChannel.h"
132#include "nsIFrame.h"
133#include "nsIGlobalObject.h"
134#include "nsIHttpChannel.h"
135#include "nsIHttpChannelInternal.h"
136#include "nsIIDNService.h"
137#include "nsIInputStreamChannel.h"
138#include "nsIInterfaceRequestorUtils.h"
139#include "nsILayoutHistoryState.h"
140#include "nsILoadInfo.h"
141#include "nsILoadURIDelegate.h"
142#include "nsIMultiPartChannel.h"
143#include "nsINestedURI.h"
144#include "nsINode.h"
145#include "nsINSSErrorsService.h"
146#include "nsIObserverService.h"
147#include "nsIOService.h"
148#include "nsIPrincipal.h"
149#include "nsIPrivacyTransitionObserver.h"
150#include "nsIPrompt.h"
151#include "nsIPromptCollection.h"
152#include "nsIPromptFactory.h"
153#include "nsIPublicKeyPinningService.h"
154#include "nsIReflowObserver.h"
155#include "nsIScriptChannel.h"
156#include "nsIScriptObjectPrincipal.h"
157#include "nsIScriptSecurityManager.h"
158#include "nsScriptSecurityManager.h"
159#include "nsIScrollObserver.h"
160#include "nsISupportsPrimitives.h"
161#include "nsISecureBrowserUI.h"
162#include "nsISeekableStream.h"
163#include "nsISelectionDisplay.h"
164#include "nsISiteSecurityService.h"
165#include "nsISocketProvider.h"
166#include "nsIStringBundle.h"
167#include "nsIStructuredCloneContainer.h"
168#include "nsIBrowserChild.h"
169#include "nsITextToSubURI.h"
170#include "nsITimedChannel.h"
171#include "nsITimer.h"
172#include "nsITransportSecurityInfo.h"
173#include "nsIUploadChannel.h"
174#include "nsIURIFixup.h"
175#include "nsIURIMutator.h"
176#include "nsIURILoader.h"
177#include "nsIViewSourceChannel.h"
178#include "nsIWebBrowserChrome.h"
179#include "nsIWebBrowserFind.h"
180#include "nsIWebProgress.h"
181#include "nsIWidget.h"
182#include "nsIWindowWatcher.h"
183#include "nsIWritablePropertyBag2.h"
184#include "nsIX509Cert.h"
185#include "nsIXULRuntime.h"
186
187#include "nsCommandManager.h"
188#include "nsPIDOMWindow.h"
189#include "nsPIWindowRoot.h"
190
191#include "IHistory.h"
192#include "IUrlClassifierUITelemetry.h"
193
194#include "nsAboutProtocolUtils.h"
195#include "nsArray.h"
196#include "nsArrayUtils.h"
197#include "nsBrowserStatusFilter.h"
198#include "nsCExternalHandlerService.h"
199#include "nsContentDLF.h"
200#include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
201#include "nsContentSecurityManager.h"
202#include "nsContentSecurityUtils.h"
203#include "nsContentUtils.h"
204#include "nsCURILoader.h"
205#include "nsDocElementCreatedNotificationRunner.h"
206#include "nsDocShellCID.h"
207#include "nsDocShellEditorData.h"
208#include "nsDocShellEnumerator.h"
209#include "nsDocShellLoadState.h"
210#include "nsDocShellLoadTypes.h"
211#include "nsDOMCID.h"
212#include "nsDOMNavigationTiming.h"
213#include "nsDSURIContentListener.h"
214#include "nsEditingSession.h"
215#include "nsError.h"
216#include "nsEscape.h"
217#include "nsFocusManager.h"
218#include "nsGlobalWindowInner.h"
219#include "nsGlobalWindowOuter.h"
220#include "nsJSEnvironment.h"
221#include "nsNetCID.h"
222#include "nsNetUtil.h"
223#include "nsObjectLoadingContent.h"
224#include "nsPIDOMWindowInlines.h"
225#include "nsPingListener.h"
226#include "nsPoint.h"
227#include "nsQueryObject.h"
228#include "nsQueryActor.h"
229#include "nsRect.h"
230#include "nsRefreshTimer.h"
231#include "nsSandboxFlags.h"
232#include "nsSHistory.h"
233#include "nsStructuredCloneContainer.h"
234#include "nsSubDocumentFrame.h"
235#include "nsURILoader.h"
236#include "nsURLHelper.h"
237#include "nsViewSourceHandler.h"
238#include "nsWebBrowserFind.h"
239#include "nsWhitespaceTokenizer.h"
240#include "nsWidgetsCID.h"
241#include "nsXULAppAPI.h"
242
243#include "CertVerifier.h"
244#include "ThirdPartyUtil.h"
245#include "GeckoProfiler.h"
246#include "mozilla/NullPrincipal.h"
247#include "Navigator.h"
248#include "prenv.h"
249#include "mozilla/ipc/URIUtils.h"
250#include "sslerr.h"
251#include "mozpkix/pkix.h"
252#include "NSSErrorsService.h"
253
254#include "nsDocShellTelemetryUtils.h"
255
256#include "nsIOpenWindowInfo.h"
257
258#ifdef MOZ_PLACES1
259# include "mozilla/places/nsFaviconService.h"
260# include "mozIPlacesPendingOperation.h"
261#endif
262
263#include "nsIDocumentViewerPrint.h"
264#include "nsIWebBrowserPrint.h"
265
266using namespace mozilla;
267using namespace mozilla::dom;
268using namespace mozilla::net;
269
270using mozilla::ipc::Endpoint;
271
272// Threshold value in ms for META refresh based redirects
273#define REFRESH_REDIRECT_TIMER15000 15000
274
275static mozilla::LazyLogModule gCharsetMenuLog("CharsetMenu");
276static mozilla::LazyLogModule gDocShellLog("nsDocShell");
277
278#define LOGCHARSETMENU(args)do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
\
279 MOZ_LOG(gCharsetMenuLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
280
281#ifdef DEBUG1
282unsigned long nsDocShell::gNumberOfDocShells = 0;
283static uint64_t gDocshellIDCounter = 0;
284
285static mozilla::LazyLogModule gDocShellAndDOMWindowLeakLogging(
286 "DocShellAndDOMWindowLeak");
287#endif
288static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");
289extern mozilla::LazyLogModule gPageCacheLog;
290extern mozilla::LazyLogModule gNavigationAPILog;
291mozilla::LazyLogModule gSHLog("SessionHistory");
292extern mozilla::LazyLogModule gSHIPBFCacheLog;
293
294const char kAppstringsBundleURL[] =
295 "chrome://global/locale/appstrings.properties";
296
297static bool IsTopLevelDoc(BrowsingContext* aBrowsingContext,
298 nsILoadInfo* aLoadInfo) {
299 MOZ_ASSERT(aBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowsingContext))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowsingContext"
, "./../../../docshell/base/nsDocShell.cpp", 299); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aBrowsingContext" ")"); do { MOZ_CrashSequence
(__null, 299); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
300 MOZ_ASSERT(aLoadInfo)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadInfo))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLoadInfo", "./../../../docshell/base/nsDocShell.cpp"
, 300); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadInfo" ")"
); do { MOZ_CrashSequence(__null, 300); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
301
302 if (aLoadInfo->GetExternalContentPolicyType() !=
303 ExtContentPolicy::TYPE_DOCUMENT) {
304 return false;
305 }
306
307 return aBrowsingContext->IsTopContent();
308}
309
310// True if loading for top level document loading in active tab.
311static bool IsUrgentStart(BrowsingContext* aBrowsingContext,
312 nsILoadInfo* aLoadInfo, uint32_t aLoadType) {
313 MOZ_ASSERT(aBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowsingContext))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowsingContext"
, "./../../../docshell/base/nsDocShell.cpp", 313); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aBrowsingContext" ")"); do { MOZ_CrashSequence
(__null, 313); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
314 MOZ_ASSERT(aLoadInfo)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadInfo))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLoadInfo", "./../../../docshell/base/nsDocShell.cpp"
, 314); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadInfo" ")"
); do { MOZ_CrashSequence(__null, 314); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
315
316 if (!IsTopLevelDoc(aBrowsingContext, aLoadInfo)) {
317 return false;
318 }
319
320 if (aLoadType &
321 (nsIDocShell::LOAD_CMD_NORMAL | nsIDocShell::LOAD_CMD_HISTORY)) {
322 return true;
323 }
324
325 return aBrowsingContext->IsActive();
326}
327
328nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
329 uint64_t aContentWindowID)
330 : nsDocLoader(true),
331 mContentWindowID(aContentWindowID),
332 mBrowsingContext(aBrowsingContext),
333 mParentCharset(nullptr),
334 mTreeOwner(nullptr),
335 mScrollbarPref(ScrollbarPreference::Auto),
336 mCharsetReloadState(eCharsetReloadInit),
337 mParentCharsetSource(0),
338 mFrameMargins(-1, -1),
339 mItemType(aBrowsingContext->IsContent() ? typeContent : typeChrome),
340 mPreviousEntryIndex(-1),
341 mLoadedEntryIndex(-1),
342 mBusyFlags(BUSY_FLAGS_NONE),
343 mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
344 mLoadType(0),
345 mFailedLoadType(0),
346 mChannelToDisconnectOnPageHide(0),
347 mCreatingDocument(false),
348#ifdef DEBUG1
349 mInEnsureScriptEnv(false),
350#endif
351 mInitialized(false),
352 mAllowSubframes(true),
353 mAllowMetaRedirects(true),
354 mAllowImages(true),
355 mAllowMedia(true),
356 mAllowDNSPrefetch(true),
357 mAllowWindowControl(true),
358 mCSSErrorReportingEnabled(false),
359 mAllowAuth(mItemType == typeContent),
360 mAllowKeywordFixup(false),
361 mDisableMetaRefreshWhenInactive(false),
362 mWindowDraggingAllowed(false),
363 mInFrameSwap(false),
364 mFiredUnloadEvent(false),
365 mFiredCrossDocPageSwap(false),
366 mEODForCurrentDocument(false),
367 mURIResultedInDocument(false),
368 mIsBeingDestroyed(false),
369 mIsExecutingOnLoadHandler(false),
370 mInvisible(false),
371 mHasLoadedNonBlankURI(false),
372 mHasStartedLoadingOtherThanInitialBlankURI(false),
373 mBlankTiming(false),
374 mTitleValidForCurrentURI(false),
375 mWillChangeProcess(false),
376 mIsNavigating(false),
377 mForcedAutodetection(false),
378 mCheckingSessionHistory(false),
379 mNeedToReportActiveAfterLoadingBecomesActive(false) {
380 // If no outer window ID was provided, generate a new one.
381 if (aContentWindowID == 0) {
382 mContentWindowID = nsContentUtils::GenerateWindowId();
383 }
384
385 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p created\n", this); } } while (
0)
;
386
387#ifdef DEBUG1
388 mDocShellID = gDocshellIDCounter++;
389 // We're counting the number of |nsDocShells| to help find leaks
390 ++gNumberOfDocShells;
391 MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "]\n", (void*)this, gNumberOfDocShells, getpid(), mDocShellID
); } } while (0)
392 ("++DOCSHELL %p == %ld [pid = %d] [id = %" PRIu64 "]\n", (void*)this,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "]\n", (void*)this, gNumberOfDocShells, getpid(), mDocShellID
); } } while (0)
393 gNumberOfDocShells, getpid(), mDocShellID))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "]\n", (void*)this, gNumberOfDocShells, getpid(), mDocShellID
); } } while (0)
;
394#endif
395}
396
397void nsDocShell::DestroyDocumentViewer() {
398 if (!mDocumentViewer) {
399 return;
400 }
401 mDocumentViewer->Close();
402 mDocumentViewer->Destroy();
403 mDocumentViewer = nullptr;
404}
405
406nsDocShell::~nsDocShell() {
407 // Avoid notifying observers while we're in the dtor.
408 mIsBeingDestroyed = true;
409
410 Destroy();
411
412 DestroyDocumentViewer();
413
414 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p destroyed\n", this); } } while
(0)
;
415
416#ifdef DEBUG1
417 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info)), 0))
) {
418 nsAutoCString url;
419 if (mLastOpenedURI) {
420 url = mLastOpenedURI->GetSpecOrDefault();
421
422 // Data URLs can be very long, so truncate to avoid flooding the log.
423 const uint32_t maxURLLength = 1000;
424 if (url.Length() > maxURLLength) {
425 url.Truncate(maxURLLength);
426 }
427 }
428
429 // We're counting the number of |nsDocShells| to help find leaks
430 --gNumberOfDocShells;
431 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "] [url = %s]\n", (void*)this, gNumberOfDocShells, getpid
(), mDocShellID, url.get()); } } while (0)
432 gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "] [url = %s]\n", (void*)this, gNumberOfDocShells, getpid
(), mDocShellID, url.get()); } } while (0)
433 ("--DOCSHELL %p == %ld [pid = %d] [id = %" PRIu64 "] [url = %s]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "] [url = %s]\n", (void*)this, gNumberOfDocShells, getpid
(), mDocShellID, url.get()); } } while (0)
434 (void*)this, gNumberOfDocShells, getpid(), mDocShellID, url.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOCSHELL %p == %ld [pid = %d] [id = %" "l"
"u" "] [url = %s]\n", (void*)this, gNumberOfDocShells, getpid
(), mDocShellID, url.get()); } } while (0)
;
435 }
436#endif
437}
438
439nsresult nsDocShell::InitWindow(nsIWidget* aParentWidget, int32_t aX,
440 int32_t aY, int32_t aWidth, int32_t aHeight,
441 nsIOpenWindowInfo* aOpenWindowInfo,
442 mozilla::dom::WindowGlobalChild* aWindowActor) {
443 SetParentWidget(aParentWidget);
444 SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
445 return Initialize(aOpenWindowInfo, aWindowActor);
446}
447
448nsresult nsDocShell::Initialize(nsIOpenWindowInfo* aOpenWindowInfo,
449 mozilla::dom::WindowGlobalChild* aWindowActor) {
450 if (mInitialized) {
451 // We've already been initialized.
452 MOZ_ASSERT(!aOpenWindowInfo,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOpenWindowInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOpenWindowInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOpenWindowInfo"
" (" "Tried to reinitialize with override principal" ")", "./../../../docshell/base/nsDocShell.cpp"
, 453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOpenWindowInfo"
") (" "Tried to reinitialize with override principal" ")"); do
{ MOZ_CrashSequence(__null, 453); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
453 "Tried to reinitialize with override principal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOpenWindowInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOpenWindowInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOpenWindowInfo"
" (" "Tried to reinitialize with override principal" ")", "./../../../docshell/base/nsDocShell.cpp"
, 453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOpenWindowInfo"
") (" "Tried to reinitialize with override principal" ")"); do
{ MOZ_CrashSequence(__null, 453); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
454 MOZ_ASSERT(!aWindowActor, "Tried to reinitialize with a window actor")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aWindowActor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aWindowActor))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aWindowActor" " ("
"Tried to reinitialize with a window actor" ")", "./../../../docshell/base/nsDocShell.cpp"
, 454); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aWindowActor"
") (" "Tried to reinitialize with a window actor" ")"); do {
MOZ_CrashSequence(__null, 454); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
455 return NS_OK;
456 }
457
458 MOZ_ASSERT(aOpenWindowInfo,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOpenWindowInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOpenWindowInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aOpenWindowInfo"
" (" "Must have openwindowinfo if not already initialized." ")"
, "./../../../docshell/base/nsDocShell.cpp", 459); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aOpenWindowInfo" ") (" "Must have openwindowinfo if not already initialized."
")"); do { MOZ_CrashSequence(__null, 459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
459 "Must have openwindowinfo if not already initialized.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOpenWindowInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOpenWindowInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aOpenWindowInfo"
" (" "Must have openwindowinfo if not already initialized." ")"
, "./../../../docshell/base/nsDocShell.cpp", 459); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aOpenWindowInfo" ") (" "Must have openwindowinfo if not already initialized."
")"); do { MOZ_CrashSequence(__null, 459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
460
461 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,do { if (!(mItemType == typeContent || mItemType == typeChrome
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Unexpected item type in docshell"
, "mItemType == typeContent || mItemType == typeChrome", "./../../../docshell/base/nsDocShell.cpp"
, 462); MOZ_PretendNoReturn(); } } while (0)
462 "Unexpected item type in docshell")do { if (!(mItemType == typeContent || mItemType == typeChrome
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Unexpected item type in docshell"
, "mItemType == typeContent || mItemType == typeChrome", "./../../../docshell/base/nsDocShell.cpp"
, 462); MOZ_PretendNoReturn(); } } while (0)
;
463
464 NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(Preferences::GetRootBranch())
), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::GetRootBranch()"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 464); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
465 mInitialized = true;
466
467 mDisableMetaRefreshWhenInactive =
468 Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
469 mDisableMetaRefreshWhenInactive);
470
471 nsresult rv = CreateInitialDocumentViewer(aOpenWindowInfo, aWindowActor);
472
473 if (nsCOMPtr<nsIObserverService> serv = services::GetObserverService()) {
474 const char* msg = mItemType == typeContent ? NS_WEBNAVIGATION_CREATE"webnavigation-create"
475 : NS_CHROME_WEBNAVIGATION_CREATE"chrome-webnavigation-create";
476 serv->NotifyWhenScriptSafe(GetAsSupports(this), msg, nullptr);
477 }
478
479 return rv;
480}
481
482/* static */
483already_AddRefed<nsDocShell> nsDocShell::Create(
484 BrowsingContext* aBrowsingContext, uint64_t aContentWindowID) {
485 MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowsingContext))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowsingContext"
" (" "DocShell without a BrowsingContext!" ")", "./../../../docshell/base/nsDocShell.cpp"
, 485); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowsingContext"
") (" "DocShell without a BrowsingContext!" ")"); do { MOZ_CrashSequence
(__null, 485); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
486
487 nsresult rv;
488 RefPtr<nsDocShell> ds = new nsDocShell(aBrowsingContext, aContentWindowID);
489
490 // Initialize the underlying nsDocLoader.
491 rv = ds->nsDocLoader::InitWithBrowsingContext(aBrowsingContext);
492 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 492)
) {
493 return nullptr;
494 }
495
496 // Create our ContentListener
497 ds->mContentListener = new nsDSURIContentListener(ds);
498
499 // We enable if we're in the parent process in order to support non-e10s
500 // configurations.
501 // Note: This check is duplicated in SharedWorkerInterfaceRequestor's
502 // constructor.
503 if (XRE_IsParentProcess()) {
504 ds->mInterceptController = MakeRefPtr<ServiceWorkerInterceptController>();
505 }
506
507 // We want to hold a strong ref to the loadgroup, so it better hold a weak
508 // ref to us... use an InterfaceRequestorProxy to do this.
509 RefPtr proxy = MakeRefPtr<InterfaceRequestorProxy>(ds);
510 ds->mLoadGroup->SetNotificationCallbacks(proxy);
511
512 // XXX(nika): We have our BrowsingContext, so we might be able to skip this.
513 // It could be nice to directly set up our DocLoader tree?
514 rv = nsDocLoader::AddDocLoaderAsChildOfRoot(ds);
515 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 515)
) {
516 return nullptr;
517 }
518
519 uint32_t notifyMask =
520 nsIWebProgress::NOTIFY_STATE_ALL | nsIWebProgress::NOTIFY_LOCATION |
521 nsIWebProgress::NOTIFY_SECURITY | nsIWebProgress::NOTIFY_STATUS;
522
523 // NOTE: Only listen for NOTIFY_PROGRESS on toplevel BrowsingContexts, as
524 // listeners in the browser UI only cares about total progress on the toplevel
525 // context. Aggregation of the total progress is currently handled within
526 // `nsDocLoader`, and does not take out-of-process iframes into account.
527 if (aBrowsingContext->IsTop()) {
528 notifyMask |= nsIWebProgress::NOTIFY_PROGRESS;
529 }
530
531 // Add |ds| as a progress listener to itself. A little weird, but simpler
532 // than reproducing all the listener-notification logic in overrides of the
533 // various methods via which nsDocLoader can be notified. Note that this
534 // holds an nsWeakPtr to |ds|, so it's ok.
535 rv = ds->AddProgressListener(ds, notifyMask);
536 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 536)
) {
537 return nullptr;
538 }
539
540 // If our BrowsingContext has private browsing enabled, update the number of
541 // private browsing docshells.
542 if (aBrowsingContext->UsePrivateBrowsing()) {
543 ds->NotifyPrivateBrowsingChanged();
544 }
545
546 // If our parent window is present in this process, set up our parent now.
547 RefPtr<WindowContext> parentWC = aBrowsingContext->GetParentWindowContext();
548 if (parentWC && parentWC->IsInProcess()) {
549 // If we don't have a parent element anymore, we can't finish this load!
550 // How'd we get here?
551 RefPtr<Element> parentElement = aBrowsingContext->GetEmbedderElement();
552 if (!parentElement) {
553 MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentElement")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"nsDocShell::Create() - !parentElement" ")", "./../../../docshell/base/nsDocShell.cpp"
, 553); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "nsDocShell::Create() - !parentElement"
")"); do { MOZ_CrashSequence(__null, 553); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
554 return nullptr;
555 }
556
557 // We have an in-process parent window, but don't have a parent nsDocShell?
558 // How'd we get here!
559 nsCOMPtr<nsIDocShell> parentShell =
560 parentElement->OwnerDoc()->GetDocShell();
561 if (!parentShell) {
562 MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentShell")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"nsDocShell::Create() - !parentShell" ")", "./../../../docshell/base/nsDocShell.cpp"
, 562); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "nsDocShell::Create() - !parentShell"
")"); do { MOZ_CrashSequence(__null, 562); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
563 return nullptr;
564 }
565 parentShell->AddChild(ds);
566 }
567
568 // Make |ds| the primary DocShell for the given context.
569 aBrowsingContext->SetDocShell(ds);
570
571 // Set |ds| default load flags on load group.
572 ds->SetLoadGroupDefaultLoadFlags(aBrowsingContext->GetDefaultLoadFlags());
573
574 return ds.forget();
575}
576
577void nsDocShell::DestroyChildren() {
578 for (auto* child : mChildList.ForwardRange()) {
579 nsCOMPtr<nsIDocShellTreeItem> shell = do_QueryObject(child);
580 NS_ASSERTION(shell, "docshell has null child")do { if (!(shell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell has null child"
, "shell", "./../../../docshell/base/nsDocShell.cpp", 580); MOZ_PretendNoReturn
(); } } while (0)
;
581
582 if (shell) {
583 shell->SetTreeOwner(nullptr);
584 }
585 }
586
587 nsDocLoader::DestroyChildren();
588}
589
590NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(nsDocShell, nsDocLoader,nsDocShell::cycleCollection nsDocShell::_cycleCollectorGlobal
; void nsDocShell::cycleCollection::Unlink(void* p) { nsDocShell
* tmp = DowncastCCParticipant<nsDocShell>(p); nsISupports
* s = static_cast<nsISupports*>(p); nsDocLoader::cycleCollection
::Unlink(s); ImplCycleCollectionUnlink(tmp->mScriptGlobal)
; ImplCycleCollectionUnlink(tmp->mInitialClientSource); ImplCycleCollectionUnlink
(tmp->mBrowsingContext); ImplCycleCollectionUnlink(tmp->
mChromeEventHandler); ImplCycleCollectionUnlink(tmp->mBCWebProgressStatusFilter
); tmp->DetachWeakPtr(); (void)tmp; } nsresult nsDocShell::
cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { nsDocShell* tmp = DowncastCCParticipant<nsDocShell
>(p); nsISupports* s = static_cast<nsISupports*>(p);
if (nsDocLoader::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mScriptGlobal, "mScriptGlobal", 0); ImplCycleCollectionTraverse
(cb, tmp->mInitialClientSource, "mInitialClientSource", 0)
; ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0); ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler
, "mChromeEventHandler", 0); ImplCycleCollectionTraverse(cb, tmp
->mBCWebProgressStatusFilter, "mBCWebProgressStatusFilter"
, 0); (void)tmp; return NS_OK; }
591 mScriptGlobal, mInitialClientSource,nsDocShell::cycleCollection nsDocShell::_cycleCollectorGlobal
; void nsDocShell::cycleCollection::Unlink(void* p) { nsDocShell
* tmp = DowncastCCParticipant<nsDocShell>(p); nsISupports
* s = static_cast<nsISupports*>(p); nsDocLoader::cycleCollection
::Unlink(s); ImplCycleCollectionUnlink(tmp->mScriptGlobal)
; ImplCycleCollectionUnlink(tmp->mInitialClientSource); ImplCycleCollectionUnlink
(tmp->mBrowsingContext); ImplCycleCollectionUnlink(tmp->
mChromeEventHandler); ImplCycleCollectionUnlink(tmp->mBCWebProgressStatusFilter
); tmp->DetachWeakPtr(); (void)tmp; } nsresult nsDocShell::
cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { nsDocShell* tmp = DowncastCCParticipant<nsDocShell
>(p); nsISupports* s = static_cast<nsISupports*>(p);
if (nsDocLoader::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mScriptGlobal, "mScriptGlobal", 0); ImplCycleCollectionTraverse
(cb, tmp->mInitialClientSource, "mInitialClientSource", 0)
; ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0); ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler
, "mChromeEventHandler", 0); ImplCycleCollectionTraverse(cb, tmp
->mBCWebProgressStatusFilter, "mBCWebProgressStatusFilter"
, 0); (void)tmp; return NS_OK; }
592 mBrowsingContext,nsDocShell::cycleCollection nsDocShell::_cycleCollectorGlobal
; void nsDocShell::cycleCollection::Unlink(void* p) { nsDocShell
* tmp = DowncastCCParticipant<nsDocShell>(p); nsISupports
* s = static_cast<nsISupports*>(p); nsDocLoader::cycleCollection
::Unlink(s); ImplCycleCollectionUnlink(tmp->mScriptGlobal)
; ImplCycleCollectionUnlink(tmp->mInitialClientSource); ImplCycleCollectionUnlink
(tmp->mBrowsingContext); ImplCycleCollectionUnlink(tmp->
mChromeEventHandler); ImplCycleCollectionUnlink(tmp->mBCWebProgressStatusFilter
); tmp->DetachWeakPtr(); (void)tmp; } nsresult nsDocShell::
cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { nsDocShell* tmp = DowncastCCParticipant<nsDocShell
>(p); nsISupports* s = static_cast<nsISupports*>(p);
if (nsDocLoader::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mScriptGlobal, "mScriptGlobal", 0); ImplCycleCollectionTraverse
(cb, tmp->mInitialClientSource, "mInitialClientSource", 0)
; ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0); ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler
, "mChromeEventHandler", 0); ImplCycleCollectionTraverse(cb, tmp
->mBCWebProgressStatusFilter, "mBCWebProgressStatusFilter"
, 0); (void)tmp; return NS_OK; }
593 mChromeEventHandler,nsDocShell::cycleCollection nsDocShell::_cycleCollectorGlobal
; void nsDocShell::cycleCollection::Unlink(void* p) { nsDocShell
* tmp = DowncastCCParticipant<nsDocShell>(p); nsISupports
* s = static_cast<nsISupports*>(p); nsDocLoader::cycleCollection
::Unlink(s); ImplCycleCollectionUnlink(tmp->mScriptGlobal)
; ImplCycleCollectionUnlink(tmp->mInitialClientSource); ImplCycleCollectionUnlink
(tmp->mBrowsingContext); ImplCycleCollectionUnlink(tmp->
mChromeEventHandler); ImplCycleCollectionUnlink(tmp->mBCWebProgressStatusFilter
); tmp->DetachWeakPtr(); (void)tmp; } nsresult nsDocShell::
cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { nsDocShell* tmp = DowncastCCParticipant<nsDocShell
>(p); nsISupports* s = static_cast<nsISupports*>(p);
if (nsDocLoader::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mScriptGlobal, "mScriptGlobal", 0); ImplCycleCollectionTraverse
(cb, tmp->mInitialClientSource, "mInitialClientSource", 0)
; ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0); ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler
, "mChromeEventHandler", 0); ImplCycleCollectionTraverse(cb, tmp
->mBCWebProgressStatusFilter, "mBCWebProgressStatusFilter"
, 0); (void)tmp; return NS_OK; }
594 mBCWebProgressStatusFilter)nsDocShell::cycleCollection nsDocShell::_cycleCollectorGlobal
; void nsDocShell::cycleCollection::Unlink(void* p) { nsDocShell
* tmp = DowncastCCParticipant<nsDocShell>(p); nsISupports
* s = static_cast<nsISupports*>(p); nsDocLoader::cycleCollection
::Unlink(s); ImplCycleCollectionUnlink(tmp->mScriptGlobal)
; ImplCycleCollectionUnlink(tmp->mInitialClientSource); ImplCycleCollectionUnlink
(tmp->mBrowsingContext); ImplCycleCollectionUnlink(tmp->
mChromeEventHandler); ImplCycleCollectionUnlink(tmp->mBCWebProgressStatusFilter
); tmp->DetachWeakPtr(); (void)tmp; } nsresult nsDocShell::
cycleCollection::TraverseNative( void* p, nsCycleCollectionTraversalCallback
& cb) { nsDocShell* tmp = DowncastCCParticipant<nsDocShell
>(p); nsISupports* s = static_cast<nsISupports*>(p);
if (nsDocLoader::cycleCollection::TraverseNative(s, cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE
) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } ImplCycleCollectionTraverse
(cb, tmp->mScriptGlobal, "mScriptGlobal", 0); ImplCycleCollectionTraverse
(cb, tmp->mInitialClientSource, "mInitialClientSource", 0)
; ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0); ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler
, "mChromeEventHandler", 0); ImplCycleCollectionTraverse(cb, tmp
->mBCWebProgressStatusFilter, "mBCWebProgressStatusFilter"
, 0); (void)tmp; return NS_OK; }
595
596NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)MozExternalRefCountType nsDocShell::AddRef(void) { static_assert
(!std::is_destructible_v<nsDocShell>, "Reference-counted class "
"nsDocShell" " should not have a public destructor. " "Make this class's destructor non-public"
); nsrefcnt r = nsDocLoader::AddRef(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<nsDocShell>) { NS_LogAddRef
((this), (r), ("nsDocShell"), (uint32_t)(sizeof(*this))); } return
r; }
597NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)MozExternalRefCountType nsDocShell::Release(void) { nsrefcnt r
= nsDocLoader::Release(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<nsDocShell>) { NS_LogRelease((this), (r), ("nsDocShell"
)); } return r; }
598
599NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)nsresult nsDocShell::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../docshell/base/nsDocShell.cpp", 599
); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::kIID), (nsCycleCollectionISupports::kIID)) && (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID)) || LowWordEquals
(aIID, (nsCycleCollectionISupports::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID))) { *aInstancePtr
= nsDocShell::cycleCollection::GetParticipant(); return NS_OK
; } if (LowWordEquals(aIID, (nsCycleCollectionISupports::kIID
))) { *aInstancePtr = nsDocShell::cycleCollection::Upcast(this
); return NS_OK; } foundInterface = nullptr; } else
600 NS_INTERFACE_MAP_ENTRY(nsIDocShell)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDocShell>)) foundInterface = static_cast
<nsIDocShell*>(this); else
601 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDocShellTreeItem>)) foundInterface
= static_cast<nsIDocShellTreeItem*>(this); else
602 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIWebNavigation>)) foundInterface
= static_cast<nsIWebNavigation*>(this); else
603 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIBaseWindow>)) foundInterface =
static_cast<nsIBaseWindow*>(this); else
604 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIRefreshURI>)) foundInterface =
static_cast<nsIRefreshURI*>(this); else
605 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIWebProgressListener>)) foundInterface
= static_cast<nsIWebProgressListener*>(this); else
606 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
607 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIWebPageDescriptor>)) foundInterface
= static_cast<nsIWebPageDescriptor*>(this); else
608 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIAuthPromptProvider>)) foundInterface
= static_cast<nsIAuthPromptProvider*>(this); else
609 NS_INTERFACE_MAP_ENTRY(nsILoadContext)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsILoadContext>)) foundInterface =
static_cast<nsILoadContext*>(this); else
610 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,if ((mInterceptController) && aIID.Equals(mozilla::detail
::kImplementedIID<std::remove_reference_t<decltype(*this
)>, nsINetworkInterceptController>)) foundInterface = static_cast
<nsINetworkInterceptController*>(this); else
611 mInterceptController)if ((mInterceptController) && aIID.Equals(mozilla::detail
::kImplementedIID<std::remove_reference_t<decltype(*this
)>, nsINetworkInterceptController>)) foundInterface = static_cast
<nsINetworkInterceptController*>(this); else
612NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)foundInterface = 0; nsresult status; if (!foundInterface) status
= nsDocLoader::QueryInterface(aIID, (void**)&foundInterface
); else { (foundInterface)->AddRef(); status = NS_OK; } *aInstancePtr
= foundInterface; return status; }
613
614NS_IMETHODIMPnsresult
615nsDocShell::GetInterface(const nsIID& aIID, void** aSink) {
616 MOZ_ASSERT(aSink, "null out param")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSink)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aSink))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aSink" " (" "null out param"
")", "./../../../docshell/base/nsDocShell.cpp", 616); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aSink" ") (" "null out param" ")"); do { MOZ_CrashSequence
(__null, 616); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
617
618 *aSink = nullptr;
619
620 if (aIID.Equals(NS_GET_IID(nsICommandManager)(nsICommandManager::kIID))) {
621 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE)do { nsresult __rv = EnsureCommandHandler(); if (((bool)(__builtin_expect
(!!(NS_FAILED_impl(__rv)), 0)))) { const char* name = mozilla
::GetStaticErrorName(__rv); mozilla::SmprintfPointer msg = mozilla
::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%"
"X" "%s%s%s", "EnsureCommandHandler()", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../docshell/base/nsDocShell.cpp", 621); return NS_ERROR_FAILURE
; } } while (false)
;
622 *aSink = static_cast<nsICommandManager*>(mCommandManager.get());
623 } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener)(nsIURIContentListener::kIID))) {
624 *aSink = mContentListener;
625 } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)(nsIScriptGlobalObject::kIID)) ||
626 aIID.Equals(NS_GET_IID(nsIGlobalObject)(nsIGlobalObject::kIID)) ||
627 aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)(nsPIDOMWindowOuter::kIID)) ||
628 aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)(mozIDOMWindowProxy::kIID)) ||
629 aIID.Equals(NS_GET_IID(nsIDOMWindow)(nsIDOMWindow::kIID))) &&
630 NS_SUCCEEDED(EnsureScriptEnvironment())((bool)(__builtin_expect(!!(!NS_FAILED_impl(EnsureScriptEnvironment
())), 1)))
) {
631 return mScriptGlobal->QueryInterface(aIID, aSink);
632 } else if (aIID.Equals(NS_GET_IID(Document)(Document::kIID)) && VerifyDocumentViewer()) {
633 RefPtr<Document> doc = mDocumentViewer->GetDocument();
634 doc.forget(aSink);
635 return *aSink ? NS_OK : NS_NOINTERFACE;
636 } else if (aIID.Equals(NS_GET_IID(nsIPrompt)(nsIPrompt::kIID)) &&
637 NS_SUCCEEDED(EnsureScriptEnvironment())((bool)(__builtin_expect(!!(!NS_FAILED_impl(EnsureScriptEnvironment
())), 1)))
) {
638 nsresult rv;
639 nsCOMPtr<nsIWindowWatcher> wwatch =
640 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
641 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 641); return rv; } } while (false)
;
642
643 // Get the an auth prompter for our window so that the parenting
644 // of the dialogs works as it should when using tabs.
645 nsIPrompt* prompt;
646 rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
647 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 647); return rv; } } while (false)
;
648
649 *aSink = prompt;
650 return NS_OK;
651 } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)(nsIAuthPrompt::kIID)) ||
652 aIID.Equals(NS_GET_IID(nsIAuthPrompt2)(nsIAuthPrompt2::kIID))) {
653 return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetAuthPrompt(PROMPT_NORMAL
, aIID, aSink))), 1)))
654 ? NS_OK
655 : NS_NOINTERFACE;
656 } else if (aIID.Equals(NS_GET_IID(nsISHistory)(nsISHistory::kIID))) {
657 // This is deprecated, you should instead directly get
658 // ChildSHistory from the browsing context.
659 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Do not try to get a nsISHistory interface from nsIDocShell"
")", "./../../../docshell/base/nsDocShell.cpp", 660); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Do not try to get a nsISHistory interface from nsIDocShell"
")"); do { MOZ_CrashSequence(__null, 660); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
660 false, "Do not try to get a nsISHistory interface from nsIDocShell")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Do not try to get a nsISHistory interface from nsIDocShell"
")", "./../../../docshell/base/nsDocShell.cpp", 660); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Do not try to get a nsISHistory interface from nsIDocShell"
")"); do { MOZ_CrashSequence(__null, 660); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
661 return NS_NOINTERFACE;
662 } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind)(nsIWebBrowserFind::kIID))) {
663 nsresult rv = EnsureFind();
664 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
665 return rv;
666 }
667
668 *aSink = mFind;
669 NS_ADDREF((nsISupports*)*aSink)((nsISupports*)*aSink)->AddRef();
670 return NS_OK;
671 } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay)(nsISelectionDisplay::kIID))) {
672 if (PresShell* presShell = GetPresShell()) {
673 return presShell->QueryInterface(aIID, aSink);
674 }
675 } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner)(nsIDocShellTreeOwner::kIID))) {
676 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
677 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
678 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && treeOwner) {
679 return treeOwner->QueryInterface(aIID, aSink);
680 }
681 } else if (aIID.Equals(NS_GET_IID(nsIBrowserChild)(nsIBrowserChild::kIID))) {
682 *aSink = GetBrowserChild().take();
683 return *aSink ? NS_OK : NS_ERROR_FAILURE;
684 } else {
685 return nsDocLoader::GetInterface(aIID, aSink);
686 }
687
688 NS_IF_ADDREF(((nsISupports*)*aSink))ns_if_addref(((nsISupports*)*aSink));
689 return *aSink ? NS_OK : NS_NOINTERFACE;
690}
691
692NS_IMETHODIMPnsresult
693nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) {
694 // Note: this gets called fairly early (before a pageload actually starts).
695 // We could probably defer this even longer.
696 if (nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild()) {
697 static_cast<BrowserChild*>(browserChild.get())
698 ->SetCancelContentJSEpoch(aEpoch);
699 }
700 return NS_OK;
701}
702
703nsresult nsDocShell::CheckDisallowedJavascriptLoad(
704 nsDocShellLoadState* aLoadState) {
705 if (!aLoadState->URI()->SchemeIs("javascript")) {
706 return NS_OK;
707 }
708
709 if (nsCOMPtr<nsIPrincipal> targetPrincipal =
710 GetInheritedPrincipal(/* aConsiderCurrentDocument */ true)) {
711 if (!aLoadState->TriggeringPrincipal()->Subsumes(targetPrincipal)) {
712 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI;
713 }
714 return NS_OK;
715 }
716 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI;
717}
718
719NS_IMETHODIMPnsresult
720nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
721 return LoadURI(aLoadState, aSetNavigating, false);
722}
723
724nsresult nsDocShell::LoadURI(nsDocShellLoadState* aLoadState,
725 bool aSetNavigating,
726 bool aContinueHandlingSubframeHistory) {
727 MOZ_ASSERT(aLoadState, "Must have a valid load state!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadState" " (" "Must have a valid load state!"
")", "./../../../docshell/base/nsDocShell.cpp", 727); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState" ") (" "Must have a valid load state!"
")"); do { MOZ_CrashSequence(__null, 727); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
728 // NOTE: This comparison between what appears to be internal/external load
729 // flags is intentional, as it's ensuring that the caller isn't using any of
730 // the flags reserved for implementations by the `nsIWebNavigation` interface.
731 // In the future, this check may be dropped.
732 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
" (" "Should not have these flags set" ")", "./../../../docshell/base/nsDocShell.cpp"
, 734); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
") (" "Should not have these flags set" ")"); do { MOZ_CrashSequence
(__null, 734); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
733 (aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
" (" "Should not have these flags set" ")", "./../../../docshell/base/nsDocShell.cpp"
, 734); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
") (" "Should not have these flags set" ")"); do { MOZ_CrashSequence
(__null, 734); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
734 "Should not have these flags set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
" (" "Should not have these flags set" ")", "./../../../docshell/base/nsDocShell.cpp"
, 734); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0"
") (" "Should not have these flags set" ")"); do { MOZ_CrashSequence
(__null, 734); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
735 MOZ_ASSERT(aLoadState->TargetBrowsingContext().IsNull(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TargetBrowsingContext().IsNull())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aLoadState->TargetBrowsingContext().IsNull()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aLoadState->TargetBrowsingContext().IsNull()"
" (" "Targeting doesn't occur until InternalLoad" ")", "./../../../docshell/base/nsDocShell.cpp"
, 736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->TargetBrowsingContext().IsNull()"
") (" "Targeting doesn't occur until InternalLoad" ")"); do {
MOZ_CrashSequence(__null, 736); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
736 "Targeting doesn't occur until InternalLoad")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TargetBrowsingContext().IsNull())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aLoadState->TargetBrowsingContext().IsNull()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aLoadState->TargetBrowsingContext().IsNull()"
" (" "Targeting doesn't occur until InternalLoad" ")", "./../../../docshell/base/nsDocShell.cpp"
, 736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->TargetBrowsingContext().IsNull()"
") (" "Targeting doesn't occur until InternalLoad" ")"); do {
MOZ_CrashSequence(__null, 736); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
737
738 if (!aLoadState->TriggeringPrincipal()) {
739 MOZ_ASSERT(false, "LoadURI must have a triggering principal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "LoadURI must have a triggering principal"
")", "./../../../docshell/base/nsDocShell.cpp", 739); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "LoadURI must have a triggering principal"
")"); do { MOZ_CrashSequence(__null, 739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
740 return NS_ERROR_FAILURE;
741 }
742
743 MOZ_TRY(CheckDisallowedJavascriptLoad(aLoadState))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CheckDisallowedJavascriptLoad(aLoadState)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
744
745 bool oldIsNavigating = mIsNavigating;
746 auto cleanupIsNavigating =
747 MakeScopeExit([&]() { mIsNavigating = oldIsNavigating; });
748 if (aSetNavigating) {
749 mIsNavigating = true;
750 }
751
752 PopupBlocker::PopupControlState popupState = PopupBlocker::openOverridden;
753 if (aLoadState->HasLoadFlags(LOAD_FLAGS_ALLOW_POPUPS)) {
754 popupState = PopupBlocker::openAllowed;
755 // If we allow popups as part of the navigation, ensure we fake a user
756 // interaction, so that popups can, in fact, be allowed to open.
757 if (WindowContext* wc = mBrowsingContext->GetCurrentWindowContext()) {
758 wc->NotifyUserGestureActivation();
759 }
760 }
761
762 AutoPopupStatePusherAutoPopupStatePusherInternal statePusher(popupState);
763
764 if (aLoadState->GetCancelContentJSEpoch().isSome()) {
765 SetCancelContentJSEpoch(*aLoadState->GetCancelContentJSEpoch());
766 }
767
768 // Note: we allow loads to get through here even if mFiredUnloadEvent is
769 // true; that case will get handled in LoadInternal or LoadHistoryEntry,
770 // so we pass false as the second parameter to IsNavigationAllowed.
771 // However, we don't allow the page to change location *in the middle of*
772 // firing beforeunload, so we do need to check if *beforeunload* is currently
773 // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
774 if (!IsNavigationAllowed(true, false)) {
775 return NS_OK; // JS may not handle returning of an error code
776 }
777
778 nsLoadFlags defaultLoadFlags = mBrowsingContext->GetDefaultLoadFlags();
779 if (aLoadState->HasLoadFlags(LOAD_FLAGS_FORCE_TRR)) {
780 defaultLoadFlags |= nsIRequest::LOAD_TRR_ONLY_MODE;
781 } else if (aLoadState->HasLoadFlags(LOAD_FLAGS_DISABLE_TRR)) {
782 defaultLoadFlags |= nsIRequest::LOAD_TRR_DISABLED_MODE;
783 }
784
785 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetDefaultLoadFlags(defaultLoadFlags))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetDefaultLoadFlags(defaultLoadFlags)))
, 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(mBrowsingContext->SetDefaultLoadFlags(defaultLoadFlags))"
, "./../../../docshell/base/nsDocShell.cpp", 785); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetDefaultLoadFlags(defaultLoadFlags))"
")"); do { MOZ_CrashSequence(__null, 785); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
786
787 if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
788 mItemType == typeContent && !NS_IsAboutBlank(aLoadState->URI())) {
789 StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
790 }
791
792 // LoadType used to be set to a default value here, if no LoadInfo/LoadState
793 // object was passed in. That functionality has been removed as of bug
794 // 1492648. LoadType should now be set up by the caller at the time they
795 // create their nsDocShellLoadState object to pass into LoadURI.
796
797 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading %s with flags 0x%08x"
, this, aLoadState->URI()->GetSpecOrDefault().get(), aLoadState
->LoadFlags()); } } while (0)
798 gDocShellLeakLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading %s with flags 0x%08x"
, this, aLoadState->URI()->GetSpecOrDefault().get(), aLoadState
->LoadFlags()); } } while (0)
799 ("nsDocShell[%p]: loading %s with flags 0x%08x", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading %s with flags 0x%08x"
, this, aLoadState->URI()->GetSpecOrDefault().get(), aLoadState
->LoadFlags()); } } while (0)
800 aLoadState->URI()->GetSpecOrDefault().get(), aLoadState->LoadFlags()))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading %s with flags 0x%08x"
, this, aLoadState->URI()->GetSpecOrDefault().get(), aLoadState
->LoadFlags()); } } while (0)
;
801
802 if ((!aLoadState->LoadIsFromSessionHistory() &&
803 !LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
804 LOAD_FLAGS_REPLACE_HISTORY)((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
) ||
805 aContinueHandlingSubframeHistory) {
806 // This is possibly a subframe, so handle it accordingly.
807 //
808 // If history exists, it will be loaded into the aLoadState object, and the
809 // LoadType will be changed.
810 if (MaybeHandleSubframeHistory(aLoadState,
811 aContinueHandlingSubframeHistory)) {
812 // MaybeHandleSubframeHistory returns true if we need to continue loading
813 // asynchronously.
814 return NS_OK;
815 }
816 }
817
818 if (aLoadState->LoadIsFromSessionHistory()) {
819 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading from session history"
, this); } } while (0)
820 ("nsDocShell[%p]: loading from session history", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: loading from session history"
, this); } } while (0)
;
821
822 // FIXME Null check aLoadState->GetLoadingSessionHistoryInfo()?
823 return LoadHistoryEntry(*aLoadState->GetLoadingSessionHistoryInfo(),
824 aLoadState->LoadType(),
825 aLoadState->HasValidUserGestureActivation(),
826 aLoadState->NotifiedBeforeUnloadListeners(),
827 aLoadState->IsResumingInterceptedNavigation(),
828 aLoadState->PageSwapFired());
829 }
830
831 // On history navigation via Back/Forward buttons, don't execute
832 // automatic JavaScript redirection such as |location.href = ...| or
833 // |window.open()|
834 //
835 // LOAD_NORMAL: window.open(...) etc.
836 // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
837 if ((aLoadState->LoadType() == LOAD_NORMAL ||
838 aLoadState->LoadType() == LOAD_STOP_CONTENT) &&
839 ShouldBlockLoadingForBackButton()) {
840 return NS_OK;
841 }
842
843 BrowsingContext::Type bcType = mBrowsingContext->GetType();
844
845 // Set up the inheriting principal in LoadState.
846 nsresult rv = aLoadState->SetupInheritingPrincipal(
847 bcType, mBrowsingContext->OriginAttributesRef());
848 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 848); return rv; } } while (false)
;
849
850 rv = aLoadState->SetupTriggeringPrincipal(
851 mBrowsingContext->OriginAttributesRef());
852 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 852); return rv; } } while (false)
;
853
854 aLoadState->CalculateLoadURIFlags();
855
856 MOZ_ASSERT(aLoadState->TypeHint().IsVoid(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TypeHint().IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TypeHint().IsVoid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TypeHint().IsVoid()" " (" "Typehint should be null when calling InternalLoad from LoadURI"
")", "./../../../docshell/base/nsDocShell.cpp", 857); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TypeHint().IsVoid()" ") (" "Typehint should be null when calling InternalLoad from LoadURI"
")"); do { MOZ_CrashSequence(__null, 857); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
857 "Typehint should be null when calling InternalLoad from LoadURI")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TypeHint().IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TypeHint().IsVoid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TypeHint().IsVoid()" " (" "Typehint should be null when calling InternalLoad from LoadURI"
")", "./../../../docshell/base/nsDocShell.cpp", 857); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TypeHint().IsVoid()" ") (" "Typehint should be null when calling InternalLoad from LoadURI"
")"); do { MOZ_CrashSequence(__null, 857); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
858 MOZ_ASSERT(aLoadState->FileName().IsVoid(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->FileName().IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->FileName().IsVoid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->FileName().IsVoid()" " (" "FileName should be null when calling InternalLoad from LoadURI"
")", "./../../../docshell/base/nsDocShell.cpp", 859); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->FileName().IsVoid()" ") (" "FileName should be null when calling InternalLoad from LoadURI"
")"); do { MOZ_CrashSequence(__null, 859); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
859 "FileName should be null when calling InternalLoad from LoadURI")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->FileName().IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->FileName().IsVoid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->FileName().IsVoid()" " (" "FileName should be null when calling InternalLoad from LoadURI"
")", "./../../../docshell/base/nsDocShell.cpp", 859); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->FileName().IsVoid()" ") (" "FileName should be null when calling InternalLoad from LoadURI"
")"); do { MOZ_CrashSequence(__null, 859); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
860 MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->LoadIsFromSessionHistory())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aLoadState->LoadIsFromSessionHistory()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aLoadState->LoadIsFromSessionHistory()"
" (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")", "./../../../docshell/base/nsDocShell.cpp"
, 862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLoadState->LoadIsFromSessionHistory()"
") (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")"); do { MOZ_CrashSequence(__null, 862); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
861 "Shouldn't be loading from an entry when calling InternalLoad "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->LoadIsFromSessionHistory())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aLoadState->LoadIsFromSessionHistory()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aLoadState->LoadIsFromSessionHistory()"
" (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")", "./../../../docshell/base/nsDocShell.cpp"
, 862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLoadState->LoadIsFromSessionHistory()"
") (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")"); do { MOZ_CrashSequence(__null, 862); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
862 "from LoadURI")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->LoadIsFromSessionHistory())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aLoadState->LoadIsFromSessionHistory()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aLoadState->LoadIsFromSessionHistory()"
" (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")", "./../../../docshell/base/nsDocShell.cpp"
, 862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLoadState->LoadIsFromSessionHistory()"
") (" "Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI" ")"); do { MOZ_CrashSequence(__null, 862); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
863
864 // If we have a system triggering principal, we can assume that this load was
865 // triggered by some UI in the browser chrome, such as the URL bar or
866 // bookmark bar. This should count as a user interaction for the current sh
867 // entry, so that the user may navigate back to the current entry, from the
868 // entry that is going to be added as part of this load.
869 nsCOMPtr<nsIPrincipal> triggeringPrincipal =
870 aLoadState->TriggeringPrincipal();
871 if (triggeringPrincipal && triggeringPrincipal->IsSystemPrincipal()) {
872 WindowContext* topWc = mBrowsingContext->GetTopWindowContext();
873 // Already set by BrowsingContext::LoadURI for a parent initiated load;
874 // notifying again could flag the entry this load is about to add.
875 if (topWc && !topWc->IsDiscarded() &&
876 !topWc->GetSHEntryHasUserInteraction()) {
877 MOZ_ALWAYS_SUCCEEDS(topWc->SetSHEntryHasUserInteraction(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(topWc->SetSHEntryHasUserInteraction(true))), 1)))), 1))) {
} else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(topWc->SetSHEntryHasUserInteraction(true))"
, "./../../../docshell/base/nsDocShell.cpp", 877); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(topWc->SetSHEntryHasUserInteraction(true))"
")"); do { MOZ_CrashSequence(__null, 877); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
878 }
879 }
880
881 rv = InternalLoad(aLoadState);
882 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 882); return rv; } } while (false)
;
883
884 if (aLoadState->GetOriginalURIString().isSome()) {
885 // Save URI string in case it's needed later when
886 // sending to search engine service in EndPageLoad()
887 mOriginalUriString = *aLoadState->GetOriginalURIString();
888 }
889
890 return NS_OK;
891}
892
893bool nsDocShell::IsLoadingFromSessionHistory() {
894 return mActiveEntryIsLoadingFromSessionHistory;
895}
896
897// StopDetector is modeled similarly to OnloadBlocker; it is a rather
898// dummy nsIRequest implementation which can be added to an nsILoadGroup to
899// detect Cancel calls.
900class StopDetector final : public nsIRequest {
901 public:
902 StopDetector() = default;
903
904 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
905 NS_DECL_NSIREQUESTvirtual nsresult GetName(nsACString& aName) override; virtual
nsresult IsPending(bool *_retval) override; virtual nsresult
GetStatus(nsresult *aStatus) override; virtual nsresult Cancel
(nsresult aStatus) override; virtual nsresult Suspend(void) override
; virtual nsresult Resume(void) override; virtual nsresult GetLoadGroup
(nsILoadGroup **aLoadGroup) override; virtual nsresult SetLoadGroup
(nsILoadGroup *aLoadGroup) override; virtual nsresult GetLoadFlags
(nsLoadFlags *aLoadFlags) override; virtual nsresult SetLoadFlags
(nsLoadFlags aLoadFlags) override; virtual nsresult GetTRRMode
(nsIRequest::TRRMode *_retval) override; virtual nsresult SetTRRMode
(nsIRequest::TRRMode mode) override; virtual nsresult CancelWithReason
(nsresult aStatus, const nsACString& aReason) override; virtual
nsresult GetCanceledReason(nsACString& aCanceledReason) override
; virtual nsresult SetCanceledReason(const nsACString& aCanceledReason
) override;
906
907 bool Canceled() { return mCanceled; }
908
909 private:
910 ~StopDetector() = default;
911
912 bool mCanceled = false;
913};
914
915NS_IMPL_ISUPPORTS(StopDetector, nsIRequest)MozExternalRefCountType StopDetector::AddRef(void) { static_assert
(!std::is_destructible_v<StopDetector>, "Reference-counted class "
"StopDetector" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../docshell/base/nsDocShell.cpp"
, 915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 915
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StopDetector" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("StopDetector" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StopDetector\" != nullptr"
" (" "Must specify a name" ")", "./../../../docshell/base/nsDocShell.cpp"
, 915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StopDetector\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 915); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("StopDetector" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("StopDetector"), (uint32_t)(
sizeof(*this))); return count; } MozExternalRefCountType StopDetector
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../docshell/base/nsDocShell.cpp"
, 915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 915
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StopDetector" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("StopDetector" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StopDetector\" != nullptr"
" (" "Must specify a name" ")", "./../../../docshell/base/nsDocShell.cpp"
, 915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StopDetector\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 915); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("StopDetector" " not thread-safe"); const char* const nametmp
= "StopDetector"; nsrefcnt count = --mRefCnt; NS_LogRelease(
(this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult StopDetector::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../docshell/base/nsDocShell.cpp", 915
); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<StopDetector, nsIRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIRequest*>((StopDetector*)0x1000
)) - reinterpret_cast<char*>((StopDetector*)0x1000))}, {
&mozilla::detail::kImplementedIID<StopDetector, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIRequest*>((StopDetector*)0x1000))
) - reinterpret_cast<char*>((StopDetector*)0x1000))}, {
nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
916
917NS_IMETHODIMPnsresult
918StopDetector::GetName(nsACString& aResult) {
919 aResult.AssignLiteral("about:stop-detector");
920 return NS_OK;
921}
922
923NS_IMETHODIMPnsresult
924StopDetector::IsPending(bool* aRetVal) {
925 *aRetVal = true;
926 return NS_OK;
927}
928
929NS_IMETHODIMPnsresult
930StopDetector::GetStatus(nsresult* aStatus) {
931 *aStatus = NS_OK;
932 return NS_OK;
933}
934
935NS_IMETHODIMPnsresult StopDetector::SetCanceledReason(const nsACString& aReason) {
936 return SetCanceledReasonImpl(aReason);
937}
938
939NS_IMETHODIMPnsresult StopDetector::GetCanceledReason(nsACString& aReason) {
940 return GetCanceledReasonImpl(aReason);
941}
942
943NS_IMETHODIMPnsresult StopDetector::CancelWithReason(nsresult aStatus,
944 const nsACString& aReason) {
945 return CancelWithReasonImpl(aStatus, aReason);
946}
947
948NS_IMETHODIMPnsresult
949StopDetector::Cancel(nsresult /*aStatus*/) {
950 mCanceled = true;
951 return NS_OK;
952}
953
954NS_IMETHODIMPnsresult
955StopDetector::Suspend(void) { return NS_OK; }
956NS_IMETHODIMPnsresult
957StopDetector::Resume(void) { return NS_OK; }
958
959NS_IMETHODIMPnsresult
960StopDetector::GetLoadGroup(nsILoadGroup** aLoadGroup) {
961 *aLoadGroup = nullptr;
962 return NS_OK;
963}
964
965NS_IMETHODIMPnsresult
966StopDetector::SetLoadGroup(nsILoadGroup* /*aLoadGroup*/) { return NS_OK; }
967
968NS_IMETHODIMPnsresult
969StopDetector::GetLoadFlags(nsLoadFlags* aLoadFlags) {
970 *aLoadFlags = nsIRequest::LOAD_NORMAL;
971 return NS_OK;
972}
973
974NS_IMETHODIMPnsresult
975StopDetector::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
976 return GetTRRModeImpl(aTRRMode);
977}
978
979NS_IMETHODIMPnsresult
980StopDetector::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
981 return SetTRRModeImpl(aTRRMode);
982}
983
984NS_IMETHODIMPnsresult
985StopDetector::SetLoadFlags(nsLoadFlags /*aLoadFlags*/) { return NS_OK; }
986
987bool nsDocShell::MaybeHandleSubframeHistory(
988 nsDocShellLoadState* aLoadState, bool aContinueHandlingSubframeHistory) {
989 // First, verify if this is a subframe.
990 // Note, it is ok to rely on docshell here and not browsing context since when
991 // an iframe is created, it has first in-process docshell.
992 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
993 GetInProcessSameTypeParent(getter_AddRefs(parentAsItem));
994 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
995
996 if (!parentDS || parentDS == static_cast<nsIDocShell*>(this)) {
997 if (mBrowsingContext && mBrowsingContext->IsTop() &&
998 !aLoadState->HistoryBehavior()) {
999 // This is the root docshell. If we got here while
1000 // executing an onLoad Handler,this load will not go
1001 // into session history.
1002 // XXX Why is this code in a method which deals with iframes!
1003 if (aLoadState->IsFormSubmission()) {
1004#ifdef DEBUG1
1005 if (!mEODForCurrentDocument) {
1006 const MaybeDiscarded<BrowsingContext>& targetBC =
1007 aLoadState->TargetBrowsingContext();
1008 MOZ_ASSERT_IF(GetBrowsingContext() == targetBC.get(),do { if (GetBrowsingContext() == targetBC.get()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aLoadState
->LoadType() == LOAD_NORMAL_REPLACE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->LoadType() ==
LOAD_NORMAL_REPLACE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->LoadType() == LOAD_NORMAL_REPLACE", "./../../../docshell/base/nsDocShell.cpp"
, 1009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
")"); do { MOZ_CrashSequence(__null, 1009); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1009 aLoadState->LoadType() == LOAD_NORMAL_REPLACE)do { if (GetBrowsingContext() == targetBC.get()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aLoadState
->LoadType() == LOAD_NORMAL_REPLACE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->LoadType() ==
LOAD_NORMAL_REPLACE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->LoadType() == LOAD_NORMAL_REPLACE", "./../../../docshell/base/nsDocShell.cpp"
, 1009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
")"); do { MOZ_CrashSequence(__null, 1009); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1010 }
1011#endif
1012 } else {
1013 bool inOnLoadHandler = false;
1014 GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1015 if (inOnLoadHandler) {
1016 aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
1017 }
1018 }
1019 }
1020 return false;
1021 }
1022
1023 /* OK. It is a subframe. Checkout the parent's loadtype. If the parent was
1024 * loaded through a history mechanism, then get the SH entry for the child
1025 * from the parent. This is done to restore frameset navigation while going
1026 * back/forward. If the parent was loaded through any other loadType, set the
1027 * child's loadType too accordingly, so that session history does not get
1028 * confused.
1029 */
1030
1031 // Get the parent's load type
1032 uint32_t parentLoadType;
1033 parentDS->GetLoadType(&parentLoadType);
1034
1035 // If parent is loading from history and we're loading the original src for a
1036 // parser-inserted iframe, instead restore it from SH.
1037 if (!aContinueHandlingSubframeHistory &&
1038 nsDocShell::Cast(parentDS.get())->IsLoadingFromSessionHistory() &&
1039 !GetCreatedDynamically() && aLoadState->OriginalFrameSrc()) {
1040 if (XRE_IsContentProcess()) {
1041 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
1042 nsCOMPtr<nsILoadGroup> loadGroup;
1043 GetLoadGroup(getter_AddRefs(loadGroup));
1044 if (contentChild && loadGroup && !GetIsAttemptingToNavigate()) {
1045 RefPtr<Document> parentDoc = parentDS->GetDocument();
1046 parentDoc->BlockOnload();
1047 RefPtr<BrowsingContext> browsingContext = mBrowsingContext;
1048 Maybe<uint64_t> currentLoadIdentifier =
1049 mBrowsingContext->GetCurrentLoadIdentifier();
1050 RefPtr<nsDocShellLoadState> loadState = aLoadState;
1051 bool isNavigating = mIsNavigating;
1052 RefPtr stopDetector = MakeRefPtr<StopDetector>();
1053 loadGroup->AddRequest(stopDetector, nullptr);
1054 // Need to set mCheckingSessionHistory so that
1055 // GetIsAttemptingToNavigate() returns true.
1056 mCheckingSessionHistory = true;
1057
1058 auto resolve =
1059 [currentLoadIdentifier, browsingContext, parentDoc, loadState,
1060 isNavigating, loadGroup,
1061 stopDetector](mozilla::Maybe<LoadingSessionHistoryInfo>&& aResult)
1062 MOZ_CAN_RUN_SCRIPT {
1063 RefPtr<nsDocShell> docShell =
1064 static_cast<nsDocShell*>(browsingContext->GetDocShell());
1065 auto unblockParent = MakeScopeExit(
1066 [loadGroup, stopDetector, parentDoc, docShell]() {
1067 if (docShell) {
1068 docShell->mCheckingSessionHistory = false;
1069 }
1070 loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
1071 parentDoc->UnblockOnload(false);
1072 });
1073
1074 if (!docShell || !docShell->mCheckingSessionHistory) {
1075 return;
1076 }
1077
1078 if (stopDetector->Canceled()) {
1079 return;
1080 }
1081 if (currentLoadIdentifier ==
1082 browsingContext->GetCurrentLoadIdentifier() &&
1083 aResult.isSome()) {
1084 loadState->SetLoadingSessionHistoryInfo(aResult.value());
1085 // This is an initial subframe load from the session
1086 // history, index doesn't need to be updated.
1087 loadState->SetLoadIsFromSessionHistory(0, false);
1088 }
1089
1090 // We got the results back from the parent process, call
1091 // LoadURI again with the possibly updated data.
1092 docShell->LoadURI(loadState, isNavigating, true);
1093 };
1094 auto reject = [loadGroup, stopDetector, browsingContext,
1095 parentDoc](mozilla::ipc::ResponseRejectReason) {
1096 RefPtr<nsDocShell> docShell =
1097 static_cast<nsDocShell*>(browsingContext->GetDocShell());
1098 if (docShell) {
1099 docShell->mCheckingSessionHistory = false;
1100 }
1101 // In practise reject shouldn't be called ever.
1102 loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
1103 parentDoc->UnblockOnload(false);
1104 };
1105 contentChild->SendAdoptChildSHEntry(
1106 mBrowsingContext, std::move(resolve), std::move(reject));
1107 return true;
1108 }
1109 } else {
1110 Maybe<LoadingSessionHistoryInfo> info;
1111 mBrowsingContext->Canonical()->AdoptChildSHEntry(info);
1112 if (info.isSome()) {
1113 aLoadState->SetLoadingSessionHistoryInfo(info.value());
1114 // This is an initial subframe load from the session
1115 // history, index doesn't need to be updated.
1116 aLoadState->SetLoadIsFromSessionHistory(0, false);
1117 }
1118 }
1119 }
1120
1121 // Make some decisions on the child frame's loadType based on the
1122 // parent's loadType, if the subframe hasn't loaded anything into it.
1123 //
1124 // In some cases privileged scripts may try to get the DOMWindow
1125 // reference of this docshell before the loading starts, causing the
1126 // initial about:blank content viewer being created and mCurrentURI being
1127 // set. To handle this case we check if mCurrentURI is about:blank.
1128
1129 if (mCurrentURI &&
1130 (!NS_IsAboutBlank(mCurrentURI) || mLoadingEntry || mActiveEntry)) {
1131 // This is a pre-existing subframe. If
1132 // 1. The load of this frame was not originally initiated by session
1133 // history directly (i.e. (!shEntry) condition succeeded, but it can
1134 // still be a history load on parent which causes this frame being
1135 // loaded), which we checked with the above assert, and
1136 // 2. mCurrentURI is not null, nor the initial about:blank,
1137 // it is possible that a parent's onLoadHandler or even self's
1138 // onLoadHandler is loading a new page in this child. Check parent's and
1139 // self's busy flag and if it is set, we don't want this onLoadHandler
1140 // load to get in to session history.
1141 if (!aLoadState->HistoryBehavior()) {
1142 BusyFlags parentBusy = parentDS->GetBusyFlags();
1143 BusyFlags selfBusy = GetBusyFlags();
1144
1145 if (parentBusy & BUSY_FLAGS_BUSY || selfBusy & BUSY_FLAGS_BUSY) {
1146 aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
1147 aLoadState->ClearLoadIsFromSessionHistory();
1148 }
1149 }
1150 return false;
1151 }
1152
1153 // This is a newly created frame. Check for exception cases first.
1154 // By default the subframe will inherit the parent's loadType.
1155 if (aLoadState->LoadIsFromSessionHistory() &&
1156 (parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK)) {
1157 // The parent was loaded normally. In this case, this *brand new*
1158 // child really shouldn't have a SHEntry. If it does, it could be
1159 // because the parent is replacing an existing frame with a new frame,
1160 // in the onLoadHandler. We don't want this url to get into session
1161 // history. Clear off shEntry, and set load type to
1162 // LOAD_BYPASS_HISTORY.
1163 bool inOnLoadHandler = false;
1164 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1165 if (inOnLoadHandler) {
1166 aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
1167 aLoadState->ClearLoadIsFromSessionHistory();
1168 }
1169 } else if (parentLoadType == LOAD_REFRESH) {
1170 // Clear shEntry. For refresh loads, we have to load
1171 // what comes through the pipe, not what's in history.
1172 aLoadState->ClearLoadIsFromSessionHistory();
1173 } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
1174 (aLoadState->LoadIsFromSessionHistory() &&
1175 ((parentLoadType & LOAD_CMD_HISTORY) ||
1176 (parentLoadType == LOAD_RELOAD_NORMAL) ||
1177 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
1178 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
1179 (parentLoadType ==
1180 LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
1181 // If the parent url, bypassed history or was loaded from
1182 // history, pass on the parent's loadType to the new child
1183 // frame too, so that the child frame will also
1184 // avoid getting into history.
1185 aLoadState->SetLoadType(parentLoadType);
1186 } else if (parentLoadType == LOAD_ERROR_PAGE) {
1187 // If the parent document is an error page, we don't
1188 // want to update global/session history. However,
1189 // this child frame is not an error page.
1190 aLoadState->SetLoadType(LOAD_BYPASS_HISTORY);
1191 } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
1192 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
1193 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
1194 // the new frame should inherit the parent's load type so that it also
1195 // bypasses the cache and/or proxy
1196 aLoadState->SetLoadType(parentLoadType);
1197 }
1198
1199 return false;
1200}
1201
1202/*
1203 * Reset state to a new content model within the current document and the
1204 * document viewer. Called by the document before initiating an out of band
1205 * document.write().
1206 */
1207NS_IMETHODIMPnsresult
1208nsDocShell::PrepareForNewContentModel() {
1209 // Clear out our form control state, because the state of controls
1210 // in the pre-open() document should not affect the state of
1211 // controls that are now going to be written.
1212 SetLayoutHistoryState(nullptr);
1213 mEODForCurrentDocument = false;
1214 return NS_OK;
1215}
1216
1217NS_IMETHODIMPnsresult
1218nsDocShell::FirePageHideNotification() {
1219 FirePageHideNotificationInternal(false);
1220 return NS_OK;
1221}
1222
1223void nsDocShell::FirePageHideNotificationInternal(
1224 bool aSkipCheckingDynEntries) {
1225 // https://html.spec.whatwg.org/#deactivate-a-document-for-a-cross-document-navigation
1226 // 5.2 Set navigable's ongoing navigation to null.
1227 SetOngoingNavigation(Nothing());
1228
1229 if (mDocumentViewer && !mFiredUnloadEvent) {
1230 // Keep an explicit reference since calling PageHide could release
1231 // mDocumentViewer
1232 nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
1233 mFiredUnloadEvent = true;
1234
1235 if (mTiming) {
1236 mTiming->NotifyUnloadEventStart();
1237 }
1238
1239 viewer->PageHide(true);
1240
1241 if (mTiming) {
1242 mTiming->NotifyUnloadEventEnd();
1243 }
1244
1245 AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
1246 uint32_t n = mChildList.Length();
1247 kids.SetCapacity(n);
1248 for (uint32_t i = 0; i < n; i++) {
1249 kids.AppendElement(do_QueryInterface(ChildAt(i)));
1250 }
1251
1252 n = kids.Length();
1253 for (uint32_t i = 0; i < n; ++i) {
1254 RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get());
1255 if (child) {
1256 // Skip checking dynamic subframe entries in our children.
1257 child->FirePageHideNotificationInternal(true);
1258 }
1259 }
1260
1261 // If the document is unloading, remove all dynamic subframe entries.
1262 if (!aSkipCheckingDynEntries) {
1263 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
1264 if (rootSH) {
1265 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p unloading, remove dynamic subframe entries"
, this); } } while (0)
1266 gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p unloading, remove dynamic subframe entries"
, this); } } while (0)
1267 ("nsDocShell %p unloading, remove dynamic subframe entries", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p unloading, remove dynamic subframe entries"
, this); } } while (0)
;
1268 if (mActiveEntry) {
1269 mBrowsingContext->RemoveDynEntriesFromActiveSessionHistoryEntry();
1270 }
1271 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p unloading, no active entries"
, this); } } while (0)
1272 ("nsDocShell %p unloading, no active entries", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p unloading, no active entries"
, this); } } while (0)
;
1273 }
1274 }
1275
1276 // Now make sure our editor, if any, is detached before we go
1277 // any farther.
1278 DetachEditorFromWindow();
1279 }
1280}
1281
1282void nsDocShell::ThawFreezeNonRecursive(bool aThaw) {
1283 MOZ_ASSERT(mozilla::BFCacheInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mozilla::BFCacheInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mozilla::BFCacheInParent()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mozilla::BFCacheInParent()"
, "./../../../docshell/base/nsDocShell.cpp", 1283); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mozilla::BFCacheInParent()" ")"); do { MOZ_CrashSequence
(__null, 1283); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1284
1285 if (!mScriptGlobal) {
1286 return;
1287 }
1288
1289 if (RefPtr<nsGlobalWindowInner> inner =
1290 nsGlobalWindowInner::Cast(mScriptGlobal->GetCurrentInnerWindow())) {
1291 if (aThaw) {
1292 inner->Thaw(false);
1293 } else {
1294 inner->Freeze(false);
1295 }
1296 }
1297}
1298
1299// Returns the Navigation object of aDocument's window, or null.
1300static Navigation* NavigationOfDocument(Document* aDocument) {
1301 nsPIDOMWindowInner* inner = aDocument ? aDocument->GetInnerWindow() : nullptr;
1302 return inner ? inner->Navigation() : nullptr;
1303}
1304
1305// https://html.spec.whatwg.org/#navigate-to-a-javascript:-url
1306// javascript: URL loads don't go through the parent process, so the loading
1307// entry is created here. The Navigation API entries of the new document are
1308// those of the previous document with the replaced entry swapped for the new
1309// one.
1310static LoadingSessionHistoryInfo CreateLoadingEntryForJavascriptURL(
1311 SessionHistoryInfo* aActiveEntry, Document& aOldDocument,
1312 Document& aNewDocument) {
1313 nsIURI* uri =
1314 aActiveEntry ? aActiveEntry->GetURI() : aNewDocument.GetDocumentURI();
1315 nsAutoString contentType;
1316 aNewDocument.GetContentType(contentType);
1317 SessionHistoryInfo info(uri, aNewDocument.NodePrincipal(),
1318 aNewDocument.NodePrincipal(),
1319 aNewDocument.PartitionedPrincipal(),
1320 aActiveEntry ? aActiveEntry->GetPolicyContainer()
1321 : aOldDocument.GetPolicyContainer(),
1322 NS_ConvertUTF16toUTF8(contentType));
1323 if (aActiveEntry) {
1324 info.NavigationKey() = aActiveEntry->NavigationKey();
1325 const nsCOMPtr<nsIReferrerInfo> referrerInfo =
1326 aActiveEntry->GetReferrerInfo();
1327 info.SetReferrerInfo(referrerInfo);
1328 info.SetName(aActiveEntry->GetName());
1329 }
1330
1331 LoadingSessionHistoryInfo loadingEntry(info);
1332 loadingEntry.mTriggeringNavigationType = Some(NavigationType::Replace);
1333 loadingEntry.mReplacesActiveEntry = !!aActiveEntry;
1334
1335 // https://html.spec.whatwg.org/#update-document-for-history-step-application
1336 // The replaced entry is the previous entry for the new document's
1337 // activation, unless it belonged to the initial about:blank document.
1338 loadingEntry.mPreviousEntry =
1339 aOldDocument.IsInitialDocument() || !aActiveEntry
1340 ? Some(PreviousSessionHistoryInfo{})
1341 : PreviousSessionHistoryInfo::CreateValidatedPreviousEntry(
1342 info, Some(*aActiveEntry), Some(NavigationType::Replace));
1343
1344 // The old document might not have entries, in which case the new entry gets
1345 // appended.
1346 bool replaced = false;
1347 if (RefPtr<Navigation> navigation = NavigationOfDocument(&aOldDocument)) {
1348 nsTArray<RefPtr<NavigationHistoryEntry>> oldEntries;
1349 navigation->Entries(oldEntries);
1350 for (const auto& entry : oldEntries) {
1351 const bool isReplaced =
1352 entry->SessionHistoryInfo()->NavigationKey() == info.NavigationKey();
1353 replaced |= isReplaced;
1354 loadingEntry.mContiguousEntries.AppendElement(
1355 isReplaced ? info : *entry->SessionHistoryInfo());
1356 }
1357 }
1358 if (!replaced) {
1359 loadingEntry.mContiguousEntries.AppendElement(info);
1360 }
1361 return loadingEntry;
1362}
1363
1364void nsDocShell::FirePageSwapWithoutTransition(
1365 const mozilla::dom::SessionHistoryInfo* aPageSwapTargetInfo,
1366 NavigationType aNavigationType) {
1367 // https://html.spec.whatwg.org/#fire-the-pageswap-event
1368 if (!StaticPrefs::dom_viewTransitions_cross_document_enabled() ||
1369 !mDocumentViewer || mFiredCrossDocPageSwap) {
1370 return;
1371 }
1372 RefPtr<Navigation> navigation =
1373 NavigationOfDocument(mDocumentViewer->GetDocument());
1374 if (!navigation) {
1375 return;
1376 }
1377 // The other pageswap paths skip once this is set.
1378 mFiredCrossDocPageSwap = true;
1379 navigation->FirePageSwapEvent(
1380 aPageSwapTargetInfo, aNavigationType,
1381 /* aCanHaveActivation = */ aPageSwapTargetInfo != nullptr, nullptr);
1382}
1383
1384void nsDocShell::MaybeFirePageSwapOnDeactivate(
1385 const mozilla::dom::SessionHistoryInfo* aPageSwapTargetInfo,
1386 NavigationType aNavigationType) {
1387 // https://html.spec.whatwg.org/#fire-the-pageswap-event
1388 if (mFiredCrossDocPageSwap) {
1389 mFiredCrossDocPageSwap = false;
1390 return;
1391 }
1392 if (!StaticPrefs::dom_viewTransitions_cross_document_enabled() ||
1393 !mBrowsingContext || !mBrowsingContext->IsTop() || !mDocumentViewer) {
1394 return;
1395 }
1396 // Nothing is captured, so drop params that an aborted navigation left.
1397 Document::ClearCrossDocViewTransitionParams(mBrowsingContext->BrowserId());
1398 RefPtr<Navigation> navigation =
1399 NavigationOfDocument(mDocumentViewer->GetDocument());
1400 if (!navigation) {
1401 return;
1402 }
1403 navigation->FirePageSwapEvent(
1404 aPageSwapTargetInfo, aNavigationType,
1405 /* aCanHaveActivation = */ aPageSwapTargetInfo != nullptr, nullptr);
1406}
1407
1408void nsDocShell::BeginDeferredOutboundCrossDocumentViewTransition(
1409 const mozilla::dom::SessionHistoryInfo* aPageSwapTargetInfo,
1410 mozilla::dom::NavigationType aNavigationType, uint64_t aSnapshotTargetTabId,
1411 std::function<void(bool)>&& aProceed) {
1412 if (!StaticPrefs::dom_viewTransitions_cross_document_enabled() ||
1413 !mBrowsingContext || !mDocumentViewer) {
1414 aProceed(false);
1415 return;
1416 }
1417 RefPtr<Document> oldDoc = mDocumentViewer->GetDocument();
1418 RefPtr<Navigation> navigation = NavigationOfDocument(oldDoc);
1419 if (!navigation) {
1420 aProceed(false);
1421 return;
1422 }
1423
1424 // https://drafts.csswg.org/css-view-transitions-2/#setup-cross-document-view-transition
1425 // A hidden document may get no rendering update, and it has nothing to
1426 // animate.
1427 RefPtr<ViewTransition> outboundVT =
1428 oldDoc->Hidden() ? nullptr
1429 : oldDoc->SetupOutboundCrossDocumentViewTransition();
1430 const TimeStamp pageSwapStart = TimeStamp::Now();
1431 navigation->FirePageSwapEvent(
1432 aPageSwapTargetInfo, aNavigationType,
1433 /* aCanHaveActivation = */ aPageSwapTargetInfo != nullptr, outboundVT);
1434 mFiredCrossDocPageSwap = true;
1435
1436 // Skip the transition if the pageswap handler ran too long. The capture
1437 // timer does not cover the time spent in the handler.
1438 const bool timedOut =
1439 (TimeStamp::Now() - pageSwapStart).ToMilliseconds() >
1440 StaticPrefs::dom_viewTransitions_cross_document_pageswap_timeout_ms();
1441
1442 if (timedOut || !outboundVT ||
1443 oldDoc->GetActiveViewTransition() != outboundVT) {
1444 // Hidden, timed out, not opted in, or the pageswap handler skipped the
1445 // transition: nothing to capture, so let the navigation proceed now.
1446 if (timedOut && outboundVT &&
1447 oldDoc->GetActiveViewTransition() == outboundVT) {
1448 outboundVT->SkipTransition(SkipTransitionReason::Timeout);
1449 }
1450 // Nothing is captured, so drop params that an aborted navigation left.
1451 if (mBrowsingContext->IsTop()) {
1452 Document::ClearCrossDocViewTransitionParams(
1453 mBrowsingContext->BrowserId());
1454 }
1455 aProceed(false);
1456 return;
1457 }
1458
1459 // Capture in the next rendering update. The new document takes the params
1460 // at its reveal, and StopInternal drops them if the navigation is aborted.
1461 const bool isTop = mBrowsingContext->IsTop();
1462 const uint64_t browserId = mBrowsingContext->BrowserId();
1463 RefPtr<nsDocShell> self = this;
1464 outboundVT->BeginDeferredOutboundCapture(
1465 [proceed = std::move(aProceed), isTop, browserId, aSnapshotTargetTabId,
1466 self](UniquePtr<ViewTransitionParams>&& aParams) {
1467 if (aParams && aSnapshotTargetTabId) {
1468 // The new document, restored from BFCache, draws through that
1469 // tab's WebRender bridge. Move the snapshots there while this
1470 // document's bridge still exists. A tab in another process cannot
1471 // take the params.
1472 if (RefPtr<BrowserChild> target =
1473 BrowserChild::FindBrowserChild(TabId(aSnapshotTargetTabId))) {
1474 widget::PuppetWidget* puppet = target->WebWidget();
1475 if (puppet && puppet->HasWindowRenderer()) {
1476 ViewTransition::AdoptOldSnapshots(puppet->GetWindowRenderer(),
1477 aParams->namedElements);
1478 }
1479 } else {
1480 aParams = nullptr;
1481 }
1482 }
1483 const bool captured = !!aParams;
1484 if (aParams) {
1485 if (isTop) {
1486 // Top-level: route via the browser id so the params survive the
1487 // BrowsingContext replacement that a BFCache/process switch causes.
1488 Document::StashCrossDocViewTransitionParams(browserId,
1489 std::move(aParams));
1490 } else {
1491 // Subframe: a same-origin (same-process) navigation reuses this
1492 // docshell, so hand the params to the incoming document
1493 // docshell-locally.
1494 self->mPendingInboundViewTransitionParams = std::move(aParams);
1495 }
1496 }
1497 proceed(captured);
1498 });
1499}
1500
1501void nsDocShell::FirePageHideShowNonRecursive(
1502 bool aShow, const mozilla::dom::SessionHistoryInfo* aPageSwapTargetInfo,
1503 NavigationType aNavigationType) {
1504 MOZ_ASSERT(mozilla::BFCacheInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mozilla::BFCacheInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mozilla::BFCacheInParent()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mozilla::BFCacheInParent()"
, "./../../../docshell/base/nsDocShell.cpp", 1504); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mozilla::BFCacheInParent()" ")"); do { MOZ_CrashSequence
(__null, 1504); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1505
1506 if (!mDocumentViewer) {
1507 return;
1508 }
1509
1510 // Emulate what non-SHIP BFCache does too. In pageshow case
1511 // add and remove a request and before that call SetCurrentURI to get
1512 // the location change notification.
1513 // For pagehide, set mFiredUnloadEvent to true, so that unload doesn't fire.
1514 nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
1515 if (aShow) {
1516 viewer->SetIsHidden(false);
1517 mRefreshURIList = std::move(mBFCachedRefreshURIList);
1518 RefreshURIFromQueue();
1519 mFiredUnloadEvent = false;
1520 RefPtr<Document> doc = viewer->GetDocument();
1521 if (doc) {
1522 doc->NotifyActivityChanged();
1523 nsCOMPtr<nsPIDOMWindowInner> inner =
1524 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
1525 if (mBrowsingContext->IsTop()) {
1526 doc->NotifyPossibleTitleChange(false);
1527 doc->SetLoadingOrRestoredFromBFCacheTimeStampToNow();
1528 if (inner) {
1529 // Now that we have found the inner window of the page restored
1530 // from the history, we have to make sure that
1531 // performance.navigation.type is 2.
1532 // Traditionally this type change has been done to the top level page
1533 // only.
1534 Performance* performance = inner->GetPerformance();
1535 if (performance) {
1536 performance->GetDOMTiming()->NotifyRestoreStart();
1537 }
1538 }
1539 }
1540
1541 nsCOMPtr<nsIChannel> channel = doc->GetChannel();
1542 if (channel) {
1543 SetLoadType(LOAD_HISTORY);
1544 mEODForCurrentDocument = false;
1545 mIsRestoringDocument = true;
1546 mLoadGroup->AddRequest(channel, nullptr);
1547 nsCOMPtr<nsIURI> uri;
1548 if (doc->FragmentDirective()) {
1549 // If we have fragment directives, then we've mutated the document
1550 // uri. Set the current URI from session history instead.
1551 uri = mActiveEntry ? mActiveEntry->GetURI() : nullptr;
1552 }
1553 if (!uri) {
1554 uri = doc->GetDocumentURI();
1555 }
1556 SetCurrentURI(uri, channel,
1557 /* aFireOnLocationChange */ true,
1558 /* aIsInitialAboutBlank */ false,
1559 /* aLocationFlags */ 0);
1560 mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
1561 mIsRestoringDocument = false;
1562 }
1563 RefPtr<PresShell> presShell = GetPresShell();
1564 if (presShell) {
1565 presShell->Thaw(false);
1566 }
1567
1568 if (inner) {
1569 inner->FireDelayedDOMEvents(false);
1570 }
1571 }
1572 } else if (!mFiredUnloadEvent) {
1573 // XXXBFCache check again that the page can enter bfcache.
1574 // XXXBFCache should mTiming->NotifyUnloadEventStart()/End() be called here?
1575
1576 if (mRefreshURIList) {
1577 RefreshURIToQueue();
1578 mBFCachedRefreshURIList = std::move(mRefreshURIList);
1579 } else {
1580 // If Stop was called, the list was moved to mSavedRefreshURIList after
1581 // calling SuspendRefreshURIs, which calls RefreshURIToQueue.
1582 mBFCachedRefreshURIList = std::move(mSavedRefreshURIList);
1583 }
1584
1585 mFiredUnloadEvent = true;
1586
1587 ClearNavigationAPIOngoingNavigationForHistoryStep();
1588
1589 MaybeFirePageSwapOnDeactivate(aPageSwapTargetInfo, aNavigationType);
1590
1591 viewer->PageHide(false);
1592
1593 RefPtr<PresShell> presShell = GetPresShell();
1594 if (presShell) {
1595 presShell->Freeze(false);
1596 }
1597 }
1598}
1599
1600nsresult nsDocShell::Dispatch(already_AddRefed<nsIRunnable> aRunnable) {
1601 nsCOMPtr<nsIRunnable> runnable(aRunnable);
1602 if (NS_WARN_IF(!GetWindow())NS_warn_if_impl(!GetWindow(), "!GetWindow()", "./../../../docshell/base/nsDocShell.cpp"
, 1602)
) {
1603 // Window should only be unavailable after destroyed.
1604 MOZ_ASSERT(mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 1604); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 1604); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1605 return NS_ERROR_FAILURE;
1606 }
1607 return SchedulerGroup::Dispatch(runnable.forget());
1608}
1609
1610NS_IMETHODIMPnsresult
1611nsDocShell::DispatchLocationChangeEvent() {
1612 return Dispatch(NewRunnableMethod("nsDocShell::FireDummyOnLocationChange",
1613 this,
1614 &nsDocShell::FireDummyOnLocationChange));
1615}
1616
1617NS_IMETHODIMPnsresult
1618nsDocShell::StartDelayedAutoplayMediaComponents() {
1619 RefPtr<nsPIDOMWindowOuter> outerWindow = GetWindow();
1620 if (outerWindow) {
1621 outerWindow->ActivateMediaComponents();
1622 }
1623 return NS_OK;
1624}
1625
1626bool nsDocShell::MaybeInitTiming() {
1627 if (mTiming && !mBlankTiming) {
1628 return false;
1629 }
1630
1631 bool canBeReset = false;
1632
1633 if (mScriptGlobal && mBlankTiming) {
1634 nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow();
1635 if (innerWin && innerWin->GetPerformance()) {
1636 mTiming = innerWin->GetPerformance()->GetDOMTiming();
1637 mBlankTiming = false;
1638 }
1639 }
1640
1641 if (!mTiming) {
1642 mTiming = new nsDOMNavigationTiming(this);
1643 canBeReset = true;
1644 }
1645
1646 mTiming->NotifyNavigationStart(
1647 mBrowsingContext->IsActive()
1648 ? nsDOMNavigationTiming::DocShellState::eActive
1649 : nsDOMNavigationTiming::DocShellState::eInactive);
1650
1651 return canBeReset;
1652}
1653
1654void nsDocShell::MaybeResetInitTiming(bool aReset) {
1655 if (aReset) {
1656 mTiming = nullptr;
1657 }
1658}
1659
1660nsDOMNavigationTiming* nsDocShell::GetNavigationTiming() const {
1661 return mTiming;
1662}
1663
1664nsPresContext* nsDocShell::GetEldestPresContext() {
1665 nsIDocumentViewer* viewer = mDocumentViewer;
1666 while (viewer) {
1667 nsIDocumentViewer* prevViewer = viewer->GetPreviousViewer();
1668 if (!prevViewer) {
1669 return viewer->GetPresContext();
1670 }
1671 viewer = prevViewer;
1672 }
1673
1674 return nullptr;
1675}
1676
1677nsPresContext* nsDocShell::GetPresContext() {
1678 if (!mDocumentViewer) {
1679 return nullptr;
1680 }
1681
1682 return mDocumentViewer->GetPresContext();
1683}
1684
1685PresShell* nsDocShell::GetPresShell() {
1686 nsPresContext* presContext = GetPresContext();
1687 return presContext ? presContext->GetPresShell() : nullptr;
1688}
1689
1690PresShell* nsDocShell::GetEldestPresShell() {
1691 nsPresContext* presContext = GetEldestPresContext();
1692
1693 if (presContext) {
1694 return presContext->GetPresShell();
1695 }
1696
1697 return nullptr;
1698}
1699
1700NS_IMETHODIMPnsresult
1701nsDocShell::GetDocViewer(nsIDocumentViewer** aDocumentViewer) {
1702 NS_ENSURE_ARG_POINTER(aDocumentViewer)do { if ((__builtin_expect(!!(!(aDocumentViewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDocumentViewer" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 1702); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
1703
1704 *aDocumentViewer = mDocumentViewer;
1705 NS_IF_ADDREF(*aDocumentViewer)ns_if_addref(*aDocumentViewer);
1706 return NS_OK;
1707}
1708
1709NS_IMETHODIMPnsresult
1710nsDocShell::GetOuterWindowID(uint64_t* aWindowID) {
1711 *aWindowID = mContentWindowID;
1712 return NS_OK;
1713}
1714
1715NS_IMETHODIMPnsresult
1716nsDocShell::SetChromeEventHandler(EventTarget* aChromeEventHandler) {
1717 mChromeEventHandler = aChromeEventHandler;
1718
1719 if (mScriptGlobal) {
1720 mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
1721 }
1722
1723 return NS_OK;
1724}
1725
1726NS_IMETHODIMPnsresult
1727nsDocShell::GetChromeEventHandler(EventTarget** aChromeEventHandler) {
1728 NS_ENSURE_ARG_POINTER(aChromeEventHandler)do { if ((__builtin_expect(!!(!(aChromeEventHandler)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChromeEventHandler"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 1728); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1729 RefPtr<EventTarget> handler = mChromeEventHandler;
1730 handler.forget(aChromeEventHandler);
1731 return NS_OK;
1732}
1733
1734NS_IMETHODIMPnsresult
1735nsDocShell::SetCurrentURIForSessionStore(nsIURI* aURI) {
1736 // Note that securityUI will set STATE_IS_INSECURE, even if
1737 // the scheme of |aURI| is "https".
1738 SetCurrentURI(aURI, nullptr,
1739 /* aFireOnLocationChange */
1740 true,
1741 /* aIsInitialAboutBlank */
1742 false,
1743 /* aLocationFlags */
1744 nsIWebProgressListener::LOCATION_CHANGE_SESSION_STORE);
1745 return NS_OK;
1746}
1747
1748bool nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
1749 bool aFireOnLocationChange,
1750 bool aIsInitialAboutBlank,
1751 uint32_t aLocationFlags) {
1752 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 1752); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 1752); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1753
1754 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p SetCurrentURI %s\n", this, aURI
? aURI->GetSpecOrDefault().get() : ""); } } while (0)
1755 ("DOCSHELL %p SetCurrentURI %s\n", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p SetCurrentURI %s\n", this, aURI
? aURI->GetSpecOrDefault().get() : ""); } } while (0)
1756 aURI ? aURI->GetSpecOrDefault().get() : ""))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p SetCurrentURI %s\n", this, aURI
? aURI->GetSpecOrDefault().get() : ""); } } while (0)
;
1757
1758 // We don't want to send a location change when we're displaying an error
1759 // page, and we don't want to change our idea of "current URI" either
1760 if (mLoadType == LOAD_ERROR_PAGE) {
1761 return false;
1762 }
1763
1764 bool uriIsEqual = false;
1765 if (!mCurrentURI || !aURI ||
1766 NS_FAILED(mCurrentURI->Equals(aURI, &uriIsEqual))((bool)(__builtin_expect(!!(NS_FAILED_impl(mCurrentURI->Equals
(aURI, &uriIsEqual))), 0)))
|| !uriIsEqual) {
1767 mTitleValidForCurrentURI = false;
1768 }
1769
1770 SetCurrentURIInternal(aURI);
1771
1772#ifdef DEBUG1
1773 mLastOpenedURI = aURI;
1774#endif
1775
1776 if (!NS_IsAboutBlankAllowQueryAndFragment(mCurrentURI)) {
1777 mHasLoadedNonBlankURI = true;
1778 }
1779
1780 // Don't fire onLocationChange when creating a the initial about:blank
1781 // document, as this can happen when it's not safe for us to run script.
1782 // Note that if this initial about:blank isn't immediately navigated
1783 // away from, the onLocationChange will be fired as part of committing
1784 // to keeping the initial about:blank as the actual first initial
1785 // navigation destination.
1786 if (aIsInitialAboutBlank) {
1787 MOZ_ASSERT(!mHasLoadedNonBlankURI && !aRequest && aLocationFlags == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasLoadedNonBlankURI && !aRequest &&
aLocationFlags == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mHasLoadedNonBlankURI &&
!aRequest && aLocationFlags == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mHasLoadedNonBlankURI && !aRequest && aLocationFlags == 0"
, "./../../../docshell/base/nsDocShell.cpp", 1787); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mHasLoadedNonBlankURI && !aRequest && aLocationFlags == 0"
")"); do { MOZ_CrashSequence(__null, 1787); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1788 return false;
1789 }
1790
1791 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()", "./../../../docshell/base/nsDocShell.cpp"
, 1791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
")"); do { MOZ_CrashSequence(__null, 1791); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1792
1793 if (aFireOnLocationChange) {
1794 FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
1795 }
1796 return !aFireOnLocationChange;
1797}
1798
1799void nsDocShell::SetCurrentURIInternal(nsIURI* aURI) {
1800 mCurrentURI = aURI;
1801 if (mBrowsingContext) {
1802 mBrowsingContext->ClearCachedValuesOfLocations();
1803 }
1804}
1805
1806NS_IMETHODIMPnsresult
1807nsDocShell::GetCharset(nsACString& aCharset) {
1808 aCharset.Truncate();
1809
1810 PresShell* presShell = GetPresShell();
1811 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 1811); return NS_ERROR_FAILURE
; } } while (false)
;
1812 Document* doc = presShell->GetDocument();
1813 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(doc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "doc" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 1813); return NS_ERROR_FAILURE; } } while (false)
;
1814 doc->GetDocumentCharacterSet()->Name(aCharset);
1815 return NS_OK;
1816}
1817
1818NS_IMETHODIMPnsresult
1819nsDocShell::ForceEncodingDetection() {
1820 nsCOMPtr<nsIDocumentViewer> viewer;
1821 GetDocViewer(getter_AddRefs(viewer));
1822 if (!viewer) {
1823 return NS_OK;
1824 }
1825
1826 Document* doc = viewer->GetDocument();
1827 if (!doc || doc->WillIgnoreCharsetOverride()) {
1828 return NS_OK;
1829 }
1830
1831 mForcedAutodetection = true;
1832
1833 nsIURI* uri = doc->GetOriginalURI();
1834 bool isFileURL = uri && uri->SchemeIs("file");
1835
1836 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
1837 auto encoding = doc->GetDocumentCharacterSet();
1838 // AsHTMLDocument is valid, because we called
1839 // WillIgnoreCharsetOverride() above.
1840 if (doc->AsHTMLDocument()->IsPlainText()) {
1841 switch (charsetSource) {
1842 case kCharsetFromInitialAutoDetectionASCII:
1843 // Deliberately no final version
1844 LOGCHARSETMENU(("TEXT:UnlabeledAscii"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:UnlabeledAscii"
); } } while (0)
;
1845 break;
1846 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
1847 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
1848 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
1849 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
1850 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
1851 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
1852 LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:UnlabeledNonUtf8"
); } } while (0)
;
1853 break;
1854 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
1855 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
1856 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
1857 LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8TLD"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:UnlabeledNonUtf8TLD"
); } } while (0)
;
1858 break;
1859 case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
1860 case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
1861 LOGCHARSETMENU(("TEXT:UnlabeledUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:UnlabeledUtf8"
); } } while (0)
;
1862 break;
1863 case kCharsetFromChannel:
1864 if (encoding == UTF_8_ENCODING) {
1865 LOGCHARSETMENU(("TEXT:ChannelUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:ChannelUtf8"
); } } while (0)
;
1866 } else {
1867 LOGCHARSETMENU(("TEXT:ChannelNonUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:ChannelNonUtf8"
); } } while (0)
;
1868 }
1869 break;
1870 default:
1871 LOGCHARSETMENU(("TEXT:Bug"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TEXT:Bug"); } } while
(0)
;
1872 break;
1873 }
1874 } else {
1875 switch (charsetSource) {
1876 case kCharsetFromInitialAutoDetectionASCII:
1877 // Deliberately no final version
1878 LOGCHARSETMENU(("HTML:UnlabeledAscii"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:UnlabeledAscii"
); } } while (0)
;
1879 break;
1880 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
1881 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
1882 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
1883 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
1884 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
1885 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
1886 LOGCHARSETMENU(("HTML:UnlabeledNonUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:UnlabeledNonUtf8"
); } } while (0)
;
1887 break;
1888 case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
1889 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
1890 case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
1891 LOGCHARSETMENU(("HTML:UnlabeledNonUtf8TLD"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:UnlabeledNonUtf8TLD"
); } } while (0)
;
1892 break;
1893 case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
1894 case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
1895 LOGCHARSETMENU(("HTML:UnlabeledUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:UnlabeledUtf8"
); } } while (0)
;
1896 break;
1897 case kCharsetFromChannel:
1898 if (encoding == UTF_8_ENCODING) {
1899 LOGCHARSETMENU(("HTML:ChannelUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:ChannelUtf8"
); } } while (0)
;
1900 } else {
1901 LOGCHARSETMENU(("HTML:ChannelNonUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:ChannelNonUtf8"
); } } while (0)
;
1902 }
1903 break;
1904 case kCharsetFromXmlDeclaration:
1905 case kCharsetFromMetaTag:
1906 if (isFileURL) {
1907 LOGCHARSETMENU(("HTML:LocalLabeled"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:LocalLabeled"
); } } while (0)
;
1908 } else if (encoding == UTF_8_ENCODING) {
1909 LOGCHARSETMENU(("HTML:MetaUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:MetaUtf8");
} } while (0)
;
1910 } else {
1911 LOGCHARSETMENU(("HTML:MetaNonUtf8"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:MetaNonUtf8"
); } } while (0)
;
1912 }
1913 break;
1914 default:
1915 LOGCHARSETMENU(("HTML:Bug"))do { const ::mozilla::LogModule* moz_real_module = gCharsetMenuLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "HTML:Bug"); } } while
(0)
;
1916 break;
1917 }
1918 }
1919 return NS_OK;
1920}
1921
1922void nsDocShell::SetParentCharset(const Encoding*& aCharset,
1923 int32_t aCharsetSource,
1924 nsIPrincipal* aPrincipal) {
1925 mParentCharset = aCharset;
1926 mParentCharsetSource = aCharsetSource;
1927 mParentCharsetPrincipal = aPrincipal;
1928}
1929
1930void nsDocShell::GetParentCharset(const Encoding*& aCharset,
1931 int32_t* aCharsetSource,
1932 nsIPrincipal** aPrincipal) {
1933 aCharset = mParentCharset;
1934 *aCharsetSource = mParentCharsetSource;
1935 NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal)ns_if_addref(*aPrincipal = mParentCharsetPrincipal);
1936}
1937
1938NS_IMETHODIMPnsresult
1939nsDocShell::GetHasTrackingContentBlocked(Promise** aPromise) {
1940 MOZ_ASSERT(aPromise)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPromise)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPromise))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPromise", "./../../../docshell/base/nsDocShell.cpp"
, 1940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPromise" ")"
); do { MOZ_CrashSequence(__null, 1940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1941
1942 ErrorResult rv;
1943 RefPtr<Document> doc(GetDocument());
1944 RefPtr<Promise> retPromise = Promise::Create(doc->GetRelevantGlobal(), rv);
1945 if (NS_WARN_IF(rv.Failed())NS_warn_if_impl(rv.Failed(), "rv.Failed()", "./../../../docshell/base/nsDocShell.cpp"
, 1945)
) {
1946 return rv.StealNSResult();
1947 }
1948
1949 // Retrieve the document's content blocking events from the parent process.
1950 RefPtr<Document::GetContentBlockingEventsPromise> promise =
1951 doc->GetContentBlockingEvents();
1952 if (promise) {
1953 promise->Then(
1954 GetCurrentSerialEventTarget(), __func__,
1955 [retPromise](const Document::GetContentBlockingEventsPromise::
1956 ResolveOrRejectValue& aValue) {
1957 if (aValue.IsResolve()) {
1958 bool has = aValue.ResolveValue() &
1959 nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
1960 retPromise->MaybeResolve(has);
1961 } else {
1962 retPromise->MaybeResolve(false);
1963 }
1964 });
1965 } else {
1966 retPromise->MaybeResolve(false);
1967 }
1968
1969 retPromise.forget(aPromise);
1970 return NS_OK;
1971}
1972
1973NS_IMETHODIMPnsresult
1974nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled) {
1975 MOZ_ASSERT(aEnabled)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEnabled)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEnabled))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEnabled", "./../../../docshell/base/nsDocShell.cpp"
, 1975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnabled" ")"
); do { MOZ_CrashSequence(__null, 1975); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1976 *aEnabled = mCSSErrorReportingEnabled;
1977 return NS_OK;
1978}
1979
1980NS_IMETHODIMPnsresult
1981nsDocShell::SetCssErrorReportingEnabled(bool aEnabled) {
1982 mCSSErrorReportingEnabled = aEnabled;
1983 return NS_OK;
1984}
1985
1986NS_IMETHODIMPnsresult
1987nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) {
1988 NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing)do { if ((__builtin_expect(!!(!(aUsePrivateBrowsing)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aUsePrivateBrowsing"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 1988); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1989 return mBrowsingContext->GetUsePrivateBrowsing(aUsePrivateBrowsing);
1990}
1991
1992void nsDocShell::NotifyPrivateBrowsingChanged() {
1993 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 1993); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 1993); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1994
1995 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
1996 while (iter.HasMore()) {
1997 nsWeakPtr ref = iter.GetNext();
1998 nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
1999 if (!obs) {
2000 iter.Remove();
2001 } else {
2002 obs->PrivateModeChanged(UsePrivateBrowsing());
2003 }
2004 }
2005}
2006
2007NS_IMETHODIMPnsresult
2008nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) {
2009 return mBrowsingContext->SetUsePrivateBrowsing(aUsePrivateBrowsing);
2010}
2011
2012NS_IMETHODIMPnsresult
2013nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing) {
2014 return mBrowsingContext->SetPrivateBrowsing(aUsePrivateBrowsing);
2015}
2016
2017NS_IMETHODIMPnsresult
2018nsDocShell::GetHasLoadedNonBlankURI(bool* aResult) {
2019 NS_ENSURE_ARG_POINTER(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2019); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2020
2021 *aResult = mHasLoadedNonBlankURI;
2022 return NS_OK;
2023}
2024
2025bool nsDocShell::HasStartedLoadingOtherThanInitialBlankURI() {
2026 return mHasStartedLoadingOtherThanInitialBlankURI;
2027}
2028
2029NS_IMETHODIMPnsresult
2030nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) {
2031 NS_ENSURE_ARG_POINTER(aUseRemoteTabs)do { if ((__builtin_expect(!!(!(aUseRemoteTabs)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aUseRemoteTabs" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2031); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2032 return mBrowsingContext->GetUseRemoteTabs(aUseRemoteTabs);
2033}
2034
2035NS_IMETHODIMPnsresult
2036nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) {
2037 return mBrowsingContext->SetRemoteTabs(aUseRemoteTabs);
2038}
2039
2040NS_IMETHODIMPnsresult
2041nsDocShell::GetUseRemoteSubframes(bool* aUseRemoteSubframes) {
2042 NS_ENSURE_ARG_POINTER(aUseRemoteSubframes)do { if ((__builtin_expect(!!(!(aUseRemoteSubframes)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aUseRemoteSubframes"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2042); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2043 return mBrowsingContext->GetUseRemoteSubframes(aUseRemoteSubframes);
2044}
2045
2046NS_IMETHODIMPnsresult
2047nsDocShell::SetRemoteSubframes(bool aUseRemoteSubframes) {
2048 return mBrowsingContext->SetRemoteSubframes(aUseRemoteSubframes);
2049}
2050
2051NS_IMETHODIMPnsresult
2052nsDocShell::AddWeakPrivacyTransitionObserver(
2053 nsIPrivacyTransitionObserver* aObserver) {
2054 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2055 if (!weakObs) {
2056 return NS_ERROR_NOT_AVAILABLE;
2057 }
2058 mPrivacyObservers.AppendElement(weakObs);
2059 return NS_OK;
2060}
2061
2062NS_IMETHODIMPnsresult
2063nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver) {
2064 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2065 if (!weakObs) {
2066 return NS_ERROR_FAILURE;
2067 }
2068 mReflowObservers.AppendElement(weakObs);
2069 return NS_OK;
2070}
2071
2072NS_IMETHODIMPnsresult
2073nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver) {
2074 nsWeakPtr obs = do_GetWeakReference(aObserver);
2075 return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
2076}
2077
2078NS_IMETHODIMPnsresult
2079nsDocShell::NotifyReflowObservers(bool aInterruptible,
2080 DOMHighResTimeStamp aStart,
2081 DOMHighResTimeStamp aEnd) {
2082 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
2083 while (iter.HasMore()) {
2084 nsWeakPtr ref = iter.GetNext();
2085 nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
2086 if (!obs) {
2087 iter.Remove();
2088 } else if (aInterruptible) {
2089 obs->ReflowInterruptible(aStart, aEnd);
2090 } else {
2091 obs->Reflow(aStart, aEnd);
2092 }
2093 }
2094 return NS_OK;
2095}
2096
2097NS_IMETHODIMPnsresult
2098nsDocShell::GetAllowMetaRedirects(bool* aReturn) {
2099 NS_ENSURE_ARG_POINTER(aReturn)do { if ((__builtin_expect(!!(!(aReturn)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aReturn" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2099); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2100
2101 *aReturn = mAllowMetaRedirects;
2102 return NS_OK;
2103}
2104
2105NS_IMETHODIMPnsresult
2106nsDocShell::SetAllowMetaRedirects(bool aValue) {
2107 mAllowMetaRedirects = aValue;
2108 return NS_OK;
2109}
2110
2111NS_IMETHODIMPnsresult
2112nsDocShell::GetAllowSubframes(bool* aAllowSubframes) {
2113 NS_ENSURE_ARG_POINTER(aAllowSubframes)do { if ((__builtin_expect(!!(!(aAllowSubframes)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aAllowSubframes" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2113); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2114
2115 *aAllowSubframes = mAllowSubframes;
2116 return NS_OK;
2117}
2118
2119NS_IMETHODIMPnsresult
2120nsDocShell::SetAllowSubframes(bool aAllowSubframes) {
2121 mAllowSubframes = aAllowSubframes;
2122 return NS_OK;
2123}
2124
2125NS_IMETHODIMPnsresult
2126nsDocShell::GetAllowImages(bool* aAllowImages) {
2127 NS_ENSURE_ARG_POINTER(aAllowImages)do { if ((__builtin_expect(!!(!(aAllowImages)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aAllowImages" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2127); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2128
2129 *aAllowImages = mAllowImages;
2130 return NS_OK;
2131}
2132
2133NS_IMETHODIMPnsresult
2134nsDocShell::SetAllowImages(bool aAllowImages) {
2135 mAllowImages = aAllowImages;
2136 return NS_OK;
2137}
2138
2139NS_IMETHODIMPnsresult
2140nsDocShell::GetAllowMedia(bool* aAllowMedia) {
2141 *aAllowMedia = mAllowMedia;
2142 return NS_OK;
2143}
2144
2145NS_IMETHODIMPnsresult
2146nsDocShell::SetAllowMedia(bool aAllowMedia) {
2147 mAllowMedia = aAllowMedia;
2148
2149 // Mute or unmute audio contexts attached to the inner window.
2150 if (mScriptGlobal) {
2151 if (nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow()) {
2152 if (aAllowMedia) {
2153 innerWin->UnmuteAudioContexts();
2154 } else {
2155 innerWin->MuteAudioContexts();
2156 }
2157 }
2158 }
2159
2160 return NS_OK;
2161}
2162
2163NS_IMETHODIMPnsresult
2164nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch) {
2165 *aAllowDNSPrefetch = mAllowDNSPrefetch;
2166 return NS_OK;
2167}
2168
2169NS_IMETHODIMPnsresult
2170nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch) {
2171 mAllowDNSPrefetch = aAllowDNSPrefetch;
2172 return NS_OK;
2173}
2174
2175NS_IMETHODIMPnsresult
2176nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl) {
2177 *aAllowWindowControl = mAllowWindowControl;
2178 return NS_OK;
2179}
2180
2181NS_IMETHODIMPnsresult
2182nsDocShell::SetAllowWindowControl(bool aAllowWindowControl) {
2183 mAllowWindowControl = aAllowWindowControl;
2184 return NS_OK;
2185}
2186
2187NS_IMETHODIMPnsresult
2188nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting) {
2189 *aAllowContentRetargeting = mBrowsingContext->GetAllowContentRetargeting();
2190 return NS_OK;
2191}
2192
2193NS_IMETHODIMPnsresult
2194nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting) {
2195 BrowsingContext::Transaction txn;
2196 txn.SetAllowContentRetargeting(aAllowContentRetargeting);
2197 txn.SetAllowContentRetargetingOnChildren(aAllowContentRetargeting);
2198 return txn.Commit(mBrowsingContext);
2199}
2200
2201NS_IMETHODIMPnsresult
2202nsDocShell::GetAllowContentRetargetingOnChildren(
2203 bool* aAllowContentRetargetingOnChildren) {
2204 *aAllowContentRetargetingOnChildren =
2205 mBrowsingContext->GetAllowContentRetargetingOnChildren();
2206 return NS_OK;
2207}
2208
2209NS_IMETHODIMPnsresult
2210nsDocShell::SetAllowContentRetargetingOnChildren(
2211 bool aAllowContentRetargetingOnChildren) {
2212 return mBrowsingContext->SetAllowContentRetargetingOnChildren(
2213 aAllowContentRetargetingOnChildren);
2214}
2215
2216NS_IMETHODIMPnsresult
2217nsDocShell::GetMayEnableCharacterEncodingMenu(
2218 bool* aMayEnableCharacterEncodingMenu) {
2219 *aMayEnableCharacterEncodingMenu = false;
2220 if (!mDocumentViewer) {
2221 return NS_OK;
2222 }
2223 Document* doc = mDocumentViewer->GetDocument();
2224 if (!doc) {
2225 return NS_OK;
2226 }
2227 if (doc->WillIgnoreCharsetOverride()) {
2228 return NS_OK;
2229 }
2230
2231 *aMayEnableCharacterEncodingMenu = true;
2232 return NS_OK;
2233}
2234
2235NS_IMETHODIMPnsresult
2236nsDocShell::GetAllDocShellsInSubtree(int32_t aItemType,
2237 DocShellEnumeratorDirection aDirection,
2238 nsTArray<RefPtr<nsIDocShell>>& aResult) {
2239 aResult.Clear();
2240
2241 nsDocShellEnumerator docShellEnum(
2242 (aDirection == ENUMERATE_FORWARDS)
2243 ? nsDocShellEnumerator::EnumerationDirection::Forwards
2244 : nsDocShellEnumerator::EnumerationDirection::Backwards,
2245 aItemType, *this);
2246
2247 nsresult rv = docShellEnum.BuildDocShellArray(aResult);
2248 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2249 return rv;
2250 }
2251
2252 return NS_OK;
2253}
2254
2255NS_IMETHODIMPnsresult
2256nsDocShell::GetAppType(AppType* aAppType) {
2257 *aAppType = mAppType;
2258 return NS_OK;
2259}
2260
2261NS_IMETHODIMPnsresult
2262nsDocShell::SetAppType(AppType aAppType) {
2263 mAppType = aAppType;
2264 return NS_OK;
2265}
2266
2267NS_IMETHODIMPnsresult
2268nsDocShell::GetAllowAuth(bool* aAllowAuth) {
2269 *aAllowAuth = mAllowAuth;
2270 return NS_OK;
2271}
2272
2273NS_IMETHODIMPnsresult
2274nsDocShell::SetAllowAuth(bool aAllowAuth) {
2275 mAllowAuth = aAllowAuth;
2276 return NS_OK;
2277}
2278
2279NS_IMETHODIMPnsresult
2280nsDocShell::GetZoom(float* aZoom) {
2281 NS_ENSURE_ARG_POINTER(aZoom)do { if ((__builtin_expect(!!(!(aZoom)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aZoom" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2281); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2282 *aZoom = 1.0f;
2283 return NS_OK;
2284}
2285
2286NS_IMETHODIMPnsresult
2287nsDocShell::SetZoom(float /*aZoom*/) { return NS_ERROR_NOT_IMPLEMENTED; }
2288
2289NS_IMETHODIMPnsresult
2290nsDocShell::GetBusyFlags(BusyFlags* aBusyFlags) {
2291 NS_ENSURE_ARG_POINTER(aBusyFlags)do { if ((__builtin_expect(!!(!(aBusyFlags)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aBusyFlags" ") failed",
nullptr, "./../../../docshell/base/nsDocShell.cpp", 2291); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2292
2293 *aBusyFlags = mBusyFlags;
2294 return NS_OK;
2295}
2296
2297NS_IMETHODIMPnsresult
2298nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate** aLoadURIDelegate) {
2299 nsCOMPtr<nsILoadURIDelegate> delegate = GetLoadURIDelegate();
2300 delegate.forget(aLoadURIDelegate);
2301 return NS_OK;
2302}
2303
2304already_AddRefed<nsILoadURIDelegate> nsDocShell::GetLoadURIDelegate() {
2305 if (nsCOMPtr<nsILoadURIDelegate> result =
2306 do_QueryActor("LoadURIDelegate", GetDocument())) {
2307 return result.forget();
2308 }
2309
2310 return nullptr;
2311}
2312
2313NS_IMETHODIMPnsresult
2314nsDocShell::GetUseErrorPages(bool* aUseErrorPages) {
2315 *aUseErrorPages = mBrowsingContext->GetUseErrorPages();
2316 return NS_OK;
2317}
2318
2319NS_IMETHODIMPnsresult
2320nsDocShell::SetUseErrorPages(bool aUseErrorPages) {
2321 return mBrowsingContext->SetUseErrorPages(aUseErrorPages);
2322}
2323
2324NS_IMETHODIMPnsresult
2325nsDocShell::GetPreviousEntryIndex(int32_t* aPreviousEntryIndex) {
2326 *aPreviousEntryIndex = mPreviousEntryIndex;
2327 return NS_OK;
2328}
2329
2330NS_IMETHODIMPnsresult
2331nsDocShell::GetLoadedEntryIndex(int32_t* aLoadedEntryIndex) {
2332 *aLoadedEntryIndex = mLoadedEntryIndex;
2333 return NS_OK;
2334}
2335
2336NS_IMETHODIMPnsresult
2337nsDocShell::HistoryPurged(int32_t aNumEntries) {
2338 // These indices are used for fastback cache eviction, to determine
2339 // which session history entries are candidates for content viewer
2340 // eviction. We need to adjust by the number of entries that we
2341 // just purged from history, so that we look at the right session history
2342 // entries during eviction.
2343 mPreviousEntryIndex = std::max(-1, mPreviousEntryIndex - aNumEntries);
2344 mLoadedEntryIndex = std::max(0, mLoadedEntryIndex - aNumEntries);
2345
2346 for (auto* child : mChildList.ForwardRange()) {
2347 nsCOMPtr<nsIDocShell> shell = do_QueryObject(child);
2348 if (shell) {
2349 shell->HistoryPurged(aNumEntries);
2350 }
2351 }
2352
2353 return NS_OK;
2354}
2355
2356nsresult nsDocShell::HistoryEntryRemoved(int32_t aIndex) {
2357 // These indices are used for fastback cache eviction, to determine
2358 // which session history entries are candidates for content viewer
2359 // eviction. We need to adjust by the number of entries that we
2360 // just purged from history, so that we look at the right session history
2361 // entries during eviction.
2362 if (aIndex == mPreviousEntryIndex) {
2363 mPreviousEntryIndex = -1;
2364 } else if (aIndex < mPreviousEntryIndex) {
2365 --mPreviousEntryIndex;
2366 }
2367 if (mLoadedEntryIndex == aIndex) {
2368 mLoadedEntryIndex = 0;
2369 } else if (aIndex < mLoadedEntryIndex) {
2370 --mLoadedEntryIndex;
2371 }
2372
2373 for (auto* child : mChildList.ForwardRange()) {
2374 nsCOMPtr<nsIDocShell> shell = do_QueryObject(child);
2375 if (shell) {
2376 static_cast<nsDocShell*>(shell.get())->HistoryEntryRemoved(aIndex);
2377 }
2378 }
2379
2380 return NS_OK;
2381}
2382
2383nsresult nsDocShell::Now(DOMHighResTimeStamp* aWhen) {
2384 *aWhen = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
2385 return NS_OK;
2386}
2387
2388NS_IMETHODIMPnsresult
2389nsDocShell::SetWindowDraggingAllowed(bool aValue) {
2390 RefPtr<nsDocShell> parent;
2391 if (!aValue && mItemType == typeChrome &&
2392 !(parent = GetInProcessParentDocshell())) {
2393 // Window dragging is always allowed for top level
2394 // chrome docshells.
2395 return NS_ERROR_FAILURE;
2396 }
2397 mWindowDraggingAllowed = aValue;
2398 return NS_OK;
2399}
2400
2401NS_IMETHODIMPnsresult
2402nsDocShell::GetWindowDraggingAllowed(bool* aValue) {
2403 // window dragging regions in CSS (-moz-window-drag:drag)
2404 // can be slow. Default behavior is to only allow it for
2405 // chrome top level windows.
2406 RefPtr<nsDocShell> parent;
2407 if (mItemType == typeChrome && !(parent = GetInProcessParentDocshell())) {
2408 // Top level chrome window
2409 *aValue = true;
2410 } else {
2411 *aValue = mWindowDraggingAllowed;
2412 }
2413 return NS_OK;
2414}
2415
2416NS_IMETHODIMPnsresult
2417nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult) {
2418 NS_IF_ADDREF(*aResult = GetCurrentDocChannel())ns_if_addref(*aResult = GetCurrentDocChannel());
2419 return NS_OK;
2420}
2421
2422nsIChannel* nsDocShell::GetCurrentDocChannel() {
2423 if (mDocumentViewer) {
2424 Document* doc = mDocumentViewer->GetDocument();
2425 if (doc) {
2426 return doc->GetChannel();
2427 }
2428 }
2429 return nullptr;
2430}
2431
2432NS_IMETHODIMPnsresult
2433nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver) {
2434 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2435 if (!weakObs) {
2436 return NS_ERROR_FAILURE;
2437 }
2438 mScrollObservers.AppendElement(weakObs);
2439 return NS_OK;
2440}
2441
2442NS_IMETHODIMPnsresult
2443nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver) {
2444 nsWeakPtr obs = do_GetWeakReference(aObserver);
2445 return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
2446}
2447
2448void nsDocShell::NotifyAsyncPanZoomStarted() {
2449 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2450 while (iter.HasMore()) {
2451 nsWeakPtr ref = iter.GetNext();
2452 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2453 if (obs) {
2454 obs->AsyncPanZoomStarted();
2455 } else {
2456 iter.Remove();
2457 }
2458 }
2459}
2460
2461void nsDocShell::NotifyAsyncPanZoomStopped() {
2462 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2463 while (iter.HasMore()) {
2464 nsWeakPtr ref = iter.GetNext();
2465 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2466 if (obs) {
2467 obs->AsyncPanZoomStopped();
2468 } else {
2469 iter.Remove();
2470 }
2471 }
2472}
2473
2474NS_IMETHODIMPnsresult
2475nsDocShell::NotifyScrollObservers() {
2476 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2477 while (iter.HasMore()) {
2478 nsWeakPtr ref = iter.GetNext();
2479 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2480 if (obs) {
2481 obs->ScrollPositionChanged();
2482 } else {
2483 iter.Remove();
2484 }
2485 }
2486 return NS_OK;
2487}
2488
2489//*****************************************************************************
2490// nsDocShell::nsIDocShellTreeItem
2491//*****************************************************************************
2492
2493NS_IMETHODIMPnsresult
2494nsDocShell::GetName(nsAString& aName) {
2495 aName = mBrowsingContext->Name();
2496 return NS_OK;
2497}
2498
2499NS_IMETHODIMPnsresult
2500nsDocShell::SetName(const nsAString& aName) {
2501 return mBrowsingContext->SetName(aName);
2502}
2503
2504NS_IMETHODIMPnsresult
2505nsDocShell::NameEquals(const nsAString& aName, bool* aResult) {
2506 NS_ENSURE_ARG_POINTER(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2506); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2507 *aResult = mBrowsingContext->NameEquals(aName);
2508 return NS_OK;
2509}
2510
2511NS_IMETHODIMPnsresult
2512nsDocShell::GetCustomUserAgent(nsACString& aCustomUserAgent) {
2513 mBrowsingContext->GetCustomUserAgent(aCustomUserAgent);
2514 return NS_OK;
2515}
2516
2517NS_IMETHODIMPnsresult
2518nsDocShell::SetCustomUserAgent(const nsACString& aCustomUserAgent) {
2519 if (mWillChangeProcess) {
2520 NS_WARNING("SetCustomUserAgent: Process is changing. Ignoring set")NS_DebugBreak(NS_DEBUG_WARNING, "SetCustomUserAgent: Process is changing. Ignoring set"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2520)
;
2521 return NS_ERROR_FAILURE;
2522 }
2523
2524 return mBrowsingContext->SetCustomUserAgent(aCustomUserAgent);
2525}
2526
2527NS_IMETHODIMPnsresult
2528nsDocShell::ClearCachedPlatform() {
2529 nsCOMPtr<nsPIDOMWindowInner> win =
2530 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
2531 if (win) {
2532 Navigator* navigator = win->Navigator();
2533 if (navigator) {
2534 navigator->ClearPlatformCache();
2535 }
2536 }
2537
2538 return NS_OK;
2539}
2540
2541NS_IMETHODIMPnsresult
2542nsDocShell::ClearCachedUserAgent() {
2543 nsCOMPtr<nsPIDOMWindowInner> win =
2544 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
2545 if (win) {
2546 Navigator* navigator = win->Navigator();
2547 if (navigator) {
2548 navigator->ClearUserAgentCache();
2549 }
2550 }
2551
2552 return NS_OK;
2553}
2554
2555/* virtual */
2556int32_t nsDocShell::ItemType() { return mItemType; }
2557
2558NS_IMETHODIMPnsresult
2559nsDocShell::GetItemType(int32_t* aItemType) {
2560 NS_ENSURE_ARG_POINTER(aItemType)do { if ((__builtin_expect(!!(!(aItemType)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aItemType" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2560); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2561
2562 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mBrowsingContext->IsContent() ? typeContent : typeChrome
) == mItemType)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((mBrowsingContext->IsContent
() ? typeContent : typeChrome) == mItemType))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("(mBrowsingContext->IsContent() ? typeContent : typeChrome) == mItemType"
, "./../../../docshell/base/nsDocShell.cpp", 2563); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "(mBrowsingContext->IsContent() ? typeContent : typeChrome) == mItemType"
")"); do { MOZ_CrashSequence(__null, 2563); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2563 (mBrowsingContext->IsContent() ? typeContent : typeChrome) == mItemType)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mBrowsingContext->IsContent() ? typeContent : typeChrome
) == mItemType)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((mBrowsingContext->IsContent
() ? typeContent : typeChrome) == mItemType))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("(mBrowsingContext->IsContent() ? typeContent : typeChrome) == mItemType"
, "./../../../docshell/base/nsDocShell.cpp", 2563); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "(mBrowsingContext->IsContent() ? typeContent : typeChrome) == mItemType"
")"); do { MOZ_CrashSequence(__null, 2563); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2564 *aItemType = mItemType;
2565 return NS_OK;
2566}
2567
2568NS_IMETHODIMPnsresult
2569nsDocShell::GetInProcessParent(nsIDocShellTreeItem** aParent) {
2570 if (!mParent) {
2571 *aParent = nullptr;
2572 } else {
2573 CallQueryInterface(mParent, aParent);
2574 }
2575 // Note that in the case when the parent is not an nsIDocShellTreeItem we
2576 // don't want to throw; we just want to return null.
2577 return NS_OK;
2578}
2579
2580// With Fission, related nsDocShell objects may exist in a different process. In
2581// that case, this method will return `nullptr`, despite a parent nsDocShell
2582// object existing.
2583//
2584// Prefer using `BrowsingContext::Parent()`, which will succeed even if the
2585// parent entry is not in the current process, and handle the case where the
2586// parent nsDocShell is inaccessible.
2587already_AddRefed<nsDocShell> nsDocShell::GetInProcessParentDocshell() {
2588 nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
2589 return docshell.forget().downcast<nsDocShell>();
2590}
2591
2592void nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal) {
2593 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 2593); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 2593); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2594
2595 // If there is an existing document then there is no need to create
2596 // a client for a future initial about:blank document.
2597 if (mScriptGlobal && mScriptGlobal->GetCurrentInnerWindow() &&
2598 mScriptGlobal->GetCurrentInnerWindow()->GetExtantDoc()) {
2599 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo
().isSome())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mScriptGlobal->GetCurrentInnerWindow
()->GetClientInfo().isSome()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo().isSome()"
, "./../../../docshell/base/nsDocShell.cpp", 2600); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo().isSome()"
")"); do { MOZ_CrashSequence(__null, 2600); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2600 mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo().isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo
().isSome())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mScriptGlobal->GetCurrentInnerWindow
()->GetClientInfo().isSome()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo().isSome()"
, "./../../../docshell/base/nsDocShell.cpp", 2600); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "mScriptGlobal->GetCurrentInnerWindow()->GetClientInfo().isSome()"
")"); do { MOZ_CrashSequence(__null, 2600); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2601 MOZ_DIAGNOSTIC_ASSERT(!mInitialClientSource)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mInitialClientSource)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mInitialClientSource))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mInitialClientSource"
, "./../../../docshell/base/nsDocShell.cpp", 2601); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mInitialClientSource" ")"); do
{ MOZ_CrashSequence(__null, 2601); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2602 return;
2603 }
2604
2605 // Don't recreate the initial client source. We call this multiple times
2606 // when DoChannelLoad() is called before CreateAboutBlankDocumentViewer.
2607 if (mInitialClientSource) {
2608 return;
2609 }
2610
2611 // Don't pre-allocate the client when we are sandboxed. The inherited
2612 // principal does not take sandboxing into account.
2613 // TODO: Refactor sandboxing principal code out so we can use it here.
2614 if (!aPrincipal && mBrowsingContext->GetSandboxFlags()) {
2615 return;
2616 }
2617
2618 // We cannot get inherited foreign partitioned principal here. Instead, we
2619 // directly check which principal we want to inherit for the service worker.
2620 nsIPrincipal* principal =
2621 aPrincipal
2622 ? aPrincipal
2623 : GetInheritedPrincipal(
2624 false, StoragePrincipalHelper::
2625 ShouldUsePartitionPrincipalForServiceWorker(this));
2626
2627 // Sometimes there is no principal available when we are called from
2628 // CreateAboutBlankDocumentViewer. For example, sometimes the principal
2629 // is only extracted from the load context after the document is created
2630 // in Document::ResetToURI(). Ideally we would do something similar
2631 // here, but for now lets just avoid the issue by not preallocating the
2632 // client.
2633 if (!principal) {
2634 return;
2635 }
2636
2637 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
2638 if (!win) {
2639 return;
2640 }
2641
2642 mInitialClientSource = ClientManager::CreateSource(
2643 ClientType::Window, GetMainThreadSerialEventTarget(), principal);
2644 MOZ_DIAGNOSTIC_ASSERT(mInitialClientSource)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInitialClientSource)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInitialClientSource))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("mInitialClientSource"
, "./../../../docshell/base/nsDocShell.cpp", 2644); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "mInitialClientSource" ")"); do {
MOZ_CrashSequence(__null, 2644); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2645
2646 // Mark the initial client as execution ready, but owned by the docshell.
2647 // If the client is actually used this will cause ClientSource to force
2648 // the creation of the initial about:blank by calling
2649 // nsDocShell::GetDocument().
2650 mInitialClientSource->DocShellExecutionReady(this);
2651
2652 // Next, check to see if the parent is controlled.
2653 MaybeInheritController(mInitialClientSource.get(), principal);
2654}
2655
2656void VerifyClientPrincipalInfosMatch(
2657 const mozilla::ipc::PrincipalInfo& aLeft,
2658 const mozilla::ipc::PrincipalInfo& aRight) {
2659 // Inheriting a controller when the principals don't match would cause a
2660 // crash. Let's do the checks earlier to crash here already instead of
2661 // ClientSource::SetController. And assert each condition separately. See bug
2662 // 1880012.
2663 MOZ_RELEASE_ASSERT(aLeft.type() == aRight.type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLeft.type() == aRight.type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLeft.type() == aRight.type(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLeft.type() == aRight.type()", "./../../../docshell/base/nsDocShell.cpp"
, 2663); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aLeft.type() == aRight.type()"
")"); do { MOZ_CrashSequence(__null, 2663); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2664
2665 switch (aLeft.type()) {
2666 case mozilla::ipc::PrincipalInfo::TContentPrincipalInfo: {
2667 const mozilla::ipc::ContentPrincipalInfo& leftContent =
2668 aLeft.get_ContentPrincipalInfo();
2669 const mozilla::ipc::ContentPrincipalInfo& rightContent =
2670 aRight.get_ContentPrincipalInfo();
2671 {
2672 // The most likely mismatch is the foreign bit in the partition key.
2673 // See bug 2006265 and 2013379.
2674 nsAutoString scheme;
2675 nsAutoString baseDomain;
2676 int32_t port;
2677 bool leftForeignBit;
2678 bool rightForeignBit;
2679 OriginAttributes::ParsePartitionKey(leftContent.attrs().mPartitionKey,
2680 scheme, baseDomain, port,
2681 leftForeignBit);
2682 OriginAttributes::ParsePartitionKey(rightContent.attrs().mPartitionKey,
2683 scheme, baseDomain, port,
2684 rightForeignBit);
2685 MOZ_RELEASE_ASSERT(leftForeignBit == rightForeignBit)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leftForeignBit == rightForeignBit)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(leftForeignBit == rightForeignBit
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"leftForeignBit == rightForeignBit", "./../../../docshell/base/nsDocShell.cpp"
, 2685); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "leftForeignBit == rightForeignBit"
")"); do { MOZ_CrashSequence(__null, 2685); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2686 }
2687 MOZ_RELEASE_ASSERT(leftContent.attrs() == rightContent.attrs())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leftContent.attrs() == rightContent.attrs())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(leftContent.attrs() == rightContent.attrs()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("leftContent.attrs() == rightContent.attrs()"
, "./../../../docshell/base/nsDocShell.cpp", 2687); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "leftContent.attrs() == rightContent.attrs()"
")"); do { MOZ_CrashSequence(__null, 2687); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2688 MOZ_RELEASE_ASSERT(leftContent.originNoSuffix() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leftContent.originNoSuffix() == rightContent.originNoSuffix
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leftContent.originNoSuffix() == rightContent.originNoSuffix
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("leftContent.originNoSuffix() == rightContent.originNoSuffix()"
, "./../../../docshell/base/nsDocShell.cpp", 2689); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "leftContent.originNoSuffix() == rightContent.originNoSuffix()"
")"); do { MOZ_CrashSequence(__null, 2689); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2689 rightContent.originNoSuffix())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leftContent.originNoSuffix() == rightContent.originNoSuffix
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leftContent.originNoSuffix() == rightContent.originNoSuffix
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("leftContent.originNoSuffix() == rightContent.originNoSuffix()"
, "./../../../docshell/base/nsDocShell.cpp", 2689); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "leftContent.originNoSuffix() == rightContent.originNoSuffix()"
")"); do { MOZ_CrashSequence(__null, 2689); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2690 return;
2691 }
2692 case mozilla::ipc::PrincipalInfo::TNullPrincipalInfo: {
2693 // null principal never matches
2694 MOZ_RELEASE_ASSERT(false, "Clients have null principals")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Clients have null principals"
")", "./../../../docshell/base/nsDocShell.cpp", 2694); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "false" ") (" "Clients have null principals"
")"); do { MOZ_CrashSequence(__null, 2694); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2695 return;
2696 }
2697 default: {
2698 break;
2699 }
2700 }
2701}
2702
2703void nsDocShell::MaybeInheritController(
2704 mozilla::dom::ClientSource* aClientSource, nsIPrincipal* aPrincipal) {
2705 nsCOMPtr<nsIDocShell> parent = GetInProcessParentDocshell();
2706 nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
2707 nsPIDOMWindowInner* parentInner =
2708 parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
2709 if (!parentInner) {
2710 return;
2711 }
2712
2713 nsCOMPtr<nsIURI> uri;
2714 MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns))), 1)))), 1
))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), \"about:blank\"_ns))"
, "./../../../docshell/base/nsDocShell.cpp", 2714); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), \"about:blank\"_ns))"
")"); do { MOZ_CrashSequence(__null, 2714); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
2715
2716 // We're done if there is no parent controller or if this docshell
2717 // is not permitted to control for some reason.
2718 Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
2719 if (controller.isNothing() ||
2720 !ServiceWorkerAllowedToControlWindow(aPrincipal, uri)) {
2721 return;
2722 }
2723
2724 VerifyClientPrincipalInfosMatch(aClientSource->Info().PrincipalInfo(),
2725 controller->PrincipalInfo());
2726 aClientSource->InheritController(controller.ref());
2727}
2728
2729Maybe<ClientInfo> nsDocShell::GetInitialClientInfo() const {
2730 if (mInitialClientSource) {
2731 Maybe<ClientInfo> result;
2732 result.emplace(mInitialClientSource->Info());
2733 return result;
2734 }
2735
2736 nsPIDOMWindowInner* innerWindow =
2737 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
2738 Document* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
2739
2740 if (!doc || !doc->IsUncommittedInitialDocument()) {
2741 // We won't reuse the inner window so let the channel determine one
2742 return Maybe<ClientInfo>();
2743 }
2744
2745 return innerWindow->GetClientInfo();
2746}
2747
2748nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
2749 bool wasFrame = IsSubframe();
2750
2751 nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
2752 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2752); return rv; } } while (false)
;
2753
2754 nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
2755 if (wasFrame != IsSubframe() && priorityGroup) {
2756 priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
2757 }
2758
2759 // Curse ambiguous nsISupports inheritance!
2760 nsISupports* parent = GetAsSupports(aParent);
2761
2762 // If parent is another docshell, we inherit all their flags for
2763 // allowing plugins, scripting etc.
2764 bool value;
2765 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
2766
2767 if (parentAsDocShell) {
2768 if (mAllowMetaRedirects &&
2769 NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(parentAsDocShell->
GetAllowMetaRedirects(&value))), 1)))
) {
2770 SetAllowMetaRedirects(value);
2771 }
2772 if (mAllowSubframes &&
2773 NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(parentAsDocShell->
GetAllowSubframes(&value))), 1)))
) {
2774 SetAllowSubframes(value);
2775 }
2776 if (mAllowImages &&
2777 NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(parentAsDocShell->
GetAllowImages(&value))), 1)))
) {
2778 SetAllowImages(value);
2779 }
2780 SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
2781 if (mAllowWindowControl &&
2782 NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(parentAsDocShell->
GetAllowWindowControl(&value))), 1)))
) {
2783 SetAllowWindowControl(value);
2784 }
2785 if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))((bool)(__builtin_expect(!!(NS_FAILED_impl(parentAsDocShell->
GetAllowDNSPrefetch(&value))), 0)))
) {
2786 value = false;
2787 }
2788 SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
2789 }
2790
2791 nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
2792 if (parentURIListener) {
2793 mContentListener->SetParentContentListener(parentURIListener);
2794 }
2795
2796 return NS_OK;
2797}
2798
2799void nsDocShell::MaybeRestoreWindowName() {
2800 if (!StaticPrefs::privacy_window_name_update_enabled()) {
2801 return;
2802 }
2803
2804 // We only restore window.name for the top-level content.
2805 if (!mBrowsingContext->IsTopContent()) {
2806 return;
2807 }
2808
2809 nsAutoString name;
2810
2811 // Following implements https://html.spec.whatwg.org/#history-traversal:
2812 // Step 4.4. Check if the loading entry has a name.
2813
2814 if (mLoadingEntry) {
2815 name = mLoadingEntry->mInfo.GetName();
2816 }
2817
2818 if (name.IsEmpty()) {
2819 return;
2820 }
2821
2822 // Step 4.4.1. Set the name to the browsing context.
2823 (void)mBrowsingContext->SetName(name);
2824
2825 // Step 4.4.2. Clear the name of all entries that are contiguous and
2826 // same-origin with the loading entry.
2827 if (mLoadingEntry) {
2828 // Clear the name of the session entry in the child side. For parent side,
2829 // the clearing will be done when we commit the history to the parent.
2830 mLoadingEntry->mInfo.SetName(EmptyString());
2831 }
2832}
2833
2834void nsDocShell::StoreWindowNameToSHEntries() {
2835 MOZ_ASSERT(mBrowsingContext->IsTopContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsTopContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsTopContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBrowsingContext->IsTopContent()", "./../../../docshell/base/nsDocShell.cpp"
, 2835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsTopContent()"
")"); do { MOZ_CrashSequence(__null, 2835); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2836
2837 nsAutoString name;
2838 mBrowsingContext->GetName(name);
2839
2840 if (XRE_IsParentProcess()) {
2841 SessionHistoryEntry* entry =
2842 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
2843 if (entry) {
2844 nsSHistory::WalkContiguousEntries(
2845 entry, [&](SessionHistoryEntry* aEntry) { aEntry->SetName(name); });
2846 }
2847 } else {
2848 // Ask parent process to store the name in entries.
2849 (void)ContentChild::GetSingleton()
2850 ->SendSessionHistoryEntryStoreWindowNameInContiguousEntries(
2851 mBrowsingContext, name);
2852 }
2853}
2854
2855NS_IMETHODIMPnsresult
2856nsDocShell::GetInProcessSameTypeParent(nsIDocShellTreeItem** aParent) {
2857 if (BrowsingContext* parentBC = mBrowsingContext->GetParent()) {
2858 *aParent = do_AddRef(parentBC->GetDocShell()).take();
2859 }
2860 return NS_OK;
2861}
2862
2863NS_IMETHODIMPnsresult
2864nsDocShell::GetInProcessRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) {
2865 NS_ENSURE_ARG_POINTER(aRootTreeItem)do { if ((__builtin_expect(!!(!(aRootTreeItem)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRootTreeItem" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2865); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2866
2867 RefPtr<nsDocShell> root = this;
2868 RefPtr<nsDocShell> parent = root->GetInProcessParentDocshell();
2869 while (parent) {
2870 root = parent;
2871 parent = root->GetInProcessParentDocshell();
2872 }
2873
2874 root.forget(aRootTreeItem);
2875 return NS_OK;
2876}
2877
2878NS_IMETHODIMPnsresult
2879nsDocShell::GetInProcessSameTypeRootTreeItem(
2880 nsIDocShellTreeItem** aRootTreeItem) {
2881 NS_ENSURE_ARG_POINTER(aRootTreeItem)do { if ((__builtin_expect(!!(!(aRootTreeItem)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRootTreeItem" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2881); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2882 *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
2883
2884 nsCOMPtr<nsIDocShellTreeItem> parent;
2885 NS_ENSURE_SUCCESS(GetInProcessSameTypeParent(getter_AddRefs(parent)),do { nsresult __rv = GetInProcessSameTypeParent(getter_AddRefs
(parent)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv
)), 0)))) { const char* name = mozilla::GetStaticErrorName(__rv
); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInProcessSameTypeParent(getter_AddRefs(parent))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2886); return NS_ERROR_FAILURE; } } while (false)
2886 NS_ERROR_FAILURE)do { nsresult __rv = GetInProcessSameTypeParent(getter_AddRefs
(parent)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv
)), 0)))) { const char* name = mozilla::GetStaticErrorName(__rv
); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInProcessSameTypeParent(getter_AddRefs(parent))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2886); return NS_ERROR_FAILURE; } } while (false)
;
2887 while (parent) {
2888 *aRootTreeItem = parent;
2889 NS_ENSURE_SUCCESS(do { nsresult __rv = (*aRootTreeItem)->GetInProcessSameTypeParent
(getter_AddRefs(parent)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "(*aRootTreeItem)->GetInProcessSameTypeParent(getter_AddRefs(parent))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2891); return NS_ERROR_FAILURE; } } while (false)
2890 (*aRootTreeItem)->GetInProcessSameTypeParent(getter_AddRefs(parent)),do { nsresult __rv = (*aRootTreeItem)->GetInProcessSameTypeParent
(getter_AddRefs(parent)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "(*aRootTreeItem)->GetInProcessSameTypeParent(getter_AddRefs(parent))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2891); return NS_ERROR_FAILURE; } } while (false)
2891 NS_ERROR_FAILURE)do { nsresult __rv = (*aRootTreeItem)->GetInProcessSameTypeParent
(getter_AddRefs(parent)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "(*aRootTreeItem)->GetInProcessSameTypeParent(getter_AddRefs(parent))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 2891); return NS_ERROR_FAILURE; } } while (false)
;
2892 }
2893 NS_ADDREF(*aRootTreeItem)(*aRootTreeItem)->AddRef();
2894 return NS_OK;
2895}
2896
2897NS_IMETHODIMPnsresult
2898nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) {
2899 NS_ENSURE_ARG_POINTER(aTreeOwner)do { if ((__builtin_expect(!!(!(aTreeOwner)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aTreeOwner" ") failed",
nullptr, "./../../../docshell/base/nsDocShell.cpp", 2899); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2900
2901 *aTreeOwner = mTreeOwner;
2902 NS_IF_ADDREF(*aTreeOwner)ns_if_addref(*aTreeOwner);
2903 return NS_OK;
2904}
2905
2906NS_IMETHODIMPnsresult
2907nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) {
2908 if (mIsBeingDestroyed && aTreeOwner) {
2909 return NS_ERROR_FAILURE;
2910 }
2911
2912 // Don't automatically set the progress based on the tree owner for frames
2913 if (!IsSubframe()) {
2914 nsCOMPtr<nsIWebProgress> webProgress =
2915 do_QueryInterface(GetAsSupports(this));
2916
2917 if (webProgress) {
2918 nsCOMPtr<nsIWebProgressListener> oldListener =
2919 do_QueryInterface(mTreeOwner);
2920 nsCOMPtr<nsIWebProgressListener> newListener =
2921 do_QueryInterface(aTreeOwner);
2922
2923 if (oldListener) {
2924 webProgress->RemoveProgressListener(oldListener);
2925 }
2926
2927 if (newListener) {
2928 webProgress->AddProgressListener(newListener,
2929 nsIWebProgress::NOTIFY_ALL);
2930 }
2931 }
2932 }
2933
2934 mTreeOwner = aTreeOwner; // Weak reference per API
2935
2936 for (auto* childDocLoader : mChildList.ForwardRange()) {
2937 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(childDocLoader);
2938 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(child)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "child" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2938); return NS_ERROR_FAILURE
; } } while (false)
;
2939
2940 if (child->ItemType() == mItemType) {
2941 child->SetTreeOwner(aTreeOwner);
2942 }
2943 }
2944
2945 // If we're in the content process and have had a TreeOwner set on us, extract
2946 // our BrowserChild actor. If we've already had our BrowserChild set, assert
2947 // that it hasn't changed.
2948 if (mTreeOwner && XRE_IsContentProcess()) {
2949 nsCOMPtr<nsIBrowserChild> newBrowserChild = do_GetInterface(mTreeOwner);
2950 MOZ_ASSERT(newBrowserChild,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newBrowserChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newBrowserChild))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("newBrowserChild"
" (" "No BrowserChild actor for tree owner in Content!" ")",
"./../../../docshell/base/nsDocShell.cpp", 2951); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "newBrowserChild" ") (" "No BrowserChild actor for tree owner in Content!"
")"); do { MOZ_CrashSequence(__null, 2951); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2951 "No BrowserChild actor for tree owner in Content!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newBrowserChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newBrowserChild))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("newBrowserChild"
" (" "No BrowserChild actor for tree owner in Content!" ")",
"./../../../docshell/base/nsDocShell.cpp", 2951); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "newBrowserChild" ") (" "No BrowserChild actor for tree owner in Content!"
")"); do { MOZ_CrashSequence(__null, 2951); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2952
2953 if (mBrowserChild) {
2954 nsCOMPtr<nsIBrowserChild> oldBrowserChild =
2955 do_QueryReferent(mBrowserChild);
2956 MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(oldBrowserChild == newBrowserChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(oldBrowserChild == newBrowserChild
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"oldBrowserChild == newBrowserChild" " (" "Cannot change BrowserChild during nsDocShell lifetime!"
")", "./../../../docshell/base/nsDocShell.cpp", 2958); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "oldBrowserChild == newBrowserChild"
") (" "Cannot change BrowserChild during nsDocShell lifetime!"
")"); do { MOZ_CrashSequence(__null, 2958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2957 oldBrowserChild == newBrowserChild,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(oldBrowserChild == newBrowserChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(oldBrowserChild == newBrowserChild
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"oldBrowserChild == newBrowserChild" " (" "Cannot change BrowserChild during nsDocShell lifetime!"
")", "./../../../docshell/base/nsDocShell.cpp", 2958); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "oldBrowserChild == newBrowserChild"
") (" "Cannot change BrowserChild during nsDocShell lifetime!"
")"); do { MOZ_CrashSequence(__null, 2958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2958 "Cannot change BrowserChild during nsDocShell lifetime!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(oldBrowserChild == newBrowserChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(oldBrowserChild == newBrowserChild
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"oldBrowserChild == newBrowserChild" " (" "Cannot change BrowserChild during nsDocShell lifetime!"
")", "./../../../docshell/base/nsDocShell.cpp", 2958); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "oldBrowserChild == newBrowserChild"
") (" "Cannot change BrowserChild during nsDocShell lifetime!"
")"); do { MOZ_CrashSequence(__null, 2958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2959 } else {
2960 mBrowserChild = do_GetWeakReference(newBrowserChild);
2961 }
2962 }
2963
2964 return NS_OK;
2965}
2966
2967NS_IMETHODIMPnsresult
2968nsDocShell::GetHistoryID(nsID& aID) {
2969 aID = mBrowsingContext->GetHistoryID();
2970 return NS_OK;
2971}
2972
2973const nsID& nsDocShell::HistoryID() { return mBrowsingContext->GetHistoryID(); }
2974
2975NS_IMETHODIMPnsresult
2976nsDocShell::GetIsInUnload(bool* aIsInUnload) {
2977 *aIsInUnload = mFiredUnloadEvent;
2978 return NS_OK;
2979}
2980
2981NS_IMETHODIMPnsresult
2982nsDocShell::GetInProcessChildCount(int32_t* aChildCount) {
2983 NS_ENSURE_ARG_POINTER(aChildCount)do { if ((__builtin_expect(!!(!(aChildCount)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChildCount" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2983); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
2984 *aChildCount = mChildList.Length();
2985 return NS_OK;
2986}
2987
2988NS_IMETHODIMPnsresult
2989nsDocShell::AddChild(nsIDocShellTreeItem* aChild) {
2990 NS_ENSURE_ARG_POINTER(aChild)do { if ((__builtin_expect(!!(!(aChild)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChild" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 2990); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
2991
2992 RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
2993 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(childAsDocLoader)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "childAsDocLoader" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 2993); return
NS_ERROR_UNEXPECTED; } } while (false)
;
2994
2995 // Make sure we're not creating a loop in the docshell tree
2996 nsDocLoader* ancestor = this;
2997 do {
2998 if (childAsDocLoader == ancestor) {
2999 return NS_ERROR_ILLEGAL_VALUE;
3000 }
3001 ancestor = ancestor->GetParent();
3002 } while (ancestor);
3003
3004 // Make sure to remove the child from its current parent.
3005 nsDocLoader* childsParent = childAsDocLoader->GetParent();
3006 if (childsParent) {
3007 nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader);
3008 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3008); return rv; } } while (false)
;
3009 }
3010
3011 // Make sure to clear the treeowner in case this child is a different type
3012 // from us.
3013 aChild->SetTreeOwner(nullptr);
3014
3015 nsresult res = AddChildLoader(childAsDocLoader);
3016 NS_ENSURE_SUCCESS(res, res)do { nsresult __rv = res; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "res", "res", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3016); return res; } } while (false)
;
3017 NS_ASSERTION(!mChildList.IsEmpty(),do { if (!(!mChildList.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "child list must not be empty after a successful add", "!mChildList.IsEmpty()"
, "./../../../docshell/base/nsDocShell.cpp", 3018); MOZ_PretendNoReturn
(); } } while (0)
3018 "child list must not be empty after a successful add")do { if (!(!mChildList.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "child list must not be empty after a successful add", "!mChildList.IsEmpty()"
, "./../../../docshell/base/nsDocShell.cpp", 3018); MOZ_PretendNoReturn
(); } } while (0)
;
3019
3020 /* Set the child's global history if the parent has one */
3021 if (mBrowsingContext->GetUseGlobalHistory()) {
3022 // childDocShell->SetUseGlobalHistory(true);
3023 // this should be set through BC inherit
3024 MOZ_ASSERT(aChild->GetBrowsingContext()->GetUseGlobalHistory())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetBrowsingContext()->GetUseGlobalHistory
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->GetBrowsingContext()->GetUseGlobalHistory
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->GetBrowsingContext()->GetUseGlobalHistory()",
"./../../../docshell/base/nsDocShell.cpp", 3024); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChild->GetBrowsingContext()->GetUseGlobalHistory()"
")"); do { MOZ_CrashSequence(__null, 3024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3025 }
3026
3027 if (aChild->ItemType() != mItemType) {
3028 return NS_OK;
3029 }
3030
3031 aChild->SetTreeOwner(mTreeOwner);
3032
3033 nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
3034 if (!childAsDocShell) {
3035 return NS_OK;
3036 }
3037
3038 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3039
3040 // Now take this document's charset and set the child's parentCharset field
3041 // to it. We'll later use that field, in the loading process, for the
3042 // charset choosing algorithm.
3043 // If we fail, at any point, we just return NS_OK.
3044 // This code has some performance impact. But this will be reduced when
3045 // the current charset will finally be stored as an Atom, avoiding the
3046 // alias resolution extra look-up.
3047
3048 // we are NOT going to propagate the charset is this Chrome's docshell
3049 if (mItemType == nsIDocShellTreeItem::typeChrome) {
3050 return NS_OK;
3051 }
3052
3053 // get the parent's current charset
3054 if (!mDocumentViewer) {
3055 return NS_OK;
3056 }
3057 Document* doc = mDocumentViewer->GetDocument();
3058 if (!doc) {
3059 return NS_OK;
3060 }
3061
3062 const Encoding* parentCS = doc->GetDocumentCharacterSet();
3063 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
3064 // set the child's parentCharset
3065 childAsDocShell->SetParentCharset(parentCS, charsetSource,
3066 doc->NodePrincipal());
3067
3068 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
3069 // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3070
3071 return NS_OK;
3072}
3073
3074NS_IMETHODIMPnsresult
3075nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild) {
3076 NS_ENSURE_ARG_POINTER(aChild)do { if ((__builtin_expect(!!(!(aChild)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChild" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3076); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3077
3078 RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3079 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(childAsDocLoader)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "childAsDocLoader" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 3079); return
NS_ERROR_UNEXPECTED; } } while (false)
;
3080
3081 nsresult rv = RemoveChildLoader(childAsDocLoader);
3082 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3082); return rv; } } while (false)
;
3083
3084 aChild->SetTreeOwner(nullptr);
3085
3086 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
3087}
3088
3089NS_IMETHODIMPnsresult
3090nsDocShell::GetInProcessChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild) {
3091 NS_ENSURE_ARG_POINTER(aChild)do { if ((__builtin_expect(!!(!(aChild)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChild" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3091); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3092
3093 RefPtr<nsDocShell> child = GetInProcessChildAt(aIndex);
3094 NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(child)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "child" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3094); return NS_ERROR_UNEXPECTED
; } } while (false)
;
3095
3096 child.forget(aChild);
3097
3098 return NS_OK;
3099}
3100
3101nsDocShell* nsDocShell::GetInProcessChildAt(int32_t aIndex) {
3102#ifdef DEBUG1
3103 if (aIndex < 0) {
3104 NS_WARNING("Negative index passed to GetChildAt")NS_DebugBreak(NS_DEBUG_WARNING, "Negative index passed to GetChildAt"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 3104)
;
3105 } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
3106 NS_WARNING("Too large an index passed to GetChildAt")NS_DebugBreak(NS_DEBUG_WARNING, "Too large an index passed to GetChildAt"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 3106)
;
3107 }
3108#endif
3109
3110 nsIDocumentLoader* child = ChildAt(aIndex);
3111
3112 // child may be nullptr here.
3113 return static_cast<nsDocShell*>(child);
3114}
3115
3116NS_IMETHODIMPnsresult nsDocShell::SynchronizeLayoutHistoryState() {
3117 if (mActiveEntry && mActiveEntry->GetLayoutHistoryState() &&
3118 mBrowsingContext) {
3119 if (XRE_IsContentProcess()) {
3120 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
3121 if (contentChild) {
3122 contentChild->SendSynchronizeLayoutHistoryState(
3123 mBrowsingContext, mActiveEntry->GetLayoutHistoryState());
3124 }
3125 } else {
3126 SessionHistoryEntry* entry =
3127 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
3128 if (entry) {
3129 entry->SetLayoutHistoryState(mActiveEntry->GetLayoutHistoryState());
3130 }
3131 }
3132 if (mLoadingEntry &&
3133 mLoadingEntry->mInfo.SharedId() == mActiveEntry->SharedId()) {
3134 mLoadingEntry->mInfo.SetLayoutHistoryState(
3135 mActiveEntry->GetLayoutHistoryState());
3136 }
3137 }
3138
3139 return NS_OK;
3140}
3141
3142void nsDocShell::SetLoadGroupDefaultLoadFlags(nsLoadFlags aLoadFlags) {
3143 if (mLoadGroup) {
3144 mLoadGroup->SetDefaultLoadFlags(aLoadFlags);
3145 } else {
3146 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "nsDocShell::SetLoadGroupDefaultLoadFlags has no loadGroup to "
"propagate the mode to", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3148)
3147 "nsDocShell::SetLoadGroupDefaultLoadFlags has no loadGroup to "NS_DebugBreak(NS_DEBUG_WARNING, "nsDocShell::SetLoadGroupDefaultLoadFlags has no loadGroup to "
"propagate the mode to", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3148)
3148 "propagate the mode to")NS_DebugBreak(NS_DEBUG_WARNING, "nsDocShell::SetLoadGroupDefaultLoadFlags has no loadGroup to "
"propagate the mode to", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3148)
;
3149 }
3150}
3151
3152nsIScriptGlobalObject* nsDocShell::GetScriptGlobalObject() {
3153 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr)do { nsresult __rv = EnsureScriptEnvironment(); if (((bool)(__builtin_expect
(!!(NS_FAILED_impl(__rv)), 0)))) { const char* name = mozilla
::GetStaticErrorName(__rv); mozilla::SmprintfPointer msg = mozilla
::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%"
"X" "%s%s%s", "EnsureScriptEnvironment()", "nullptr", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3153); return nullptr
; } } while (false)
;
3154 return mScriptGlobal;
3155}
3156
3157Document* nsDocShell::GetDocument() {
3158 NS_ENSURE_TRUE(VerifyDocumentViewer(), nullptr)do { if ((__builtin_expect(!!(!(VerifyDocumentViewer())), 0))
) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "VerifyDocumentViewer()"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3158); return nullptr; } } while (false)
;
3159 return mDocumentViewer->GetDocument();
3160}
3161
3162Document* nsDocShell::GetExtantDocument() {
3163 return mDocumentViewer ? mDocumentViewer->GetDocument() : nullptr;
3164}
3165
3166nsPIDOMWindowOuter* nsDocShell::GetWindow() {
3167 if (NS_FAILED(EnsureScriptEnvironment())((bool)(__builtin_expect(!!(NS_FAILED_impl(EnsureScriptEnvironment
())), 0)))
) {
3168 return nullptr;
3169 }
3170 return mScriptGlobal;
3171}
3172
3173NS_IMETHODIMPnsresult
3174nsDocShell::GetDomWindow(mozIDOMWindowProxy** aWindow) {
3175 NS_ENSURE_ARG_POINTER(aWindow)do { if ((__builtin_expect(!!(!(aWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWindow" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3175); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3176
3177 nsresult rv = EnsureScriptEnvironment();
3178 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3178); return rv; } } while (false)
;
3179
3180 RefPtr<nsGlobalWindowOuter> window = mScriptGlobal;
3181 window.forget(aWindow);
3182 return NS_OK;
3183}
3184
3185NS_IMETHODIMPnsresult
3186nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) {
3187 RefPtr<ContentFrameMessageManager> mm;
3188 if (RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(this)) {
3189 mm = browserChild->GetMessageManager();
3190 } else if (nsPIDOMWindowOuter* win = GetWindow()) {
3191 mm = win->GetMessageManager();
3192 }
3193 mm.forget(aMessageManager);
3194 return NS_OK;
3195}
3196
3197NS_IMETHODIMPnsresult
3198nsDocShell::GetIsNavigating(bool* aOut) {
3199 *aOut = mIsNavigating;
3200 return NS_OK;
3201}
3202
3203//-------------------------------------
3204//-- Helper Method for Print discovery
3205//-------------------------------------
3206bool nsDocShell::NavigationBlockedByPrinting(bool aDisplayErrorDialog) {
3207 if (!mBrowsingContext->Top()->GetIsPrinting()) {
3208 return false;
3209 }
3210 if (aDisplayErrorDialog) {
3211 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
3212 }
3213 return true;
3214}
3215
3216bool nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
3217 bool aCheckIfUnloadFired) {
3218 bool isAllowed = !NavigationBlockedByPrinting(aDisplayPrintErrorDialog) &&
3219 (!aCheckIfUnloadFired || !mFiredUnloadEvent);
3220 if (!isAllowed) {
3221 return false;
3222 }
3223 if (!mDocumentViewer) {
3224 return true;
3225 }
3226 bool firingBeforeUnload;
3227 mDocumentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
3228 return !firingBeforeUnload;
3229}
3230
3231//*****************************************************************************
3232// nsDocShell::nsIWebNavigation
3233//*****************************************************************************
3234
3235NS_IMETHODIMPnsresult
3236nsDocShell::GetCanGoBack(bool* aCanGoBack) {
3237 *aCanGoBack = false;
3238 if (!IsNavigationAllowed(false)) {
3239 return NS_OK; // JS may not handle returning of an error code
3240 }
3241 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3242 if (rootSH) {
3243 *aCanGoBack = rootSH->CanGo(
3244 -1, StaticPrefs::browser_navigation_requireUserInteraction());
3245 MOZ_LOG(gSHLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoBack()->%d", this
, *aCanGoBack); } } while (0)
3246 ("nsDocShell %p CanGoBack()->%d", this, *aCanGoBack))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoBack()->%d", this
, *aCanGoBack); } } while (0)
;
3247
3248 return NS_OK;
3249 }
3250 return NS_ERROR_FAILURE;
3251}
3252
3253NS_IMETHODIMPnsresult
3254nsDocShell::GetCanGoBackIgnoringUserInteraction(bool* aCanGoBack) {
3255 *aCanGoBack = false;
3256 if (!IsNavigationAllowed(false)) {
3257 return NS_OK; // JS may not handle returning of an error code
3258 }
3259 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3260 if (rootSH) {
3261 *aCanGoBack = rootSH->CanGo(-1, false);
3262 MOZ_LOG(gSHLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoBackIgnoringUserInteraction()->%d"
, this, *aCanGoBack); } } while (0)
3263 ("nsDocShell %p CanGoBackIgnoringUserInteraction()->%d", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoBackIgnoringUserInteraction()->%d"
, this, *aCanGoBack); } } while (0)
3264 *aCanGoBack))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoBackIgnoringUserInteraction()->%d"
, this, *aCanGoBack); } } while (0)
;
3265
3266 return NS_OK;
3267 }
3268 return NS_ERROR_FAILURE;
3269}
3270
3271NS_IMETHODIMPnsresult
3272nsDocShell::GetCanGoForward(bool* aCanGoForward) {
3273 *aCanGoForward = false;
3274 if (!IsNavigationAllowed(false)) {
3275 return NS_OK; // JS may not handle returning of an error code
3276 }
3277 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3278 if (rootSH) {
3279 *aCanGoForward = rootSH->CanGo(
3280 1, StaticPrefs::browser_navigation_requireUserInteraction());
3281 MOZ_LOG(gSHLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoForward()->%d", this
, *aCanGoForward); } } while (0)
3282 ("nsDocShell %p CanGoForward()->%d", this, *aCanGoForward))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "nsDocShell %p CanGoForward()->%d", this
, *aCanGoForward); } } while (0)
;
3283 return NS_OK;
3284 }
3285 return NS_ERROR_FAILURE;
3286}
3287
3288NS_IMETHODIMPnsresult
3289nsDocShell::GoBack(bool aRequireUserInteraction, bool aUserActivation) {
3290 if (!IsNavigationAllowed()) {
3291 return NS_OK; // JS may not handle returning of an error code
3292 }
3293
3294 auto cleanupIsNavigating = MakeScopeExit([&]() { mIsNavigating = false; });
3295 mIsNavigating = true;
3296
3297 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3298 NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(rootSH)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "rootSH" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3298); return NS_ERROR_FAILURE
; } } while (false)
;
3299 ErrorResult rv;
3300 rootSH->Go(-1, aRequireUserInteraction, aUserActivation, rv);
3301 return rv.StealNSResult();
3302}
3303
3304NS_IMETHODIMPnsresult
3305nsDocShell::GoForward(bool aRequireUserInteraction, bool aUserActivation) {
3306 if (!IsNavigationAllowed()) {
3307 return NS_OK; // JS may not handle returning of an error code
3308 }
3309
3310 auto cleanupIsNavigating = MakeScopeExit([&]() { mIsNavigating = false; });
3311 mIsNavigating = true;
3312
3313 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3314 NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(rootSH)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "rootSH" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3314); return NS_ERROR_FAILURE
; } } while (false)
;
3315 ErrorResult rv;
3316 rootSH->Go(1, aRequireUserInteraction, aUserActivation, rv);
3317 return rv.StealNSResult();
3318}
3319
3320// XXX(nika): We may want to stop exposing this API in the child process? Going
3321// to a specific index from multiple different processes could definitely race.
3322NS_IMETHODIMPnsresult
3323nsDocShell::GotoIndex(int32_t aIndex, bool aUserActivation) {
3324 if (!IsNavigationAllowed()) {
3325 return NS_OK; // JS may not handle returning of an error code
3326 }
3327
3328 auto cleanupIsNavigating = MakeScopeExit([&]() { mIsNavigating = false; });
3329 mIsNavigating = true;
3330
3331 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3332 NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(rootSH)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "rootSH" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3332); return NS_ERROR_FAILURE
; } } while (false)
;
3333
3334 rootSH->GotoIndex(aIndex, aIndex - rootSH->Index(), false, aUserActivation);
3335 return NS_OK;
3336}
3337
3338nsresult nsDocShell::LoadURI(nsIURI* aURI,
3339 const LoadURIOptions& aLoadURIOptions) {
3340 if (!IsNavigationAllowed()) {
3341 return NS_OK; // JS may not handle returning of an error code
3342 }
3343 RefPtr<nsDocShellLoadState> loadState;
3344 nsresult rv = nsDocShellLoadState::CreateFromLoadURIOptions(
3345 aURI, aLoadURIOptions, getter_AddRefs(loadState));
3346 MOZ_ASSERT(rv != NS_ERROR_MALFORMED_URI)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rv != NS_ERROR_MALFORMED_URI)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rv != NS_ERROR_MALFORMED_URI
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rv != NS_ERROR_MALFORMED_URI", "./../../../docshell/base/nsDocShell.cpp"
, 3346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_ERROR_MALFORMED_URI"
")"); do { MOZ_CrashSequence(__null, 3346); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3347 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !loadState) {
3348 return NS_ERROR_FAILURE;
3349 }
3350
3351 // Set the captive portal tab flag on the browsing context if requested
3352 if (loadState->GetIsCaptivePortalTab()) {
3353 (void)mBrowsingContext->SetIsCaptivePortalTab(true);
3354 }
3355
3356 return LoadURI(loadState, true);
3357}
3358
3359NS_IMETHODIMPnsresult
3360nsDocShell::LoadURIFromScript(nsIURI* aURI,
3361 JS::Handle<JS::Value> aLoadURIOptions,
3362 JSContext* aCx) {
3363 // generate dictionary for aLoadURIOptions and forward call
3364 LoadURIOptions loadURIOptions;
3365 if (!loadURIOptions.Init(aCx, aLoadURIOptions)) {
3366 return NS_ERROR_INVALID_ARG;
3367 }
3368 return LoadURI(aURI, loadURIOptions);
3369}
3370
3371nsresult nsDocShell::FixupAndLoadURIString(
3372 const nsAString& aURIString, const LoadURIOptions& aLoadURIOptions) {
3373 if (!IsNavigationAllowed()) {
3374 return NS_OK; // JS may not handle returning of an error code
3375 }
3376
3377 RefPtr<nsDocShellLoadState> loadState;
3378 nsresult rv = nsDocShellLoadState::CreateFromLoadURIOptions(
3379 mBrowsingContext, aURIString, aLoadURIOptions, getter_AddRefs(loadState));
3380
3381 uint32_t loadFlags = aLoadURIOptions.mLoadFlags;
3382 if (NS_ERROR_MALFORMED_URI == rv) {
3383 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s (because "
"we're showing an error page)", this, NS_ConvertUTF16toUTF8(
aURIString).get()); } } while (0)
3384 ("Creating an active entry on nsDocShell %p to %s (because "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s (because "
"we're showing an error page)", this, NS_ConvertUTF16toUTF8(
aURIString).get()); } } while (0)
3385 "we're showing an error page)",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s (because "
"we're showing an error page)", this, NS_ConvertUTF16toUTF8(
aURIString).get()); } } while (0)
3386 this, NS_ConvertUTF16toUTF8(aURIString).get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s (because "
"we're showing an error page)", this, NS_ConvertUTF16toUTF8(
aURIString).get()); } } while (0)
;
3387
3388 // We need to store a session history entry. We don't have a valid URI, so
3389 // we use about:blank instead.
3390 nsCOMPtr<nsIURI> uri;
3391 MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns))), 1)))), 1
))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), \"about:blank\"_ns))"
, "./../../../docshell/base/nsDocShell.cpp", 3391); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), \"about:blank\"_ns))"
")"); do { MOZ_CrashSequence(__null, 3391); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
3392 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
3393 if (aLoadURIOptions.mTriggeringPrincipal) {
3394 triggeringPrincipal = aLoadURIOptions.mTriggeringPrincipal;
3395 } else {
3396 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
3397 }
3398 UniquePtr<SessionHistoryInfo> previousActiveEntry(mActiveEntry.release());
3399 mActiveEntry = std::make_unique<SessionHistoryInfo>(
3400 uri, triggeringPrincipal, nullptr, nullptr, nullptr,
3401 nsLiteralCString("text/html"));
3402 mBrowsingContext->SetActiveSessionHistoryEntry(
3403 Nothing(), mActiveEntry.get(), previousActiveEntry.get(),
3404 MAKE_LOAD_TYPE(LOAD_NORMAL, loadFlags)((LOAD_NORMAL) | ((loadFlags) << 16)),
3405 /* aUpdatedCacheKey = */ 0);
3406 if (DisplayLoadError(rv, nullptr, PromiseFlatStringTPromiseFlatString<char16_t>(aURIString).get(),
3407 nullptr) &&
3408 (loadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
3409 return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
3410 }
3411 }
3412
3413 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !loadState) {
3414 return NS_ERROR_FAILURE;
3415 }
3416
3417 // Set the captive portal tab flag on the browsing context if requested
3418 if (loadState->GetIsCaptivePortalTab()) {
3419 (void)mBrowsingContext->SetIsCaptivePortalTab(true);
3420 }
3421
3422 return LoadURI(loadState, true);
3423}
3424
3425NS_IMETHODIMPnsresult
3426nsDocShell::FixupAndLoadURIStringFromScript(
3427 const nsAString& aURIString, JS::Handle<JS::Value> aLoadURIOptions,
3428 JSContext* aCx) {
3429 // generate dictionary for aLoadURIOptions and forward call
3430 LoadURIOptions loadURIOptions;
3431 if (!loadURIOptions.Init(aCx, aLoadURIOptions)) {
3432 return NS_ERROR_INVALID_ARG;
3433 }
3434 return FixupAndLoadURIString(aURIString, loadURIOptions);
3435}
3436
3437void nsDocShell::UnblockEmbedderLoadEventForFailure(bool aFireFrameErrorEvent) {
3438 // If we're not in a content frame, or are at a BrowsingContext tree boundary,
3439 // such as the content-chrome boundary, don't fire the error event.
3440 if (mBrowsingContext->IsTopContent() || mBrowsingContext->IsChrome()) {
3441 return;
3442 }
3443
3444 // If embedder is same-process, then unblocking the load event is already
3445 // handled by nsDocLoader. Fire the error event on our embedder element if
3446 // requested.
3447 //
3448 // XXX: Bug 1440212 is looking into potentially changing this behaviour to act
3449 // more like the remote case when in-process.
3450 RefPtr<Element> element = mBrowsingContext->GetEmbedderElement();
3451 if (element) {
3452 if (aFireFrameErrorEvent) {
3453 if (RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(element)) {
3454 if (RefPtr<nsFrameLoader> fl = flo->GetFrameLoader()) {
3455 fl->FireErrorEvent();
3456 }
3457 }
3458 }
3459 return;
3460 }
3461
3462 // If we have a cross-process parent document, we must notify it that we no
3463 // longer block its load event. This is necessary for OOP sub-documents
3464 // because error documents do not result in a call to
3465 // SendMaybeFireEmbedderLoadEvents via any of the normal call paths.
3466 // (Obviously, we must do this before any of the returns below.)
3467 RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(this);
3468 if (browserChild &&
3469 !mBrowsingContext->GetParentWindowContext()->IsInProcess()) {
3470 (void)browserChild->SendMaybeFireEmbedderLoadEvents(
3471 aFireFrameErrorEvent ? EmbedderElementEventType::ErrorEvent
3472 : EmbedderElementEventType::NoEvent);
3473 }
3474}
3475
3476// If aChannel failed while it was following a redirect, returns the URI of the
3477// redirect target when that target uses a different scheme, otherwise nullptr.
3478// The channel itself keeps reporting the URI it was redirected away from, which
3479// isn't the URI that we were unable to load.
3480static already_AddRefed<nsIURI> GetUnhandledRedirectURI(nsIChannel* aChannel) {
3481 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
3482 if (!httpChannel) {
3483 return nullptr;
3484 }
3485
3486 nsAutoCString location;
3487 if (NS_FAILED(httpChannel->GetResponseHeader("Location"_ns, location))((bool)(__builtin_expect(!!(NS_FAILED_impl(httpChannel->GetResponseHeader
("Location"_ns, location))), 0)))
) {
3488 return nullptr;
3489 }
3490
3491 nsCOMPtr<nsIURI> channelURI;
3492 if (NS_FAILED(httpChannel->GetURI(getter_AddRefs(channelURI)))((bool)(__builtin_expect(!!(NS_FAILED_impl(httpChannel->GetURI
(getter_AddRefs(channelURI)))), 0)))
) {
3493 return nullptr;
3494 }
3495
3496 nsCOMPtr<nsIURI> redirectURI;
3497 if (NS_FAILED(NS_NewURI(getter_AddRefs(redirectURI), location, nullptr,((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(redirectURI), location, nullptr, channelURI))), 0)))
3498 channelURI))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(redirectURI), location, nullptr, channelURI))), 0)))
) {
3499 return nullptr;
3500 }
3501
3502 nsAutoCString channelScheme;
3503 nsAutoCString redirectScheme;
3504 channelURI->GetScheme(channelScheme);
3505 redirectURI->GetScheme(redirectScheme);
3506 if (channelScheme.Equals(redirectScheme)) {
3507 return nullptr;
3508 }
3509
3510 return redirectURI.forget();
3511}
3512
3513NS_IMETHODIMPnsresult
3514nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
3515 const char16_t* aURL, nsIChannel* aFailedChannel,
3516 bool* aDisplayedErrorPage) {
3517 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p DisplayLoadError %s\n", this,
aURI ? aURI->GetSpecOrDefault().get() : ""); } } while (0
)
3518 ("DOCSHELL %p DisplayLoadError %s\n", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p DisplayLoadError %s\n", this,
aURI ? aURI->GetSpecOrDefault().get() : ""); } } while (0
)
3519 aURI ? aURI->GetSpecOrDefault().get() : ""))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p DisplayLoadError %s\n", this,
aURI ? aURI->GetSpecOrDefault().get() : ""); } } while (0
)
;
3520
3521 *aDisplayedErrorPage = false;
3522 // Get prompt and string bundle services
3523 nsCOMPtr<nsIPrompt> prompter;
3524 nsCOMPtr<nsIStringBundle> stringBundle;
3525 GetPromptAndStringBundle(getter_AddRefs(prompter),
3526 getter_AddRefs(stringBundle));
3527
3528 NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(stringBundle)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "stringBundle" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 3528); return
NS_ERROR_FAILURE; } } while (false)
;
3529 NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(prompter)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "prompter" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3529); return NS_ERROR_FAILURE
; } } while (false)
;
3530
3531 const char* error = nullptr;
3532 // The key used to select the appropriate error message from the properties
3533 // file.
3534 const char* errorDescriptionID = nullptr;
3535 AutoTArray<nsString, 3> formatStrs;
3536 bool addHostPort = false;
3537 bool isBadStsCertError = false;
3538 nsresult rv = NS_OK;
3539 nsAutoString messageStr;
3540 nsAutoCString cssClass;
3541 nsAutoCString errorPage;
3542
3543 errorPage.AssignLiteral("neterror");
3544
3545 // Turn the error code into a human readable error message.
3546 if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
3547 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3547); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3548
3549 // A load that failed while following a redirect reports the URI it was
3550 // redirected away from, so name the protocol we could not handle rather
3551 // than the one of the server which sent us there.
3552 nsCOMPtr<nsIURI> unknownProtocolURI =
3553 GetUnhandledRedirectURI(aFailedChannel);
3554 if (!unknownProtocolURI) {
3555 unknownProtocolURI = aURI;
3556 }
3557
3558 // Extract the schemes into a comma delimited list.
3559 nsAutoCString scheme;
3560 unknownProtocolURI->GetScheme(scheme);
3561 CopyASCIItoUTF16(scheme, *formatStrs.AppendElement());
3562 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(unknownProtocolURI);
3563 while (nestedURI) {
3564 nsCOMPtr<nsIURI> tempURI;
3565 nsresult rv2;
3566 rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
3567 if (NS_SUCCEEDED(rv2)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv2)), 1))) && tempURI) {
3568 tempURI->GetScheme(scheme);
3569 formatStrs[0].AppendLiteral(", ");
3570 AppendASCIItoUTF16(scheme, formatStrs[0]);
3571 }
3572 nestedURI = do_QueryInterface(tempURI);
3573 }
3574 error = "unknownProtocolFound";
3575 } else if (NS_ERROR_NET_EMPTY_RESPONSE == aError) {
3576 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3576); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3577 error = "httpErrorPage";
3578 } else if (NS_ERROR_NET_ERROR_RESPONSE == aError) {
3579 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3579); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3580 error = "serverError";
3581 } else if (NS_ERROR_FILE_NOT_FOUND == aError) {
3582 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3582); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3583 error = "fileNotFound";
3584 } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) {
3585 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3585); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3586 error = "fileAccessDenied";
3587 } else if (NS_ERROR_UNKNOWN_HOST == aError) {
3588 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3588); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3589 // Get the host
3590 nsAutoCString host;
3591 nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
3592 innermostURI->GetHost(host);
3593 CopyUTF8toUTF16(host, *formatStrs.AppendElement());
3594 errorDescriptionID = "dnsNotFound2";
3595 error = "dnsNotFound";
3596 } else if (NS_ERROR_CONNECTION_REFUSED == aError ||
3597 NS_ERROR_PROXY_BAD_GATEWAY == aError) {
3598 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3598); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3599 addHostPort = true;
3600 error = "connectionFailure";
3601 } else if (NS_ERROR_NET_INTERRUPT == aError) {
3602 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3602); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3603 addHostPort = true;
3604 error = "netInterrupt";
3605 } else if (NS_ERROR_NET_TIMEOUT == aError ||
3606 NS_ERROR_PROXY_GATEWAY_TIMEOUT == aError ||
3607 NS_ERROR_NET_TIMEOUT_EXTERNAL == aError) {
3608 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 3608); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
3609 // Get the host
3610 nsAutoCString host;
3611 aURI->GetHost(host);
3612 CopyUTF8toUTF16(host, *formatStrs.AppendElement());
3613 error = "netTimeout";
3614 } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError ||
3615 NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) {
3616 // CSP error
3617 cssClass.AssignLiteral("neterror");
3618 error = "cspBlocked";
3619 } else if (NS_ERROR_CONNECTION_ALLOWLIST_VIOLATION == aError) {
3620 cssClass.AssignLiteral("neterror");
3621 error = "blockedByConnectionAllowlist";
3622 // TODO(Bug 2089542): Update strings
3623 errorDescriptionID = "blockedByCORP";
3624 } else if (NS_ERROR_XFO_VIOLATION == aError) {
3625 // XFO error
3626 cssClass.AssignLiteral("neterror");
3627 error = "xfoBlocked";
3628 } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY21) {
3629 nsCOMPtr<nsINSSErrorsService> nsserr =
3630 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID"@mozilla.org/nss_errors_service;1");
3631
3632 uint32_t errorClass;
3633 if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsserr->GetErrorClass
(aError, &errorClass))), 0)))
) {
3634 errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
3635 }
3636
3637 nsCOMPtr<nsITransportSecurityInfo> tsi;
3638 if (aFailedChannel) {
3639 aFailedChannel->GetSecurityInfo(getter_AddRefs(tsi));
3640 }
3641 if (tsi) {
3642 uint32_t securityState;
3643 tsi->GetSecurityState(&securityState);
3644 if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
3645 error = "sslv3Used";
Value stored to 'error' is never read
3646 addHostPort = true;
3647 } else if (securityState &
3648 nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
3649 error = "weakCryptoUsed";
3650 addHostPort = true;
3651 }
3652 } else {
3653 // No channel, let's obtain the generic error message
3654 if (nsserr) {
3655 nsserr->GetErrorMessage(aError, messageStr);
3656 }
3657 }
3658 // We don't have a message string here anymore but DisplayLoadError
3659 // requires a non-empty messageStr.
3660 messageStr.Truncate();
3661 messageStr.AssignLiteral(u" ");
3662 if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
3663 error = "nssBadCert";
3664
3665 // If this is an HTTP Strict Transport Security host or a pinned host
3666 // and the certificate is bad, don't allow overrides (RFC 6797 section
3667 // 12.1).
3668 bool isStsHost = false;
3669 bool isPinnedHost = false;
3670 OriginAttributes attrsForHSTS;
3671 if (aFailedChannel) {
3672 StoragePrincipalHelper::GetOriginAttributesForHSTS(aFailedChannel,
3673 attrsForHSTS);
3674 } else {
3675 attrsForHSTS = GetOriginAttributes();
3676 }
3677
3678 if (XRE_IsParentProcess()) {
3679 nsCOMPtr<nsISiteSecurityService> sss =
3680 do_GetService(NS_SSSERVICE_CONTRACTID"@mozilla.org/ssservice;1", &rv);
3681 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3681); return rv; } } while (false)
;
3682 rv = sss->IsSecureURI(aURI, attrsForHSTS, &isStsHost);
3683 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3683); return rv; } } while (false)
;
3684 } else {
3685 mozilla::dom::ContentChild* cc =
3686 mozilla::dom::ContentChild::GetSingleton();
3687 cc->SendIsSecureURI(aURI, attrsForHSTS, &isStsHost);
3688 }
3689 nsCOMPtr<nsIPublicKeyPinningService> pkps =
3690 do_GetService(NS_PKPSERVICE_CONTRACTID"@mozilla.org/security/publickeypinningservice;1", &rv);
3691 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3691); return rv; } } while (false)
;
3692 rv = pkps->HostHasPins(aURI, &isPinnedHost);
3693
3694 if (Preferences::GetBool("browser.xul.error_pages.expert_bad_cert",
3695 false)) {
3696 cssClass.AssignLiteral("expertBadCert");
3697 }
3698
3699 // HSTS/pinning takes precedence over the expert bad cert pref. We
3700 // never want to show the "Add Exception" button for these sites.
3701 // In the future we should differentiate between an HSTS host and a
3702 // pinned host and display a more informative message to the user.
3703 if (isStsHost || isPinnedHost) {
3704 isBadStsCertError = true;
3705 cssClass.AssignLiteral("badStsCert");
3706 }
3707
3708 errorPage.Assign("certerror");
3709 } else {
3710 error = "nssFailure2";
3711 }
3712 } else if (NS_ERROR_PHISHING_URI == aError ||
3713 NS_ERROR_MALWARE_URI == aError ||
3714 NS_ERROR_UNWANTED_URI == aError ||
3715 NS_ERROR_HARMFULADDON_URI == aError ||
3716 NS_ERROR_HARMFUL_URI == aError) {
3717 nsAutoCString host;
3718 aURI->GetHost(host);
3719 CopyUTF8toUTF16(host, *formatStrs.AppendElement());
3720
3721 // Malware and phishing detectors may want to use an alternate error
3722 // page, but if the pref's not set, we'll fall back on the standard page
3723 nsAutoCString alternateErrorPage;
3724 nsresult rv = Preferences::GetCString("urlclassifier.alternate_error_page",
3725 alternateErrorPage);
3726 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3727 errorPage.Assign(alternateErrorPage);
3728 }
3729
3730 if (NS_ERROR_PHISHING_URI == aError) {
3731 error = "deceptiveBlocked";
3732 } else if (NS_ERROR_MALWARE_URI == aError) {
3733 error = "malwareBlocked";
3734 } else if (NS_ERROR_UNWANTED_URI == aError) {
3735 error = "unwantedBlocked";
3736 } else if (NS_ERROR_HARMFUL_URI == aError) {
3737 error = "harmfulBlocked";
3738 } else if (NS_ERROR_HARMFULADDON_URI == aError) {
3739 error = "addonBlocked";
3740 }
3741
3742 cssClass.AssignLiteral("blacklist");
3743 } else if (NS_ERROR_CONTENT_CRASHED == aError) {
3744 errorPage.AssignLiteral("tabcrashed");
3745 error = "tabcrashed";
3746
3747 RefPtr<EventTarget> handler = mChromeEventHandler;
3748 if (handler) {
3749 nsCOMPtr<Element> element = do_QueryInterface(handler);
3750 element->GetAttribute(u"crashedPageTitle"_ns, messageStr);
3751 }
3752
3753 // DisplayLoadError requires a non-empty messageStr to proceed and call
3754 // LoadErrorPage. If the page doesn't have a title, we will use a blank
3755 // space which will be trimmed and thus treated as empty by the front-end.
3756 if (messageStr.IsEmpty()) {
3757 messageStr.AssignLiteral(u" ");
3758 }
3759 } else if (NS_ERROR_FRAME_CRASHED == aError) {
3760 errorPage.AssignLiteral("framecrashed");
3761 error = "framecrashed";
3762 messageStr.AssignLiteral(u" ");
3763 } else if (NS_ERROR_BUILDID_MISMATCH == aError) {
3764 errorPage.AssignLiteral("restartrequired");
3765 error = "restartrequired";
3766
3767 // DisplayLoadError requires a non-empty messageStr to proceed and call
3768 // LoadErrorPage. If the page doesn't have a title, we will use a blank
3769 // space which will be trimmed and thus treated as empty by the front-end.
3770 if (messageStr.IsEmpty()) {
3771 messageStr.AssignLiteral(u" ");
3772 }
3773 } else if (aError == NS_ERROR_RESTRICTED_CONTENT) {
3774 errorPage.AssignLiteral("restricted");
3775 error = "restrictedcontent";
3776 if (messageStr.IsEmpty()) {
3777 messageStr.AssignLiteral(u" ");
3778 }
3779 } else {
3780 // Errors requiring simple formatting
3781 switch (aError) {
3782 case NS_ERROR_MALFORMED_URI:
3783 // URI is malformed
3784 error = "malformedURI";
3785 errorDescriptionID = "malformedURI2";
3786 break;
3787 case NS_ERROR_REDIRECT_LOOP:
3788 // Doc failed to load because the server generated too many redirects
3789 error = "redirectLoop";
3790 break;
3791 case NS_ERROR_UNKNOWN_SOCKET_TYPE:
3792 // Doc failed to load because the client is misconfigured
3793 error = "clientSocketMisconfiguration";
3794 break;
3795 case NS_ERROR_NET_RESET:
3796 case NS_ERROR_OS_LOCAL_NETWORK_ACCESS_DENIED:
3797 // Doc failed to load because the server kept reseting the connection
3798 // before we could read any data from it
3799 // NS_ERROR_OS_LOCAL_NETWORK_ACCESS_DENIED is temporarily grouped
3800 // with netReset; it will get its own dedicated error page in
3801 // bug 2060188.
3802 error = "netReset";
3803 break;
3804 case NS_ERROR_DOCUMENT_NOT_CACHED:
3805 // Doc failed to load because the cache does not contain a copy of
3806 // the document.
3807 error = "notCached";
3808 break;
3809 case NS_ERROR_OFFLINE:
3810 // Doc failed to load because we are offline.
3811 error = "netOffline";
3812 break;
3813 case NS_ERROR_DOCUMENT_IS_PRINTMODE:
3814 // Doc navigation attempted while Printing or Print Preview
3815 error = "isprinting";
3816 break;
3817 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
3818 // Port blocked for security reasons
3819 addHostPort = true;
3820 error = "deniedPortAccess";
3821 break;
3822 case NS_ERROR_UNKNOWN_PROXY_HOST:
3823 // Proxy hostname could not be resolved.
3824 error = "proxyResolveFailure";
3825 break;
3826 case NS_ERROR_PROXY_CONNECTION_REFUSED:
3827 case NS_ERROR_PROXY_FORBIDDEN:
3828 case NS_ERROR_PROXY_NOT_IMPLEMENTED:
3829 case NS_ERROR_PROXY_AUTHENTICATION_FAILED:
3830 case NS_ERROR_PROXY_TOO_MANY_REQUESTS:
3831 // Proxy connection was refused.
3832 error = "proxyConnectFailure";
3833 break;
3834 case NS_ERROR_INVALID_CONTENT_ENCODING:
3835 // Bad Content Encoding.
3836 error = "contentEncodingError";
3837 break;
3838 case NS_ERROR_UNSAFE_CONTENT_TYPE:
3839 // Channel refused to load from an unrecognized content type.
3840 error = "unsafeContentType";
3841 break;
3842 case NS_ERROR_CORRUPTED_CONTENT:
3843 // Broken Content Detected. e.g. Content-MD5 check failure.
3844 error = "corruptedContentErrorv2";
3845 break;
3846 case NS_ERROR_INTERCEPTION_FAILED:
3847 // ServiceWorker intercepted request, but something went wrong.
3848 error = "corruptedContentErrorv2";
3849 break;
3850 case NS_ERROR_NET_INADEQUATE_SECURITY:
3851 // Server negotiated bad TLS for HTTP/2.
3852 error = "inadequateSecurityError";
3853 addHostPort = true;
3854 break;
3855 case NS_ERROR_BLOCKED_BY_POLICY:
3856 // Page blocked by policy
3857 error = "blockedByPolicy";
3858 break;
3859 case NS_ERROR_DOM_COOP_FAILED:
3860 error = "blockedByCOOP";
3861 errorDescriptionID = "blockedByCORP";
3862 break;
3863 case NS_ERROR_DOM_COEP_FAILED:
3864 error = "blockedByCOEP";
3865 errorDescriptionID = "blockedByCORP";
3866 break;
3867 case NS_ERROR_DOM_INVALID_HEADER_VALUE:
3868 error = "invalidHeaderValue";
3869 break;
3870 case NS_ERROR_NET_HTTP2_SENT_GOAWAY:
3871 case NS_ERROR_NET_HTTP3_PROTOCOL_ERROR:
3872 // HTTP/2 or HTTP/3 stack detected a protocol error
3873 error = "networkProtocolError";
3874 break;
3875 case NS_ERROR_BASIC_HTTP_AUTH_DISABLED:
3876 error = "basicHttpAuthDisabled";
3877 break;
3878 default:
3879 break;
3880 }
3881 }
3882
3883 nsresult delegateErrorCode = aError;
3884 // If the HTTPS-Only Mode upgraded this request and the upgrade might have
3885 // caused this error, we replace the error-page with about:httpsonlyerror
3886 if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aFailedChannel, aError)) {
3887 errorPage.AssignLiteral("httpsonlyerror");
3888 delegateErrorCode = NS_ERROR_HTTPS_ONLY;
3889 } else if (isBadStsCertError) {
3890 delegateErrorCode = NS_ERROR_BAD_HSTS_CERT;
3891 }
3892
3893 if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) {
3894 nsCOMPtr<nsIURI> errorPageURI;
3895 rv = loadURIDelegate->HandleLoadError(
3896 aURI, delegateErrorCode, NS_ERROR_GET_MODULE(delegateErrorCode),
3897 getter_AddRefs(errorPageURI));
3898 // If the docshell is going away there's no point in showing an error page.
3899 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || mIsBeingDestroyed) {
3900 *aDisplayedErrorPage = false;
3901 return NS_OK;
3902 }
3903
3904 if (errorPageURI) {
3905 *aDisplayedErrorPage =
3906 NS_SUCCEEDED(LoadErrorPage(errorPageURI, aURI, aFailedChannel))((bool)(__builtin_expect(!!(!NS_FAILED_impl(LoadErrorPage(errorPageURI
, aURI, aFailedChannel))), 1)))
;
3907 return NS_OK;
3908 }
3909 }
3910
3911 // Test if the error should be displayed
3912 if (!error) {
3913 return NS_OK;
3914 }
3915
3916 if (!errorDescriptionID) {
3917 errorDescriptionID = error;
3918 }
3919
3920 glean::page::load_error
3921 .Get(IsSubframe() ? "frame"_ns : "top"_ns,
3922 mozilla::dom::LoadErrorToTelemetryLabel(aError))
3923 .Add();
3924
3925 // Test if the error needs to be formatted
3926 if (!messageStr.IsEmpty()) {
3927 // already obtained message
3928 } else {
3929 if (addHostPort) {
3930 // Build up the host:port string.
3931 nsAutoCString hostport;
3932 if (aURI) {
3933 aURI->GetHostPort(hostport);
3934 } else {
3935 hostport.Assign('?');
3936 }
3937 CopyUTF8toUTF16(hostport, *formatStrs.AppendElement());
3938 }
3939
3940 nsAutoCString spec;
3941 rv = NS_ERROR_NOT_AVAILABLE;
3942 auto& nextFormatStr = *formatStrs.AppendElement();
3943 if (aURI) {
3944 // displaying "file://" is aesthetically unpleasing and could even be
3945 // confusing to the user
3946 if (aURI->SchemeIs("file")) {
3947 aURI->GetPathQueryRef(spec);
3948 } else {
3949 aURI->GetSpec(spec);
3950 }
3951
3952 nsCOMPtr<nsITextToSubURI> textToSubURI(
3953 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID"@mozilla.org/intl/texttosuburi;1", &rv));
3954 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3955 rv = textToSubURI->UnEscapeURIForUI(spec, nextFormatStr);
3956 }
3957 } else {
3958 spec.Assign('?');
3959 }
3960 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3961 CopyUTF8toUTF16(spec, nextFormatStr);
3962 }
3963 rv = NS_OK;
3964
3965 nsAutoString str;
3966 rv =
3967 stringBundle->FormatStringFromName(errorDescriptionID, formatStrs, str);
3968 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3968); return rv; } } while (false)
;
3969 messageStr.Assign(str);
3970 }
3971
3972 // Display the error as a page or an alert prompt
3973 NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(!(messageStr.IsEmpty()))), 0)
)) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!(messageStr.IsEmpty())"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 3973); return NS_ERROR_FAILURE; } } while (false)
;
3974
3975 if (mBrowsingContext->GetUseErrorPages()) {
3976 // Display an error page
3977 nsresult loadedPage =
3978 LoadErrorPage(aURI, aURL, errorPage.get(), error, messageStr.get(),
3979 cssClass.get(), aFailedChannel);
3980 *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage)((bool)(__builtin_expect(!!(!NS_FAILED_impl(loadedPage)), 1))
)
;
3981 } else {
3982 // The prompter reqires that our private window has a document (or it
3983 // asserts). Satisfy that assertion now since GetDoc will force
3984 // creation of one if it hasn't already been created.
3985 if (mScriptGlobal) {
3986 (void)mScriptGlobal->GetDoc();
3987 }
3988
3989 // Display a message box
3990 prompter->Alert(nullptr, messageStr.get());
3991 }
3992
3993 return NS_OK;
3994}
3995
3996#define PREF_SAFEBROWSING_ALLOWOVERRIDE"browser.safebrowsing.allowOverride" "browser.safebrowsing.allowOverride"
3997
3998nsresult nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
3999 const char* aErrorPage,
4000 const char* aErrorType,
4001 const char16_t* aDescription,
4002 const char* aCSSClass,
4003 nsIChannel* aFailedChannel) {
4004 if (mIsBeingDestroyed) {
4005 return NS_ERROR_NOT_AVAILABLE;
4006 }
4007
4008#if defined(DEBUG1)
4009 if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellLog, LogLevel
::Debug)), 0))
) {
4010 nsAutoCString chanName;
4011 if (aFailedChannel) {
4012 aFailedChannel->GetName(chanName);
4013 } else {
4014 chanName.AssignLiteral("<no channel>");
4015 }
4016
4017 MOZ_LOG(gDocShellLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n"
, this, aURI ? aURI->GetSpecOrDefault().get() : "", NS_ConvertUTF16toUTF8
(aURL).get(), chanName.get()); } } while (0)
4018 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n"
, this, aURI ? aURI->GetSpecOrDefault().get() : "", NS_ConvertUTF16toUTF8
(aURL).get(), chanName.get()); } } while (0)
4019 this, aURI ? aURI->GetSpecOrDefault().get() : "",do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n"
, this, aURI ? aURI->GetSpecOrDefault().get() : "", NS_ConvertUTF16toUTF8
(aURL).get(), chanName.get()); } } while (0)
4020 NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n"
, this, aURI ? aURI->GetSpecOrDefault().get() : "", NS_ConvertUTF16toUTF8
(aURL).get(), chanName.get()); } } while (0)
;
4021 }
4022#endif
4023
4024 nsAutoCString url;
4025 if (aURI) {
4026 nsresult rv = aURI->GetSpec(url);
4027 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4027); return rv; } } while (false)
;
4028 } else if (aURL) {
4029 CopyUTF16toUTF8(MakeStringSpan(aURL), url);
4030 } else {
4031 return NS_ERROR_INVALID_POINTER;
4032 }
4033
4034 // Create a URL to pass all the error information through to the page.
4035
4036#undef SAFE_ESCAPE
4037#define SAFE_ESCAPE(output, input, params)if (NS_warn_if_impl(!NS_Escape(input, output, params), "!NS_Escape(input, output, params)"
, "./../../../docshell/base/nsDocShell.cpp", 4037)) { return NS_ERROR_OUT_OF_MEMORY
; }
\
4038 if (NS_WARN_IF(!NS_Escape(input, output, params))NS_warn_if_impl(!NS_Escape(input, output, params), "!NS_Escape(input, output, params)"
, "./../../../docshell/base/nsDocShell.cpp", 4038)
) { \
4039 return NS_ERROR_OUT_OF_MEMORY; \
4040 }
4041
4042 nsCString escapedUrl, escapedError, escapedDescription, escapedCSSClass;
4043 SAFE_ESCAPE(escapedUrl, url, url_Path)if (NS_warn_if_impl(!NS_Escape(url, escapedUrl, url_Path), "!NS_Escape(url, escapedUrl, url_Path)"
, "./../../../docshell/base/nsDocShell.cpp", 4043)) { return NS_ERROR_OUT_OF_MEMORY
; }
;
4044 SAFE_ESCAPE(escapedError, nsDependentCString(aErrorType), url_Path)if (NS_warn_if_impl(!NS_Escape(nsDependentCString(aErrorType)
, escapedError, url_Path), "!NS_Escape(nsDependentCString(aErrorType), escapedError, url_Path)"
, "./../../../docshell/base/nsDocShell.cpp", 4044)) { return NS_ERROR_OUT_OF_MEMORY
; }
;
4045 SAFE_ESCAPE(escapedDescription, NS_ConvertUTF16toUTF8(aDescription),if (NS_warn_if_impl(!NS_Escape(NS_ConvertUTF16toUTF8(aDescription
), escapedDescription, url_Path), "!NS_Escape(NS_ConvertUTF16toUTF8(aDescription), escapedDescription, url_Path)"
, "./../../../docshell/base/nsDocShell.cpp", 4046)) { return NS_ERROR_OUT_OF_MEMORY
; }
4046 url_Path)if (NS_warn_if_impl(!NS_Escape(NS_ConvertUTF16toUTF8(aDescription
), escapedDescription, url_Path), "!NS_Escape(NS_ConvertUTF16toUTF8(aDescription), escapedDescription, url_Path)"
, "./../../../docshell/base/nsDocShell.cpp", 4046)) { return NS_ERROR_OUT_OF_MEMORY
; }
;
4047 if (aCSSClass) {
4048 nsCString cssClass(aCSSClass);
4049 SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path)if (NS_warn_if_impl(!NS_Escape(cssClass, escapedCSSClass, url_Path
), "!NS_Escape(cssClass, escapedCSSClass, url_Path)", "./../../../docshell/base/nsDocShell.cpp"
, 4049)) { return NS_ERROR_OUT_OF_MEMORY; }
;
4050 }
4051 nsCString errorPageUrl("about:");
4052 errorPageUrl.AppendASCII(aErrorPage);
4053 errorPageUrl.AppendLiteral("?e=");
4054
4055 errorPageUrl.AppendASCII(escapedError.get());
4056 errorPageUrl.AppendLiteral("&u=");
4057 errorPageUrl.AppendASCII(escapedUrl.get());
4058 if ((strcmp(aErrorPage, "blocked") == 0) &&
4059 Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE"browser.safebrowsing.allowOverride", true)) {
4060 errorPageUrl.AppendLiteral("&o=1");
4061 }
4062 if (!escapedCSSClass.IsEmpty()) {
4063 errorPageUrl.AppendLiteral("&s=");
4064 errorPageUrl.AppendASCII(escapedCSSClass.get());
4065 }
4066 errorPageUrl.AppendLiteral("&c=UTF-8");
4067
4068 nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID{ 0xbdbe0555, 0xfc3d, 0x4f7b, {0x92, 0x05, 0xc3, 0x09, 0xce, 0xb2
, 0xd6, 0x41}}
);
4069 int32_t cpsState;
4070 if (cps && NS_SUCCEEDED(cps->GetState(&cpsState))((bool)(__builtin_expect(!!(!NS_FAILED_impl(cps->GetState(
&cpsState))), 1)))
) {
4071 if (cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
4072 errorPageUrl.AppendLiteral("&captive=true");
4073 }
4074 if (strcmp(aErrorPage, "neterror") == 0) {
4075 static const char* const kCaptivePortalStateNames[] = {
4076 "unknown", "not_captive", "unlocked_portal", "locked_portal"};
4077 if (cpsState >= 0 &&
4078 size_t(cpsState) < std::size(kCaptivePortalStateNames)) {
4079 errorPageUrl.AppendLiteral("&captivePortalState=");
4080 errorPageUrl.AppendASCII(kCaptivePortalStateNames[cpsState]);
4081 }
4082 }
4083 }
4084
4085 errorPageUrl.AppendLiteral("&d=");
4086 errorPageUrl.AppendASCII(escapedDescription.get());
4087
4088 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aFailedChannel));
4089 if (props) {
4090 nsAutoCString addonName;
4091 props->GetPropertyAsACString(u"blockedExtension"_ns, addonName);
4092
4093 nsCString escapedAddonName;
4094 SAFE_ESCAPE(escapedAddonName, addonName, url_Path)if (NS_warn_if_impl(!NS_Escape(addonName, escapedAddonName, url_Path
), "!NS_Escape(addonName, escapedAddonName, url_Path)", "./../../../docshell/base/nsDocShell.cpp"
, 4094)) { return NS_ERROR_OUT_OF_MEMORY; }
;
4095
4096 errorPageUrl.AppendLiteral("&a=");
4097 errorPageUrl.AppendASCII(escapedAddonName.get());
4098 }
4099
4100 nsCOMPtr<nsIURI> errorPageURI;
4101 nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
4102 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4102); return rv; } } while (false)
;
4103
4104 return LoadErrorPage(errorPageURI, aURI, aFailedChannel);
4105}
4106
4107nsresult nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI,
4108 nsIChannel* aFailedChannel) {
4109 mFailedChannel = aFailedChannel;
4110 mFailedURI = aFailedURI;
4111 mFailedLoadType = mLoadType;
4112
4113 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(aErrorURI);
4114 loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
4115 if (mBrowsingContext) {
4116 loadState->SetTriggeringSandboxFlags(mBrowsingContext->GetSandboxFlags());
4117 loadState->SetTriggeringWindowId(
4118 mBrowsingContext->GetCurrentInnerWindowId());
4119 }
4120 loadState->SetLoadType(LOAD_ERROR_PAGE);
4121 loadState->SetFirstParty(true);
4122 loadState->SetSourceBrowsingContext(mBrowsingContext);
4123 if (mLoadingEntry) {
4124 // We keep the loading entry for the load that failed here. If the user
4125 // reloads we want to try to reload the original load, not the error page.
4126 loadState->SetLoadingSessionHistoryInfo(
4127 std::make_unique<LoadingSessionHistoryInfo>(*mLoadingEntry));
4128 }
4129
4130 // Prevent initial about:blank handling, as it's likely irrelevant and
4131 // keeps us from needing to change GeckoView / NavigationDelegateTest.
4132 // It also makes the load more consistent with non-about-blank cases.
4133 loadState->ProhibitInitialAboutBlankHandling();
4134
4135 return InternalLoad(loadState);
4136}
4137
4138MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMPnsresult
4139nsDocShell::Reload(uint32_t aReloadFlags) {
4140 return ReloadNavigable(Nothing(), aReloadFlags, nullptr,
4141 UserNavigationInvolvement::BrowserUI);
4142}
4143
4144// https://html.spec.whatwg.org/#reload
4145// To reload a navigable navigable given an optional serialized state-or-null
4146// navigationAPIState (default null) and an optional user navigation
4147// involvement userInvolvement (default "none"):
4148nsresult nsDocShell::ReloadNavigable(
4149 mozilla::Maybe<NotNull<JSContext*>> aCx, uint32_t aReloadFlags,
4150 nsIStructuredCloneContainer* aNavigationAPIState,
4151 UserNavigationInvolvement aUserInvolvement,
4152 NavigationAPIMethodTracker* aNavigationAPIMethodTracker) {
4153 AUTO_PROFILER_MARKER_UNTYPED(AutoProfilerUntypedMarker raiiObject4156( "nsDocShell:ReloadNavigable"
, ::mozilla::baseprofiler::category::DOM, MarkerOptions(MarkerStack
::Capture(), MarkerInnerWindowIdFromDocShell(this)))
4154 "nsDocShell:ReloadNavigable", DOM,AutoProfilerUntypedMarker raiiObject4156( "nsDocShell:ReloadNavigable"
, ::mozilla::baseprofiler::category::DOM, MarkerOptions(MarkerStack
::Capture(), MarkerInnerWindowIdFromDocShell(this)))
4155 MarkerOptions(MarkerStack::Capture(),AutoProfilerUntypedMarker raiiObject4156( "nsDocShell:ReloadNavigable"
, ::mozilla::baseprofiler::category::DOM, MarkerOptions(MarkerStack
::Capture(), MarkerInnerWindowIdFromDocShell(this)))
4156 MarkerInnerWindowIdFromDocShell(this)))AutoProfilerUntypedMarker raiiObject4156( "nsDocShell:ReloadNavigable"
, ::mozilla::baseprofiler::category::DOM, MarkerOptions(MarkerStack
::Capture(), MarkerInnerWindowIdFromDocShell(this)))
;
4157
4158 if (!IsNavigationAllowed()) {
4159 return NS_OK; // JS may not handle returning of an error code
4160 }
4161
4162 NS_ASSERTION(((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0),do { if (!(((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Reload command not updated to use load flags!"
, "((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0)"
, "./../../../docshell/base/nsDocShell.cpp", 4163); MOZ_PretendNoReturn
(); } } while (0)
4163 "Reload command not updated to use load flags!")do { if (!(((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS
) == 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Reload command not updated to use load flags!"
, "((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0)"
, "./../../../docshell/base/nsDocShell.cpp", 4163); MOZ_PretendNoReturn
(); } } while (0)
;
4164 NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,do { if (!((aReloadFlags & (nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL
| nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD | nsIWebNavigation
::LOAD_FLAGS_ALLOW_POPUPS | 0xffff0000)) == 0)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Don't pass these flags to Reload", "(aReloadFlags & EXTRA_LOAD_FLAGS) == 0"
, "./../../../docshell/base/nsDocShell.cpp", 4165); MOZ_PretendNoReturn
(); } } while (0)
4165 "Don't pass these flags to Reload")do { if (!((aReloadFlags & (nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL
| nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD | nsIWebNavigation
::LOAD_FLAGS_ALLOW_POPUPS | 0xffff0000)) == 0)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Don't pass these flags to Reload", "(aReloadFlags & EXTRA_LOAD_FLAGS) == 0"
, "./../../../docshell/base/nsDocShell.cpp", 4165); MOZ_PretendNoReturn
(); } } while (0)
;
4166
4167 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags)((LOAD_RELOAD_NORMAL) | ((aReloadFlags) << 16));
4168 NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(IsValidLoadType(loadType))), 0
))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "IsValidLoadType(loadType)"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4168); return NS_ERROR_INVALID_ARG; } } while (false)
;
4169 NS_ENSURE_TRUE(do { if ((__builtin_expect(!!(!(aUserInvolvement == UserNavigationInvolvement
::BrowserUI || aCx)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aUserInvolvement == UserNavigationInvolvement::BrowserUI || aCx"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4171); return NS_ERROR_INVALID_ARG; } } while (false)
4170 aUserInvolvement == UserNavigationInvolvement::BrowserUI || aCx,do { if ((__builtin_expect(!!(!(aUserInvolvement == UserNavigationInvolvement
::BrowserUI || aCx)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aUserInvolvement == UserNavigationInvolvement::BrowserUI || aCx"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4171); return NS_ERROR_INVALID_ARG; } } while (false)
4171 NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aUserInvolvement == UserNavigationInvolvement
::BrowserUI || aCx)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aUserInvolvement == UserNavigationInvolvement::BrowserUI || aCx"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4171); return NS_ERROR_INVALID_ARG; } } while (false)
;
4172
4173 RefPtr<nsDocShell> docShell(this);
4174
4175 // 1. If userInvolvement is not "browser UI", then:
4176 if (aUserInvolvement != UserNavigationInvolvement::BrowserUI) {
4177 // 1.1 Let navigation be navigable's active window's navigation API.
4178 nsPIDOMWindowOuter* windowOuter = GetWindow();
4179 MOZ_DIAGNOSTIC_ASSERT(windowOuter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(windowOuter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(windowOuter))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("windowOuter", "./../../../docshell/base/nsDocShell.cpp"
, 4179); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "windowOuter"
")"); do { MOZ_CrashSequence(__null, 4179); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4180 nsPIDOMWindowInner* windowInner = windowOuter->GetCurrentInnerWindow();
4181 MOZ_DIAGNOSTIC_ASSERT(windowInner)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(windowInner)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(windowInner))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("windowInner", "./../../../docshell/base/nsDocShell.cpp"
, 4181); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "windowInner"
")"); do { MOZ_CrashSequence(__null, 4181); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4182 RefPtr navigation = windowInner->Navigation();
4183
4184 // 1.2 Let destinationNavigationAPIState be navigable's active session
4185 // history entry's navigation API state.
4186 // 1.3 If navigationAPIState is not null, then set
4187 // destinationNavigationAPIState to navigationAPIState.
4188 RefPtr<nsIStructuredCloneContainer> destinationNavigationAPIState =
4189 aNavigationAPIState;
4190 if (!destinationNavigationAPIState) {
4191 destinationNavigationAPIState =
4192 mActiveEntry ? mActiveEntry->GetNavigationAPIState() : nullptr;
4193 }
4194
4195 // 1.4 Let continue be the result of firing a push/replace/reload navigate
4196 // event at navigation with navigationType set to "reload",
4197 // isSameDocument set to false, userInvolvement set to userInvolvement,
4198 // destinationURL set to navigable's active session history entry's URL,
4199 // and navigationAPIState set to destinationNavigationAPIState.
4200 // 1.5 If continue is false, then return.
4201 RefPtr destinationURL = mActiveEntry ? mActiveEntry->GetURI() : nullptr;
4202 if (navigation &&
4203 !navigation->FirePushReplaceReloadNavigateEvent(
4204 *aCx, NavigationType::Reload, destinationURL,
4205 /* aIsSameDocument */ false, Some(aUserInvolvement),
4206 /* aSourceElement*/ nullptr, /* aFormDataEntryList */ nullptr,
4207 destinationNavigationAPIState,
4208 /* aClassiCHistoryAPIState */ nullptr,
4209 aNavigationAPIMethodTracker)) {
4210 return NS_OK;
4211 }
4212 }
4213
4214 // The following steps are implemented by the remainder of ReloadNavigable.
4215
4216 // Send notifications to the HistoryListener if any, about the impending
4217 // reload
4218 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4219 MOZ_LOG(gSHLog, LogLevel::Debug, ("nsDocShell %p Reload", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload", this); } } while (
0)
;
4220 if (!XRE_IsParentProcess()) {
4221 ++mPendingReloadCount;
4222 nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
4223 NS_ENSURE_STATE(viewer)do { if ((__builtin_expect(!!(!(viewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "viewer" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 4223); return NS_ERROR_UNEXPECTED
; } } while (false)
;
4224
4225 bool okToUnload = true;
4226 MOZ_TRY(viewer->PermitUnload(&okToUnload))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(viewer->PermitUnload(&okToUnload)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
4227 if (mIsBeingDestroyed) {
4228 // unload handler destroyed this docshell.
4229 return NS_ERROR_NOT_AVAILABLE;
4230 }
4231 if (!okToUnload) {
4232 return NS_OK;
4233 }
4234
4235 RefPtr<Document> doc(GetDocument());
4236 RefPtr<BrowsingContext> browsingContext(mBrowsingContext);
4237 nsCOMPtr<nsIURI> currentURI(mCurrentURI);
4238 nsCOMPtr<nsIReferrerInfo> referrerInfo(mReferrerInfo);
4239 RefPtr stopDetector = MakeRefPtr<StopDetector>();
4240 nsCOMPtr<nsILoadGroup> loadGroup;
4241 GetLoadGroup(getter_AddRefs(loadGroup));
4242 if (loadGroup) {
4243 // loadGroup may be null in theory. In that case stopDetector just
4244 // doesn't do anything.
4245 loadGroup->AddRequest(stopDetector, nullptr);
4246 }
4247
4248 ContentChild::GetSingleton()->SendNotifyOnHistoryReload(
4249 mBrowsingContext, aReloadFlags,
4250 [docShell, doc, loadType, browsingContext, currentURI, referrerInfo,
4251 loadGroup, stopDetector](
4252 std::tuple<bool, Maybe<NotNull<RefPtr<nsDocShellLoadState>>>>&&
4253 aResult) MOZ_CAN_RUN_SCRIPT {
4254 auto scopeExit = MakeScopeExit([loadGroup, stopDetector]() {
4255 if (loadGroup) {
4256 loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
4257 }
4258 });
4259
4260 // Decrease mPendingReloadCount before any other early returns!
4261 if (--(docShell->mPendingReloadCount) > 0) {
4262 return;
4263 }
4264
4265 if (stopDetector->Canceled()) {
4266 return;
4267 }
4268 bool canReload;
4269 Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
4270
4271 std::tie(canReload, loadState) = aResult;
4272
4273 if (!canReload) {
4274 return;
4275 }
4276
4277 if (loadState.isSome()) {
4278 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload - LoadHistoryEntry",
docShell.get()); } } while (0)
4279 gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload - LoadHistoryEntry",
docShell.get()); } } while (0)
4280 ("nsDocShell %p Reload - LoadHistoryEntry", docShell.get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload - LoadHistoryEntry",
docShell.get()); } } while (0)
;
4281 loadState.ref()->SetNotifiedBeforeUnloadListeners(true);
4282 docShell->LoadHistoryEntry(MOZ_KnownLive(loadState.ref().get())(loadState.ref().get()),
4283 loadType);
4284 } else {
4285 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p ReloadDocument", docShell.get
()); } } while (0)
4286 ("nsDocShell %p ReloadDocument", docShell.get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p ReloadDocument", docShell.get
()); } } while (0)
;
4287 ReloadDocument(docShell, doc, loadType, browsingContext, currentURI,
4288 referrerInfo,
4289 /* aNotifiedBeforeUnloadListeners */ true);
4290 }
4291 },
4292 [](mozilla::ipc::ResponseRejectReason) {});
4293 } else {
4294 // Parent process
4295 bool canReload = false;
4296 Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
4297 if (!mBrowsingContext->IsDiscarded()) {
4298 mBrowsingContext->Canonical()->NotifyOnHistoryReload(
4299 aReloadFlags, canReload, loadState);
4300 }
4301 if (canReload) {
4302 if (loadState.isSome()) {
4303 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload - LoadHistoryEntry",
this); } } while (0)
4304 ("nsDocShell %p Reload - LoadHistoryEntry", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p Reload - LoadHistoryEntry",
this); } } while (0)
;
4305 LoadHistoryEntry(MOZ_KnownLive(loadState.ref().get())(loadState.ref().get()), loadType);
4306 } else {
4307 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p ReloadDocument", this); } }
while (0)
4308 ("nsDocShell %p ReloadDocument", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p ReloadDocument", this); } }
while (0)
;
4309 RefPtr<Document> doc = GetDocument();
4310 RefPtr<BrowsingContext> bc = mBrowsingContext;
4311 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
4312 nsCOMPtr<nsIReferrerInfo> referrerInfo = mReferrerInfo;
4313 ReloadDocument(this, doc, loadType, bc, currentURI, referrerInfo);
4314 }
4315 }
4316 }
4317 return NS_OK;
4318}
4319
4320void nsDocShell::DisplayRestrictedContentError() {
4321 bool didDisplayLoadError = false;
4322 RefPtr<mozilla::dom::Document> doc = GetDocument();
4323 if (!doc) {
4324 return;
4325 }
4326 doc->TerminateParserAndDisableScripts();
4327 DisplayLoadError(NS_ERROR_RESTRICTED_CONTENT, doc->GetDocumentURI(), nullptr,
4328 nullptr, &didDisplayLoadError);
4329}
4330
4331/* static */
4332nsresult nsDocShell::ReloadDocument(nsDocShell* aDocShell, Document* aDocument,
4333 uint32_t aLoadType,
4334 BrowsingContext* aBrowsingContext,
4335 nsIURI* aCurrentURI,
4336 nsIReferrerInfo* aReferrerInfo,
4337 bool aNotifiedBeforeUnloadListeners) {
4338 if (!aDocument) {
4339 return NS_OK;
4340 }
4341
4342 // Do not inherit owner from document
4343 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
4344 nsAutoString srcdoc;
4345 nsIURI* baseURI = nullptr;
4346 nsCOMPtr<nsIURI> originalURI;
4347 nsCOMPtr<nsIURI> resultPrincipalURI;
4348 bool loadReplace = false;
4349
4350 nsIPrincipal* triggeringPrincipal = aDocument->NodePrincipal();
4351 nsCOMPtr<nsIPolicyContainer> policyContainer =
4352 aDocument->GetPolicyContainer();
4353 uint32_t triggeringSandboxFlags = aDocument->GetSandboxFlags();
4354 uint64_t triggeringWindowId = aDocument->InnerWindowID();
4355 net::ClassificationFlags triggeringClassificationFlags =
4356 aDocument->GetScriptTrackingFlags();
4357
4358 nsAutoString contentTypeHint;
4359 aDocument->GetContentType(contentTypeHint);
4360
4361 if (aDocument->IsSrcdocDocument()) {
4362 aDocument->GetSrcdocData(srcdoc);
4363 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
4364 baseURI = aDocument->GetBaseURI();
4365 } else {
4366 srcdoc = VoidString();
4367 }
4368 nsCOMPtr<nsIChannel> chan = aDocument->GetChannel();
4369 if (chan) {
4370 uint32_t loadFlags;
4371 chan->GetLoadFlags(&loadFlags);
4372 loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
4373 nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
4374 if (httpChan) {
4375 httpChan->GetOriginalURI(getter_AddRefs(originalURI));
4376 }
4377
4378 nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
4379 loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
4380 }
4381
4382 if (!triggeringPrincipal) {
4383 MOZ_ASSERT(false, "Reload needs a valid triggeringPrincipal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Reload needs a valid triggeringPrincipal"
")", "./../../../docshell/base/nsDocShell.cpp", 4383); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "Reload needs a valid triggeringPrincipal"
")"); do { MOZ_CrashSequence(__null, 4383); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4384 return NS_ERROR_FAILURE;
4385 }
4386
4387 // Stack variables to ensure changes to the member variables don't affect to
4388 // the call.
4389 nsCOMPtr<nsIURI> currentURI = aCurrentURI;
4390
4391 // Reload always rewrites result principal URI.
4392 Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
4393 emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
4394
4395 RefPtr<WindowContext> context = aBrowsingContext->GetCurrentWindowContext();
4396 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(currentURI);
4397 loadState->SetReferrerInfo(aReferrerInfo);
4398 loadState->SetOriginalURI(originalURI);
4399 loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
4400 loadState->SetLoadReplace(loadReplace);
4401 loadState->SetTriggeringPrincipal(triggeringPrincipal);
4402 loadState->SetTriggeringSandboxFlags(triggeringSandboxFlags);
4403 loadState->SetTriggeringWindowId(triggeringWindowId);
4404 loadState->SetTriggeringClassificationFlags(triggeringClassificationFlags);
4405 loadState->SetPrincipalToInherit(triggeringPrincipal);
4406 loadState->SetPolicyContainer(policyContainer);
4407 loadState->SetInternalLoadFlags(flags);
4408 loadState->SetTypeHint(NS_ConvertUTF16toUTF8(contentTypeHint));
4409 loadState->SetLoadType(aLoadType);
4410 loadState->SetFirstParty(true);
4411 loadState->SetSrcdocData(srcdoc);
4412 loadState->SetSourceBrowsingContext(aBrowsingContext);
4413 loadState->SetBaseURI(baseURI);
4414 loadState->SetHasValidUserGestureActivation(
4415 context && context->HasValidTransientUserGestureActivation());
4416
4417 loadState->SetTextDirectiveUserActivation(
4418 aDocument->ConsumeTextDirectiveUserActivation() ||
4419 loadState->HasValidUserGestureActivation());
4420
4421 loadState->SetNotifiedBeforeUnloadListeners(aNotifiedBeforeUnloadListeners);
4422 return aDocShell->InternalLoad(loadState);
4423}
4424
4425// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
4426MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMPnsresult
4427nsDocShell::Stop(uint32_t aStopFlags) {
4428 return StopInternal(aStopFlags, UnsetOngoingNavigation::Yes);
4429}
4430
4431nsresult nsDocShell::StopInternal(
4432 uint32_t aStopFlags, UnsetOngoingNavigation aUnsetOngoingNavigation) {
4433 RefPtr kungFuDeathGrip = this;
4434
4435 // Drop the view transition state of an aborted or superseded navigation.
4436 mFiredCrossDocPageSwap = false;
4437 mPendingInboundViewTransitionParams = nullptr;
4438 // When a BrowsingContext is replaced, Destroy() calls Stop() on the old
4439 // docshell, but the new document still needs the params. So keep them.
4440 if (!mIsBeingDestroyed) {
4441 // Clear only the params that this BrowsingContext captured. The
4442 // BrowsingContext that replaces this one also stops its initial
4443 // about:blank, and that must not clear the params of the old one.
4444 if (mBrowsingContext && mBrowsingContext->IsTop()) {
4445 Document::ClearCrossDocViewTransitionParams(mBrowsingContext->BrowserId(),
4446 Some(mBrowsingContext->Id()));
4447 }
4448 if (RefPtr<Document> doc = GetExtantDocument()) {
4449 if (RefPtr<ViewTransition> vt = doc->GetActiveViewTransition();
4450 vt && vt->IsOutboundCrossDocument()) {
4451 vt->SkipTransition(SkipTransitionReason::NavigationAborted);
4452 }
4453 }
4454 }
4455 if (RefPtr<Document> doc = GetExtantDocument();
4456 aUnsetOngoingNavigation == UnsetOngoingNavigation::Yes && doc &&
4457 !doc->ShouldIgnoreOpens() &&
4458 mOngoingNavigation == Some(OngoingNavigation::NavigationID)) {
4459 ResetOngoingNavigation(Nothing());
4460 }
4461
4462 if (mLoadType == LOAD_ERROR_PAGE) {
4463 mActiveEntryIsLoadingFromSessionHistory = false;
4464
4465 mFailedChannel = nullptr;
4466 mFailedURI = nullptr;
4467 }
4468
4469 if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
4470 // Stop the document loading and animations
4471 if (mDocumentViewer) {
4472 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
4473 viewer->Stop();
4474 }
4475 } else if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
4476 // Stop the document loading only
4477 if (mDocumentViewer) {
4478 RefPtr<Document> doc = mDocumentViewer->GetDocument();
4479 if (doc) {
4480 doc->StopDocumentLoad();
4481 }
4482 }
4483 }
4484
4485 if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
4486 // Suspend any timers that were set for this loader. We'll clear
4487 // them out for good in CreateDocumentViewer.
4488 if (mRefreshURIList) {
4489 SuspendRefreshURIs();
4490 mSavedRefreshURIList.swap(mRefreshURIList);
4491 mRefreshURIList = nullptr;
4492 }
4493
4494 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4495 // just call Stop() on us as an nsIDocumentLoader... We need fewer
4496 // redundant apis!
4497 if (aUnsetOngoingNavigation == UnsetOngoingNavigation::No && mLoadGroup) {
4498 // Tag load group cancellation as navigation-caused so that XHR can
4499 // suppress abort events (bug 1505389). SetCanceledReason is
4500 // first-write-wins, so nsDocLoader::Stop's reason won't overwrite.
4501
4502 // XXX Consider using a flag on LoadGroup instead of CanceledReason
4503 mLoadGroup->SetCanceledReason("navigation"_ns);
4504 }
4505 // Cancel <form> planned navigations.
4506 // Not currently in the spec, but it follows other browsers' behaviour:
4507 // https://github.com/whatwg/html/issues/12609
4508 CancelPlannedFormNavigation();
4509 Stop();
4510
4511 // Clear out mChannelToDisconnectOnPageHide. This page won't go in the
4512 // BFCache now, and the Stop above will have removed the DocumentChannel
4513 // from the loadgroup.
4514 mChannelToDisconnectOnPageHide = 0;
4515 }
4516
4517 for (auto* child : mChildList.ForwardRange()) {
4518 nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(child));
4519 if (shellAsNav) {
4520 shellAsNav->Stop(aStopFlags);
4521 }
4522 }
4523
4524 return NS_OK;
4525}
4526
4527NS_IMETHODIMPnsresult
4528nsDocShell::GetDocument(Document** aDocument) {
4529 NS_ENSURE_ARG_POINTER(aDocument)do { if ((__builtin_expect(!!(!(aDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDocument" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 4529); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
4530 NS_ENSURE_TRUE(VerifyDocumentViewer(), NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(VerifyDocumentViewer())), 0))
) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "VerifyDocumentViewer()"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4530); return NS_ERROR_FAILURE; } } while (false)
;
4531
4532 RefPtr<Document> doc = mDocumentViewer->GetDocument();
4533 if (!doc) {
4534 return NS_ERROR_NOT_AVAILABLE;
4535 }
4536
4537 doc.forget(aDocument);
4538 return NS_OK;
4539}
4540
4541NS_IMETHODIMPnsresult
4542nsDocShell::GetCurrentURI(nsIURI** aURI) {
4543 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 4543); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
4544
4545 nsCOMPtr<nsIURI> uri = mCurrentURI;
4546 uri.forget(aURI);
4547 return NS_OK;
4548}
4549
4550NS_IMETHODIMPnsresult
4551nsDocShell::GetSessionHistoryXPCOM(nsISupports** aSessionHistory) {
4552 NS_ENSURE_ARG_POINTER(aSessionHistory)do { if ((__builtin_expect(!!(!(aSessionHistory)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aSessionHistory" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 4552); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
4553 RefPtr<ChildSHistory> shistory = GetSessionHistory();
4554 shistory.forget(aSessionHistory);
4555 return NS_OK;
4556}
4557
4558//*****************************************************************************
4559// nsDocShell::nsIWebPageDescriptor
4560//*****************************************************************************
4561
4562NS_IMETHODIMPnsresult
4563nsDocShell::LoadPageAsViewSource(nsIDocShell* aOtherDocShell,
4564 const nsAString& aURI) {
4565 if (!aOtherDocShell) {
4566 return NS_ERROR_INVALID_POINTER;
4567 }
4568 auto* otherDocShell = nsDocShell::Cast(aOtherDocShell);
4569
4570 Document* otherDoc = otherDocShell->GetDocument();
4571 NS_ENSURE_TRUE(otherDoc, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(otherDoc)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "otherDoc" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 4571); return NS_ERROR_UNEXPECTED
; } } while (false)
;
4572
4573 nsCOMPtr<nsIURI> newURI;
4574 nsresult rv = NS_NewURI(getter_AddRefs(newURI), aURI);
4575 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4576 return rv;
4577 }
4578
4579 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(newURI);
4580 if (!otherDocShell->FillLoadStateFromCurrentEntry(*loadState)) {
4581 return NS_ERROR_INVALID_POINTER;
4582 }
4583 uint32_t cacheKey = otherDocShell->GetCacheKeyFromCurrentEntry().valueOr(0);
4584
4585 // We're doing a load of the page, via an API that
4586 // is only exposed to system code. The triggering principal for this load
4587 // should be the system principal.
4588 loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
4589 RefPtr<nsIPrincipal> nullPrincipal =
4590 NullPrincipal::CreateWithInheritedAttributes(otherDoc->NodePrincipal());
4591 loadState->SetPrincipalToInherit(nullPrincipal);
4592 loadState->SetPartitionedPrincipalToInherit(nullPrincipal);
4593 loadState->SetOriginalURI(nullptr);
4594 loadState->SetResultPrincipalURI(nullptr);
4595
4596 // Initial about:blank handling is probably irrelevant, but newURI shouldn't
4597 // anyway be about:blank. Otherwise we should prohibit initial about blank
4598 // handling.
4599 MOZ_ASSERT(!NS_IsAboutBlankAllowQueryAndFragment(newURI),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!NS_IsAboutBlankAllowQueryAndFragment(newURI))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!NS_IsAboutBlankAllowQueryAndFragment(newURI)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!NS_IsAboutBlankAllowQueryAndFragment(newURI)"
" (" "We only expect view-source:// URIs" ")", "./../../../docshell/base/nsDocShell.cpp"
, 4600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsAboutBlankAllowQueryAndFragment(newURI)"
") (" "We only expect view-source:// URIs" ")"); do { MOZ_CrashSequence
(__null, 4600); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
4600 "We only expect view-source:// URIs")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!NS_IsAboutBlankAllowQueryAndFragment(newURI))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!NS_IsAboutBlankAllowQueryAndFragment(newURI)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!NS_IsAboutBlankAllowQueryAndFragment(newURI)"
" (" "We only expect view-source:// URIs" ")", "./../../../docshell/base/nsDocShell.cpp"
, 4600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsAboutBlankAllowQueryAndFragment(newURI)"
") (" "We only expect view-source:// URIs" ")"); do { MOZ_CrashSequence
(__null, 4600); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4601
4602 return InternalLoad(loadState, Some(cacheKey));
4603}
4604
4605already_AddRefed<nsIInputStream> nsDocShell::GetPostDataFromCurrentEntry()
4606 const {
4607 nsCOMPtr<nsIInputStream> postData;
4608 if (mActiveEntry) {
4609 postData = mActiveEntry->GetPostData();
4610 } else if (mLoadingEntry) {
4611 postData = mLoadingEntry->mInfo.GetPostData();
4612 }
4613
4614 return postData.forget();
4615}
4616
4617Maybe<uint32_t> nsDocShell::GetCacheKeyFromCurrentEntry() const {
4618 if (mActiveEntry) {
4619 return Some(mActiveEntry->GetCacheKey());
4620 }
4621
4622 if (mLoadingEntry) {
4623 return Some(mLoadingEntry->mInfo.GetCacheKey());
4624 }
4625
4626 return Nothing();
4627}
4628
4629UniquePtr<ViewTransitionParams>
4630nsDocShell::TakePendingInboundViewTransitionParams() {
4631 return std::move(mPendingInboundViewTransitionParams);
4632}
4633
4634bool nsDocShell::FillLoadStateFromCurrentEntry(
4635 nsDocShellLoadState& aLoadState) {
4636 if (mLoadingEntry) {
4637 mLoadingEntry->mInfo.FillLoadInfo(aLoadState);
4638 return true;
4639 }
4640 if (mActiveEntry) {
4641 mActiveEntry->FillLoadInfo(aLoadState);
4642 return true;
4643 }
4644 return false;
4645}
4646
4647//*****************************************************************************
4648// nsDocShell::nsIBaseWindow
4649//*****************************************************************************
4650
4651NS_IMETHODIMPnsresult
4652nsDocShell::Destroy() {
4653 // XXX: We allow this function to be called just once. If you are going to
4654 // reset new variables in this function, please make sure the variables will
4655 // never be re-initialized. Adding assertions to check |mIsBeingDestroyed|
4656 // in the setter functions for the variables would be enough.
4657 if (mIsBeingDestroyed) {
4658 return NS_ERROR_DOCSHELL_DYING;
4659 }
4660
4661 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,do { if (!(mItemType == typeContent || mItemType == typeChrome
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Unexpected item type in docshell"
, "mItemType == typeContent || mItemType == typeChrome", "./../../../docshell/base/nsDocShell.cpp"
, 4662); MOZ_PretendNoReturn(); } } while (0)
4662 "Unexpected item type in docshell")do { if (!(mItemType == typeContent || mItemType == typeChrome
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Unexpected item type in docshell"
, "mItemType == typeContent || mItemType == typeChrome", "./../../../docshell/base/nsDocShell.cpp"
, 4662); MOZ_PretendNoReturn(); } } while (0)
;
4663
4664 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4665 if (serv) {
4666 const char* msg = mItemType == typeContent
4667 ? NS_WEBNAVIGATION_DESTROY"webnavigation-destroy"
4668 : NS_CHROME_WEBNAVIGATION_DESTROY"chrome-webnavigation-destroy";
4669 serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
4670 }
4671
4672 mIsBeingDestroyed = true;
4673
4674 // Brak the cycle with the initial client, if present.
4675 mInitialClientSource.reset();
4676
4677 // Make sure to blow away our mLoadingURI just in case. No loads
4678 // from inside this pagehide.
4679 mLoadingURI = nullptr;
4680
4681 // Fire unload event before we blow anything away.
4682 (void)FirePageHideNotification();
4683
4684 // Note: mContentListener can be null if Init() failed and we're being
4685 // called from the destructor.
4686 if (mContentListener) {
4687 mContentListener->DropDocShellReference();
4688 mContentListener->SetParentContentListener(nullptr);
4689 // Note that we do NOT set mContentListener to null here; that
4690 // way if someone tries to do a load in us after this point
4691 // the nsDSURIContentListener will block it. All of which
4692 // means that we should do this before calling Stop(), of
4693 // course.
4694 }
4695
4696 if (BrowsingContext* browsingContext = GetBrowsingContext();
4697 browsingContext && !browsingContext->IsTop()) {
4698 InformNavigationAPIAboutChildNavigableDestruction();
4699 }
4700
4701 // Stop any URLs that are currently being loaded...
4702 Stop(nsIWebNavigation::STOP_ALL);
4703
4704 mEditorData = nullptr;
4705
4706 // Save the state of the current document, before destroying the window.
4707 // This is needed to capture the state of a frameset when the new document
4708 // causes the frameset to be destroyed...
4709 PersistLayoutHistoryState();
4710
4711 // Remove this docshell from its parent's child list
4712 nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
4713 do_QueryInterface(GetAsSupports(mParent));
4714 if (docShellParentAsItem) {
4715 docShellParentAsItem->RemoveChild(this);
4716 }
4717
4718 DestroyDocumentViewer();
4719
4720 nsDocLoader::Destroy();
4721
4722 mParentWidget = nullptr;
4723 SetCurrentURIInternal(nullptr);
4724
4725 if (mScriptGlobal) {
4726 mScriptGlobal->DetachFromDocShell(!mWillChangeProcess);
4727 mScriptGlobal = nullptr;
4728 }
4729
4730 if (mWillChangeProcess && !mBrowsingContext->IsDiscarded()) {
4731 mBrowsingContext->PrepareForProcessChange();
4732 }
4733
4734 SetTreeOwner(nullptr);
4735
4736 mBrowserChild = nullptr;
4737
4738 mChromeEventHandler = nullptr;
4739
4740 mBCWebProgressStatusFilter = nullptr;
4741
4742 // Cancel any timers that were set for this docshell; this is needed
4743 // to break the cycle between us and the timers.
4744 CancelRefreshURITimers();
4745
4746 return NS_OK;
4747}
4748
4749double nsDocShell::GetWidgetCSSToDeviceScale() {
4750 if (mParentWidget) {
4751 return mParentWidget->GetDefaultScale().scale;
4752 }
4753 if (nsCOMPtr<nsIBaseWindow> ownerWindow = do_QueryInterface(mTreeOwner)) {
4754 return ownerWindow->GetWidgetCSSToDeviceScale();
4755 }
4756 return 1.0;
4757}
4758
4759NS_IMETHODIMPnsresult
4760nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale) {
4761 if (mParentWidget) {
4762 *aScale = mParentWidget->GetDesktopToDeviceScale().scale;
4763 return NS_OK;
4764 }
4765
4766 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
4767 if (ownerWindow) {
4768 return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale);
4769 }
4770
4771 *aScale = 1.0;
4772 return NS_OK;
4773}
4774
4775NS_IMETHODIMPnsresult
4776nsDocShell::SetPosition(int32_t aX, int32_t aY) {
4777 mBounds.MoveTo(aX, aY);
4778
4779 if (mDocumentViewer) {
4780 NS_ENSURE_SUCCESS(mDocumentViewer->Move(aX, aY), NS_ERROR_FAILURE)do { nsresult __rv = mDocumentViewer->Move(aX, aY); if (((
bool)(__builtin_expect(!!(NS_FAILED_impl(__rv)), 0)))) { const
char* name = mozilla::GetStaticErrorName(__rv); mozilla::SmprintfPointer
msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "mDocumentViewer->Move(aX, aY)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 4780); return NS_ERROR_FAILURE; } } while (false)
;
4781 }
4782
4783 return NS_OK;
4784}
4785
4786NS_IMETHODIMPnsresult
4787nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY) {
4788 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
4789 if (ownerWindow) {
4790 return ownerWindow->SetPositionDesktopPix(aX, aY);
4791 }
4792
4793 double scale = 1.0;
4794 GetDevicePixelsPerDesktopPixel(&scale);
4795 return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
4796}
4797
4798NS_IMETHODIMPnsresult
4799nsDocShell::GetPosition(int32_t* aX, int32_t* aY) {
4800 return GetPositionAndSize(aX, aY, nullptr, nullptr);
4801}
4802
4803NS_IMETHODIMPnsresult
4804nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint) {
4805 int32_t x = 0, y = 0;
4806 GetPosition(&x, &y);
4807 return SetPositionAndSize(x, y, aWidth, aHeight,
4808 aRepaint ? nsIBaseWindow::eRepaint : 0);
4809}
4810
4811NS_IMETHODIMPnsresult
4812nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight) {
4813 return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
4814}
4815
4816NS_IMETHODIMPnsresult
4817nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
4818 int32_t aHeight, uint32_t aFlags) {
4819 mBounds.SetRect(aX, aY, aWidth, aHeight);
4820
4821 // Hold strong ref, since SetBounds can make us null out mDocumentViewer
4822 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
4823 if (viewer) {
4824 uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize)
4825 ? nsIDocumentViewer::eDelayResize
4826 : 0;
4827 // XXX Border figured in here or is that handled elsewhere?
4828 nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
4829 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../docshell/base/nsDocShell.cpp", 4829); return NS_ERROR_FAILURE
; } } while (false)
;
4830 }
4831
4832 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
4833 obs->NotifyObservers(GetAsSupports(this), "docshell-position-size-changed",
4834 nullptr);
4835 }
4836
4837 return NS_OK;
4838}
4839
4840NS_IMETHODIMPnsresult
4841nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
4842 int32_t* aHeight) {
4843 if (mParentWidget) {
4844 // ensure size is up-to-date if window has changed resolution
4845 LayoutDeviceIntRect r = mParentWidget->GetClientBounds();
4846 SetPositionAndSize(mBounds.X(), mBounds.Y(), r.Width(), r.Height(), 0);
4847 }
4848
4849 // We should really consider just getting this information from
4850 // our window instead of duplicating the storage and code...
4851 if (aWidth || aHeight) {
4852 // Caller wants to know our size; make sure to give them up to
4853 // date information.
4854 RefPtr<Document> doc(do_GetInterface(GetAsSupports(mParent)));
4855 if (doc) {
4856 doc->FlushPendingNotifications(FlushType::Layout);
4857 }
4858 }
4859
4860 DoGetPositionAndSize(aX, aY, aWidth, aHeight);
4861 return NS_OK;
4862}
4863
4864void nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
4865 int32_t* aHeight) {
4866 if (aX) {
4867 *aX = mBounds.X();
4868 }
4869 if (aY) {
4870 *aY = mBounds.Y();
4871 }
4872 if (aWidth) {
4873 *aWidth = mBounds.Width();
4874 }
4875 if (aHeight) {
4876 *aHeight = mBounds.Height();
4877 }
4878}
4879
4880NS_IMETHODIMPnsresult
4881nsDocShell::SetDimensions(DimensionRequest&& /*aRequest*/) {
4882 return NS_ERROR_NOT_IMPLEMENTED;
4883}
4884
4885NS_IMETHODIMPnsresult
4886nsDocShell::GetParentWidget(nsIWidget** aParentWidget) {
4887 NS_ENSURE_ARG_POINTER(aParentWidget)do { if ((__builtin_expect(!!(!(aParentWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aParentWidget" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 4887); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
4888
4889 *aParentWidget = mParentWidget;
4890 NS_IF_ADDREF(*aParentWidget)ns_if_addref(*aParentWidget);
4891
4892 return NS_OK;
4893}
4894
4895NS_IMETHODIMPnsresult
4896nsDocShell::SetParentWidget(nsIWidget* aParentWidget) {
4897 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 4897); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 4897); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4898 mParentWidget = aParentWidget;
4899
4900 return NS_OK;
4901}
4902
4903NS_IMETHODIMPnsresult
4904nsDocShell::GetNativeHandle(nsAString& /*aNativeHandle*/) {
4905 // the nativeHandle should be accessed from nsIAppWindow
4906 return NS_ERROR_NOT_IMPLEMENTED;
4907}
4908
4909NS_IMETHODIMPnsresult
4910nsDocShell::GetVisibility(bool* aVisibility) {
4911 NS_ENSURE_ARG_POINTER(aVisibility)do { if ((__builtin_expect(!!(!(aVisibility)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aVisibility" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 4911); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
4912
4913 *aVisibility = false;
4914
4915 if (!mDocumentViewer) {
4916 return NS_OK;
4917 }
4918
4919 PresShell* presShell = GetPresShell();
4920 if (!presShell || presShell->IsUnderHiddenEmbedderElement()) {
4921 // NOTE(emilio): IsUnderHiddenEmbedderElement() accounts for ancestors as
4922 // well.
4923 return NS_OK;
4924 }
4925
4926 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
4927 if (!treeOwnerAsWin) {
4928 *aVisibility = true;
4929 return NS_OK;
4930 }
4931
4932 // Check with the tree owner as well to give embedders a chance to
4933 // expose visibility as well.
4934 nsresult rv = treeOwnerAsWin->GetVisibility(aVisibility);
4935 if (rv == NS_ERROR_NOT_IMPLEMENTED) {
4936 // The tree owner had no opinion on our visibility.
4937 *aVisibility = true;
4938 return NS_OK;
4939 }
4940 return rv;
4941}
4942
4943void nsDocShell::ActivenessMaybeChanged() {
4944 const bool isActive = mBrowsingContext->IsActive();
4945 if (RefPtr<PresShell> presShell = GetPresShell()) {
4946 presShell->ActivenessMaybeChanged();
4947 }
4948
4949 // Tell the window about it
4950 if (mScriptGlobal) {
4951 mScriptGlobal->SetIsBackground(!isActive);
4952 if (RefPtr<Document> doc = mScriptGlobal->GetExtantDoc()) {
4953 // Update orientation when the top-level browsing context becomes active.
4954 if (isActive && mBrowsingContext->IsTop() &&
4955 !mBrowsingContext->Windowless()) {
4956 // We only care about the top-level browsing context.
4957 auto orientation = mBrowsingContext->GetOrientationLock();
4958 ScreenOrientation::UpdateActiveOrientationLock(orientation);
4959 }
4960
4961 doc->PostVisibilityUpdateEvent();
4962 }
4963 }
4964
4965 // Tell the nsDOMNavigationTiming about it
4966 RefPtr<nsDOMNavigationTiming> timing = mTiming;
4967 if (!timing && mDocumentViewer) {
4968 if (Document* doc = mDocumentViewer->GetDocument()) {
4969 timing = doc->GetNavigationTiming();
4970 }
4971 }
4972 if (timing) {
4973 timing->NotifyDocShellStateChanged(
4974 isActive ? nsDOMNavigationTiming::DocShellState::eActive
4975 : nsDOMNavigationTiming::DocShellState::eInactive);
4976 }
4977
4978 // Restart or stop meta refresh timers if necessary
4979 if (mDisableMetaRefreshWhenInactive) {
4980 if (isActive) {
4981 ResumeRefreshURIs();
4982 } else {
4983 SuspendRefreshURIs();
4984 }
4985 }
4986
4987 if (InputTaskManager::CanSuspendInputEvent()) {
4988 mBrowsingContext->Group()->UpdateInputTaskManagerIfNeeded(isActive);
4989 }
4990}
4991
4992NS_IMETHODIMPnsresult
4993nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags) {
4994 if (!mWillChangeProcess) {
4995 // Intentionally ignoring handling discarded browsing contexts.
4996 (void)mBrowsingContext->SetDefaultLoadFlags(aDefaultLoadFlags);
4997 } else {
4998 // Bug 1623565: DevTools tries to clean up defaultLoadFlags on
4999 // shutdown. Sorry DevTools, your DocShell is in another process.
5000 NS_WARNING("nsDocShell::SetDefaultLoadFlags called on Zombie DocShell")NS_DebugBreak(NS_DEBUG_WARNING, "nsDocShell::SetDefaultLoadFlags called on Zombie DocShell"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 5000)
;
5001 }
5002 return NS_OK;
5003}
5004
5005NS_IMETHODIMPnsresult
5006nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags) {
5007 *aDefaultLoadFlags = mBrowsingContext->GetDefaultLoadFlags();
5008 return NS_OK;
5009}
5010
5011NS_IMETHODIMPnsresult
5012nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel) {
5013 NS_ENSURE_ARG_POINTER(aFailedChannel)do { if ((__builtin_expect(!!(!(aFailedChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFailedChannel" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 5013); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
5014 Document* doc = GetDocument();
5015 if (!doc) {
5016 *aFailedChannel = nullptr;
5017 return NS_OK;
5018 }
5019 NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel())ns_if_addref(*aFailedChannel = doc->GetFailedChannel());
5020 return NS_OK;
5021}
5022
5023NS_IMETHODIMPnsresult
5024nsDocShell::SetVisibility(bool aVisibility) {
5025 // Show()/Hide() may change mDocumentViewer.
5026 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
5027 if (!viewer) {
5028 return NS_OK;
5029 }
5030 if (aVisibility) {
5031 viewer->Show();
5032 } else {
5033 viewer->Hide();
5034 }
5035
5036 return NS_OK;
5037}
5038
5039NS_IMETHODIMPnsresult
5040nsDocShell::GetEnabled(bool* aEnabled) {
5041 NS_ENSURE_ARG_POINTER(aEnabled)do { if ((__builtin_expect(!!(!(aEnabled)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEnabled" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 5041); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
5042 *aEnabled = true;
5043 return NS_ERROR_NOT_IMPLEMENTED;
5044}
5045
5046NS_IMETHODIMPnsresult
5047nsDocShell::SetEnabled(bool /*aEnabled*/) { return NS_ERROR_NOT_IMPLEMENTED; }
5048
5049NS_IMETHODIMPnsresult
5050nsDocShell::GetMainWidget(nsIWidget** aMainWidget) {
5051 // We don't create our own widget, so simply return the parent one.
5052 return GetParentWidget(aMainWidget);
5053}
5054
5055void nsDocShell::SetTitle(const nsAString& aTitle) {
5056 // Avoid unnecessary updates of the title if the URI and the title haven't
5057 // changed.
5058 if (mTitleValidForCurrentURI && mTitle == aTitle) {
5059 return;
5060 }
5061
5062 // Store local title
5063 mTitle = aTitle;
5064 mTitleValidForCurrentURI = true;
5065
5066 if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
5067 UpdateGlobalHistoryTitle(mCurrentURI);
5068 }
5069
5070 // Update SessionHistory with the document's title.
5071 if (mLoadType != LOAD_BYPASS_HISTORY && mLoadType != LOAD_ERROR_PAGE) {
5072 SetTitleOnHistoryEntry(true);
5073 }
5074}
5075
5076void nsDocShell::SetTitleOnHistoryEntry(bool aUpdateEntryInSessionHistory) {
5077 if (mActiveEntry && mBrowsingContext) {
5078 mActiveEntry->SetTitle(mTitle);
5079 if (aUpdateEntryInSessionHistory) {
5080 if (XRE_IsParentProcess()) {
5081 SessionHistoryEntry* entry =
5082 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
5083 if (entry) {
5084 entry->SetTitle(mTitle);
5085 }
5086 } else {
5087 (void)ContentChild::GetSingleton()->SendSessionHistoryEntryTitle(
5088 mBrowsingContext, mTitle);
5089 }
5090 }
5091 }
5092}
5093
5094nsPoint nsDocShell::GetCurScrollPos() {
5095 nsPoint scrollPos;
5096 if (ScrollContainerFrame* sf = GetRootScrollContainerFrame()) {
5097 scrollPos = sf->GetVisualViewportOffset();
5098 }
5099 return scrollPos;
5100}
5101
5102nsresult nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos,
5103 int32_t aCurVerticalPos) {
5104 ScrollContainerFrame* sf = GetRootScrollContainerFrame();
5105 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(sf)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "sf" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5105); return NS_ERROR_FAILURE; } } while (false)
;
5106
5107 ScrollMode scrollMode = sf->ScrollModeForScrollBehavior();
5108
5109 nsPoint targetPos(aCurHorizontalPos, aCurVerticalPos);
5110 sf->ScrollTo(targetPos, scrollMode);
5111
5112 // Set the visual viewport offset as well.
5113
5114 RefPtr<PresShell> presShell = GetPresShell();
5115 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 5115); return NS_ERROR_FAILURE
; } } while (false)
;
5116
5117 nsPresContext* presContext = presShell->GetPresContext();
5118 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(presContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presContext" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 5118); return
NS_ERROR_FAILURE; } } while (false)
;
5119
5120 // Only the root content document can have a distinct visual viewport offset.
5121 if (!presContext->IsRootContentDocumentCrossProcess()) {
5122 return NS_OK;
5123 }
5124
5125 // Not on a platform with a distinct visual viewport - don't bother setting
5126 // the visual viewport offset.
5127 if (!presShell->IsVisualViewportSizeSet()) {
5128 return NS_OK;
5129 }
5130
5131 presShell->ScrollToVisual(
5132 targetPos, layers::ScrollOffsetUpdateType::MainThread, scrollMode);
5133
5134 return NS_OK;
5135}
5136
5137void nsDocShell::RestoreScrollPositionFromTargetSessionHistoryInfo(
5138 SessionHistoryInfo* aTarget) {
5139 nscoord bx = 0;
5140 nscoord by = 0;
5141 if (aTarget) {
5142 aTarget->GetScrollPosition(&bx, &by);
5143 }
5144 SetCurScrollPosEx(bx, by);
5145}
5146
5147void nsDocShell::SetScrollbarPreference(mozilla::ScrollbarPreference aPref) {
5148 if (mScrollbarPref == aPref) {
5149 return;
5150 }
5151 mScrollbarPref = aPref;
5152 auto* ps = GetPresShell();
5153 if (!ps) {
5154 return;
5155 }
5156 nsIFrame* rootScrollContainerFrame = ps->GetRootScrollContainerFrame();
5157 if (!rootScrollContainerFrame) {
5158 return;
5159 }
5160 ps->FrameNeedsReflow(rootScrollContainerFrame,
5161 IntrinsicDirty::FrameAncestorsAndDescendants,
5162 NS_FRAME_IS_DIRTY);
5163}
5164
5165//*****************************************************************************
5166// nsDocShell::nsIRefreshURI
5167//*****************************************************************************
5168
5169NS_IMETHODIMPnsresult
5170nsDocShell::RefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
5171 uint32_t aDelay) {
5172 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 5172); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 5172); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5173
5174 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 5174); return NS_ERROR_INVALID_ARG
; } } while (false)
;
5175
5176 /* Check if Meta refresh/redirects are permitted. Some
5177 * embedded applications may not want to do this.
5178 * Must do this before sending out NOTIFY_REFRESH events
5179 * because listeners may have side effects (e.g. displaying a
5180 * button to manually trigger the refresh later).
5181 */
5182 bool allowRedirects = true;
5183 GetAllowMetaRedirects(&allowRedirects);
5184 if (!allowRedirects) {
5185 return NS_OK;
5186 }
5187
5188 // If any web progress listeners are listening for NOTIFY_REFRESH events,
5189 // give them a chance to block this refresh.
5190 bool sameURI;
5191 nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
5192 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5193 sameURI = false;
5194 }
5195 if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
5196 return NS_OK;
5197 }
5198
5199 nsCOMPtr<nsITimerCallback> refreshTimer =
5200 MakeRefPtr<nsRefreshTimer>(this, aURI, aPrincipal, aDelay);
5201
5202 BusyFlags busyFlags = GetBusyFlags();
5203
5204 if (!mRefreshURIList) {
5205 mRefreshURIList = nsArray::Create();
5206 }
5207
5208 if (busyFlags & BUSY_FLAGS_BUSY ||
5209 (!mBrowsingContext->IsActive() && mDisableMetaRefreshWhenInactive)) {
5210 // We don't want to create the timer right now. Instead queue up the
5211 // request and trigger the timer in EndPageLoad() or whenever we become
5212 // active.
5213 mRefreshURIList->AppendElement(refreshTimer);
5214 } else {
5215 // There is no page loading going on right now. Create the
5216 // timer and fire it right away.
5217 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
5218 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(win)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "win" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5218); return NS_ERROR_FAILURE; } } while (false)
;
5219
5220 nsCOMPtr<nsITimer> timer = MOZ_TRY(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewTimerWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT
)); if ((__builtin_expect(!!(mozTryVarTempResult.isErr()), 0)
)) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult
.unwrap(); })
5221 NS_NewTimerWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewTimerWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT
)); if ((__builtin_expect(!!(mozTryVarTempResult.isErr()), 0)
)) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult
.unwrap(); })
;
5222
5223 mRefreshURIList->AppendElement(timer); // owning timer ref
5224 }
5225 return NS_OK;
5226}
5227
5228nsresult nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI,
5229 nsIPrincipal* aPrincipal,
5230 uint32_t aDelay,
5231 nsITimer* aTimer) {
5232 MOZ_ASSERT(aTimer, "Must have a timer here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTimer)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aTimer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTimer" " (" "Must have a timer here"
")", "./../../../docshell/base/nsDocShell.cpp", 5232); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aTimer" ") (" "Must have a timer here" ")"
); do { MOZ_CrashSequence(__null, 5232); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5233
5234 // Remove aTimer from mRefreshURIList if needed
5235 if (mRefreshURIList) {
5236 uint32_t n = 0;
5237 mRefreshURIList->GetLength(&n);
5238
5239 for (uint32_t i = 0; i < n; ++i) {
5240 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
5241 if (timer == aTimer) {
5242 mRefreshURIList->RemoveElementAt(i);
5243 break;
5244 }
5245 }
5246 }
5247
5248 return ForceRefreshURI(aURI, aPrincipal, aDelay);
5249}
5250
5251NS_IMETHODIMPnsresult
5252nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
5253 uint32_t aDelay) {
5254 NS_ENSURE_ARG(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 5254); return NS_ERROR_INVALID_ARG
; } } while (false)
;
5255
5256 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(aURI);
5257 loadState->SetOriginalURI(mCurrentURI);
5258 loadState->SetResultPrincipalURI(aURI);
5259 loadState->SetResultPrincipalURIIsSome(true);
5260 loadState->SetKeepResultPrincipalURIIfSet(true);
5261 loadState->SetIsMetaRefresh(true);
5262
5263 RefPtr<Document> doc = GetDocument();
5264 NS_ENSURE_STATE(doc)do { if ((__builtin_expect(!!(!(doc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "doc" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5264); return NS_ERROR_UNEXPECTED; } } while (false)
;
5265
5266 // Set the triggering pricipal to aPrincipal if available, or current
5267 // document's principal otherwise.
5268 nsCOMPtr<nsIPrincipal> principal = aPrincipal;
5269 if (!principal) {
5270 principal = doc->NodePrincipal();
5271 }
5272 loadState->SetTriggeringPrincipal(principal);
5273 loadState->SetPolicyContainer(doc->GetPolicyContainer());
5274 loadState->SetHasValidUserGestureActivation(
5275 doc->HasValidTransientUserGestureActivation());
5276
5277 loadState->SetTextDirectiveUserActivation(
5278 doc->ConsumeTextDirectiveUserActivation() ||
5279 loadState->HasValidUserGestureActivation());
5280 loadState->SetTriggeringSandboxFlags(doc->GetSandboxFlags());
5281 loadState->SetTriggeringWindowId(doc->InnerWindowID());
5282 loadState->SetTriggeringClassificationFlags(doc->GetScriptTrackingFlags());
5283
5284 loadState->SetPrincipalIsExplicit(true);
5285
5286 /* Check if this META refresh causes a redirection
5287 * to another site.
5288 */
5289 bool equalUri = false;
5290 nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
5291
5292 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !equalUri && aDelay <= REFRESH_REDIRECT_TIMER15000) {
5293 /* It is a META refresh based redirection within the threshold time
5294 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
5295 * Pass a REPLACE flag to LoadURI().
5296 */
5297 loadState->SetLoadType(LOAD_REFRESH_REPLACE);
5298 } else {
5299 loadState->SetLoadType(LOAD_REFRESH);
5300 }
5301
5302 const bool sendReferrer = StaticPrefs::network_http_referer_sendFromRefresh();
5303 /* The document's referrer policy is needed instead of mReferrerInfo's
5304 * referrer policy.
5305 */
5306 const RefPtr referrerInfo = MakeRefPtr<ReferrerInfo>(*doc, sendReferrer);
5307 /* We mimic HTTP, which passes the original referrer. See step 3 of
5308 * <https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-by-fetching>.
5309 */
5310 loadState->SetReferrerInfo(referrerInfo);
5311
5312 loadState->SetLoadFlags(
5313 nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL);
5314 loadState->SetFirstParty(true);
5315
5316 /*
5317 * LoadURI(...) will cancel all refresh timers... This causes the
5318 * Timer and its refreshData instance to be released...
5319 */
5320 LoadURI(loadState, false);
5321
5322 return NS_OK;
5323}
5324
5325static const char16_t* SkipASCIIWhitespace(const char16_t* aStart,
5326 const char16_t* aEnd) {
5327 const char16_t* iter = aStart;
5328 while (iter != aEnd && mozilla::IsAsciiWhitespace(*iter)) {
5329 ++iter;
5330 }
5331 return iter;
5332}
5333
5334static std::tuple<const char16_t*, const char16_t*> ExtractURLString(
5335 const char16_t* aPosition, const char16_t* aEnd) {
5336 MOZ_ASSERT(aPosition != aEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPosition != aEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPosition != aEnd))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aPosition != aEnd"
, "./../../../docshell/base/nsDocShell.cpp", 5336); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPosition != aEnd" ")"); do { MOZ_CrashSequence
(__null, 5336); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5337
5338 // 1. Let urlString be the substring of input from the code point at
5339 // position to the end of the string.
5340 const char16_t* urlStart = aPosition;
5341 const char16_t* urlEnd = aEnd;
5342
5343 // 2. If the code point in input pointed to by position is U+0055 (U) or
5344 // U+0075 (u), then advance position to the next code point.
5345 // Otherwise, jump to the step labeled skip quotes.
5346 if (*aPosition == 'U' || *aPosition == 'u') {
5347 ++aPosition;
5348
5349 // 3. If the code point in input pointed to by position is U+0052 (R) or
5350 // U+0072 (r), then advance position to the next code point.
5351 // Otherwise, jump to the step labeled parse.
5352 if (aPosition == aEnd || (*aPosition != 'R' && *aPosition != 'r')) {
5353 return std::make_tuple(urlStart, urlEnd);
5354 }
5355
5356 ++aPosition;
5357
5358 // 4. If the code point in input pointed to by position is U+004C (L) or
5359 // U+006C (l), then advance position to the next code point.
5360 // Otherwise, jump to the step labeled parse.
5361 if (aPosition == aEnd || (*aPosition != 'L' && *aPosition != 'l')) {
5362 return std::make_tuple(urlStart, urlEnd);
5363 }
5364
5365 ++aPosition;
5366
5367 // 5. Skip ASCII whitespace within input given position.
5368 aPosition = SkipASCIIWhitespace(aPosition, aEnd);
5369
5370 // 6. If the code point in input pointed to by position is U+003D (=),
5371 // then advance position to the next code point. Otherwise, jump to
5372 // the step labeled parse.
5373 if (aPosition == aEnd || *aPosition != '=') {
5374 return std::make_tuple(urlStart, urlEnd);
5375 }
5376
5377 ++aPosition;
5378
5379 // 7. Skip ASCII whitespace within input given position.
5380 aPosition = SkipASCIIWhitespace(aPosition, aEnd);
5381 }
5382
5383 // 8. Skip quotes: If the code point in input pointed to by position is
5384 // U+0027 (') or U+0022 ("), then let quote be that code point, and
5385 // advance position to the next code point. Otherwise, let quote be
5386 // the empty string.
5387 Maybe<char> quote;
5388 if (aPosition != aEnd && (*aPosition == '\'' || *aPosition == '"')) {
5389 quote.emplace(*aPosition);
5390 ++aPosition;
5391 }
5392
5393 // 9. Set urlString to the substring of input from the code point at
5394 // position to the end of the string.
5395 urlStart = aPosition;
5396 urlEnd = aEnd;
5397
5398 // 10. If quote is not the empty string, and there is a code point in
5399 // urlString equal to quote, then truncate urlString at that code
5400 // point, so that it and all subsequent code points are removed.
5401 const char16_t* quotePos;
5402 if (quote.isSome() &&
5403 (quotePos = nsCharTraits<char16_t>::find(
5404 urlStart, std::distance(urlStart, aEnd), quote.value()))) {
5405 urlEnd = quotePos;
5406 }
5407
5408 return std::make_tuple(urlStart, urlEnd);
5409}
5410
5411void nsDocShell::SetupRefreshURIFromHeader(Document* aDocument,
5412 const nsAString& aHeader) {
5413 if (mIsBeingDestroyed) {
5414 return;
5415 }
5416
5417 const char16_t* position = aHeader.BeginReading();
5418 const char16_t* end = aHeader.EndReading();
5419
5420 // See https://html.spec.whatwg.org/#shared-declarative-refresh-steps.
5421
5422 // 3. Skip ASCII whitespace
5423 position = SkipASCIIWhitespace(position, end);
5424
5425 // 4. Let time be 0.
5426 CheckedInt<uint32_t> milliSeconds;
5427
5428 // 5. Collect a sequence of code points that are ASCII digits
5429 const char16_t* digitsStart = position;
5430 while (position != end && mozilla::IsAsciiDigit(*position)) {
5431 ++position;
5432 }
5433
5434 if (position == digitsStart) {
5435 // 6. If timeString is the empty string, then:
5436 // 1. If the code point in input pointed to by position is not U+002E
5437 // (.), then return.
5438 if (position == end || *position != '.') {
5439 return;
5440 }
5441 } else {
5442 // 7. Otherwise, set time to the result of parsing timeString using the
5443 // rules for parsing non-negative integers.
5444 nsContentUtils::ParseHTMLIntegerResultFlags result;
5445 uint32_t seconds =
5446 nsContentUtils::ParseHTMLInteger(digitsStart, position, &result);
5447 MOZ_ASSERT(!(result & nsContentUtils::eParseHTMLInteger_Negative))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & nsContentUtils::eParseHTMLInteger_Negative
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(result & nsContentUtils::eParseHTMLInteger_Negative
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(result & nsContentUtils::eParseHTMLInteger_Negative)"
, "./../../../docshell/base/nsDocShell.cpp", 5447); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & nsContentUtils::eParseHTMLInteger_Negative)"
")"); do { MOZ_CrashSequence(__null, 5447); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5448 if (result & nsContentUtils::eParseHTMLInteger_Error) {
5449 // The spec assumes no errors here (since we only pass ASCII digits in),
5450 // but we can still overflow, so this block should deal with that (and
5451 // only that).
5452 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
| nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::
eParseHTMLInteger_ErrorOverflow)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(result & ~(nsContentUtils
::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error
| nsContentUtils::eParseHTMLInteger_ErrorOverflow))))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
, "./../../../docshell/base/nsDocShell.cpp", 5455); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
")"); do { MOZ_CrashSequence(__null, 5455); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5453 !(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput |do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
| nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::
eParseHTMLInteger_ErrorOverflow)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(result & ~(nsContentUtils
::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error
| nsContentUtils::eParseHTMLInteger_ErrorOverflow))))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
, "./../../../docshell/base/nsDocShell.cpp", 5455); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
")"); do { MOZ_CrashSequence(__null, 5455); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5454 nsContentUtils::eParseHTMLInteger_Error |do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
| nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::
eParseHTMLInteger_ErrorOverflow)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(result & ~(nsContentUtils
::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error
| nsContentUtils::eParseHTMLInteger_ErrorOverflow))))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
, "./../../../docshell/base/nsDocShell.cpp", 5455); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
")"); do { MOZ_CrashSequence(__null, 5455); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5455 nsContentUtils::eParseHTMLInteger_ErrorOverflow)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
| nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::
eParseHTMLInteger_ErrorOverflow)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(result & ~(nsContentUtils
::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error
| nsContentUtils::eParseHTMLInteger_ErrorOverflow))))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
, "./../../../docshell/base/nsDocShell.cpp", 5455); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & ~(nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput | nsContentUtils::eParseHTMLInteger_Error | nsContentUtils::eParseHTMLInteger_ErrorOverflow))"
")"); do { MOZ_CrashSequence(__null, 5455); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5456 return;
5457 }
5458 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput)"
, "./../../../docshell/base/nsDocShell.cpp", 5459); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput)"
")"); do { MOZ_CrashSequence(__null, 5459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5459 !(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput)"
, "./../../../docshell/base/nsDocShell.cpp", 5459); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput)"
")"); do { MOZ_CrashSequence(__null, 5459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5460
5461 milliSeconds = seconds;
5462 milliSeconds *= 1000;
5463 if (!milliSeconds.isValid()) {
5464 return;
5465 }
5466 }
5467
5468 // 8. Collect a sequence of code points that are ASCII digits and U+002E FULL
5469 // STOP characters (.) from input given position. Ignore any collected
5470 // characters.
5471 while (position != end &&
5472 (mozilla::IsAsciiDigit(*position) || *position == '.')) {
5473 ++position;
5474 }
5475
5476 // 9. Let urlRecord be document's URL.
5477 nsCOMPtr<nsIURI> urlRecord(aDocument->GetDocumentURI());
5478
5479 // 10. If position is not past the end of input
5480 if (position != end) {
5481 // 1. If the code point in input pointed to by position is not U+003B (;),
5482 // U+002C (,), or ASCII whitespace, then return.
5483 if (*position != ';' && *position != ',' &&
5484 !mozilla::IsAsciiWhitespace(*position)) {
5485 return;
5486 }
5487
5488 // 2. Skip ASCII whitespace within input given position.
5489 position = SkipASCIIWhitespace(position, end);
5490
5491 // 3. If the code point in input pointed to by position is U+003B (;) or
5492 // U+002C (,), then advance position to the next code point.
5493 if (position != end && (*position == ';' || *position == ',')) {
5494 ++position;
5495
5496 // 4. Skip ASCII whitespace within input given position.
5497 position = SkipASCIIWhitespace(position, end);
5498 }
5499
5500 // 11. If position is not past the end of input, then:
5501 if (position != end) {
5502 const char16_t* urlStart;
5503 const char16_t* urlEnd;
5504
5505 // 1-10. See ExtractURLString.
5506 std::tie(urlStart, urlEnd) = ExtractURLString(position, end);
5507
5508 // 11. Parse: Parse urlString relative to document. If that fails, return.
5509 // Otherwise, set urlRecord to the resulting URL record.
5510 nsresult rv =
5511 NS_NewURI(getter_AddRefs(urlRecord),
5512 Substring(urlStart, std::distance(urlStart, urlEnd)),
5513 /* charset = */ nullptr, aDocument->GetDocBaseURI());
5514 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5514); return; } } while (false)
;
5515 }
5516 }
5517
5518 nsIPrincipal* principal = aDocument->NodePrincipal();
5519 nsCOMPtr<nsIScriptSecurityManager> securityManager =
5520 nsContentUtils::GetSecurityManager();
5521 nsresult rv = securityManager->CheckLoadURIWithPrincipal(
5522 principal, urlRecord,
5523 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT,
5524 aDocument->InnerWindowID());
5525 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5525); return; } } while (false)
;
5526
5527 bool isjs = true;
5528 rv = NS_URIChainHasFlags(
5529 urlRecord, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
5530 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5530); return; } } while (false)
;
5531
5532 if (isjs) {
5533 return;
5534 }
5535
5536 RefreshURI(urlRecord, principal, milliSeconds.value());
5537}
5538
5539static void DoCancelRefreshURITimers(nsIMutableArray* aTimerList) {
5540 if (!aTimerList) {
5541 return;
5542 }
5543
5544 uint32_t n = 0;
5545 aTimerList->GetLength(&n);
5546
5547 while (n) {
5548 nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
5549
5550 aTimerList->RemoveElementAt(n); // bye bye owning timer ref
5551
5552 if (timer) {
5553 timer->Cancel();
5554 }
5555 }
5556}
5557
5558NS_IMETHODIMPnsresult
5559nsDocShell::CancelRefreshURITimers() {
5560 DoCancelRefreshURITimers(mRefreshURIList);
5561 DoCancelRefreshURITimers(mSavedRefreshURIList);
5562 DoCancelRefreshURITimers(mBFCachedRefreshURIList);
5563 mRefreshURIList = nullptr;
5564 mSavedRefreshURIList = nullptr;
5565 mBFCachedRefreshURIList = nullptr;
5566
5567 return NS_OK;
5568}
5569
5570NS_IMETHODIMPnsresult
5571nsDocShell::GetRefreshPending(bool* aResult) {
5572 if (!mRefreshURIList) {
5573 *aResult = false;
5574 return NS_OK;
5575 }
5576
5577 uint32_t count;
5578 nsresult rv = mRefreshURIList->GetLength(&count);
5579 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5580 *aResult = (count != 0);
5581 }
5582 return rv;
5583}
5584
5585void nsDocShell::RefreshURIToQueue() {
5586 if (mRefreshURIList) {
5587 uint32_t n = 0;
5588 mRefreshURIList->GetLength(&n);
5589
5590 for (uint32_t i = 0; i < n; ++i) {
5591 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
5592 if (!timer) {
5593 continue; // this must be a nsRefreshURI already
5594 }
5595
5596 // Replace this timer object with a nsRefreshTimer object.
5597 nsCOMPtr<nsITimerCallback> callback;
5598 timer->GetCallback(getter_AddRefs(callback));
5599
5600 timer->Cancel();
5601
5602 mRefreshURIList->ReplaceElementAt(callback, i);
5603 }
5604 }
5605}
5606
5607NS_IMETHODIMPnsresult
5608nsDocShell::SuspendRefreshURIs() {
5609 RefreshURIToQueue();
5610
5611 // Suspend refresh URIs for our child shells as well.
5612 for (auto* child : mChildList.ForwardRange()) {
5613 nsCOMPtr<nsIDocShell> shell = do_QueryObject(child);
5614 if (shell) {
5615 shell->SuspendRefreshURIs();
5616 }
5617 }
5618
5619 return NS_OK;
5620}
5621
5622NS_IMETHODIMPnsresult
5623nsDocShell::ResumeRefreshURIs() {
5624 RefreshURIFromQueue();
5625
5626 // Resume refresh URIs for our child shells as well.
5627 for (auto* child : mChildList.ForwardRange()) {
5628 nsCOMPtr<nsIDocShell> shell = do_QueryObject(child);
5629 if (shell) {
5630 shell->ResumeRefreshURIs();
5631 }
5632 }
5633
5634 return NS_OK;
5635}
5636
5637nsresult nsDocShell::RefreshURIFromQueue() {
5638 if (!mRefreshURIList) {
5639 return NS_OK;
5640 }
5641 uint32_t n = 0;
5642 mRefreshURIList->GetLength(&n);
5643
5644 while (n) {
5645 nsCOMPtr<nsITimerCallback> refreshInfo =
5646 do_QueryElementAt(mRefreshURIList, --n);
5647
5648 if (refreshInfo) {
5649 // This is the nsRefreshTimer object, waiting to be
5650 // setup in a timer object and fired.
5651 // Create the timer and trigger it.
5652 uint32_t delay = static_cast<nsRefreshTimer*>(
5653 static_cast<nsITimerCallback*>(refreshInfo))
5654 ->GetDelay();
5655 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
5656 if (win) {
5657 nsCOMPtr<nsITimer> timer;
5658 NS_NewTimerWithCallback(getter_AddRefs(timer), refreshInfo, delay,
5659 nsITimer::TYPE_ONE_SHOT);
5660
5661 if (timer) {
5662 // Replace the nsRefreshTimer element in the queue with
5663 // its corresponding timer object, so that in case another
5664 // load comes through before the timer can go off, the timer will
5665 // get cancelled in CancelRefreshURITimer()
5666 mRefreshURIList->ReplaceElementAt(timer, n);
5667 }
5668 }
5669 }
5670 }
5671
5672 return NS_OK;
5673}
5674
5675static bool IsFollowupPartOfMultipart(nsIRequest* aRequest) {
5676 nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(aRequest);
5677 bool firstPart = false;
5678 return multiPartChannel &&
5679 NS_SUCCEEDED(multiPartChannel->GetIsFirstPart(&firstPart))((bool)(__builtin_expect(!!(!NS_FAILED_impl(multiPartChannel->
GetIsFirstPart(&firstPart))), 1)))
&&
5680 !firstPart;
5681}
5682
5683nsresult nsDocShell::Embed(nsIDocumentViewer* aDocumentViewer,
5684 WindowGlobalChild* aWindowActor,
5685 bool aIsTransientAboutBlank, nsIRequest* aRequest,
5686 nsIURI* aPreviousURI) {
5687 // Save the LayoutHistoryState of the previous document, before
5688 // setting up new document
5689 PersistLayoutHistoryState();
5690
5691 nsresult rv = SetupNewViewer(aDocumentViewer, aWindowActor);
5692 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 5692); return rv; } } while (false)
;
5693
5694 // XXX What if SetupNewViewer fails?
5695 if (mLoadingEntry) {
5696 // Set history.state
5697 SetDocCurrentStateObj(mLoadingEntry ? &mLoadingEntry->mInfo : nullptr);
5698 }
5699
5700 if (!aIsTransientAboutBlank && !IsFollowupPartOfMultipart(aRequest)) {
5701 bool expired = false;
5702 uint32_t cacheKey = 0;
5703 nsCOMPtr<nsICacheInfoChannel> cacheChannel = do_QueryInterface(aRequest);
5704 if (cacheChannel) {
5705 // Check if the page has expired from cache
5706 uint32_t expTime = 0;
5707 cacheChannel->GetCacheTokenExpirationTime(&expTime);
5708 uint32_t now = PRTimeToSeconds(PR_Now());
5709 if (expTime <= now) {
5710 expired = true;
5711 }
5712
5713 // The checks for updating cache key are similar to the old session
5714 // history in OnNewURI. Try to update the cache key if
5715 // - we should update session history and aren't doing a session
5716 // history load.
5717 // - we're doing a forced reload.
5718 if (((!mLoadingEntry || !mLoadingEntry->mLoadIsFromSessionHistory) &&
5719 mBrowsingContext->ShouldUpdateSessionHistory(mLoadType)) ||
5720 IsForceReloadType(mLoadType)) {
5721 cacheChannel->GetCacheKey(&cacheKey);
5722 }
5723 }
5724
5725 MOZ_LOG(gSHLog, LogLevel::Debug, ("document %p Embed", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "document %p Embed", this); } } while (0)
;
5726 MoveLoadingToActiveEntry(expired, cacheKey, aPreviousURI);
5727 }
5728
5729 bool updateHistory = true;
5730
5731 // Determine if this type of load should update history
5732 switch (mLoadType) {
5733 case LOAD_NORMAL_REPLACE:
5734 case LOAD_REFRESH_REPLACE:
5735 case LOAD_STOP_CONTENT_AND_REPLACE:
5736 case LOAD_RELOAD_BYPASS_CACHE:
5737 case LOAD_RELOAD_BYPASS_PROXY:
5738 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
5739 case LOAD_REPLACE_BYPASS_CACHE:
5740 updateHistory = false;
5741 break;
5742 default:
5743 break;
5744 }
5745
5746 if (!updateHistory) {
5747 SetLayoutHistoryState(nullptr);
5748 }
5749
5750 return NS_OK;
5751}
5752
5753//*****************************************************************************
5754// nsDocShell::nsIWebProgressListener
5755//*****************************************************************************
5756
5757NS_IMETHODIMPnsresult
5758nsDocShell::OnProgressChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
5759 int32_t aCurSelfProgress, int32_t aMaxSelfProgress,
5760 int32_t aCurTotalProgress,
5761 int32_t aMaxTotalProgress) {
5762 // Listeners in the parent process only care about aCurTotalProgress and
5763 // aMaxTotalProgress, which is internally managed by nsDocLoader. Because of
5764 // this, we don't send progress notifications except when they are recorded by
5765 // the toplevel context, and only report them on the toplevel context in the
5766 // parent process.
5767 //
5768 // FIXME: We should track progress for out-of-process iframes and manage total
5769 // progress in the parent process for more accurate notifications.
5770 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsTop()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mBrowsingContext->IsTop()" " (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")", "./../../../docshell/base/nsDocShell.cpp", 5772); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBrowsingContext->IsTop()" ") (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")"); do { MOZ_CrashSequence(__null, 5772); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5771 mBrowsingContext->IsTop(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsTop()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mBrowsingContext->IsTop()" " (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")", "./../../../docshell/base/nsDocShell.cpp", 5772); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBrowsingContext->IsTop()" ") (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")"); do { MOZ_CrashSequence(__null, 5772); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5772 "notification excluded in AddProgressListener(...) for non-toplevel BCs")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsTop()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mBrowsingContext->IsTop()" " (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")", "./../../../docshell/base/nsDocShell.cpp", 5772); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBrowsingContext->IsTop()" ") (" "notification excluded in AddProgressListener(...) for non-toplevel BCs"
")"); do { MOZ_CrashSequence(__null, 5772); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5773
5774 if (nsCOMPtr<nsIWebProgressListener> listener = BCWebProgressListener()) {
5775 listener->OnProgressChange(aProgress, aRequest, aCurSelfProgress,
5776 aMaxSelfProgress, aCurTotalProgress,
5777 aMaxTotalProgress);
5778 }
5779
5780 return NS_OK;
5781}
5782
5783NS_IMETHODIMPnsresult
5784nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
5785 uint32_t aStateFlags, nsresult aStatus) {
5786 // If we're receiving a notification on ourselves which has at least one of
5787 // the state change flags in kStateChangeFlagFilter, also notify WebProgress
5788 // on BrowsingContextWebProgress, potentially over IPC.
5789 //
5790 // NOTE: We don't notify for bubbled notifications (aProgress != this), as
5791 // BrowsingContextWebProgress independently handles event bubbling in the
5792 // parent process.
5793 //
5794 // NOTE: We don't filter notifications when registering our listener, as
5795 // `STATE_IS_REDIRECTED_DOCUMENT` cannot be filtered for at registration time.
5796 static constexpr uint32_t kStateChangeFlagFilter =
5797 STATE_IS_NETWORK | STATE_IS_DOCUMENT | STATE_IS_WINDOW |
5798 STATE_IS_REDIRECTED_DOCUMENT;
5799 if (aProgress == this && (aStateFlags & kStateChangeFlagFilter) != 0) {
5800 if (nsCOMPtr<nsIWebProgressListener> listener = BCWebProgressListener()) {
5801 listener->OnStateChange(aProgress, aRequest, aStateFlags, aStatus);
5802 }
5803 }
5804
5805 if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
5806 // Save timing statistics.
5807 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
5808 nsCOMPtr<nsIURI> uri;
5809 channel->GetURI(getter_AddRefs(uri));
5810 nsAutoCString aURI;
5811 uri->GetAsciiSpec(aURI);
5812
5813 if (this == aProgress) {
5814 (void)MaybeInitTiming();
5815 mTiming->NotifyFetchStart(uri,
5816 ConvertLoadTypeToNavigationType(mLoadType));
5817 // If we are starting a DocumentChannel, we need to pass the timing
5818 // statistics so that should a process switch occur, the starting type can
5819 // be passed to the new DocShell running in the other content process.
5820 if (RefPtr<DocumentChannel> docChannel = do_QueryObject(aRequest)) {
5821 docChannel->SetNavigationTiming(mTiming);
5822 }
5823 }
5824
5825 // Page has begun to load
5826 mBusyFlags = (BusyFlags)(BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD);
5827
5828 if ((aStateFlags & STATE_RESTORING) == 0) {
5829 if (SessionStorePlatformCollection()) {
5830 if (IsForceReloadType(mLoadType)) {
5831 if (WindowContext* windowContext =
5832 mBrowsingContext->GetCurrentWindowContext()) {
5833 SessionStoreChild::From(windowContext->GetWindowGlobalChild())
5834 ->ResetSessionStore(mBrowsingContext,
5835 mBrowsingContext->GetSessionStoreEpoch());
5836 }
5837 }
5838 }
5839 }
5840 } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
5841 // Page is loading
5842 mBusyFlags = (BusyFlags)(BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING);
5843 } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
5844 // Page has finished loading
5845 mBusyFlags = BUSY_FLAGS_NONE;
5846 }
5847
5848 if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
5849 nsCOMPtr<nsIWebProgress> webProgress =
5850 do_QueryInterface(GetAsSupports(this));
5851 // Is the document stop notification for this document?
5852 if (aProgress == webProgress.get()) {
5853 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
5854 EndPageLoad(channel, aStatus);
5855 }
5856 }
5857 // note that redirect state changes will go through here as well, but it
5858 // is better to handle those in OnRedirectStateChange where more
5859 // information is available.
5860 return NS_OK;
5861}
5862
5863NS_IMETHODIMPnsresult
5864nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
5865 nsIURI* aURI, uint32_t aFlags) {
5866 // If we're receiving a notification on ourselves, also notify WebProgress on
5867 // BrowsingContextWebProgress, potentially over IPC.
5868 //
5869 // NOTE: We don't notify for bubbled notifications (aProgress != this), as
5870 // BrowsingContextWebProgress independently handles event bubbling in the
5871 // parent process.
5872 //
5873 // NOTE: Tests depend on this happening before UpdateSecurityState.
5874 if (aProgress == this) {
5875 if (nsCOMPtr<nsIWebProgressListener> listener = BCWebProgressListener()) {
5876 listener->OnLocationChange(aProgress, aRequest, aURI, aFlags);
5877 }
5878 }
5879
5880 // Since we've now changed Documents, notify the BrowsingContext that we've
5881 // changed. Ideally we'd just let the BrowsingContext do this when it
5882 // changes the current window global, but that happens before this and we
5883 // have a lot of tests that depend on the specific ordering of messages.
5884 bool isTopLevel = false;
5885 if (XRE_IsParentProcess() &&
5886 !(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT) &&
5887 NS_SUCCEEDED(aProgress->GetIsTopLevel(&isTopLevel))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aProgress->GetIsTopLevel
(&isTopLevel))), 1)))
&& isTopLevel) {
5888 GetBrowsingContext()->Canonical()->UpdateSecurityState();
5889 }
5890 return NS_OK;
5891}
5892
5893void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
5894 nsIChannel* aNewChannel,
5895 uint32_t aRedirectFlags,
5896 uint32_t aStateFlags) {
5897 NS_ASSERTION(aStateFlags & STATE_REDIRECTING,do { if (!(aStateFlags & STATE_REDIRECTING)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Calling OnRedirectStateChange when there is no redirect"
, "aStateFlags & STATE_REDIRECTING", "./../../../docshell/base/nsDocShell.cpp"
, 5898); MOZ_PretendNoReturn(); } } while (0)
5898 "Calling OnRedirectStateChange when there is no redirect")do { if (!(aStateFlags & STATE_REDIRECTING)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Calling OnRedirectStateChange when there is no redirect"
, "aStateFlags & STATE_REDIRECTING", "./../../../docshell/base/nsDocShell.cpp"
, 5898); MOZ_PretendNoReturn(); } } while (0)
;
5899
5900 if (!(aStateFlags & STATE_IS_DOCUMENT)) {
5901 return; // not a toplevel document
5902 }
5903
5904 nsCOMPtr<nsIURI> oldURI, newURI;
5905 aOldChannel->GetURI(getter_AddRefs(oldURI));
5906 aNewChannel->GetURI(getter_AddRefs(newURI));
5907 if (!oldURI || !newURI) {
5908 return;
5909 }
5910
5911 // DocumentChannel adds redirect chain to global history in the parent
5912 // process. The redirect chain can't be queried from the content process, so
5913 // there's no need to update global history here.
5914 RefPtr<DocumentChannel> docChannel = do_QueryObject(aOldChannel);
5915 if (!docChannel) {
5916 // Below a URI visit is saved (see AddURIVisit method doc).
5917 // The visit chain looks something like:
5918 // ...
5919 // Site N - 1
5920 // => Site N
5921 // (redirect to =>) Site N + 1 (we are here!)
5922
5923 // Get N - 1 and transition type
5924 nsCOMPtr<nsIURI> previousURI;
5925 uint32_t previousFlags = 0;
5926 ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
5927
5928 if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
5929 net::ChannelIsPost(aOldChannel)) {
5930 // 1. Internal redirects are ignored because they are specific to the
5931 // channel implementation.
5932 // 2. POSTs are not saved by global history.
5933 //
5934 // Regardless, we need to propagate the previous visit to the new
5935 // channel.
5936 SaveLastVisit(aNewChannel, previousURI, previousFlags);
5937 } else {
5938 // Get the HTTP response code, if available.
5939 uint32_t responseStatus = 0;
5940 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
5941 if (httpChannel) {
5942 (void)httpChannel->GetResponseStatus(&responseStatus);
5943 }
5944
5945 // Add visit N -1 => N
5946 AddURIVisit(oldURI, previousURI, previousFlags, responseStatus);
5947
5948 // Since N + 1 could be the final destination, we will not save N => N + 1
5949 // here. OnNewURI will do that, so we will cache it.
5950 SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
5951 }
5952 }
5953
5954 if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
5955 mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
5956 mLoadType = LOAD_NORMAL_REPLACE;
5957 }
5958}
5959
5960NS_IMETHODIMPnsresult
5961nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
5962 nsresult aStatus, const char16_t* aMessage) {
5963 // If we're receiving a notification on ourselves, also notify WebProgress on
5964 // BrowsingContextWebProgress, potentially over IPC.
5965 //
5966 // NOTE: We don't notify for bubbled notifications (aWebProgress != this), as
5967 // BrowsingContextWebProgress independently handles event bubbling in the
5968 // parent process.
5969 if (aWebProgress == this) {
5970 if (nsCOMPtr<nsIWebProgressListener> listener = BCWebProgressListener()) {
5971 listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
5972 }
5973 }
5974
5975 return NS_OK;
5976}
5977
5978NS_IMETHODIMPnsresult
5979nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
5980 uint32_t aState) {
5981 // If we're receiving a notification on ourselves, also notify WebProgress on
5982 // BrowsingContextWebProgress, potentially over IPC.
5983 //
5984 // NOTE: We don't notify for bubbled notifications (aWebProgress != this), as
5985 // BrowsingContextWebProgress independently handles event bubbling in the
5986 // parent process.
5987 if (aWebProgress == this) {
5988 if (nsCOMPtr<nsIWebProgressListener> listener = BCWebProgressListener()) {
5989 listener->OnSecurityChange(aWebProgress, aRequest, aState);
5990 }
5991 }
5992
5993 return NS_OK;
5994}
5995
5996NS_IMETHODIMPnsresult
5997nsDocShell::OnContentBlockingEvent(nsIWebProgress* /*aWebProgress*/,
5998 nsIRequest* /*aRequest*/,
5999 uint32_t /*aEvent*/) {
6000 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"notification excluded in AddProgressListener(...)" ")", "./../../../docshell/base/nsDocShell.cpp"
, 6000); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "notification excluded in AddProgressListener(...)"
")"); do { MOZ_CrashSequence(__null, 6000); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6001 return NS_OK;
6002}
6003
6004already_AddRefed<nsIWebProgressListener> nsDocShell::BCWebProgressListener() {
6005 // If this BrowsingContext has been replaced, we should discard any
6006 // notifications which would otherwise be delivered in-process.
6007 if (XRE_IsParentProcess() && mBrowsingContext->Canonical()->IsReplaced()) {
6008 return nullptr;
6009 }
6010
6011 // Create a nsBrowserStatusFilter to perform some throttling of
6012 // OnProgressChange and OnStatusChange notifications which are delivered to
6013 // our BCWebProgress listener. This reduces the amount of IPC traffic.
6014 if (!mBCWebProgressStatusFilter && !mIsBeingDestroyed) {
6015 nsCOMPtr<nsIWebProgressListener> innerListener;
6016 if (XRE_IsParentProcess()) {
6017 innerListener = mBrowsingContext->Canonical()->GetWebProgress();
6018 } else {
6019 innerListener = do_QueryReferent(mBrowserChild);
6020 }
6021 if (innerListener) {
6022 // NOTE: We need to disable filtering of StateChange events here, as
6023 // listeners on BrowsingContextWebProgress may depend on state change
6024 // notifications are otherwise filtered.
6025 // NOTE: Unlike other nsIWebProgress types, nsBrowserStatusFilter holds a
6026 // strong cycle-collected reference to the inner listener.
6027 mBCWebProgressStatusFilter = MakeRefPtr<nsBrowserStatusFilter>(
6028 /* aDisableStateChangeFilters */ true);
6029 mBCWebProgressStatusFilter->AddProgressListener(
6030 innerListener, nsIWebProgress::NOTIFY_ALL);
6031 }
6032 }
6033
6034 return do_AddRef(mBCWebProgressStatusFilter);
6035}
6036
6037already_AddRefed<nsIURIFixupInfo> nsDocShell::KeywordToURI(
6038 const nsACString& aKeyword, bool aIsPrivateContext) {
6039 nsCOMPtr<nsIURIFixupInfo> info;
6040 if (!XRE_IsContentProcess()) {
6041 nsCOMPtr<nsIURIFixup> uriFixup = components::URIFixup::Service();
6042 if (uriFixup) {
6043 uriFixup->KeywordToURI(aKeyword, aIsPrivateContext, getter_AddRefs(info));
6044 }
6045 }
6046 return info.forget();
6047}
6048
6049/* static */
6050already_AddRefed<nsIURI> nsDocShell::MaybeFixBadCertDomainErrorURI(
6051 nsIChannel* aChannel, nsIURI* aUrl) {
6052 if (!aChannel) {
6053 return nullptr;
6054 }
6055
6056 nsresult rv = NS_OK;
6057 nsAutoCString host;
6058 rv = aUrl->GetAsciiHost(host);
6059 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 6059)
) {
6060 return nullptr;
6061 }
6062
6063 // Return if fixup enable pref is turned off.
6064 if (!mozilla::StaticPrefs::security_bad_cert_domain_error_url_fix_enabled()) {
6065 return nullptr;
6066 }
6067
6068 // Return if scheme is not HTTPS.
6069 if (!aUrl->SchemeIs("https")) {
6070 return nullptr;
6071 }
6072
6073 nsCOMPtr<nsILoadInfo> info = aChannel->LoadInfo();
6074 if (!info) {
6075 return nullptr;
6076 }
6077
6078 // Skip doing the fixup if our channel was redirected, because we
6079 // shouldn't be guessing things about the post-redirect URI.
6080 if (!info->RedirectChain().IsEmpty()) {
6081 return nullptr;
6082 }
6083
6084 int32_t port = 0;
6085 rv = aUrl->GetPort(&port);
6086 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 6086)
) {
6087 return nullptr;
6088 }
6089
6090 // Don't fix up hosts with ports.
6091 if (port != -1) {
6092 return nullptr;
6093 }
6094
6095 // Don't fix up localhost url.
6096 if (host == "localhost") {
6097 return nullptr;
6098 }
6099
6100 // Don't fix up hostnames with IP address.
6101 if (net_IsValidIPv4Addr(host) || net_IsValidIPv6Addr(host)) {
6102 return nullptr;
6103 }
6104
6105 nsAutoCString userPass;
6106 rv = aUrl->GetUserPass(userPass);
6107 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 6107)
) {
6108 return nullptr;
6109 }
6110
6111 // Security - URLs with user / password info should NOT be modified.
6112 if (!userPass.IsEmpty()) {
6113 return nullptr;
6114 }
6115
6116 nsCOMPtr<nsITransportSecurityInfo> tsi;
6117 rv = aChannel->GetSecurityInfo(getter_AddRefs(tsi));
6118 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 6118)
) {
6119 return nullptr;
6120 }
6121
6122 if (NS_WARN_IF(!tsi)NS_warn_if_impl(!tsi, "!tsi", "./../../../docshell/base/nsDocShell.cpp"
, 6122)
) {
6123 return nullptr;
6124 }
6125
6126 nsCOMPtr<nsIX509Cert> cert;
6127 rv = tsi->GetServerCert(getter_AddRefs(cert));
6128 if (NS_WARN_IF(NS_FAILED(rv) || !cert)NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))) || !cert, "NS_FAILED(rv) || !cert", "./../../../docshell/base/nsDocShell.cpp"
, 6128)
) {
6129 return nullptr;
6130 }
6131
6132 nsTArray<uint8_t> certBytes;
6133 rv = cert->GetRawDER(certBytes);
6134 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
6135 return nullptr;
6136 }
6137
6138 mozilla::pkix::Input serverCertInput;
6139 mozilla::pkix::Result result =
6140 serverCertInput.Init(certBytes.Elements(), certBytes.Length());
6141 if (result != mozilla::pkix::Success) {
6142 return nullptr;
6143 }
6144
6145 constexpr auto wwwPrefix = "www."_ns;
6146 nsAutoCString newHost;
6147 if (StringBeginsWith(host, wwwPrefix)) {
6148 // Try www.example.com -> example.com
6149 newHost.Assign(Substring(host, wwwPrefix.Length()));
6150 } else {
6151 // Try example.com -> www.example.com
6152 newHost.Assign(wwwPrefix);
6153 newHost.Append(host);
6154 }
6155
6156 mozilla::pkix::Input newHostInput;
6157 result = newHostInput.Init(
6158 BitwiseCast<const uint8_t*, const char*>(newHost.BeginReading()),
6159 newHost.Length());
6160 if (result != mozilla::pkix::Success) {
6161 return nullptr;
6162 }
6163
6164 // Because certificate verification returned Result::ERROR_BAD_CERT_DOMAIN /
6165 // SSL_ERROR_BAD_CERT_DOMAIN, a chain was built and we know whether or not
6166 // the root was a built-in.
6167 bool rootIsBuiltIn;
6168 if (NS_FAILED(tsi->GetIsBuiltCertChainRootBuiltInRoot(&rootIsBuiltIn))((bool)(__builtin_expect(!!(NS_FAILED_impl(tsi->GetIsBuiltCertChainRootBuiltInRoot
(&rootIsBuiltIn))), 0)))
) {
6169 return nullptr;
6170 }
6171 mozilla::psm::SkipInvalidSANsForNonBuiltInRootsPolicy nameMatchingPolicy(
6172 rootIsBuiltIn);
6173
6174 // Check if the certificate is valid for the new hostname.
6175 result = mozilla::pkix::CheckCertHostname(serverCertInput, newHostInput,
6176 nameMatchingPolicy);
6177 if (result != mozilla::pkix::Success) {
6178 return nullptr;
6179 }
6180
6181 nsCOMPtr<nsIURI> newURI;
6182 (void)NS_MutateURI(aUrl).SetHost(newHost).Finalize(getter_AddRefs(newURI));
6183
6184 return newURI.forget();
6185}
6186
6187/* static */
6188already_AddRefed<nsIURI> nsDocShell::AttemptURIFixup(
6189 nsIChannel* aChannel, nsresult aStatus,
6190 const mozilla::Maybe<nsCString>& aOriginalURIString, uint32_t aLoadType,
6191 bool aIsTopFrame, bool aAllowKeywordFixup, bool aUsePrivateBrowsing,
6192 bool aNotifyKeywordSearchLoading, nsIInputStream** aNewPostData,
6193 nsILoadInfo::SchemelessInputType* outSchemelessInput) {
6194 if (aStatus != NS_ERROR_UNKNOWN_HOST && aStatus != NS_ERROR_NET_RESET &&
6195 aStatus != NS_ERROR_CONNECTION_REFUSED &&
6196 aStatus !=
6197 mozilla::psm::GetXPCOMFromNSSError(SSL_ERROR_BAD_CERT_DOMAIN)) {
6198 return nullptr;
6199 }
6200
6201 if (!(aLoadType == LOAD_NORMAL && aIsTopFrame) && !aAllowKeywordFixup) {
6202 return nullptr;
6203 }
6204
6205 nsCOMPtr<nsIURI> url;
6206 nsresult rv = aChannel->GetURI(getter_AddRefs(url));
6207 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
6208 return nullptr;
6209 }
6210
6211 //
6212 // Try and make an alternative URI from the old one
6213 //
6214 nsCOMPtr<nsIURI> newURI;
6215 nsCOMPtr<nsIInputStream> newPostData;
6216
6217 nsAutoCString oldSpec;
6218 url->GetSpec(oldSpec);
6219
6220 //
6221 // First try keyword fixup
6222 //
6223 nsCOMPtr<nsIURIFixupInfo> keywordInfo;
6224 if (aStatus == NS_ERROR_UNKNOWN_HOST && aAllowKeywordFixup) {
6225 // we should only perform a keyword search under the following
6226 // conditions:
6227 // (0) Pref keyword.enabled is true
6228 // (1) the url scheme is http (or https)
6229 // (2) the url does not have a protocol scheme
6230 // If we don't enforce such a policy, then we end up doing
6231 // keyword searchs on urls we don't intend like imap, file,
6232 // mailbox, etc. This could lead to a security problem where we
6233 // send data to the keyword server that we shouldn't be.
6234 // Someone needs to clean up keywords in general so we can
6235 // determine on a per url basis if we want keywords
6236 // enabled...this is just a bandaid...
6237 if (Preferences::GetBool("keyword.enabled", false) &&
6238 net::SchemeIsHttpOrHttps(url)) {
6239 bool attemptFixup = false;
6240 nsAutoCString host;
6241 (void)url->GetHost(host);
6242 if (host.FindChar('.') == kNotFound) {
6243 attemptFixup = true;
6244 } else {
6245 // For domains with dots, we check the public suffix validity.
6246 nsCOMPtr<nsIEffectiveTLDService> tldService =
6247 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID"@mozilla.org/network/effective-tld-service;1");
6248 if (tldService) {
6249 nsAutoCString suffix;
6250 attemptFixup =
6251 NS_SUCCEEDED(tldService->GetKnownPublicSuffix(url, suffix))((bool)(__builtin_expect(!!(!NS_FAILED_impl(tldService->GetKnownPublicSuffix
(url, suffix))), 1)))
&&
6252 suffix.IsEmpty();
6253 }
6254 }
6255 if (attemptFixup) {
6256 nsCOMPtr<nsIURIFixupInfo> info;
6257 // only send non-qualified hosts to the keyword server
6258 if (aOriginalURIString && !aOriginalURIString->IsEmpty()) {
6259 info = KeywordToURI(*aOriginalURIString, aUsePrivateBrowsing);
6260 } else {
6261 //
6262 // If this string was passed through nsStandardURL by
6263 // chance, then it may have been converted from UTF-8 to
6264 // Punycode, which would result in a completely bogus keyword
6265 // query. Here we try to recover the original Unicode
6266 // value, but this is not 100% correct since the value may
6267 // have been normalized per the IDN normalization rules.
6268 //
6269 // Since we don't have access to the exact original string
6270 // that was entered by the user, this will just have to do.
6271 nsAutoCString utf8Host;
6272 mozilla_net_recover_keyword_from_punycode(&host, &utf8Host);
6273 info = KeywordToURI(utf8Host, aUsePrivateBrowsing);
6274 }
6275 if (info) {
6276 info->GetPreferredURI(getter_AddRefs(newURI));
6277 info->GetSchemelessInput(outSchemelessInput);
6278 if (newURI) {
6279 keywordInfo = info;
6280 info->GetPostData(getter_AddRefs(newPostData));
6281 }
6282 }
6283 }
6284 }
6285 }
6286
6287 //
6288 // Now try change the address, e.g. turn http://foo into
6289 // http://www.foo.com, and if that doesn't work try https with
6290 // https://foo and https://www.foo.com.
6291 //
6292 if (aStatus == NS_ERROR_UNKNOWN_HOST || aStatus == NS_ERROR_NET_RESET) {
6293 // Skip fixup for anything except a normal document load
6294 // operation on the topframe.
6295 bool doCreateAlternate = aLoadType == LOAD_NORMAL && aIsTopFrame;
6296
6297 if (doCreateAlternate) {
6298 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
6299 nsIPrincipal* principal = loadInfo->TriggeringPrincipal();
6300 // Only do this if our channel was loaded directly by the user from the
6301 // URL bar or similar (system principal) and not redirected, because we
6302 // shouldn't be guessing things about links from other sites, or a
6303 // post-redirect URI.
6304 doCreateAlternate = principal && principal->IsSystemPrincipal() &&
6305 loadInfo->RedirectChain().IsEmpty();
6306 }
6307 // Test if keyword lookup produced a new URI or not
6308 if (doCreateAlternate && newURI) {
6309 bool sameURI = false;
6310 url->Equals(newURI, &sameURI);
6311 if (!sameURI) {
6312 // Keyword lookup made a new URI so no need to try
6313 // an alternate one.
6314 doCreateAlternate = false;
6315 }
6316 }
6317 if (doCreateAlternate) {
6318 newURI = nullptr;
6319 newPostData = nullptr;
6320 keywordInfo = nullptr;
6321 nsCOMPtr<nsIURIFixup> uriFixup = components::URIFixup::Service();
6322 if (uriFixup) {
6323 nsCOMPtr<nsIURIFixupInfo> fixupInfo;
6324 uriFixup->GetFixupURIInfo(oldSpec, nsIURIFixup::FIXUP_FLAG_NONE,
6325 getter_AddRefs(fixupInfo));
6326 if (fixupInfo) {
6327 fixupInfo->GetPreferredURI(getter_AddRefs(newURI));
6328 }
6329 }
6330 }
6331 } else if (aStatus == NS_ERROR_CONNECTION_REFUSED &&
6332 Preferences::GetBool("browser.fixup.fallback-to-https", false)) {
6333 // Try HTTPS, since http didn't work
6334 if (url->SchemeIs("http")) {
6335 int32_t port = 0;
6336 url->GetPort(&port);
6337
6338 // Fall back to HTTPS only if port is default
6339 if (port == -1) {
6340 newURI = nullptr;
6341 newPostData = nullptr;
6342 (void)NS_MutateURI(url)
6343 .SetScheme("https"_ns)
6344 .Finalize(getter_AddRefs(newURI));
6345 }
6346 }
6347 }
6348
6349 // If we have a SSL_ERROR_BAD_CERT_DOMAIN error, try adding or removing
6350 // "www." to/from the beginning of the domain name to see if we can avoid
6351 // showing the cert error page. For example, https://example.com ->
6352 // https://www.example.com or https://www.example.com -> https://example.com.
6353 if (aStatus ==
6354 mozilla::psm::GetXPCOMFromNSSError(SSL_ERROR_BAD_CERT_DOMAIN)) {
6355 newPostData = nullptr;
6356 newURI = MaybeFixBadCertDomainErrorURI(aChannel, url);
6357 }
6358
6359 // Did we make a new URI that is different to the old one? If so
6360 // load it.
6361 //
6362 if (newURI) {
6363 // Make sure the new URI is different from the old one,
6364 // otherwise there's little point trying to load it again.
6365 bool sameURI = false;
6366 url->Equals(newURI, &sameURI);
6367 if (!sameURI) {
6368 if (aNewPostData) {
6369 newPostData.forget(aNewPostData);
6370 }
6371 if (aNotifyKeywordSearchLoading) {
6372 // This notification is meant for Firefox Health Report so it
6373 // can increment counts from the search engine
6374 MaybeNotifyKeywordSearchLoading(keywordInfo);
6375 }
6376 return newURI.forget();
6377 }
6378 }
6379
6380 return nullptr;
6381}
6382
6383nsresult nsDocShell::FilterStatusForErrorPage(
6384 nsresult aStatus, nsIChannel* aChannel, uint32_t aLoadType,
6385 bool aIsTopFrame, bool aUseErrorPages,
6386 bool* aSkippedUnknownProtocolNavigation) {
6387 // Errors to be shown only on top-level frames
6388 if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
6389 aStatus == NS_ERROR_CONNECTION_REFUSED ||
6390 aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
6391 aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
6392 aStatus == NS_ERROR_PROXY_FORBIDDEN ||
6393 aStatus == NS_ERROR_PROXY_NOT_IMPLEMENTED ||
6394 aStatus == NS_ERROR_PROXY_AUTHENTICATION_FAILED ||
6395 aStatus == NS_ERROR_PROXY_TOO_MANY_REQUESTS ||
6396 aStatus == NS_ERROR_MALFORMED_URI ||
6397 aStatus == NS_ERROR_HARMFULADDON_URI ||
6398 aStatus == NS_ERROR_BLOCKED_BY_POLICY ||
6399 aStatus == NS_ERROR_DOM_COOP_FAILED ||
6400 aStatus == NS_ERROR_DOM_COEP_FAILED ||
6401 aStatus == NS_ERROR_DOM_INVALID_HEADER_VALUE) &&
6402 (aIsTopFrame || aUseErrorPages)) {
6403 return aStatus;
6404 }
6405
6406 if (aStatus == NS_ERROR_NET_TIMEOUT ||
6407 aStatus == NS_ERROR_NET_TIMEOUT_EXTERNAL ||
6408 aStatus == NS_ERROR_OS_LOCAL_NETWORK_ACCESS_DENIED ||
6409 aStatus == NS_ERROR_NET_EMPTY_RESPONSE ||
6410 aStatus == NS_ERROR_NET_ERROR_RESPONSE ||
6411 aStatus == NS_ERROR_PROXY_GATEWAY_TIMEOUT ||
6412 aStatus == NS_ERROR_REDIRECT_LOOP ||
6413 aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
6414 aStatus == NS_ERROR_NET_INTERRUPT || aStatus == NS_ERROR_NET_RESET ||
6415 aStatus == NS_ERROR_NET_UNCLEAN_SHUTDOWN ||
6416 aStatus == NS_ERROR_PROXY_BAD_GATEWAY || aStatus == NS_ERROR_OFFLINE ||
6417 aStatus == NS_ERROR_MALWARE_URI || aStatus == NS_ERROR_PHISHING_URI ||
6418 aStatus == NS_ERROR_UNWANTED_URI || aStatus == NS_ERROR_HARMFUL_URI ||
6419 aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
6420 aStatus == NS_ERROR_INTERCEPTION_FAILED ||
6421 aStatus == NS_ERROR_NET_INADEQUATE_SECURITY ||
6422 aStatus == NS_ERROR_NET_HTTP2_SENT_GOAWAY ||
6423 aStatus == NS_ERROR_NET_HTTP3_PROTOCOL_ERROR ||
6424 aStatus == NS_ERROR_BASIC_HTTP_AUTH_DISABLED ||
6425 aStatus == NS_ERROR_DOM_BAD_URI || aStatus == NS_ERROR_FILE_NOT_FOUND ||
6426 aStatus == NS_ERROR_FILE_ACCESS_DENIED ||
6427 aStatus == NS_ERROR_CORRUPTED_CONTENT ||
6428 aStatus == NS_ERROR_INVALID_CONTENT_ENCODING ||
6429 NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY21) {
6430 // Errors to be shown for any frame
6431 return aStatus;
6432 }
6433
6434 if (aStatus == NS_ERROR_UNKNOWN_PROTOCOL) {
6435 // For unknown protocols we only display an error if the load is triggered
6436 // by the browser itself. Showing the error for page-triggered navigations
6437 // causes annoying behavior for users when a page tries to open an external
6438 // app which has not been installed, see bug 1528305. A missing WebExtension
6439 // protocol handlers will however always load the error page, as it is not
6440 // expected to be opened externally, see bug 1921426.
6441 nsCOMPtr<nsILoadInfo> info = aChannel->LoadInfo();
6442 if (!info->TriggeringPrincipal()->IsSystemPrincipal() &&
6443 !BasePrincipal::Cast(info->TriggeringPrincipal())->AddonPolicy()) {
6444 if (aSkippedUnknownProtocolNavigation) {
6445 *aSkippedUnknownProtocolNavigation = true;
6446 }
6447 return NS_OK;
6448 }
6449 return aStatus;
6450 }
6451
6452 if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
6453 // Non-caching channels will simply return NS_ERROR_OFFLINE.
6454 // Caching channels would have to look at their flags to work
6455 // out which error to return. Or we can fix up the error here.
6456 if (!(aLoadType & LOAD_CMD_HISTORY)) {
6457 return NS_ERROR_OFFLINE;
6458 }
6459 return aStatus;
6460 }
6461
6462 return NS_OK;
6463}
6464
6465nsresult nsDocShell::EndPageLoad(nsIChannel* aChannel, nsresult aStatus) {
6466 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p EndPageLoad status: %" "x" "\n"
, this, static_cast<uint32_t>(aStatus)); } } while (0)
6467 ("DOCSHELL %p EndPageLoad status: %" PRIx32 "\n", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p EndPageLoad status: %" "x" "\n"
, this, static_cast<uint32_t>(aStatus)); } } while (0)
6468 static_cast<uint32_t>(aStatus)))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p EndPageLoad status: %" "x" "\n"
, this, static_cast<uint32_t>(aStatus)); } } while (0)
;
6469 if (!aChannel) {
6470 return NS_ERROR_NULL_POINTER;
6471 }
6472
6473 // Make sure to discard the initial client if we never created the initial
6474 // about:blank document. Do this before possibly returning from the method
6475 // due to an error.
6476 mInitialClientSource.reset();
6477
6478 nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
6479 if (reporter) {
6480 nsCOMPtr<nsILoadGroup> loadGroup;
6481 aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
6482 if (loadGroup) {
6483 reporter->FlushConsoleReports(loadGroup);
6484 } else {
6485 reporter->FlushConsoleReports(GetDocument());
6486 }
6487 }
6488
6489 nsCOMPtr<nsIURI> url;
6490 nsresult rv = aChannel->GetURI(getter_AddRefs(url));
6491 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
6492 return rv;
6493 }
6494
6495 nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel);
6496 if (timingChannel) {
6497 TimeStamp channelCreationTime;
6498 rv = timingChannel->GetChannelCreation(&channelCreationTime);
6499 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !channelCreationTime.IsNull()) {
6500 glean::performance_page::total_content_page_load.AccumulateRawDuration(
6501 TimeStamp::Now() - channelCreationTime);
6502 }
6503 }
6504
6505 // Timing is picked up by the window, we don't need it anymore
6506 mTiming = nullptr;
6507
6508 // clean up reload state for meta charset
6509 if (eCharsetReloadRequested == mCharsetReloadState) {
6510 mCharsetReloadState = eCharsetReloadStopOrigional;
6511 } else {
6512 mCharsetReloadState = eCharsetReloadInit;
6513 }
6514
6515 //
6516 // one of many safeguards that prevent death and destruction if
6517 // someone is so very very rude as to bring this window down
6518 // during this load handler.
6519 //
6520 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
6521
6522 // Notify the DocumentViewer that the Document has finished loading. This
6523 // will cause any OnLoad(...) and PopState(...) handlers to fire.
6524 if (!mEODForCurrentDocument && mDocumentViewer) {
6525 mIsExecutingOnLoadHandler = true;
6526 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
6527 viewer->LoadComplete(aStatus);
6528 mIsExecutingOnLoadHandler = false;
6529
6530 mEODForCurrentDocument = true;
6531 }
6532 /* Check if the httpChannel has any cache-control related response headers,
6533 * like no-store, no-cache. If so, update SHEntry so that
6534 * when a user goes back/forward to this page, we appropriately do
6535 * form value restoration or load from server.
6536 */
6537 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
6538 if (!httpChannel) {
6539 // HttpChannel could be hiding underneath a Multipart channel.
6540 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
6541 }
6542
6543 mActiveEntryIsLoadingFromSessionHistory = false;
6544
6545 // if there's a refresh header in the channel, this method
6546 // will set it up for us.
6547 if (mBrowsingContext->IsActive() || !mDisableMetaRefreshWhenInactive)
6548 RefreshURIFromQueue();
6549
6550 // Test whether this is the top frame or a subframe
6551 bool isTopFrame = mBrowsingContext->IsTop();
6552
6553 bool hadErrorStatus = false;
6554 // If status code indicates an error it means that DocumentChannel already
6555 // tried to fixup the uri and failed. Throw an error dialog box here.
6556 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
6557 // If we got CONTENT_BLOCKED from EndPageLoad, then we need to fire
6558 // the error event to our embedder, since tests are relying on this.
6559 // The error event is usually fired by the caller of InternalLoad, but
6560 // this particular error can happen asynchronously.
6561 // Bug 1629201 is filed for having much clearer decision making around
6562 // which cases need error events.
6563 bool fireFrameErrorEvent =
6564 (aStatus == NS_ERROR_CONTENT_BLOCKED_SHOW_ALT ||
6565 aStatus == NS_ERROR_CONTENT_BLOCKED ||
6566 aStatus == NS_ERROR_CONNECTION_ALLOWLIST_VIOLATION);
6567 UnblockEmbedderLoadEventForFailure(fireFrameErrorEvent);
6568
6569 bool skippedUnknownProtocolNavigation = false;
6570 aStatus = FilterStatusForErrorPage(aStatus, aChannel, mLoadType, isTopFrame,
6571 mBrowsingContext->GetUseErrorPages(),
6572 &skippedUnknownProtocolNavigation);
6573 hadErrorStatus = true;
6574 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
6575 if (!mIsBeingDestroyed) {
6576 DisplayLoadError(aStatus, url, nullptr, aChannel);
6577 }
6578 } else if (skippedUnknownProtocolNavigation) {
6579 nsAutoCString sanitized;
6580 nsTArray<nsString> params;
6581 if (NS_SUCCEEDED(NS_GetSanitizedURIStringFromURI(url, sanitized))((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_GetSanitizedURIStringFromURI
(url, sanitized))), 1)))
) {
6582 params.AppendElement(NS_ConvertUTF8toUTF16(sanitized));
6583 } else {
6584 params.AppendElement(u"(unknown uri)"_ns);
6585 }
6586 nsContentUtils::ReportToConsole(
6587 nsIScriptError::warningFlag, "DOM"_ns, GetExtantDocument(),
6588 PropertiesFile::DOM_PROPERTIES, "UnknownProtocolNavigationPrevented",
6589 params);
6590 }
6591 }
6592
6593 if (hadErrorStatus) {
6594 // Don't send session store updates if the reason EndPageLoad was called is
6595 // because we are process switching. Sometimes the update takes too long and
6596 // incorrectly overrides session store data from the following load.
6597 return NS_OK;
6598 }
6599 if (SessionStorePlatformCollection()) {
6600 if (WindowContext* windowContext =
6601 mBrowsingContext->GetCurrentWindowContext()) {
6602 using Change = SessionStoreChangeListener::Change;
6603
6604 // We've finished loading the page and now we want to collect all the
6605 // session store state that the page is initialized with.
6606 SessionStoreChangeListener::CollectSessionStoreData(
6607 windowContext,
6608 EnumSet<Change>(Change::Input, Change::Scroll, Change::SessionHistory,
6609 Change::WireFrame));
6610 }
6611 }
6612
6613 return NS_OK;
6614}
6615
6616//*****************************************************************************
6617// nsDocShell: Content Viewer Management
6618//*****************************************************************************
6619
6620bool nsDocShell::VerifyDocumentViewer() {
6621 if (mDocumentViewer) {
6622 return true;
6623 }
6624 if (mIsBeingDestroyed) {
6625 return false;
6626 }
6627 if (!mInitialized) {
6628 // The viewer should be created during docshell initialization. If something
6629 // wants a viewer or document, it has to initialize the docshell first.
6630 MOZ_ASSERT_UNREACHABLE(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"The docshell should be initialized to get a viewer." ")", "./../../../docshell/base/nsDocShell.cpp"
, 6631); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "The docshell should be initialized to get a viewer."
")"); do { MOZ_CrashSequence(__null, 6631); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6631 "The docshell should be initialized to get a viewer.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"The docshell should be initialized to get a viewer." ")", "./../../../docshell/base/nsDocShell.cpp"
, 6631); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "The docshell should be initialized to get a viewer."
")"); do { MOZ_CrashSequence(__null, 6631); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6632 } else {
6633 NS_WARNING("No document viewer, docshell failed to initialize.")NS_DebugBreak(NS_DEBUG_WARNING, "No document viewer, docshell failed to initialize."
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 6633)
;
6634 }
6635 return false;
6636}
6637
6638nsresult nsDocShell::CreateInitialDocumentViewer(
6639 nsIOpenWindowInfo* aOpenWindowInfo,
6640 mozilla::dom::WindowGlobalChild* aWindowActor) {
6641 if (mIsBeingDestroyed) {
6642 return NS_ERROR_FAILURE;
6643 }
6644 MOZ_DIAGNOSTIC_ASSERT(!mDocumentViewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDocumentViewer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDocumentViewer))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mDocumentViewer"
, "./../../../docshell/base/nsDocShell.cpp", 6644); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mDocumentViewer" ")"); do { MOZ_CrashSequence
(__null, 6644); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6645 MOZ_ASSERT(aOpenWindowInfo, "Why don't we have openwindowinfo?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOpenWindowInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOpenWindowInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aOpenWindowInfo"
" (" "Why don't we have openwindowinfo?" ")", "./../../../docshell/base/nsDocShell.cpp"
, 6645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOpenWindowInfo"
") (" "Why don't we have openwindowinfo?" ")"); do { MOZ_CrashSequence
(__null, 6645); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6646
6647 nsCOMPtr<nsIPrincipal> principal =
6648 aOpenWindowInfo->PrincipalToInheritForAboutBlank();
6649 nsCOMPtr<nsIPrincipal> partitionedPrincipal =
6650 aOpenWindowInfo->PartitionedPrincipalToInheritForAboutBlank();
6651
6652 // Previously, CreateDocumentViewerForActor would've used the actor's
6653 // principal.
6654 MOZ_ASSERT_IF(aWindowActor, aWindowActor->DocumentPrincipal() == principal)do { if (aWindowActor) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aWindowActor->DocumentPrincipal
() == principal)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aWindowActor->DocumentPrincipal
() == principal))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aWindowActor->DocumentPrincipal() == principal", "./../../../docshell/base/nsDocShell.cpp"
, 6654); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindowActor->DocumentPrincipal() == principal"
")"); do { MOZ_CrashSequence(__null, 6654); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6655 MOZ_ASSERT_IF(aWindowActor,do { if (aWindowActor) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aWindowActor->DocumentPrincipal
() == partitionedPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindowActor->DocumentPrincipal
() == partitionedPrincipal))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aWindowActor->DocumentPrincipal() == partitionedPrincipal"
, "./../../../docshell/base/nsDocShell.cpp", 6656); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aWindowActor->DocumentPrincipal() == partitionedPrincipal"
")"); do { MOZ_CrashSequence(__null, 6656); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
6656 aWindowActor->DocumentPrincipal() == partitionedPrincipal)do { if (aWindowActor) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aWindowActor->DocumentPrincipal
() == partitionedPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindowActor->DocumentPrincipal
() == partitionedPrincipal))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aWindowActor->DocumentPrincipal() == partitionedPrincipal"
, "./../../../docshell/base/nsDocShell.cpp", 6656); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aWindowActor->DocumentPrincipal() == partitionedPrincipal"
")"); do { MOZ_CrashSequence(__null, 6656); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6657
6658 nsCOMPtr<nsIPolicyContainer> policyContainer =
6659 aOpenWindowInfo->PolicyContainerToInheritForAboutBlank();
6660 nsCOMPtr<nsIURI> base = aOpenWindowInfo->BaseUriToInheritForAboutBlank();
6661 MOZ_TRY(CreateAboutBlankDocumentViewer(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CreateAboutBlankDocumentViewer( principal, partitionedPrincipal
, policyContainer, base, true, aOpenWindowInfo->CoepToInheritForAboutBlank
(), false, aWindowActor)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
6662 principal, partitionedPrincipal, policyContainer, base,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CreateAboutBlankDocumentViewer( principal, partitionedPrincipal
, policyContainer, base, true, aOpenWindowInfo->CoepToInheritForAboutBlank
(), false, aWindowActor)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
6663 /* aIsInitialDocument */ true,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CreateAboutBlankDocumentViewer( principal, partitionedPrincipal
, policyContainer, base, true, aOpenWindowInfo->CoepToInheritForAboutBlank
(), false, aWindowActor)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
6664 aOpenWindowInfo->CoepToInheritForAboutBlank(),__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CreateAboutBlankDocumentViewer( principal, partitionedPrincipal
, policyContainer, base, true, aOpenWindowInfo->CoepToInheritForAboutBlank
(), false, aWindowActor)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
6665 /* aCheckPermitUnload */ false, aWindowActor))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CreateAboutBlankDocumentViewer( principal, partitionedPrincipal
, policyContainer, base, true, aOpenWindowInfo->CoepToInheritForAboutBlank
(), false, aWindowActor)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
;
6666
6667 NS_ENSURE_STATE(mDocumentViewer)do { if ((__builtin_expect(!!(!(mDocumentViewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocumentViewer" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 6667); return
NS_ERROR_UNEXPECTED; } } while (false)
;
6668
6669 RefPtr<Document> doc(GetDocument());
6670 MOZ_ASSERT(doc,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(doc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("doc" " (" "Should have doc if CreateAboutBlankDocumentViewer succeeded!"
")", "./../../../docshell/base/nsDocShell.cpp", 6671); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "doc" ") (" "Should have doc if CreateAboutBlankDocumentViewer succeeded!"
")"); do { MOZ_CrashSequence(__null, 6671); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6671 "Should have doc if CreateAboutBlankDocumentViewer succeeded!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(doc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("doc" " (" "Should have doc if CreateAboutBlankDocumentViewer succeeded!"
")", "./../../../docshell/base/nsDocShell.cpp", 6671); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "doc" ") (" "Should have doc if CreateAboutBlankDocumentViewer succeeded!"
")"); do { MOZ_CrashSequence(__null, 6671); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6672 MOZ_ASSERT(doc->IsInitialDocument(), "Document should be initial document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(doc->IsInitialDocument())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("doc->IsInitialDocument()"
" (" "Document should be initial document" ")", "./../../../docshell/base/nsDocShell.cpp"
, 6672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc->IsInitialDocument()"
") (" "Document should be initial document" ")"); do { MOZ_CrashSequence
(__null, 6672); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6673
6674 // Documents created using CreateInitialDocumentViewer may be transient
6675 // placeholders created by framescripts before content has a
6676 // chance to load. In some cases, window.open(..., "noopener")
6677 // will create such a document and then synchronously tear it
6678 // down, firing a "pagehide" event. Doing so violates our
6679 // assertions about DocGroups. It's easier to silence the
6680 // assertion here than to avoid creating the extra document.
6681 doc->IgnoreDocGroupMismatches();
6682
6683 return NS_OK;
6684}
6685
6686// Location.ancestorOrigins for about:blank, need special case handling.
6687// Particularly in the case for initial about:blank, which does not go through
6688// normal code that happen with navigations.
6689static void CreateAboutBlankAncestorOriginsForNonTopLevel(Document* aDoc) {
6690 BrowsingContext* bc = aDoc->GetBrowsingContext();
6691 MOZ_ASSERT(bc && !bc->IsDiscarded() && bc->GetEmbedderElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc && !bc->IsDiscarded() && bc->
GetEmbedderElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc && !bc->IsDiscarded
() && bc->GetEmbedderElement()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("bc && !bc->IsDiscarded() && bc->GetEmbedderElement()"
, "./../../../docshell/base/nsDocShell.cpp", 6691); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "bc && !bc->IsDiscarded() && bc->GetEmbedderElement()"
")"); do { MOZ_CrashSequence(__null, 6691); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6692 // We're not even going to attempt to deal with location.ancestorOrigins stuff
6693 // in the parent process.
6694 if (!XRE_IsContentProcess()) {
6695 return;
6696 }
6697
6698 const auto* frame = bc->GetEmbedderElement();
6699 const auto referrerPolicy = frame->GetReferrerPolicyAsEnum();
6700 // Inform the parent process that it needs to create an internal ancestor
6701 // origins list for this browsing context `bc`
6702 (void)ContentChild::GetSingleton()->SendUpdateAncestorOriginsList(bc);
6703
6704 const bool masked = referrerPolicy == ReferrerPolicy::No_referrer;
6705 BrowsingContext* parent = bc->GetParent();
6706 MOZ_DIAGNOSTIC_ASSERT(parent && parent->IsInProcess() &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent && parent->IsInProcess() &&
parent->GetExtantDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parent && parent->
IsInProcess() && parent->GetExtantDocument()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("parent && parent->IsInProcess() && parent->GetExtantDocument()"
, "./../../../docshell/base/nsDocShell.cpp", 6707); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent && parent->IsInProcess() && parent->GetExtantDocument()"
")"); do { MOZ_CrashSequence(__null, 6707); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6707 parent->GetExtantDocument())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent && parent->IsInProcess() &&
parent->GetExtantDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parent && parent->
IsInProcess() && parent->GetExtantDocument()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("parent && parent->IsInProcess() && parent->GetExtantDocument()"
, "./../../../docshell/base/nsDocShell.cpp", 6707); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent && parent->IsInProcess() && parent->GetExtantDocument()"
")"); do { MOZ_CrashSequence(__null, 6707); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6708
6709 nsTArray<nsCOMPtr<nsIPrincipal>> ancestorPrincipals;
6710 constexpr auto getPrincipal =
6711 [](const BrowsingContext* ctx) -> nsIPrincipal* {
6712 if (!ctx) {
6713 return nullptr;
6714 }
6715 auto* doc = ctx->GetExtantDocument();
6716 return doc ? doc->GetPrincipal() : nullptr;
6717 };
6718 BrowsingContext* ancestorContextToCopyAncestorListFrom = parent;
6719
6720 // about:blank is different from normal docs.
6721 // We only care about in-process, same-origin ancestors.
6722 // Therefore run the algorithm all the way up to the last same-origin doc
6723 // add that origin to the list, and then append that origin's ancestor origins
6724 // list
6725 if (masked) {
6726 ancestorPrincipals.AppendElement(nullptr);
6727 // 16.1.1. If ancestorOrigin is same origin with parentDoc's origin, then
6728 // append a new opaque origin to output.
6729 auto* parentDocPrincipal = getPrincipal(parent);
6730 for (auto* ancestor = parent->GetParent(); ancestor;
6731 ancestor = ancestor->GetParent()) {
6732 auto* principal = getPrincipal(ancestor);
6733 if (principal && principal->Equals(parentDocPrincipal)) {
6734 // same principal, same process, adding nullptr for
6735 // parentContextToCopyAncestorListFrom
6736 ancestorContextToCopyAncestorListFrom = ancestor;
6737 ancestorPrincipals.AppendElement(nullptr);
6738 } else {
6739 // 16.1.2 Otherwise, append ancestorOrigin to output and set masked to
6740 // false.
6741 // Note: But in the case of about:blank, ancestorOrigin can
6742 // potentially live in another process. So we stop right before it, and
6743 // just copy `ancestorContextToCopyAncestorListFrom` list, since the
6744 // masking steps should finish here.
6745 break;
6746 }
6747 }
6748 } else {
6749 ancestorPrincipals.AppendElement(getPrincipal(parent));
6750 }
6751
6752 nsTArray<nsString> list = ProduceAncestorOriginsList(ancestorPrincipals);
6753 Document* ancestorDoc =
6754 ancestorContextToCopyAncestorListFrom->GetExtantDocument();
6755 MOZ_DIAGNOSTIC_ASSERT(ancestorDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorDoc)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ancestorDoc))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ancestorDoc", "./../../../docshell/base/nsDocShell.cpp"
, 6755); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "ancestorDoc"
")"); do { MOZ_CrashSequence(__null, 6755); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6756 list.AppendElements(ancestorDoc->GetAncestorOriginsList());
6757 aDoc->SetAncestorOriginsList(std::move(list));
6758}
6759
6760nsresult nsDocShell::CreateAboutBlankDocumentViewer(
6761 nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal,
6762 nsIPolicyContainer* aPolicyContainer, nsIURI* aBaseURI,
6763 bool aIsInitialDocument,
6764 const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP,
6765 bool aCheckPermitUnload, WindowGlobalChild* aActor) {
6766 RefPtr<Document> blankDoc;
6767 nsCOMPtr<nsIDocumentViewer> viewer;
6768 nsresult rv = NS_ERROR_FAILURE;
6769
6770 // Pageswap can fire for a navigation that then creates about:blank instead
6771 // of the new document. Clear the flag so that the next navigation can fire
6772 // pageswap.
6773 mFiredCrossDocPageSwap = false;
6774
6775 PROFILER_MARKER_UNTYPED("CreateAboutBlankDocumentViewer", DOM,do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("CreateAboutBlankDocumentViewer", ::geckoprofiler::category::
DOM, MarkerStack::Capture()); } } while (false); } while (false
)
6776 MarkerStack::Capture())do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("CreateAboutBlankDocumentViewer", ::geckoprofiler::category::
DOM, MarkerStack::Capture()); } } while (false); } while (false
)
;
6777
6778 MOZ_ASSERT_IF(aActor, aActor->DocumentPrincipal() == aPrincipal)do { if (aActor) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aActor->DocumentPrincipal() == aPrincipal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aActor->DocumentPrincipal() == aPrincipal))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aActor->DocumentPrincipal() == aPrincipal"
, "./../../../docshell/base/nsDocShell.cpp", 6778); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aActor->DocumentPrincipal() == aPrincipal"
")"); do { MOZ_CrashSequence(__null, 6778); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6779
6780 MOZ_DIAGNOSTIC_ASSERT(mInitialized, "Must initialize before viewer creation")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInitialized)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInitialized))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mInitialized" " ("
"Must initialize before viewer creation" ")", "./../../../docshell/base/nsDocShell.cpp"
, 6780); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mInitialized"
") (" "Must initialize before viewer creation" ")"); do { MOZ_CrashSequence
(__null, 6780); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6781
6782 /* mCreatingDocument should never be true at this point. However, it's
6783 a theoretical possibility. We want to know about it and make it stop,
6784 and this sounds like a job for an assertion. */
6785 NS_ASSERTION(!mCreatingDocument,do { if (!(!mCreatingDocument)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "infinite(?) loop creating document averted", "!mCreatingDocument"
, "./../../../docshell/base/nsDocShell.cpp", 6786); MOZ_PretendNoReturn
(); } } while (0)
6786 "infinite(?) loop creating document averted")do { if (!(!mCreatingDocument)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "infinite(?) loop creating document averted", "!mCreatingDocument"
, "./../../../docshell/base/nsDocShell.cpp", 6786); MOZ_PretendNoReturn
(); } } while (0)
;
6787 if (mCreatingDocument) {
6788 return NS_ERROR_FAILURE;
6789 }
6790
6791 if (!mBrowsingContext->AncestorsAreCurrent() ||
6792 mBrowsingContext->IsInBFCache()) {
6793 mBrowsingContext->RemoveRootFromBFCacheSync();
6794 return NS_ERROR_NOT_AVAILABLE;
6795 }
6796
6797 // mDocumentViewer->PermitUnload may release |this| docshell.
6798 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
6799
6800 // Ensure that UsesOriginAgentCluster has been initialized for this
6801 // BrowsingContextGroup/principal pair before creating the document.
6802 if (aPrincipal) {
6803 mBrowsingContext->Group()->EnsureUsesOriginAgentClusterInitialized(
6804 aPrincipal);
6805 }
6806
6807 AutoRestore<bool> creatingDocument(mCreatingDocument);
6808 mCreatingDocument = true;
6809
6810 if (aPrincipal && !aPrincipal->IsSystemPrincipal() &&
6811 mItemType != typeChrome) {
6812 if (GetIsTopLevelContentDocShell()) {
6813 // Bug 1948216 tracks having a FPD for top-level initial about:blank
6814 MOZ_ASSERT(aPrincipal->OriginAttributesRef().EqualsIgnoringFPD(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal->OriginAttributesRef().EqualsIgnoringFPD
( mBrowsingContext->OriginAttributesRef()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal->OriginAttributesRef
().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrincipal->OriginAttributesRef().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef())"
, "./../../../docshell/base/nsDocShell.cpp", 6815); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrincipal->OriginAttributesRef().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef())"
")"); do { MOZ_CrashSequence(__null, 6815); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6815 mBrowsingContext->OriginAttributesRef()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal->OriginAttributesRef().EqualsIgnoringFPD
( mBrowsingContext->OriginAttributesRef()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal->OriginAttributesRef
().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrincipal->OriginAttributesRef().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef())"
, "./../../../docshell/base/nsDocShell.cpp", 6815); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrincipal->OriginAttributesRef().EqualsIgnoringFPD( mBrowsingContext->OriginAttributesRef())"
")"); do { MOZ_CrashSequence(__null, 6815); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6816 } else {
6817 MOZ_ASSERT(aPrincipal->OriginAttributesRef() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal->OriginAttributesRef() == mBrowsingContext
->OriginAttributesRef())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal->OriginAttributesRef
() == mBrowsingContext->OriginAttributesRef()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aPrincipal->OriginAttributesRef() == mBrowsingContext->OriginAttributesRef()"
, "./../../../docshell/base/nsDocShell.cpp", 6818); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrincipal->OriginAttributesRef() == mBrowsingContext->OriginAttributesRef()"
")"); do { MOZ_CrashSequence(__null, 6818); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6818 mBrowsingContext->OriginAttributesRef())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal->OriginAttributesRef() == mBrowsingContext
->OriginAttributesRef())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal->OriginAttributesRef
() == mBrowsingContext->OriginAttributesRef()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aPrincipal->OriginAttributesRef() == mBrowsingContext->OriginAttributesRef()"
, "./../../../docshell/base/nsDocShell.cpp", 6818); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrincipal->OriginAttributesRef() == mBrowsingContext->OriginAttributesRef()"
")"); do { MOZ_CrashSequence(__null, 6818); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6819 }
6820 }
6821
6822 // Make sure timing is created. But first record whether we had it
6823 // already, so we don't clobber the timing for an in-progress load.
6824 bool hadTiming = mTiming;
6825 bool toBeReset = MaybeInitTiming();
6826 if (mDocumentViewer) {
6827 if (aCheckPermitUnload) {
6828 // We've got a content viewer already. Make sure the user
6829 // permits us to discard the current document and replace it
6830 // with about:blank. And also ensure we fire the unload events
6831 // in the current document.
6832
6833 // Unload gets fired first for
6834 // document loaded from the session history.
6835 mTiming->NotifyBeforeUnload();
6836
6837 bool okToUnload;
6838 rv = mDocumentViewer->PermitUnload(&okToUnload);
6839 if (mIsBeingDestroyed) {
6840 // unload handler destroyed this docshell.
6841 return NS_ERROR_NOT_AVAILABLE;
6842 }
6843 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !okToUnload) {
6844 // The user chose not to unload the page, interrupt the load.
6845 MaybeResetInitTiming(toBeReset);
6846 return NS_ERROR_FAILURE;
6847 }
6848 if (mTiming) {
6849 mTiming->NotifyUnloadAccepted(mCurrentURI);
6850 }
6851 }
6852
6853 // Make sure to blow away our mLoadingURI just in case. No loads
6854 // from inside this pagehide.
6855 mLoadingURI = nullptr;
6856
6857 // Stop any in-progress loading, so that we don't accidentally trigger any
6858 // PageShow notifications from Embed() interrupting our loading below.
6859 Stop();
6860
6861 // Notify the current document that it is about to be unloaded!!
6862 //
6863 // It is important to fire the unload() notification *before* any state
6864 // is changed within the DocShell - otherwise, javascript will get the
6865 // wrong information :-(
6866 //
6867 (void)FirePageHideNotification();
6868 // pagehide notification might destroy this docshell.
6869 if (mIsBeingDestroyed) {
6870 return NS_ERROR_DOCSHELL_DYING;
6871 }
6872 }
6873
6874 // Now make sure we don't think we're in the middle of firing unload after
6875 // this point. This will make us fire unload when the about:blank document
6876 // unloads... but that's ok, more or less. Would be nice if it fired load
6877 // too, of course.
6878 mFiredUnloadEvent = false;
6879
6880 nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
6881 nsContentUtils::FindInternalDocumentViewer("text/html"_ns);
6882
6883 if (docFactory) {
6884 nsCOMPtr<nsIPrincipal> principal, partitionedPrincipal;
6885 const uint32_t sandboxFlags =
6886 mBrowsingContext->GetHasLoadedNonInitialDocument()
6887 ? mBrowsingContext->GetSandboxFlags()
6888 : mBrowsingContext->GetInitialSandboxFlags();
6889 // If we're sandboxed, then create a new null principal. We skip
6890 // this if we're being created from WindowGlobalChild, since in
6891 // that case we already have a null principal if required.
6892 // We can't compare againt the BrowsingContext sandbox flag, since
6893 // the value was taken when the load initiated and may have since
6894 // changed.
6895 if ((sandboxFlags & SANDBOXED_ORIGIN) && !aActor) {
6896 if (aPrincipal) {
6897 principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal);
6898 } else {
6899 principal = NullPrincipal::Create(GetOriginAttributes());
6900 }
6901 partitionedPrincipal = principal;
6902 } else {
6903 principal = aPrincipal;
6904 partitionedPrincipal = aPartitionedPrincipal;
6905 }
6906
6907 // We cannot get the foreign partitioned principal for the initial
6908 // about:blank page. So, we change to check if we need to use the
6909 // partitioned principal for the service worker here.
6910 MaybeCreateInitialClientSource(
6911 StoragePrincipalHelper::ShouldUsePartitionPrincipalForServiceWorker(
6912 this)
6913 ? partitionedPrincipal
6914 : principal);
6915
6916 // generate (about:blank) document to load
6917 blankDoc = nsContentDLF::CreateBlankDocument(mLoadGroup, principal,
6918 partitionedPrincipal, this);
6919 if (blankDoc) {
6920 // Hack: manually set the policyContainer for the new document
6921 // Please create an actual copy of the policyContainer (do not share the
6922 // same reference) otherwise modifying the new container (such as
6923 // appending a new policy to CSP) within the new document will be
6924 // incorrectly propagated to the opening doc.
6925 RefPtr policyContainerToInherit = MakeRefPtr<PolicyContainer>();
6926 if (aPolicyContainer) {
6927 policyContainerToInherit->InitFromOther(
6928 PolicyContainer::Cast(aPolicyContainer));
6929 }
6930 blankDoc->SetPolicyContainer(policyContainerToInherit);
6931 if (!PolicyContainer::GetCSP(policyContainerToInherit)) {
6932 RefPtr newCsp = MakeRefPtr<nsCSPContext>();
6933 policyContainerToInherit->SetCSP(newCsp);
6934 nsresult rv = newCsp->SetRequestContextWithDocument(blankDoc);
6935 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 6935)
) {
6936 return rv;
6937 }
6938 }
6939
6940 blankDoc->SetInitialStatus(
6941 aIsInitialDocument ? Document::InitialStatus::IsInitialUncommitted
6942 : Document::InitialStatus::NeverInitial);
6943
6944 blankDoc->SetEmbedderPolicy(aCOEP);
6945
6946 // Hack: set the base URI manually, since this document never
6947 // got Reset() with a channel.
6948 blankDoc->SetBaseURI(aBaseURI);
6949
6950 // Copy our sandbox flags to the document. These are immutable
6951 // after being set here.
6952 blankDoc->SetSandboxFlags(sandboxFlags);
6953
6954 // We inherit the classification flags from the parent document if the
6955 // principal matches.
6956 nsCOMPtr<nsIDocShellTreeItem> parentItem;
6957 GetInProcessSameTypeParent(getter_AddRefs(parentItem));
6958 if (parentItem) {
6959 RefPtr<Document> parentDocument = parentItem->GetDocument();
6960 if (parentDocument && principal &&
6961 principal->Equals(parentDocument->NodePrincipal())) {
6962 blankDoc->SetClassificationFlags(
6963 parentDocument->GetClassificationFlags());
6964 }
6965 }
6966
6967 // create a content viewer for us and the new document
6968 docFactory->CreateInstanceForDocument(
6969 NS_ISUPPORTS_CAST(nsIDocShell*, this)static_cast<nsISupports*>(static_cast<nsIDocShell*>
(this))
, blankDoc, "view",
6970 getter_AddRefs(viewer));
6971
6972 // hook 'em up
6973 if (viewer) {
6974 viewer->SetContainer(this);
6975 if (mLoadingEntry && mBrowsingContext->IsTop()) {
6976 mLoadingEntry->mInfo.SetTransient();
6977 }
6978 const nsCOMPtr<nsIURI> uri = mCurrentURI;
6979 rv = Embed(viewer, aActor, true, nullptr, uri);
6980 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 6980); return rv; } } while (false)
;
6981
6982 SetCurrentURI(blankDoc->GetDocumentURI(), nullptr,
6983 /* aFireLocationChange */ true,
6984 /* aIsInitialAboutBlank */ aIsInitialDocument,
6985 /* aLocationFlags */ 0);
6986 rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
6987 }
6988
6989 if (Element* embedderElement = blankDoc->GetEmbedderElement()) {
6990 blankDoc->InitPermissionsPolicy(AsVariant(embedderElement));
6991 } else {
6992 blankDoc->InitPermissionsPolicy(AsVariant(Nothing{}));
6993 }
6994
6995 // Perform redacted location.ancestorOrigins algorithm for about:blank
6996 if (BrowsingContext* bc = GetBrowsingContext();
6997 bc && bc->GetEmbedderElement()) {
6998 CreateAboutBlankAncestorOriginsForNonTopLevel(blankDoc);
6999 }
7000 }
7001 }
7002
7003 // Clear out our mTiming like we would in EndPageLoad, if we didn't
7004 // have one before entering this function.
7005 if (!hadTiming) {
7006 mTiming = nullptr;
7007 mBlankTiming = true;
7008 }
7009
7010 return rv;
7011}
7012
7013NS_IMETHODIMPnsresult
7014nsDocShell::CreateAboutBlankDocumentViewer(
7015 nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal,
7016 nsIPolicyContainer* aPolicyContainer) {
7017 return CreateAboutBlankDocumentViewer(aPrincipal, aPartitionedPrincipal,
7018 aPolicyContainer, nullptr,
7019 /* aIsInitialDocument */ false);
7020}
7021
7022/* static */
7023void nsDocShell::ReportBFCacheComboTelemetry(uint32_t aCombo) {
7024 // There are many possible reasons to make a request fails to use BFCache
7025 // (see BFCacheStatus in dom/base/Document.h), and we'd like to record
7026 // the common combinations for reasons which make requests fail to use
7027 // BFCache. These combinations are generated based on some local browsings,
7028 // we need to adjust them when necessary.
7029 enum BFCacheStatusCombo : uint32_t {
7030 BFCACHE_SUCCESS,
7031 NOT_ONLY_TOPLEVEL = mozilla::dom::BFCacheStatus::NOT_ONLY_TOPLEVEL_IN_BCG,
7032 // If both unload and beforeunload listeners are presented, it'll be
7033 // recorded as unload
7034 UNLOAD = mozilla::dom::BFCacheStatus::UNLOAD_LISTENER,
7035 UNLOAD_REQUEST = mozilla::dom::BFCacheStatus::UNLOAD_LISTENER |
7036 mozilla::dom::BFCacheStatus::REQUEST,
7037 REQUEST = mozilla::dom::BFCacheStatus::REQUEST,
7038 UNLOAD_REQUEST_PEER = mozilla::dom::BFCacheStatus::UNLOAD_LISTENER |
7039 mozilla::dom::BFCacheStatus::REQUEST |
7040 mozilla::dom::BFCacheStatus::ACTIVE_PEER_CONNECTION,
7041 UNLOAD_REQUEST_PEER_MSE =
7042 mozilla::dom::BFCacheStatus::UNLOAD_LISTENER |
7043 mozilla::dom::BFCacheStatus::REQUEST |
7044 mozilla::dom::BFCacheStatus::ACTIVE_PEER_CONNECTION |
7045 mozilla::dom::BFCacheStatus::CONTAINS_MSE_CONTENT,
7046 UNLOAD_REQUEST_MSE = mozilla::dom::BFCacheStatus::UNLOAD_LISTENER |
7047 mozilla::dom::BFCacheStatus::REQUEST |
7048 mozilla::dom::BFCacheStatus::CONTAINS_MSE_CONTENT,
7049 SUSPENDED_UNLOAD_REQUEST_PEER =
7050 mozilla::dom::BFCacheStatus::SUSPENDED |
7051 mozilla::dom::BFCacheStatus::UNLOAD_LISTENER |
7052 mozilla::dom::BFCacheStatus::REQUEST |
7053 mozilla::dom::BFCacheStatus::ACTIVE_PEER_CONNECTION,
7054 REMOTE_SUBFRAMES = mozilla::dom::BFCacheStatus::CONTAINS_REMOTE_SUBFRAMES,
7055 BEFOREUNLOAD = mozilla::dom::BFCacheStatus::BEFOREUNLOAD_LISTENER,
7056 };
7057
7058 // A document whose load event hasn't fired usually also has in-flight
7059 // requests and other transient blockers, so record it as loading regardless
7060 // of the other flags.
7061 if (aCombo & mozilla::dom::BFCacheStatus::PAGE_LOADING) {
7062 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::ePageLoading)
7063 .Add();
7064 return;
7065 }
7066
7067 // Beforeunload is recorded as a blocker only if it is the only one to block
7068 // bfcache.
7069 if (aCombo != mozilla::dom::BFCacheStatus::BEFOREUNLOAD_LISTENER) {
7070 aCombo &= ~mozilla::dom::BFCacheStatus::BEFOREUNLOAD_LISTENER;
7071 }
7072 switch (aCombo) {
7073 case BFCACHE_SUCCESS:
7074 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eBfcacheSuccess)
7075 .Add();
7076 break;
7077 case NOT_ONLY_TOPLEVEL:
7078 if (StaticPrefs::docshell_shistory_bfcache_require_no_opener()) {
7079 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eOther).Add();
7080 break;
7081 }
7082 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eBfcacheSuccess)
7083 .Add();
7084 glean::bfcache::combo
7085 .EnumGet(glean::bfcache::ComboLabel::eSuccessNotToplevel)
7086 .Add();
7087 break;
7088 case UNLOAD:
7089 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eUnload).Add();
7090 break;
7091 case BEFOREUNLOAD:
7092 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eBeforeunload)
7093 .Add();
7094 break;
7095 case UNLOAD_REQUEST:
7096 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eUnloadReq)
7097 .Add();
7098 break;
7099 case REQUEST:
7100 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eReq).Add();
7101 break;
7102 case UNLOAD_REQUEST_PEER:
7103 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eUnloadReqPeer)
7104 .Add();
7105 break;
7106 case UNLOAD_REQUEST_PEER_MSE:
7107 glean::bfcache::combo
7108 .EnumGet(glean::bfcache::ComboLabel::eUnloadReqPeerMse)
7109 .Add();
7110 break;
7111 case UNLOAD_REQUEST_MSE:
7112 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eUnloadReqMse)
7113 .Add();
7114 break;
7115 case SUSPENDED_UNLOAD_REQUEST_PEER:
7116 glean::bfcache::combo
7117 .EnumGet(glean::bfcache::ComboLabel::eSpdUnloadReqPeer)
7118 .Add();
7119 break;
7120 case REMOTE_SUBFRAMES:
7121 glean::bfcache::combo
7122 .EnumGet(glean::bfcache::ComboLabel::eRemoteSubframes)
7123 .Add();
7124 break;
7125 default:
7126 glean::bfcache::combo.EnumGet(glean::bfcache::ComboLabel::eOther).Add();
7127 break;
7128 }
7129};
7130
7131void nsDocShell::DetachEditorFromWindow() {
7132 if (!mEditorData || mEditorData->WaitingForLoad()) {
7133 // If there's nothing to detach, or if the editor data is actually set
7134 // up for the _new_ page that's coming in, don't detach.
7135 return;
7136 }
7137
7138 nsresult res = mEditorData->DetachFromWindow();
7139 NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(res)),
1))))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to detach editor"
, "NS_SUCCEEDED(res)", "./../../../docshell/base/nsDocShell.cpp"
, 7139); MOZ_PretendNoReturn(); } } while (0)
;
7140
7141 if (NS_SUCCEEDED(res)((bool)(__builtin_expect(!!(!NS_FAILED_impl(res)), 1)))) {
7142 mEditorData = nullptr;
7143 }
7144
7145#ifdef DEBUG1
7146 {
7147 bool isEditable;
7148 GetEditable(&isEditable);
7149 NS_ASSERTION(!isEditable,do { if (!(!isEditable)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Window is still editable after detaching editor."
, "!isEditable", "./../../../docshell/base/nsDocShell.cpp", 7150
); MOZ_PretendNoReturn(); } } while (0)
7150 "Window is still editable after detaching editor.")do { if (!(!isEditable)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Window is still editable after detaching editor."
, "!isEditable", "./../../../docshell/base/nsDocShell.cpp", 7150
); MOZ_PretendNoReturn(); } } while (0)
;
7151 }
7152#endif // DEBUG
7153}
7154
7155NS_IMETHODIMPnsresult
7156nsDocShell::GetRestoringDocument(bool* aRestoring) {
7157 *aRestoring = mIsRestoringDocument;
7158 return NS_OK;
7159}
7160
7161bool nsDocShell::SandboxFlagsImplyCookies(const uint32_t& aSandboxFlags) {
7162 return (aSandboxFlags & (SANDBOXED_ORIGIN | SANDBOXED_SCRIPTS)) == 0;
7163}
7164
7165nsresult nsDocShell::CreateDocumentViewer(const nsACString& aContentType,
7166 nsIRequest* aRequest,
7167 nsIStreamListener** aContentHandler) {
7168 *aContentHandler = nullptr;
7169
7170 if (!mTreeOwner || mIsBeingDestroyed) {
7171 // If we don't have a tree owner, then we're in the process of being
7172 // destroyed. Rather than continue trying to load something, just give up.
7173 return NS_ERROR_DOCSHELL_DYING;
7174 }
7175
7176 if (!mBrowsingContext->AncestorsAreCurrent() ||
7177 mBrowsingContext->IsInBFCache()) {
7178 mBrowsingContext->RemoveRootFromBFCacheSync();
7179 return NS_ERROR_NOT_AVAILABLE;
7180 }
7181
7182 // Can we check the content type of the current content viewer
7183 // and reuse it without destroying it and re-creating it?
7184
7185 NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?")do { if (!(mLoadGroup)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Someone ignored return from Init()?"
, "mLoadGroup", "./../../../docshell/base/nsDocShell.cpp", 7185
); MOZ_PretendNoReturn(); } } while (0)
;
7186
7187 // Instantiate the content viewer object
7188 nsCOMPtr<nsIDocumentViewer> viewer;
7189 nsresult rv = NewDocumentViewerObj(aContentType, aRequest, mLoadGroup,
7190 aContentHandler, getter_AddRefs(viewer));
7191
7192 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
7193 return rv;
7194 }
7195
7196 // Notify the current document that it is about to be unloaded!!
7197 //
7198 // It is important to fire the unload() notification *before* any state
7199 // is changed within the DocShell - otherwise, javascript will get the
7200 // wrong information :-(
7201 //
7202
7203 NS_ASSERTION(!mLoadingURI, "Re-entering unload?")do { if (!(!mLoadingURI)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Re-entering unload?", "!mLoadingURI", "./../../../docshell/base/nsDocShell.cpp"
, 7203); MOZ_PretendNoReturn(); } } while (0)
;
7204
7205 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
7206 if (aOpenedChannel) {
7207 aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
7208 }
7209
7210 // Grab the current URI, we need to pass it to Embed, and OnNewURI will reset
7211 // it before we do call Embed.
7212 nsCOMPtr<nsIURI> previousURI = mCurrentURI;
7213
7214 // A reload's target entry still holds the active document, so the history
7215 // step doesn't move away from it.
7216 if (!(mLoadType & LOAD_CMD_RELOAD)) {
7217 ClearNavigationAPIOngoingNavigationForHistoryStep();
7218 }
7219
7220 // https://html.spec.whatwg.org/#fire-the-pageswap-event
7221 // Fire pageswap without a view transition if no earlier path fired it for
7222 // this navigation.
7223 const bool alreadyFiredCrossDocPageSwap = mFiredCrossDocPageSwap;
7224 mFiredCrossDocPageSwap = false;
7225 if (!alreadyFiredCrossDocPageSwap &&
7226 StaticPrefs::dom_viewTransitions_cross_document_enabled() &&
7227 mLoadingEntry) {
7228 if (Maybe<NavigationType> navType =
7229 NavigationUtils::NavigationTypeFromLoadType(mLoadType)) {
7230 RefPtr<Document> oldDoc =
7231 mDocumentViewer ? mDocumentViewer->GetDocument() : nullptr;
7232 if (RefPtr<Navigation> navigation = NavigationOfDocument(oldDoc)) {
7233 nsCOMPtr<nsIURI> oldURI = oldDoc->GetDocumentURI();
7234 bool sameOrigin =
7235 oldURI && mLoadingURI &&
7236 NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( oldURI, mLoadingURI, false, false)
)), 1)))
7237 nsContentUtils::GetSecurityManager()->CheckSameOriginURI(((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( oldURI, mLoadingURI, false, false)
)), 1)))
7238 oldURI, mLoadingURI, false, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( oldURI, mLoadingURI, false, false)
)), 1)))
;
7239
7240 // A document created via cross-origin redirects must not expose an
7241 // activation for a fresh navigation.
7242 // https://html.spec.whatwg.org/#fire-the-pageswap-event step 4
7243 const bool hasCrossOriginRedirect =
7244 NavigationUtils::HasCrossOriginRedirect(aOpenedChannel);
7245 const bool canHaveActivation = sameOrigin && !hasCrossOriginRedirect;
7246
7247 navigation->FirePageSwapEvent(&mLoadingEntry->mInfo, *navType,
7248 canHaveActivation, nullptr);
7249 }
7250 }
7251 }
7252
7253 FirePageHideNotification();
7254 if (mIsBeingDestroyed) {
7255 // Force to stop the newly created orphaned viewer.
7256 viewer->Stop();
7257 return NS_ERROR_DOCSHELL_DYING;
7258 }
7259 mLoadingURI = nullptr;
7260
7261 // Set mFiredUnloadEvent = false so that the unload handler for the
7262 // *new* document will fire.
7263 mFiredUnloadEvent = false;
7264
7265 // we've created a new document so go ahead and call
7266 // OnNewURI(), but don't fire OnLocationChange()
7267 // notifications before we've called Embed(). See bug 284993.
7268 mURIResultedInDocument = true;
7269 bool errorOnLocationChangeNeeded = false;
7270 nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
7271 nsCOMPtr<nsIURI> failedURI;
7272
7273 if (const nsCOMPtr<nsIScriptChannel> scriptChannel =
7274 do_QueryInterface(aOpenedChannel);
7275 scriptChannel && mBrowsingContext->Top()->GetHasSessionHistory()) {
7276 MOZ_ASSERT(mDocumentViewer && mDocumentViewer->GetDocument(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer && mDocumentViewer->GetDocument
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mDocumentViewer && mDocumentViewer->GetDocument
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentViewer && mDocumentViewer->GetDocument()"
" (" "javascript: URLs evaluate in the active document" ")",
"./../../../docshell/base/nsDocShell.cpp", 7277); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer && mDocumentViewer->GetDocument()"
") (" "javascript: URLs evaluate in the active document" ")"
); do { MOZ_CrashSequence(__null, 7277); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7277 "javascript: URLs evaluate in the active document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer && mDocumentViewer->GetDocument
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mDocumentViewer && mDocumentViewer->GetDocument
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentViewer && mDocumentViewer->GetDocument()"
" (" "javascript: URLs evaluate in the active document" ")",
"./../../../docshell/base/nsDocShell.cpp", 7277); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer && mDocumentViewer->GetDocument()"
") (" "javascript: URLs evaluate in the active document" ")"
); do { MOZ_CrashSequence(__null, 7277); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7278 SetLoadingSessionHistoryInfo(
7279 CreateLoadingEntryForJavascriptURL(mActiveEntry.get(),
7280 *mDocumentViewer->GetDocument(),
7281 *viewer->GetDocument()),
7282 !mActiveEntry);
7283 }
7284
7285 // https://html.spec.whatwg.org/#finalize-a-cross-document-navigation
7286 // 9. If entryToReplace is null, then: ...
7287 // Otherwise: ...
7288 // 4. If historyEntry's document state's origin is same origin with
7289 // entryToReplace's document state's origin, then set
7290 // historyEntry's navigation API key to entryToReplace's
7291 // navigation API key.
7292 //
7293 // Check that the top BC has session history, as without it the parent doesn't
7294 // track the active entry and so can't reuse the key, which would leave us out
7295 // of sync with the contiguous entries it sends.
7296 bool isReplace =
7297 mActiveEntry && mLoadingEntry &&
7298 mBrowsingContext->Top()->GetHasSessionHistory() &&
7299 mLoadingEntry->mTriggeringNavigationType
7300 .map([](auto type) { return type == NavigationType::Replace; })
7301 .valueOr(false);
7302 if (isReplace) {
7303 nsCOMPtr<nsIURI> uri =
7304 mActiveEntry->GetURIOrInheritedForAboutBlankOrSrcdoc();
7305 nsCOMPtr<nsIURI> targetURI =
7306 mLoadingEntry->mInfo.GetURIOrInheritedForAboutBlankOrSrcdoc();
7307 bool sameOrigin =
7308 NS_SUCCEEDED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( targetURI, uri, false, false))), 1
)))
7309 targetURI, uri, false, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( targetURI, uri, false, false))), 1
)))
;
7310 if (sameOrigin) {
7311 mLoadingEntry->mInfo.NavigationKey() = mActiveEntry->NavigationKey();
7312 }
7313 }
7314
7315 if (mLoadType == LOAD_ERROR_PAGE) {
7316 // We need to set the SH entry and our current URI here and not
7317 // at the moment we load the page. We want the same behavior
7318 // of Stop() as for a normal page load. See bug 514232 for details.
7319
7320 // Revert mLoadType to load type to state the page load failed,
7321 // following function calls need it.
7322 mLoadType = mFailedLoadType;
7323
7324 Document* doc = viewer->GetDocument();
7325 if (doc) {
7326 doc->SetFailedChannel(failedChannel);
7327 }
7328
7329 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
7330 if (failedChannel) {
7331 // Make sure we have a URI to set currentURI.
7332 NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
7333 } else {
7334 // if there is no failed channel we have to explicitly provide
7335 // a triggeringPrincipal for the history entry.
7336 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
7337 }
7338
7339 if (!failedURI) {
7340 failedURI = mFailedURI;
7341 }
7342 if (!failedURI) {
7343 // We need a URI object to store a session history entry, so make up a URI
7344 NS_NewURI(getter_AddRefs(failedURI), "about:blank");
7345 }
7346
7347 // When we don't have failedURI, something wrong will happen. See
7348 // bug 291876.
7349 MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(failedURI)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(failedURI))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("failedURI" " (" "We don't have a URI for history APIs."
")", "./../../../docshell/base/nsDocShell.cpp", 7349); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "failedURI" ") (" "We don't have a URI for history APIs."
")"); do { MOZ_CrashSequence(__null, 7349); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7350
7351 mFailedChannel = nullptr;
7352 mFailedURI = nullptr;
7353
7354 // Create an shistory entry for the old load.
7355 if (failedURI) {
7356 errorOnLocationChangeNeeded = OnNewURI(
7357 failedURI, failedChannel, triggeringPrincipal, nullptr, false, false);
7358 }
7359
7360 mLoadType = LOAD_ERROR_PAGE;
7361 }
7362
7363 nsCOMPtr<nsIURI> finalURI;
7364 // If this a redirect, use the final url (uri)
7365 // else use the original url
7366 //
7367 // Note that this should match what documents do (see Document::Reset).
7368 NS_GetFinalChannelURI(aOpenedChannel, getter_AddRefs(finalURI));
7369
7370 bool onLocationChangeNeeded = false;
7371 if (finalURI) {
7372 // Pass false for aCloneSHChildren, since we're loading a new page here.
7373 onLocationChangeNeeded =
7374 OnNewURI(finalURI, aOpenedChannel, nullptr, nullptr, true, false);
7375 }
7376
7377 // We inherit the classification flags from the parent document if the
7378 // document is about:blank and the principal matches.
7379 nsCOMPtr<nsIDocShellTreeItem> parentItem;
7380 GetInProcessSameTypeParent(getter_AddRefs(parentItem));
7381 if (parentItem && finalURI && NS_IsAboutBlank(finalURI)) {
7382 RefPtr<Document> doc = viewer->GetDocument();
7383 RefPtr<Document> parentDocument = parentItem->GetDocument();
7384 if (parentDocument && doc &&
7385 doc->NodePrincipal()->Equals(parentDocument->NodePrincipal())) {
7386 doc->SetClassificationFlags(parentDocument->GetClassificationFlags());
7387 }
7388 }
7389
7390 // let's try resetting the load group if we need to...
7391 nsCOMPtr<nsILoadGroup> currentLoadGroup;
7392 NS_ENSURE_SUCCESS(do { nsresult __rv = aOpenedChannel->GetLoadGroup(getter_AddRefs
(currentLoadGroup)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7394); return NS_ERROR_FAILURE; } } while (false)
7393 aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),do { nsresult __rv = aOpenedChannel->GetLoadGroup(getter_AddRefs
(currentLoadGroup)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7394); return NS_ERROR_FAILURE; } } while (false)
7394 NS_ERROR_FAILURE)do { nsresult __rv = aOpenedChannel->GetLoadGroup(getter_AddRefs
(currentLoadGroup)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7394); return NS_ERROR_FAILURE; } } while (false)
;
7395
7396 if (currentLoadGroup != mLoadGroup) {
7397 nsLoadFlags loadFlags = 0;
7398
7399 // Cancel any URIs that are currently loading...
7400 // XXX: Need to do this eventually Stop();
7401 //
7402 // Retarget the document to this loadgroup...
7403 //
7404 /* First attach the channel to the right loadgroup
7405 * and then remove from the old loadgroup. This
7406 * puts the notifications in the right order and
7407 * we don't null-out mLSHE in OnStateChange() for
7408 * all redirected urls
7409 */
7410 aOpenedChannel->SetLoadGroup(mLoadGroup);
7411
7412 // Mark the channel as being a document URI...
7413 aOpenedChannel->GetLoadFlags(&loadFlags);
7414 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
7415 nsCOMPtr<nsILoadInfo> loadInfo = aOpenedChannel->LoadInfo();
7416 if (SandboxFlagsImplyCookies(loadInfo->GetSandboxFlags())) {
7417 loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
7418 }
7419
7420 aOpenedChannel->SetLoadFlags(loadFlags);
7421
7422 mLoadGroup->AddRequest(aRequest, nullptr);
7423 if (currentLoadGroup) {
7424 currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED);
7425 }
7426
7427 // Update the notification callbacks, so that progress and
7428 // status information are sent to the right docshell...
7429 aOpenedChannel->SetNotificationCallbacks(this);
7430 }
7431
7432 NS_ENSURE_SUCCESS(Embed(viewer, nullptr, false, aOpenedChannel, previousURI),do { nsresult __rv = Embed(viewer, nullptr, false, aOpenedChannel
, previousURI); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "Embed(viewer, nullptr, false, aOpenedChannel, previousURI)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7433); return NS_ERROR_FAILURE; } } while (false)
7433 NS_ERROR_FAILURE)do { nsresult __rv = Embed(viewer, nullptr, false, aOpenedChannel
, previousURI); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "Embed(viewer, nullptr, false, aOpenedChannel, previousURI)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7433); return NS_ERROR_FAILURE; } } while (false)
;
7434
7435 if (!mBrowsingContext->GetHasLoadedNonInitialDocument()) {
7436 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetHasLoadedNonInitialDocument(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetHasLoadedNonInitialDocument(true))),
1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(mBrowsingContext->SetHasLoadedNonInitialDocument(true))"
, "./../../../docshell/base/nsDocShell.cpp", 7436); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetHasLoadedNonInitialDocument(true))"
")"); do { MOZ_CrashSequence(__null, 7436); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
7437 }
7438
7439 mSavedRefreshURIList = nullptr;
7440 mEODForCurrentDocument = false;
7441
7442 // if this document is part of a multipart document,
7443 // the ID can be used to distinguish it from the other parts.
7444 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
7445 if (multiPartChannel) {
7446 if (PresShell* presShell = GetPresShell()) {
7447 if (Document* doc = presShell->GetDocument()) {
7448 uint32_t partID;
7449 multiPartChannel->GetPartID(&partID);
7450 doc->SetPartID(partID);
7451 }
7452 }
7453 }
7454
7455 if (errorOnLocationChangeNeeded) {
7456 FireOnLocationChange(this, failedChannel, failedURI,
7457 LOCATION_CHANGE_ERROR_PAGE);
7458 } else if (onLocationChangeNeeded) {
7459 uint32_t locationFlags =
7460 (mLoadType & LOAD_CMD_RELOAD) ? uint32_t(LOCATION_CHANGE_RELOAD) : 0;
7461 FireOnLocationChange(this, aRequest, mCurrentURI, locationFlags);
7462 }
7463
7464 return NS_OK;
7465}
7466
7467nsresult nsDocShell::NewDocumentViewerObj(const nsACString& aContentType,
7468 nsIRequest* aRequest,
7469 nsILoadGroup* aLoadGroup,
7470 nsIStreamListener** aContentHandler,
7471 nsIDocumentViewer** aViewer) {
7472 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
7473
7474 nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
7475 nsContentUtils::FindInternalDocumentViewer(aContentType);
7476 if (!docLoaderFactory) {
7477 return NS_ERROR_FAILURE;
7478 }
7479
7480 // Now create an instance of the content viewer nsLayoutDLF makes the
7481 // determination if it should be a "view-source" instead of "view"
7482 nsresult rv = docLoaderFactory->CreateInstance(
7483 "view", aOpenedChannel, aLoadGroup, aContentType, this, nullptr,
7484 aContentHandler, aViewer);
7485 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7485); return rv; } } while (false)
;
7486
7487 (*aViewer)->SetContainer(this);
7488 return NS_OK;
7489}
7490
7491nsresult nsDocShell::SetupNewViewer(nsIDocumentViewer* aNewViewer,
7492 WindowGlobalChild* aWindowActor) {
7493 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 7493); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 7493); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7494
7495 //
7496 // Copy content viewer state from previous or parent content viewer.
7497 //
7498 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
7499 //
7500 // Do NOT to maintain a reference to the old content viewer outside
7501 // of this "copying" block, or it will not be destroyed until the end of
7502 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
7503 //
7504 // In this block of code, if we get an error result, we return it
7505 // but if we get a null pointer, that's perfectly legal for parent
7506 // and parentDocumentViewer.
7507 //
7508
7509 int32_t x = 0;
7510 int32_t y = 0;
7511 int32_t cx = 0;
7512 int32_t cy = 0;
7513
7514 // This will get the size from the current content viewer or from the
7515 // Init settings
7516 DoGetPositionAndSize(&x, &y, &cx, &cy);
7517
7518 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
7519 NS_ENSURE_SUCCESS(GetInProcessSameTypeParent(getter_AddRefs(parentAsItem)),do { nsresult __rv = GetInProcessSameTypeParent(getter_AddRefs
(parentAsItem)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInProcessSameTypeParent(getter_AddRefs(parentAsItem))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7520); return NS_ERROR_FAILURE; } } while (false)
7520 NS_ERROR_FAILURE)do { nsresult __rv = GetInProcessSameTypeParent(getter_AddRefs
(parentAsItem)); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInProcessSameTypeParent(getter_AddRefs(parentAsItem))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7520); return NS_ERROR_FAILURE; } } while (false)
;
7521 nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
7522
7523 const Encoding* reloadEncoding = nullptr;
7524 int32_t reloadEncodingSource = kCharsetUninitialized;
7525 // |newMUDV| also serves as a flag to set the data from the above vars
7526 nsCOMPtr<nsIDocumentViewer> newViewer;
7527
7528 if (mDocumentViewer || parent) {
7529 nsCOMPtr<nsIDocumentViewer> oldViewer;
7530 if (mDocumentViewer) {
7531 // Get any interesting state from old content viewer
7532 // XXX: it would be far better to just reuse the document viewer ,
7533 // since we know we're just displaying the same document as before
7534 oldViewer = mDocumentViewer;
7535 } else {
7536 // No old content viewer, so get state from parent's content viewer
7537 parent->GetDocViewer(getter_AddRefs(oldViewer));
7538 }
7539
7540 if (oldViewer) {
7541 newViewer = aNewViewer;
7542 if (newViewer) {
7543 reloadEncoding =
7544 oldViewer->GetReloadEncodingAndSource(&reloadEncodingSource);
7545 }
7546 }
7547 }
7548
7549 SingleCanvasBackground canvasBg = {};
7550 bool isUnderHiddenEmbedderElement = false;
7551 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
7552 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
7553 if (viewer) {
7554 // Stop any activity that may be happening in the old document before
7555 // releasing it...
7556 viewer->Stop();
7557
7558 // Try to extract the canvas background color from the old
7559 // presentation shell, so we can use it for the next document.
7560 if (PresShell* presShell = viewer->GetPresShell()) {
7561 canvasBg = presShell->GetViewportCanvasBackground();
7562 isUnderHiddenEmbedderElement = presShell->IsUnderHiddenEmbedderElement();
7563 }
7564
7565 viewer->Close();
7566 aNewViewer->SetPreviousViewer(viewer);
7567 }
7568
7569 mDocumentViewer = nullptr;
7570
7571 // Now that we're about to switch documents, forget all of our children.
7572 // Note that we cached them as needed up in CaptureState above.
7573 DestroyChildren();
7574
7575 mDocumentViewer = aNewViewer;
7576
7577 nsCOMPtr<nsIWidget> widget = GetMainWidget();
7578 LayoutDeviceIntRect bounds(x, y, cx, cy);
7579
7580 mDocumentViewer->SetNavigationTiming(mTiming);
7581
7582 nsresult rv =
7583 MOZ_KnownLive(mDocumentViewer)(mDocumentViewer)->Init(widget, bounds, aWindowActor);
7584 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
7585 nsCOMPtr<nsIDocumentViewer> viewer = mDocumentViewer;
7586 viewer->Close();
7587 viewer->Destroy();
7588 mDocumentViewer = nullptr;
7589 SetCurrentURIInternal(nullptr);
7590 NS_WARNING("DocumentViewer Initialization failed")NS_DebugBreak(NS_DEBUG_WARNING, "DocumentViewer Initialization failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 7590)
;
7591 return rv;
7592 }
7593
7594 // If we have old state to copy, set the old state onto the new content
7595 // viewer
7596 if (newViewer) {
7597 newViewer->SetReloadEncodingAndSource(reloadEncoding, reloadEncodingSource);
7598 }
7599
7600 NS_ENSURE_TRUE(mDocumentViewer, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocumentViewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocumentViewer" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 7600); return
NS_ERROR_FAILURE; } } while (false)
;
7601
7602 // Stuff the bgcolor from the old pres shell into the new
7603 // pres shell. This improves page load continuity.
7604 if (RefPtr<PresShell> presShell = mDocumentViewer->GetPresShell()) {
7605 presShell->SetViewportCanvasBackground(canvasBg);
7606 presShell->ActivenessMaybeChanged();
7607 if (isUnderHiddenEmbedderElement) {
7608 presShell->SetIsUnderHiddenEmbedderElement(isUnderHiddenEmbedderElement);
7609 }
7610 }
7611
7612 // XXX: It looks like the LayoutState gets restored again in Embed()
7613 // right after the call to SetupNewViewer(...)
7614
7615 // We don't show the mDocumentViewer yet, since we want to draw the old page
7616 // until we have enough of the new page to show. Just return with the new
7617 // viewer still set to hidden.
7618
7619 return NS_OK;
7620}
7621
7622void nsDocShell::SetDocCurrentStateObj(SessionHistoryInfo* aInfo) {
7623 NS_ENSURE_TRUE_VOID(mDocumentViewer)do { if ((__builtin_expect(!!(!(mDocumentViewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocumentViewer" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 7623); return
; } } while (false)
;
7624
7625 RefPtr<Document> document = GetDocument();
7626 NS_ENSURE_TRUE_VOID(document)do { if ((__builtin_expect(!!(!(document)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "document" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 7626); return; }
} while (false)
;
7627
7628 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
7629 // If aInfo is null, just set the document's state object to null.
7630 if (aInfo) {
7631 scContainer = aInfo->GetStateData();
7632 }
7633 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p SetCurrentDocState %p", this
, scContainer.get()); } } while (0)
7634 ("nsDocShell %p SetCurrentDocState %p", this, scContainer.get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p SetCurrentDocState %p", this
, scContainer.get()); } } while (0)
;
7635
7636 // It's OK for scContainer too be null here; that just means there's no
7637 // state data associated with this history entry.
7638 document->SetStateObject(scContainer);
7639}
7640
7641nsresult nsDocShell::CheckLoadingPermissions() {
7642 // This method checks whether the caller may load content into
7643 // this docshell. Even though we've done our best to hide windows
7644 // from code that doesn't have the right to access them, it's
7645 // still possible for an evil site to open a window and access
7646 // frames in the new window through window.frames[] (which is
7647 // allAccess for historic reasons), so we still need to do this
7648 // check on load.
7649 nsresult rv = NS_OK;
7650
7651 if (!IsSubframe()) {
7652 // We're not a frame. Permit all loads.
7653 return rv;
7654 }
7655
7656 // Note - The check for a current JSContext here isn't necessarily sensical.
7657 // It's just designed to preserve the old semantics during a mass-conversion
7658 // patch.
7659 if (!nsContentUtils::GetCurrentJSContext()) {
7660 return NS_OK;
7661 }
7662
7663 // Check if the caller is from the same origin as this docshell,
7664 // or any of its ancestors.
7665 nsIPrincipal* subjectPrincipal = nsContentUtils::SubjectPrincipal();
7666 for (RefPtr<BrowsingContext> bc = mBrowsingContext; bc;
7667 bc = bc->GetParent()) {
7668 // If the BrowsingContext is not in process, then it
7669 // is true by construction that its principal will not
7670 // subsume the current docshell principal.
7671 if (!bc->IsInProcess()) {
7672 continue;
7673 }
7674
7675 nsCOMPtr<nsIScriptGlobalObject> sgo =
7676 bc->GetDocShell()->GetScriptGlobalObject();
7677 nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
7678
7679 nsIPrincipal* p;
7680 if (!sop || !(p = sop->GetPrincipal())) {
7681 return NS_ERROR_UNEXPECTED;
7682 }
7683
7684 // file: URIs are considered the same domain for the purpose of frame
7685 // navigation by clicking a targeted link, regardless of script
7686 // accessibility (bug 1934807).
7687 if (subjectPrincipal->Subsumes(p) ||
7688 (subjectPrincipal->SchemeIs("file") && p->SchemeIs("file"))) {
7689 // Same origin, permit load
7690 return NS_OK;
7691 }
7692 }
7693
7694 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
7695}
7696
7697//*****************************************************************************
7698// nsDocShell: Site Loading
7699//*****************************************************************************
7700
7701void nsDocShell::CopyFavicon(nsIURI* aOldURI, nsIURI* aNewURI,
7702 bool aInPrivateBrowsing) {
7703 if (XRE_IsContentProcess()) {
7704 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
7705 if (contentChild) {
7706 contentChild->SendCopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
7707 }
7708 return;
7709 }
7710
7711#ifdef MOZ_PLACES1
7712 auto* faviconService = nsFaviconService::GetFaviconService();
7713 if (faviconService) {
7714 faviconService->AsyncTryCopyFavicons(
7715 aOldURI, aNewURI,
7716 aInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE
7717 : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE);
7718 }
7719#endif
7720}
7721
7722class InternalLoadEvent : public Runnable {
7723 public:
7724 InternalLoadEvent(nsDocShell* aDocShell, nsDocShellLoadState* aLoadState)
7725 : mozilla::Runnable("InternalLoadEvent"),
7726 mDocShell(aDocShell),
7727 mLoadState(aLoadState) {
7728 // For events, both target and filename should be the version of "null" they
7729 // expect. By the time the event is fired, both window targeting and file
7730 // downloading have been handled, so we should never have an internal load
7731 // event that retargets or had a download.
7732 mLoadState->SetTarget(u""_ns);
7733 mLoadState->SetFileName(VoidString());
7734 }
7735
7736 NS_IMETHODvirtual nsresult
7737 Run() override {
7738#ifndef ANDROID
7739 MOZ_ASSERT(mLoadState->TriggeringPrincipal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mLoadState->TriggeringPrincipal()" " (" "InternalLoadEvent: Should always have a principal here"
")", "./../../../docshell/base/nsDocShell.cpp", 7740); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mLoadState->TriggeringPrincipal()" ") ("
"InternalLoadEvent: Should always have a principal here" ")"
); do { MOZ_CrashSequence(__null, 7740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7740 "InternalLoadEvent: Should always have a principal here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mLoadState->TriggeringPrincipal()" " (" "InternalLoadEvent: Should always have a principal here"
")", "./../../../docshell/base/nsDocShell.cpp", 7740); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mLoadState->TriggeringPrincipal()" ") ("
"InternalLoadEvent: Should always have a principal here" ")"
); do { MOZ_CrashSequence(__null, 7740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7741#endif
7742 return mDocShell->InternalLoad(mLoadState);
7743 }
7744
7745 private:
7746 RefPtr<nsDocShell> mDocShell;
7747 RefPtr<nsDocShellLoadState> mLoadState;
7748};
7749
7750/**
7751 * Returns true if we started an asynchronous load (i.e., from the network), but
7752 * the document we're loading there hasn't yet become this docshell's active
7753 * document.
7754 *
7755 * When JustStartedNetworkLoad is true, you should be careful about modifying
7756 * mLoadType and mLSHE. These are both set when the asynchronous load first
7757 * starts, and the load expects that, when it eventually runs InternalLoad,
7758 * mLoadType and mLSHE will have their original values.
7759 */
7760bool nsDocShell::JustStartedNetworkLoad() {
7761 return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
7762}
7763
7764// The contentType will be INTERNAL_(I)FRAME if this docshell is for a
7765// non-toplevel browsing context in spec terms. (frame, iframe, <object>,
7766// <embed>, etc)
7767//
7768// This return value will be used when we call NS_CheckContentLoadPolicy, and
7769// later when we call DoURILoad.
7770nsContentPolicyType nsDocShell::DetermineContentType() {
7771 if (!IsSubframe()) {
7772 return nsIContentPolicy::TYPE_DOCUMENT;
7773 }
7774
7775 const auto& maybeEmbedderElementType =
7776 GetBrowsingContext()->GetEmbedderElementType();
7777 if (!maybeEmbedderElementType) {
7778 // If the EmbedderElementType hasn't been set yet, just assume we're
7779 // an iframe since that's more common.
7780 return nsIContentPolicy::TYPE_INTERNAL_IFRAME;
7781 }
7782
7783 return maybeEmbedderElementType->EqualsLiteral("iframe")
7784 ? nsIContentPolicy::TYPE_INTERNAL_IFRAME
7785 : nsIContentPolicy::TYPE_INTERNAL_FRAME;
7786}
7787
7788bool nsDocShell::NoopenerForceEnabled() {
7789 // If current's top-level browsing context's active document's
7790 // cross-origin-opener-policy is "same-origin" or "same-origin + COEP" then
7791 // if currentDoc's origin is not same origin with currentDoc's top-level
7792 // origin, noopener is force enabled, and name is cleared to "_blank".
7793 auto topPolicy = mBrowsingContext->Top()->GetOpenerPolicy();
7794 return (topPolicy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN ||
7795 topPolicy ==
7796 nsILoadInfo::
7797 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP) &&
7798 !mBrowsingContext->SameOriginWithTop();
7799}
7800
7801nsresult nsDocShell::ComputeNamedTargetBrowsingContext(
7802 nsDocShellLoadState* aLoadState) {
7803 if (aLoadState->HasComputedNamedTargetBrowsingContext() ||
7804 aLoadState->Target().IsEmpty()) {
7805 return NS_OK;
7806 }
7807 // Only _self, _parent, and _top are supported in noopener case. But we
7808 // have to be careful to not apply that to the noreferrer case. See bug
7809 // 1358469.
7810 bool allowNamedTarget =
7811 !aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
7812 aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
7813 if (allowNamedTarget ||
7814 aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
7815 aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
7816 aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
7817 Document* document = GetDocument();
7818 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(document)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "document" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 7818); return NS_ERROR_FAILURE
; } } while (false)
;
7819 WindowGlobalChild* wgc = document->GetWindowGlobalChild();
7820 NS_ENSURE_TRUE(wgc, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(wgc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "wgc" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7820); return NS_ERROR_FAILURE; } } while (false)
;
7821 aLoadState->SetTargetBrowsingContext(wgc->FindBrowsingContextWithName(
7822 aLoadState->Target(), /* aUseEntryGlobalForAccessCheck */ false));
7823 }
7824 aLoadState->SetHasComputedNamedTargetBrowsingContext(true);
7825 return NS_OK;
7826}
7827
7828nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
7829 MOZ_ASSERT(aLoadState, "need a load state!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadState" " (" "need a load state!"
")", "./../../../docshell/base/nsDocShell.cpp", 7829); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState" ") (" "need a load state!" ")"
); do { MOZ_CrashSequence(__null, 7829); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7830 MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->Target().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aLoadState->Target().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aLoadState->Target().IsEmpty()" " (" "should have a target here!"
")", "./../../../docshell/base/nsDocShell.cpp", 7830); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aLoadState->Target().IsEmpty()" ") (" "should have a target here!"
")"); do { MOZ_CrashSequence(__null, 7830); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7831
7832 nsresult rv = NS_OK;
7833
7834 rv = ComputeNamedTargetBrowsingContext(aLoadState);
7835 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7835); return rv; } } while (false)
;
7836 const MaybeDiscarded<BrowsingContext>& targetBCMaybeDiscarded =
7837 aLoadState->TargetBrowsingContext();
7838 if (targetBCMaybeDiscarded.IsDiscarded()) {
7839 // e.g. target frame navigated to cross-origin site before async navigation
7840 // happened
7841 return NS_BINDING_ABORTED;
7842 }
7843 RefPtr<BrowsingContext> targetContext =
7844 targetBCMaybeDiscarded.GetMaybeDiscarded();
7845
7846 if (!targetContext) {
7847 // If the targetContext doesn't exist, then this is a new docShell and we
7848 // should consider this a TYPE_DOCUMENT load
7849 //
7850 // For example, when target="_blank"
7851
7852 // If there's no targetContext, that means we are about to create a new
7853 // window. Perform a content policy check before creating the window. Please
7854 // note for all other docshell loads content policy checks are performed
7855 // within the contentSecurityManager when the channel is about to be
7856 // openend.
7857 nsISupports* requestingContext = nullptr;
7858 if (XRE_IsContentProcess()) {
7859 // In e10s the child process doesn't have access to the element that
7860 // contains the browsing context (because that element is in the chrome
7861 // process). So we just pass mScriptGlobal.
7862 requestingContext = ToSupports(mScriptGlobal);
7863 } else {
7864 // This is for loading non-e10s tabs and toplevel windows of various
7865 // sorts.
7866 // For the toplevel window cases, requestingElement will be null.
7867 nsCOMPtr<Element> requestingElement =
7868 mScriptGlobal->GetFrameElementInternal();
7869 requestingContext = requestingElement;
7870 }
7871
7872 // Ideally we should use the same loadinfo as within DoURILoad which
7873 // should match this one when both are applicable.
7874 RefPtr secCheckLoadInfo = MakeRefPtr<LoadInfo>(
7875 mScriptGlobal, aLoadState->URI(), aLoadState->TriggeringPrincipal(),
7876 requestingContext, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
7877 0);
7878
7879 // Since Content Policy checks are performed within docShell as well as
7880 // the ContentSecurityManager we need a reliable way to let certain
7881 // nsIContentPolicy consumers ignore duplicate calls.
7882 secCheckLoadInfo->SetSkipContentPolicyCheckForWebRequest(true);
7883
7884 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
7885 rv = NS_CheckContentLoadPolicy(aLoadState->URI(), secCheckLoadInfo,
7886 &shouldLoad);
7887
7888 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || NS_CP_REJECTED(shouldLoad)((shouldLoad) != nsIContentPolicy::ACCEPT)) {
7889 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
7890 if (shouldLoad == nsIContentPolicy::REJECT_TYPE) {
7891 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
7892 }
7893 if (shouldLoad == nsIContentPolicy::REJECT_POLICY) {
7894 return NS_ERROR_BLOCKED_BY_POLICY;
7895 }
7896 }
7897
7898 return NS_ERROR_CONTENT_BLOCKED;
7899 }
7900 }
7901
7902 //
7903 // Resolve the window target before going any further...
7904 // If the load has been targeted to another DocShell, then transfer the
7905 // load to it...
7906 //
7907
7908 // We've already done our owner-inheriting. Mask out that bit, so we
7909 // don't try inheriting an owner from the target window if we came up
7910 // with a null owner above.
7911 aLoadState->UnsetInternalLoadFlag(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
7912
7913 if (!targetContext) {
7914 // If the docshell's document is sandboxed, only open a new window
7915 // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
7916 // (i.e. if allow-popups is specified)
7917 NS_ENSURE_TRUE(mDocumentViewer, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocumentViewer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocumentViewer" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 7917); return
NS_ERROR_FAILURE; } } while (false)
;
7918 Document* doc = mDocumentViewer->GetDocument();
7919
7920 const bool isDocumentAuxSandboxed =
7921 doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
7922
7923 if (isDocumentAuxSandboxed) {
7924 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
7925 }
7926
7927 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
7928 NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(win)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "win" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 7928); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7929
7930 RefPtr<BrowsingContext> newBC;
7931 nsAutoCString spec;
7932 aLoadState->URI()->GetSpec(spec);
7933
7934 // If we are a noopener load, we just hand the whole thing over to our
7935 // window.
7936 if (aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
7937 NoopenerForceEnabled()) {
7938 // Various asserts that we know to hold because NO_OPENER loads can only
7939 // happen for links.
7940 MOZ_ASSERT(!aLoadState->LoadReplace())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->LoadReplace())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aLoadState->LoadReplace(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aLoadState->LoadReplace()", "./../../../docshell/base/nsDocShell.cpp"
, 7940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLoadState->LoadReplace()"
")"); do { MOZ_CrashSequence(__null, 7940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7941 MOZ_ASSERT(aLoadState->PrincipalToInherit() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->PrincipalToInherit() == aLoadState->
TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->PrincipalToInherit
() == aLoadState->TriggeringPrincipal()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLoadState->PrincipalToInherit() == aLoadState->TriggeringPrincipal()"
, "./../../../docshell/base/nsDocShell.cpp", 7942); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->PrincipalToInherit() == aLoadState->TriggeringPrincipal()"
")"); do { MOZ_CrashSequence(__null, 7942); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7942 aLoadState->TriggeringPrincipal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->PrincipalToInherit() == aLoadState->
TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->PrincipalToInherit
() == aLoadState->TriggeringPrincipal()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLoadState->PrincipalToInherit() == aLoadState->TriggeringPrincipal()"
, "./../../../docshell/base/nsDocShell.cpp", 7942); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->PrincipalToInherit() == aLoadState->TriggeringPrincipal()"
")"); do { MOZ_CrashSequence(__null, 7942); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7943 MOZ_ASSERT(!(aLoadState->InternalLoadFlags() &do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER
| INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aLoadState->InternalLoadFlags
() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
" (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")", "./../../../docshell/base/nsDocShell.cpp", 7947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
") (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")"); do { MOZ_CrashSequence(__null, 7947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7944 ~(INTERNAL_LOAD_FLAGS_NO_OPENER |do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER
| INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aLoadState->InternalLoadFlags
() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
" (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")", "./../../../docshell/base/nsDocShell.cpp", 7947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
") (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")"); do { MOZ_CrashSequence(__null, 7947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7945 INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER
| INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aLoadState->InternalLoadFlags
() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
" (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")", "./../../../docshell/base/nsDocShell.cpp", 7947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
") (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")"); do { MOZ_CrashSequence(__null, 7947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7946 "Only INTERNAL_LOAD_FLAGS_NO_OPENER and "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER
| INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aLoadState->InternalLoadFlags
() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
" (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")", "./../../../docshell/base/nsDocShell.cpp", 7947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
") (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")"); do { MOZ_CrashSequence(__null, 7947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7947 "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER
| INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aLoadState->InternalLoadFlags
() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
" (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")", "./../../../docshell/base/nsDocShell.cpp", 7947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!(aLoadState->InternalLoadFlags() & ~(INTERNAL_LOAD_FLAGS_NO_OPENER | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER))"
") (" "Only INTERNAL_LOAD_FLAGS_NO_OPENER and " "INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER can be set"
")"); do { MOZ_CrashSequence(__null, 7947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7948 MOZ_ASSERT_IF(aLoadState->PostDataStream(),do { if (aLoadState->PostDataStream()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aLoadState
->IsFormSubmission())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->IsFormSubmission
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->IsFormSubmission()", "./../../../docshell/base/nsDocShell.cpp"
, 7949); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->IsFormSubmission()"
")"); do { MOZ_CrashSequence(__null, 7949); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
7949 aLoadState->IsFormSubmission())do { if (aLoadState->PostDataStream()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aLoadState
->IsFormSubmission())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->IsFormSubmission
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->IsFormSubmission()", "./../../../docshell/base/nsDocShell.cpp"
, 7949); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->IsFormSubmission()"
")"); do { MOZ_CrashSequence(__null, 7949); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
7950 MOZ_ASSERT(!aLoadState->HeadersStream())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->HeadersStream())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aLoadState->HeadersStream
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aLoadState->HeadersStream()", "./../../../docshell/base/nsDocShell.cpp"
, 7950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLoadState->HeadersStream()"
")"); do { MOZ_CrashSequence(__null, 7950); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7951 // If OnLinkClickSync was invoked inside the onload handler, the load
7952 // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
7953 // LOAD_LINK.
7954 MOZ_ASSERT(aLoadState->LoadType() == LOAD_LINK ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->LoadType() == LOAD_LINK || aLoadState
->LoadType() == LOAD_NORMAL_REPLACE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->LoadType() ==
LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aLoadState->LoadType() == LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
, "./../../../docshell/base/nsDocShell.cpp", 7955); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->LoadType() == LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
")"); do { MOZ_CrashSequence(__null, 7955); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7955 aLoadState->LoadType() == LOAD_NORMAL_REPLACE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->LoadType() == LOAD_LINK || aLoadState
->LoadType() == LOAD_NORMAL_REPLACE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->LoadType() ==
LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aLoadState->LoadType() == LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
, "./../../../docshell/base/nsDocShell.cpp", 7955); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->LoadType() == LOAD_LINK || aLoadState->LoadType() == LOAD_NORMAL_REPLACE"
")"); do { MOZ_CrashSequence(__null, 7955); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7956 MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLoadState->LoadIsFromSessionHistory())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aLoadState->LoadIsFromSessionHistory()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aLoadState->LoadIsFromSessionHistory()"
, "./../../../docshell/base/nsDocShell.cpp", 7956); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aLoadState->LoadIsFromSessionHistory()"
")"); do { MOZ_CrashSequence(__null, 7956); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7957 MOZ_ASSERT(aLoadState->FirstParty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->FirstParty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->FirstParty())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aLoadState->FirstParty()"
, "./../../../docshell/base/nsDocShell.cpp", 7957); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->FirstParty()" ")"); do { MOZ_CrashSequence
(__null, 7957); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
; // Windowwatcher will assume this.
7958
7959 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(aLoadState->URI());
7960
7961 // Set up our loadinfo so it will do the load as much like we would have
7962 // as possible.
7963 loadState->SetReferrerInfo(aLoadState->GetReferrerInfo());
7964 loadState->SetOriginalURI(aLoadState->OriginalURI());
7965
7966 Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
7967 aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
7968
7969 loadState->SetMaybeResultPrincipalURI(resultPrincipalURI);
7970 loadState->SetKeepResultPrincipalURIIfSet(
7971 aLoadState->KeepResultPrincipalURIIfSet());
7972 // LoadReplace will always be false due to asserts above, skip setting
7973 // it.
7974 loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
7975 loadState->SetTriggeringSandboxFlags(
7976 aLoadState->TriggeringSandboxFlags());
7977 loadState->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
7978 loadState->SetTriggeringClassificationFlags(
7979 aLoadState->TriggeringClassificationFlags());
7980 loadState->SetPolicyContainer(aLoadState->PolicyContainer());
7981 loadState->SetInheritPrincipal(aLoadState->HasInternalLoadFlags(
7982 INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
7983 // Explicit principal because we do not want any guesses as to what the
7984 // principal to inherit is: it should be aTriggeringPrincipal.
7985 loadState->SetPrincipalIsExplicit(true);
7986 loadState->SetLoadType(aLoadState->LoadType());
7987 loadState->SetForceAllowDataURI(aLoadState->HasInternalLoadFlags(
7988 INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
7989
7990 loadState->SetHasValidUserGestureActivation(
7991 aLoadState->HasValidUserGestureActivation());
7992
7993 loadState->SetTextDirectiveUserActivation(
7994 aLoadState->GetTextDirectiveUserActivation());
7995
7996 // Propagate POST data to the new load.
7997 loadState->SetPostDataStream(aLoadState->PostDataStream());
7998 loadState->SetIsFormSubmission(aLoadState->IsFormSubmission());
7999
8000 loadState->SetNavigationAPIState(aLoadState->GetNavigationAPIState());
8001
8002 rv = win->Open(spec,
8003 aLoadState->Target(), // window name
8004 u""_ns, // Features
8005 loadState,
8006 true, // aForceNoOpener
8007 getter_AddRefs(newBC));
8008 MOZ_ASSERT(!newBC)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newBC)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!newBC))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!newBC", "./../../../docshell/base/nsDocShell.cpp"
, 8008); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newBC" ")"
); do { MOZ_CrashSequence(__null, 8008); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8009 return rv;
8010 }
8011
8012 rv = win->OpenNoNavigate(spec,
8013 aLoadState->Target(), // window name
8014 u""_ns, // Features
8015 getter_AddRefs(newBC));
8016
8017 // In some cases the Open call doesn't actually result in a new
8018 // window being opened. We can detect these cases by examining the
8019 // document in |newBC|, if any.
8020 nsCOMPtr<nsPIDOMWindowOuter> piNewWin =
8021 newBC ? newBC->GetDOMWindow() : nullptr;
8022 if (piNewWin) {
8023 RefPtr<Document> newDoc = piNewWin->GetExtantDoc();
8024 if (!newDoc || newDoc->IsInitialDocument()) {
8025 aLoadState->SetInternalLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
8026 }
8027 }
8028
8029 if (newBC) {
8030 targetContext = newBC;
8031 }
8032 }
8033 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8033); return rv; } } while (false)
;
8034 NS_ENSURE_TRUE(targetContext, rv)do { if ((__builtin_expect(!!(!(targetContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "targetContext" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 8034); return
rv; } } while (false)
;
8035
8036 // If our target BrowsingContext is still pending initialization, ignore the
8037 // navigation request targeting it.
8038 if (NS_WARN_IF(targetContext->GetPendingInitialization())NS_warn_if_impl(targetContext->GetPendingInitialization(),
"targetContext->GetPendingInitialization()", "./../../../docshell/base/nsDocShell.cpp"
, 8038)
) {
8039 return NS_OK;
8040 }
8041
8042 aLoadState->SetTargetBrowsingContext(targetContext);
8043 if (aLoadState->IsFormSubmission()) {
8044 aLoadState->SetLoadType(
8045 GetLoadTypeForFormSubmission(targetContext, aLoadState));
8046 }
8047
8048 //
8049 // Transfer the load to the target BrowsingContext... Clear the window target
8050 // name to the empty string to prevent recursive retargeting!
8051 //
8052 // No window target
8053 aLoadState->SetTarget(u""_ns);
8054 // No forced download
8055 aLoadState->SetFileName(VoidString());
8056 return targetContext->InternalLoad(aLoadState);
8057}
8058
8059static nsAutoCString RefMaybeNull(nsIURI* aURI) {
8060 nsAutoCString result;
8061 if (NS_FAILED(aURI->GetRef(result))((bool)(__builtin_expect(!!(NS_FAILED_impl(aURI->GetRef(result
))), 0)))
) {
8062 result.SetIsVoid(true);
8063 }
8064 return result;
8065}
8066
8067uint32_t nsDocShell::GetSameDocumentNavigationFlags(nsIURI* aNewURI) {
8068 uint32_t flags = LOCATION_CHANGE_SAME_DOCUMENT;
8069
8070 bool equal = false;
8071 if (mCurrentURI &&
8072 NS_SUCCEEDED(mCurrentURI->EqualsExceptRef(aNewURI, &equal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mCurrentURI->EqualsExceptRef
(aNewURI, &equal))), 1)))
&& equal &&
8073 RefMaybeNull(mCurrentURI) != RefMaybeNull(aNewURI)) {
8074 flags |= LOCATION_CHANGE_HASHCHANGE;
8075 }
8076
8077 return flags;
8078}
8079
8080struct SameDocumentNavigationState {
8081 nsAutoCString mCurrentHash;
8082 nsAutoCString mNewHash;
8083 nsTArray<TextDirective> mTextDirectives;
8084 bool mCurrentURIHasRef = false;
8085 bool mNewURIHasRef = false;
8086 bool mSameExceptHashes = false;
8087 bool mSecureUpgradeURI = false;
8088 bool mHistoryNavBetweenSameDoc = false;
8089 bool mIdentical = false;
8090};
8091
8092static bool IsSamePrincipalForDocumentURI(nsIPrincipal* aCurrentPrincipal,
8093 nsIURI* aCurrentURI,
8094 nsIURI* aNewURI) {
8095 nsCOMPtr<nsIURI> principalURI = aCurrentPrincipal->GetURI();
8096 if (aCurrentPrincipal->GetIsNullPrincipal()) {
8097 if (nsCOMPtr<nsIPrincipal> precursor =
8098 aCurrentPrincipal->GetPrecursorPrincipal()) {
8099 principalURI = precursor->GetURI();
8100 }
8101 }
8102
8103 return !nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
8104 aNewURI) &&
8105 !nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
8106 aCurrentURI) &&
8107 !nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(aCurrentURI,
8108 aNewURI);
8109}
8110
8111bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
8112 SameDocumentNavigationState& aState) {
8113 MOZ_ASSERT(aLoadState)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadState", "./../../../docshell/base/nsDocShell.cpp"
, 8113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState"
")"); do { MOZ_CrashSequence(__null, 8113); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8114 if (!(aLoadState->LoadType() == LOAD_NORMAL ||
8115 aLoadState->LoadType() == LOAD_STOP_CONTENT ||
8116 LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
8117 LOAD_FLAGS_REPLACE_HISTORY)((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
||
8118 aLoadState->LoadType() == LOAD_HISTORY ||
8119 aLoadState->LoadType() == LOAD_LINK)) {
8120 return false;
8121 }
8122
8123 if (GetExtantDocument() &&
8124 GetExtantDocument()->IsUncommittedInitialDocument()) {
8125 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, document is "
"uncommitted initial", this); } } while (0)
8126 ("nsDocShell::IsSameDocumentNavigation %p false, document is "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, document is "
"uncommitted initial", this); } } while (0)
8127 "uncommitted initial",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, document is "
"uncommitted initial", this); } } while (0)
8128 this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, document is "
"uncommitted initial", this); } } while (0)
;
8129 return false;
8130 }
8131
8132 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
8133
8134 nsresult rvURINew = aLoadState->URI()->GetRef(aState.mNewHash);
8135 if (NS_SUCCEEDED(rvURINew)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURINew)), 1)))) {
8136 rvURINew = aLoadState->URI()->GetHasRef(&aState.mNewURIHasRef);
8137 }
8138
8139 // A Fragment Directive must be removed from the new hash in order to allow
8140 // fallback element id scroll.
8141 FragmentDirective::ParseAndRemoveFragmentDirectiveFromFragmentString(
8142 aState.mNewHash, &aState.mTextDirectives, aLoadState->URI());
8143
8144 if (currentURI && NS_SUCCEEDED(rvURINew)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURINew)), 1)))) {
8145 nsresult rvURIOld = currentURI->GetRef(aState.mCurrentHash);
8146 if (NS_SUCCEEDED(rvURIOld)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURIOld)), 1)))) {
8147 rvURIOld = currentURI->GetHasRef(&aState.mCurrentURIHasRef);
8148 }
8149 if (NS_SUCCEEDED(rvURIOld)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURIOld)), 1)))) {
8150 if (NS_FAILED(currentURI->EqualsExceptRef(aLoadState->URI(),((bool)(__builtin_expect(!!(NS_FAILED_impl(currentURI->EqualsExceptRef
(aLoadState->URI(), &aState.mSameExceptHashes))), 0)))
8151 &aState.mSameExceptHashes))((bool)(__builtin_expect(!!(NS_FAILED_impl(currentURI->EqualsExceptRef
(aLoadState->URI(), &aState.mSameExceptHashes))), 0)))
) {
8152 aState.mSameExceptHashes = false;
8153 }
8154 }
8155 }
8156
8157 if (!aState.mSameExceptHashes && currentURI && NS_SUCCEEDED(rvURINew)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURINew)), 1)))) {
8158 // Maybe aLoadState->URI() came from the exposable form of currentURI?
8159 nsCOMPtr<nsIURI> currentExposableURI =
8160 nsIOService::CreateExposableURI(currentURI);
8161 nsresult rvURIOld = currentExposableURI->GetRef(aState.mCurrentHash);
8162 if (NS_SUCCEEDED(rvURIOld)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURIOld)), 1)))) {
8163 rvURIOld = currentExposableURI->GetHasRef(&aState.mCurrentURIHasRef);
8164 }
8165 if (NS_SUCCEEDED(rvURIOld)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvURIOld)), 1)))) {
8166 if (NS_FAILED(currentExposableURI->EqualsExceptRef(((bool)(__builtin_expect(!!(NS_FAILED_impl(currentExposableURI
->EqualsExceptRef( aLoadState->URI(), &aState.mSameExceptHashes
))), 0)))
8167 aLoadState->URI(), &aState.mSameExceptHashes))((bool)(__builtin_expect(!!(NS_FAILED_impl(currentExposableURI
->EqualsExceptRef( aLoadState->URI(), &aState.mSameExceptHashes
))), 0)))
) {
8168 aState.mSameExceptHashes = false;
8169 }
8170 // HTTPS-Only Mode upgrades schemes from http to https in Necko, hence we
8171 // have to perform a special check here to avoid an actual navigation. If
8172 // HTTPS-Only Mode is enabled and the two URIs are same-origin (modulo the
8173 // fact that the new URI is currently http), then set mSameExceptHashes to
8174 // true and only perform a fragment navigation.
8175 if (!aState.mSameExceptHashes) {
8176 if (nsCOMPtr<nsIChannel> docChannel = GetCurrentDocChannel()) {
8177 nsCOMPtr<nsILoadInfo> docLoadInfo = docChannel->LoadInfo();
8178 nsHTTPSOnlyUtils::UpgradeMode upgradeMode =
8179 nsHTTPSOnlyUtils::GetUpgradeMode(docLoadInfo);
8180 if (!docLoadInfo->GetLoadErrorPage() &&
8181 (upgradeMode == nsHTTPSOnlyUtils::HTTPS_ONLY_MODE ||
8182 upgradeMode == nsHTTPSOnlyUtils::HTTPS_FIRST_MODE) &&
8183 nsHTTPSOnlyUtils::IsHttpDowngrade(currentExposableURI,
8184 aLoadState->URI())) {
8185 uint32_t status = docLoadInfo->GetHttpsOnlyStatus();
8186 if ((status &
8187 (nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED |
8188 nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) &&
8189 !(status & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
8190 // At this point the requested URI is for sure a fragment
8191 // navigation via HTTP and HTTPS-Only mode or HTTPS-First is
8192 // enabled. Also it is not interfering the upgrade order of
8193 // https://searchfox.org/firefox-main/source/netwerk/base/nsNetUtil.cpp#2948-2953.
8194 // Since we are on an HTTPS site the fragment
8195 // navigation should also be an HTTPS.
8196 // For that reason we should upgrade the URI to HTTPS.
8197 aState.mSecureUpgradeURI = true;
8198 aState.mSameExceptHashes = true;
8199 }
8200 }
8201 }
8202 }
8203 }
8204 }
8205
8206 if (mActiveEntry && aLoadState->LoadIsFromSessionHistory()) {
8207 aState.mHistoryNavBetweenSameDoc = mActiveEntry->SharesDocumentWith(
8208 aLoadState->GetLoadingSessionHistoryInfo()->mInfo);
8209 }
8210
8211 // Two URIs are identical if they're same except hashes, they both have
8212 // hashes, and their hashes are the same.
8213 aState.mIdentical = aState.mSameExceptHashes &&
8214 (aState.mNewURIHasRef == aState.mCurrentURIHasRef) &&
8215 aState.mCurrentHash.Equals(aState.mNewHash);
8216
8217 // A same document navigation happens when we navigate between two SHEntries
8218 // for the same document. We do a same document navigation under two
8219 // circumstances. Either
8220 //
8221 // a) we're navigating between two different SHEntries which share a
8222 // document, or
8223 //
8224 // b) we're navigating to a new shentry whose URI differs from the
8225 // current URI only in its hash, the new hash is non-empty, and
8226 // we're not doing a POST.
8227 //
8228 // The restriction that the SHEntries in (a) must be different ensures
8229 // that history.go(0) and the like trigger full refreshes, rather than
8230 // same document navigations.
8231 if (aLoadState->LoadIsFromSessionHistory()) {
8232 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation history nav %p "
"NavBetweenSameDoc=%d", this, aState.mHistoryNavBetweenSameDoc
); } } while (0)
8233 ("nsDocShell::IsSameDocumentNavigation history nav %p "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation history nav %p "
"NavBetweenSameDoc=%d", this, aState.mHistoryNavBetweenSameDoc
); } } while (0)
8234 "NavBetweenSameDoc=%d",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation history nav %p "
"NavBetweenSameDoc=%d", this, aState.mHistoryNavBetweenSameDoc
); } } while (0)
8235 this, aState.mHistoryNavBetweenSameDoc))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation history nav %p "
"NavBetweenSameDoc=%d", this, aState.mHistoryNavBetweenSameDoc
); } } while (0)
;
8236 if (!aState.mHistoryNavBetweenSameDoc ||
8237 aLoadState->GetLoadingSessionHistoryInfo()->mLoadingCurrentEntry) {
8238 return false;
8239 }
8240 } else {
8241 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
8242 ("nsDocShell::IsSameDocumentNavigation new shentry %p "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
8243 "!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
8244 this, !aLoadState->PostDataStream() ? "true" : "false",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
8245 aState.mSameExceptHashes ? "true" : "false",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
8246 aState.mNewURIHasRef ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation new shentry %p "
"!PostDataStream: %s mSameExceptHashes: %s mNewURIHasRef: %s"
, this, !aLoadState->PostDataStream() ? "true" : "false", aState
.mSameExceptHashes ? "true" : "false", aState.mNewURIHasRef ?
"true" : "false"); } } while (0)
;
8247 if (aLoadState->PostDataStream() || !aState.mSameExceptHashes ||
8248 !aState.mNewURIHasRef) {
8249 return false;
8250 }
8251 }
8252
8253 // The navigation looks same-document, but check if documentPrincipal,
8254 // mCurrentURI, and new URI are same origin to avoid failing
8255 // UpdateDocumentURI checks in the parent (bug 1783504).
8256 nsCOMPtr<nsIURI> newURI = aLoadState->URI();
8257 if (aState.mSecureUpgradeURI) {
8258 // We need to upgrade the new URI from http: to https:
8259 nsresult rv =
8260 NS_GetSecureUpgradedURI(aLoadState->URI(), getter_AddRefs(newURI));
8261 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8261); return false; } } while (false)
;
8262 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Upgraded URI to %s", newURI->GetSpecOrDefault
().get()); } } while (0)
8263 ("Upgraded URI to %s", newURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Upgraded URI to %s", newURI->GetSpecOrDefault
().get()); } } while (0)
;
8264 }
8265 RefPtr<Document> doc = GetExtantDocument();
8266 NS_ENSURE_TRUE(doc, false)do { if ((__builtin_expect(!!(!(doc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "doc" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8266); return false; } } while (false)
;
8267 if (!IsSamePrincipalForDocumentURI(doc->NodePrincipal(), mCurrentURI,
8268 newURI)) {
8269 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, possible "
"violation of the same origin policy", this); } } while (0)
8270 ("nsDocShell::IsSameDocumentNavigation %p false, possible "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, possible "
"violation of the same origin policy", this); } } while (0)
8271 "violation of the same origin policy",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, possible "
"violation of the same origin policy", this); } } while (0)
8272 this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::IsSameDocumentNavigation %p false, possible "
"violation of the same origin policy", this); } } while (0)
;
8273 return false;
8274 }
8275
8276 return true;
8277}
8278
8279nsresult nsDocShell::HandleSameDocumentNavigation(
8280 nsDocShellLoadState* aLoadState, SameDocumentNavigationState& aState) {
8281 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::HandleSameDocumentNavigation %p %s -> %s"
, this, mCurrentURI->GetSpecOrDefault().get(), aLoadState->
URI()->GetSpecOrDefault().get()); } } while (0)
8282 ("nsDocShell::HandleSameDocumentNavigation %p %s -> %s", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::HandleSameDocumentNavigation %p %s -> %s"
, this, mCurrentURI->GetSpecOrDefault().get(), aLoadState->
URI()->GetSpecOrDefault().get()); } } while (0)
8283 mCurrentURI->GetSpecOrDefault().get(),do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::HandleSameDocumentNavigation %p %s -> %s"
, this, mCurrentURI->GetSpecOrDefault().get(), aLoadState->
URI()->GetSpecOrDefault().get()); } } while (0)
8284 aLoadState->URI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell::HandleSameDocumentNavigation %p %s -> %s"
, this, mCurrentURI->GetSpecOrDefault().get(), aLoadState->
URI()->GetSpecOrDefault().get()); } } while (0)
;
8285
8286 RefPtr<Document> doc = GetDocument();
8287 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(doc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "doc" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8287); return NS_ERROR_FAILURE; } } while (false)
;
8288
8289 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
8290
8291 // We need to upgrade the new URI from http: to https:
8292 nsCOMPtr<nsIURI> newURI = aLoadState->URI();
8293 if (aState.mSecureUpgradeURI) {
8294 MOZ_TRY(NS_GetSecureUpgradedURI(aLoadState->URI(), getter_AddRefs(newURI)))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_GetSecureUpgradedURI(aLoadState->URI(), getter_AddRefs
(newURI))); if ((__builtin_expect(!!(mozTryVarTempResult.isErr
()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult
.unwrap(); })
;
8295 }
8296
8297 // https://html.spec.whatwg.org/#navigate-fragid
8298 // Step 2
8299 RefPtr<nsIStructuredCloneContainer> destinationNavigationAPIState =
8300 mActiveEntry ? mActiveEntry->GetNavigationAPIState() : nullptr;
8301 // Step 3
8302 if (auto* navigationAPIState = aLoadState->GetNavigationAPIState()) {
8303 destinationNavigationAPIState = navigationAPIState;
8304 }
8305
8306 // After firing the navigate event, we no longer need the source element.
8307 // So we take ownership of it here to avoid keeping it alive too long.
8308 RefPtr<Element> sourceElement = aLoadState->TakeSourceElement();
8309
8310 if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow(); window) {
8311 if (!aState.mHistoryNavBetweenSameDoc) {
8312 // https://html.spec.whatwg.org/#navigate-fragid
8313 // Step 1
8314 if (RefPtr<Navigation> navigation = window->Navigation()) {
8315 AutoJSAPI jsapi;
8316 if (jsapi.Init(window)) {
8317 // Step 4
8318 RefPtr apiMethodTracker = aLoadState->GetNavigationAPIMethodTracker();
8319 bool shouldContinue = navigation->FirePushReplaceReloadNavigateEvent(
8320 jsapi.cx(), aLoadState->GetNavigationType(), newURI,
8321 /* aIsSameDocument */ true,
8322 Some(aLoadState->UserNavigationInvolvement()), sourceElement,
8323 /* aFormDataEntryList */ nullptr,
8324 /* aNavigationAPIState */ destinationNavigationAPIState,
8325 /* aClassicHistoryAPIState */ nullptr, apiMethodTracker);
8326
8327 // Step 5
8328 if (!shouldContinue) {
8329 return NS_OK;
8330 }
8331 }
8332 }
8333 } else if (aLoadState->LoadType() == LOAD_HISTORY) {
8334 MaybeFireTraverseHistory(aLoadState);
8335 }
8336
8337 if (mIsBeingDestroyed) {
8338 // navigate handler destroyed this docshell.
8339 return NS_ERROR_NOT_AVAILABLE;
8340 }
8341 }
8342
8343 doc->DoNotifyPossibleTitleChange();
8344
8345 // Store the pending uninvoked directives if it is a same document
8346 // navigation. We need to set it here, in case the navigation happens before
8347 // the document has actually finished loading.
8348 doc->FragmentDirective()->SetTextDirectives(
8349 std::move(aState.mTextDirectives));
8350
8351#ifdef DEBUG1
8352 if (aState.mSameExceptHashes) {
8353 bool sameExceptHashes = false;
8354 currentURI->EqualsExceptRef(newURI, &sameExceptHashes);
8355 MOZ_ASSERT(sameExceptHashes)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sameExceptHashes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sameExceptHashes))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("sameExceptHashes"
, "./../../../docshell/base/nsDocShell.cpp", 8355); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "sameExceptHashes" ")"); do { MOZ_CrashSequence
(__null, 8355); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8356 }
8357#endif
8358 const nsCOMPtr<nsILoadInfo> loadInfo =
8359 doc->GetChannel() ? doc->GetChannel()->LoadInfo() : nullptr;
8360 if (loadInfo) {
8361 loadInfo->SetIsSameDocumentNavigation(true);
8362 }
8363 // Save the position of the scrollers.
8364 nsPoint scrollPos = GetCurScrollPos();
8365
8366 // Reset mLoadType to its original value once we exit this block, because this
8367 // same document navigation might have started after a normal, network load,
8368 // and we don't want to clobber its load type. See bug 737307.
8369 Maybe<AutoRestore<uint32_t>> loadTypeResetter;
8370 if (StaticPrefs::
8371 docshell_shistory_sameDocumentNavigationOverridesLoadType() &&
8372 !doc->NodePrincipal()->IsURIInPrefList(
8373 "docshell.shistory.sameDocumentNavigationOverridesLoadType."
8374 "forceDisable")) {
8375 loadTypeResetter.emplace(mLoadType);
8376 }
8377 if (JustStartedNetworkLoad() && !loadTypeResetter.isSome()) {
8378 loadTypeResetter.emplace(mLoadType);
8379 }
8380
8381 // If a non-same-document-navigation (i.e., a network load) is pending, make
8382 // this a replacement load, so that we don't add a SHEntry here and the
8383 // network load goes into the SHEntry it expects to.
8384 if (JustStartedNetworkLoad() && (aLoadState->LoadType() & LOAD_CMD_NORMAL)) {
8385 mLoadType = LOAD_NORMAL_REPLACE;
8386 } else {
8387 mLoadType = aLoadState->LoadType();
8388 }
8389
8390 mURIResultedInDocument = true;
8391
8392 // we need to assign aLoadState->SHEntry() to mLoadingEntry right here, so
8393 // that on History loads, SetCurrentURI() called from OnNewURI() will send
8394 // proper onLocationChange() notifications to the browser to update
8395 // back/forward buttons.
8396 UniquePtr<mozilla::dom::LoadingSessionHistoryInfo> oldLoadingEntry;
8397 mLoadingEntry.swap(oldLoadingEntry);
8398 if (aLoadState->GetLoadingSessionHistoryInfo()) {
8399 mLoadingEntry = std::make_unique<LoadingSessionHistoryInfo>(
8400 *aLoadState->GetLoadingSessionHistoryInfo());
8401 mNeedToReportActiveAfterLoadingBecomesActive = false;
8402 }
8403
8404 // Set the doc's URI according to the new history entry's URI.
8405 doc->SetDocumentURI(newURI);
8406
8407 /* This is a anchor traversal within the same page.
8408 * call OnNewURI() so that, this traversal will be
8409 * recorded in session and global history.
8410 */
8411 nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit,
8412 newURIPartitionedPrincipalToInherit;
8413 nsCOMPtr<nsIPolicyContainer> newPolicyContainer;
8414 if (mActiveEntry) {
8415 newURITriggeringPrincipal = mActiveEntry->GetTriggeringPrincipal();
8416 newURIPrincipalToInherit = mActiveEntry->GetPrincipalToInherit();
8417 newURIPartitionedPrincipalToInherit =
8418 mActiveEntry->GetPartitionedPrincipalToInherit();
8419 newPolicyContainer = mActiveEntry->GetPolicyContainer();
8420 } else {
8421 newURITriggeringPrincipal = aLoadState->TriggeringPrincipal();
8422 newURIPrincipalToInherit = doc->NodePrincipal();
8423 newURIPartitionedPrincipalToInherit = doc->PartitionedPrincipal();
8424 newPolicyContainer = doc->GetPolicyContainer();
8425 }
8426
8427 uint32_t locationChangeFlags = GetSameDocumentNavigationFlags(newURI);
8428
8429 // Pass true for aCloneSHChildren, since we're not
8430 // changing documents here, so all of our subframes are
8431 // still relevant to the new session history entry.
8432 //
8433 // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
8434 // flag on firing onLocationChange(...).
8435 // Anyway, aCloneSHChildren param is simply reflecting
8436 // doSameDocumentNavigation in this scope.
8437 //
8438 // Note: we'll actually fire onLocationChange later, in order to preserve
8439 // ordering of HistoryCommit() in the parent vs onLocationChange (bug
8440 // 1668126)
8441 bool locationChangeNeeded =
8442 OnNewURI(newURI, nullptr, newURITriggeringPrincipal,
8443 newURIPrincipalToInherit, true, true);
8444
8445 nsCOMPtr<nsIInputStream> postData;
8446 nsCOMPtr<nsIReferrerInfo> referrerInfo;
8447
8448 bool scrollRestorationIsManual = false;
8449 if (mActiveEntry) {
8450 mActiveEntry->SetScrollPosition(scrollPos.x, scrollPos.y);
8451 if (mBrowsingContext) {
8452 CollectWireframe();
8453 if (XRE_IsParentProcess()) {
8454 SessionHistoryEntry* entry =
8455 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
8456 if (entry) {
8457 entry->SetScrollPosition(scrollPos.x, scrollPos.y);
8458 }
8459 } else {
8460 (void)ContentChild::GetSingleton()
8461 ->SendSessionHistoryEntryScrollPosition(mBrowsingContext,
8462 scrollPos.x, scrollPos.y);
8463 }
8464 }
8465 }
8466 if (mLoadingEntry && !mLoadingEntry->mLoadIsFromSessionHistory) {
8467 // If we're not doing a history load, scroll restoration
8468 // should be inherited from the previous session history entry.
8469 // XXX This needs most probably tweaks once fragment navigation is
8470 // fixed to work with session-history-in-parent.
8471 SetScrollRestorationIsManualOnHistoryEntry(scrollRestorationIsManual);
8472 }
8473
8474 // If we're doing a history load, use its scroll restoration state.
8475 if (aLoadState->LoadIsFromSessionHistory()) {
8476 scrollRestorationIsManual = aLoadState->GetLoadingSessionHistoryInfo()
8477 ->mInfo.GetScrollRestorationIsManual();
8478 }
8479
8480 /* Make a new mActiveEntry. This will either be a new entry created
8481 * by OnNewURI() for normal loads or aLoadState->SHEntry() for history
8482 * loads.
8483 */
8484 if (aLoadState->LoadIsFromSessionHistory()) {
8485 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p to "
"%s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
8486 ("Moving the loading entry to the active entry on nsDocShell %p to "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p to "
"%s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
8487 "%s",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p to "
"%s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
8488 this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p to "
"%s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
;
8489
8490 nsCOMPtr<nsILayoutHistoryState> currentLayoutHistoryState;
8491 if (mActiveEntry) {
8492 currentLayoutHistoryState = mActiveEntry->GetLayoutHistoryState();
8493 }
8494
8495 UniquePtr<SessionHistoryInfo> previousActiveEntry(mActiveEntry.release());
8496 mActiveEntry = std::make_unique<SessionHistoryInfo>(mLoadingEntry->mInfo);
8497 if (currentLayoutHistoryState) {
8498 // Restore the existing nsILayoutHistoryState object, since it is
8499 // possibly being used by the layout. When doing a new load, the
8500 // shared state is copied from the existing active entry, so this
8501 // special case is needed only with the history loads.
8502 mActiveEntry->SetLayoutHistoryState(currentLayoutHistoryState);
8503 }
8504
8505 // We're passing in mCurrentURI, which could be null. SessionHistoryCommit
8506 // does require a non-null uri if this is for a refresh load of the same
8507 // URI, but in that case mCurrentURI won't be null here.
8508 mBrowsingContext->SessionHistoryCommit(
8509 *mLoadingEntry, mLoadType, mCurrentURI, previousActiveEntry.get(), true,
8510 /* No expiration update on the same document loads*/
8511 false, 0);
8512 // FIXME Need to set postdata.
8513
8514 // Set the title for the SH entry for this target url so that
8515 // SH menus in go/back/forward buttons won't be empty for this.
8516 // Note, when session history lives in the parent process, this does not
8517 // update the title there.
8518 SetTitleOnHistoryEntry(false);
8519 } else {
8520 Maybe<bool> scrollRestorationIsManual;
8521 uint32_t cacheKey = 0;
8522 if (mActiveEntry) {
8523 scrollRestorationIsManual.emplace(
8524 mActiveEntry->GetScrollRestorationIsManual());
8525
8526 // Get the postdata, page ident and referrer info from the current page,
8527 // if the new load is being done via normal means. Note that "normal
8528 // means" can be checked for just by checking for LOAD_CMD_NORMAL, given
8529 // the loadType and allowScroll check above -- it filters out some
8530 // LOAD_CMD_NORMAL cases that we wouldn't want here.
8531 if (aLoadState->LoadType() & LOAD_CMD_NORMAL) {
8532 postData = mActiveEntry->GetPostData();
8533 cacheKey = mActiveEntry->GetCacheKey();
8534 referrerInfo = mActiveEntry->GetReferrerInfo();
8535 }
8536 }
8537
8538 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, newURI->GetSpecOrDefault().get()); } } while (0)
8539 ("Creating an active entry on nsDocShell %p to %s", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, newURI->GetSpecOrDefault().get()); } } while (0)
8540 newURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, newURI->GetSpecOrDefault().get()); } } while (0)
;
8541 UniquePtr<SessionHistoryInfo> previousActiveEntry(mActiveEntry.release());
8542 if (previousActiveEntry) {
8543 mActiveEntry =
8544 std::make_unique<SessionHistoryInfo>(*previousActiveEntry, newURI);
8545 } else {
8546 mActiveEntry = std::make_unique<SessionHistoryInfo>(
8547 newURI, newURITriggeringPrincipal, newURIPrincipalToInherit,
8548 newURIPartitionedPrincipalToInherit, newPolicyContainer,
8549 mContentTypeHint);
8550 }
8551
8552 // Save the postData obtained from the previous page in to the session
8553 // history entry created for the anchor page, so that any history load of
8554 // the anchor page will restore the appropriate postData.
8555 if (postData) {
8556 mActiveEntry->SetPostData(postData);
8557 }
8558
8559 // Make sure we won't just repost without hitting the
8560 // cache first
8561 if (cacheKey != 0) {
8562 mActiveEntry->SetCacheKey(cacheKey);
8563 }
8564
8565 // As the document has not changed, the referrer info hasn't changed too,
8566 // so we can just copy it over.
8567 if (referrerInfo) {
8568 mActiveEntry->SetReferrerInfo(referrerInfo);
8569 }
8570
8571 // Set the title for the SH entry for this target url so that
8572 // SH menus in go/back/forward buttons won't be empty for this.
8573 mActiveEntry->SetTitle(mTitle);
8574
8575 if (scrollRestorationIsManual.isSome()) {
8576 mActiveEntry->SetScrollRestorationIsManual(
8577 scrollRestorationIsManual.value());
8578 }
8579
8580 if (destinationNavigationAPIState) {
8581 mActiveEntry->SetNavigationAPIState(destinationNavigationAPIState);
8582 }
8583
8584 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)((mLoadType) & ((LOAD_FLAGS_REPLACE_HISTORY) << 16)
)
) {
8585 if (previousActiveEntry) {
8586 mActiveEntry->NavigationKey() = previousActiveEntry->NavigationKey();
8587 }
8588 mBrowsingContext->ReplaceActiveSessionHistoryEntry(mActiveEntry.get());
8589 } else {
8590 mBrowsingContext->IncrementHistoryEntryCountForBrowsingContext();
8591 // FIXME We should probably just compute mChildOffset in the parent
8592 // instead of passing it over IPC here.
8593 mBrowsingContext->SetActiveSessionHistoryEntry(
8594 Some(scrollPos), mActiveEntry.get(), previousActiveEntry.get(),
8595 mLoadType, cacheKey);
8596 // FIXME Do we need to update mPreviousEntryIndex and mLoadedEntryIndex?
8597 }
8598 }
8599
8600 if (locationChangeNeeded) {
8601 FireOnLocationChange(this, nullptr, newURI, locationChangeFlags);
8602 }
8603
8604 /* Restore the original LSHE if we were loading something
8605 * while same document navigation was initiated.
8606 */
8607 mLoadingEntry.swap(oldLoadingEntry);
8608
8609 /* Set the title for the Global History entry for this anchor url.
8610 */
8611 UpdateGlobalHistoryTitle(newURI);
8612
8613 SetDocCurrentStateObj(mActiveEntry.get());
8614
8615 // Inform the favicon service that the favicon for oldURI also
8616 // applies to newURI.
8617 CopyFavicon(currentURI, newURI, UsePrivateBrowsing());
8618
8619 RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal;
8620 nsCOMPtr<nsPIDOMWindowInner> win =
8621 scriptGlobal ? scriptGlobal->GetCurrentInnerWindow() : nullptr;
8622
8623 // https://html.spec.whatwg.org/#scroll-to-fragid
8624 // 14. Update document for history step application given navigable's
8625 // active document, historyEntry, true, scriptHistoryIndex,
8626 // scriptHistoryLength, and historyHandling.
8627 if (RefPtr navigation = win ? win->Navigation() : nullptr) {
8628 MOZ_LOG(gNavigationAPILog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event from "
"HandleSameDocumentNavigation", this); } } while (0)
8629 ("nsDocShell %p triggering a navigation event from "do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event from "
"HandleSameDocumentNavigation", this); } } while (0)
8630 "HandleSameDocumentNavigation",do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event from "
"HandleSameDocumentNavigation", this); } } while (0)
8631 this))do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event from "
"HandleSameDocumentNavigation", this); } } while (0)
;
8632 // https://html.spec.whatwg.org/#update-document-for-history-step-application
8633 // 6.4.2. Update the navigation API entries for a same-document
8634 // navigation given navigation, entry, and navigationType.
8635 navigation->UpdateEntriesForSameDocumentNavigation(
8636 mActiveEntry.get(),
8637 NavigationUtils::NavigationTypeFromLoadType(mLoadType).valueOr(
8638 NavigationType::Push));
8639 }
8640
8641 // The check for uninvoked directives must come before ScrollToAnchor() is
8642 // called.
8643 const bool hasTextDirectives =
8644 doc->FragmentDirective()->HasUninvokedDirectives();
8645
8646 // https://html.spec.whatwg.org/#scroll-to-fragid
8647 // 15. Scroll to the fragment given navigable's active document.
8648
8649 // ScrollToAnchor doesn't necessarily cause us to scroll the window;
8650 // the function decides whether a scroll is appropriate based on the
8651 // arguments it receives. But even if we don't end up scrolling,
8652 // ScrollToAnchor performs other important tasks, such as informing
8653 // the presShell that we have a new hash. See bug 680257.
8654 nsresult rv = ScrollToAnchor(aState.mCurrentURIHasRef, aState.mNewURIHasRef,
8655 aState.mNewHash, aLoadState->LoadType());
8656 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8656); return rv; } } while (false)
;
8657
8658 /* restore previous position of scroller(s), if we're moving
8659 * back in history (bug 59774)
8660 */
8661 nscoord bx = 0;
8662 nscoord by = 0;
8663 bool needsScrollPosUpdate = false;
8664 if (mActiveEntry &&
8665 (aLoadState->LoadType() == LOAD_HISTORY ||
8666 aLoadState->LoadType() == LOAD_RELOAD_NORMAL) &&
8667 !scrollRestorationIsManual) {
8668 needsScrollPosUpdate = true;
8669 mActiveEntry->GetScrollPosition(&bx, &by);
8670 }
8671
8672 // Dispatch the popstate and hashchange events, as appropriate.
8673 //
8674 // The event dispatch below can cause us to re-enter script and
8675 // destroy the docshell, nulling out mScriptGlobal. Hold a stack
8676 // reference to avoid null derefs. See bug 914521.
8677 if (win) {
8678 // Fire a hashchange event URIs differ, and only in their hashes.
8679 // If the fragment contains a directive, compare hasRef.
8680 bool doHashchange = aState.mSameExceptHashes &&
8681 (!aState.mCurrentHash.Equals(aState.mNewHash) ||
8682 (hasTextDirectives &&
8683 aState.mCurrentURIHasRef != aState.mNewURIHasRef));
8684
8685 // We enqueue the hashchange event first before dispatching popstate,
8686 // differing from the spec.
8687 // See: https://github.com/whatwg/html/issues/12190
8688 if (doHashchange) {
8689 // Note that currentURI hasn't changed because it's on the
8690 // stack, so we can just use it directly as the old URI.
8691 win->DispatchAsyncHashchange(currentURI, newURI);
8692 }
8693
8694 win->DispatchSyncPopState();
8695
8696 if (needsScrollPosUpdate && win->HasActiveDocument()) {
8697 SetCurScrollPosEx(bx, by);
8698 }
8699 }
8700
8701 return NS_OK;
8702}
8703
8704static bool NavigationShouldTakeFocus(nsDocShell* aDocShell,
8705 nsDocShellLoadState* aLoadState) {
8706 if (!aLoadState->AllowFocusMove()) {
8707 return false;
8708 }
8709 if (!aLoadState->HasValidUserGestureActivation()) {
8710 return false;
8711 }
8712 const auto& sourceBC = aLoadState->SourceBrowsingContext();
8713 if (!sourceBC || !sourceBC->IsActive()) {
8714 // If the navigation didn't come from a foreground tab, then we don't steal
8715 // focus.
8716 return false;
8717 }
8718 auto* bc = aDocShell->GetBrowsingContext();
8719 if (sourceBC.get() == bc) {
8720 // If it comes from the same tab / frame, don't steal focus either.
8721 return false;
8722 }
8723 auto* fm = nsFocusManager::GetFocusManager();
8724 if (fm && bc->IsActive() && fm->IsInActiveWindow(bc)) {
8725 // If we're already on the foreground tab of the foreground window, then we
8726 // don't need to do this. This helps to e.g. not steal focus from the
8727 // browser chrome unnecessarily.
8728 return false;
8729 }
8730 if (auto* doc = aDocShell->GetExtantDocument()) {
8731 if (doc->IsInitialDocument()) {
8732 // If we're the initial load for the browsing context, the browser
8733 // chrome determines what to focus. This is important because the
8734 // browser chrome may want to e.g focus the url-bar
8735 return false;
8736 }
8737 }
8738 // Take loadDivertedInBackground into account so the behavior would be the
8739 // same as how the tab first opened.
8740 return !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false);
8741}
8742
8743uint32_t nsDocShell::GetLoadTypeForFormSubmission(
8744 BrowsingContext* aTargetBC, nsDocShellLoadState* aLoadState) {
8745 MOZ_ASSERT(aLoadState->IsFormSubmission())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->IsFormSubmission())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->IsFormSubmission
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->IsFormSubmission()", "./../../../docshell/base/nsDocShell.cpp"
, 8745); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadState->IsFormSubmission()"
")"); do { MOZ_CrashSequence(__null, 8745); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8746
8747 // https://html.spec.whatwg.org/#form-submission-algorithm
8748 // 22. Let historyHandling be "push".
8749 // 23. If form document equals targetNavigable's active document, and
8750 // form document has not yet completely loaded, then set
8751 // historyHandling to "replace".
8752 return GetBrowsingContext() == aTargetBC && !mEODForCurrentDocument
8753 ? LOAD_NORMAL_REPLACE
8754 : LOAD_LINK;
8755}
8756
8757static void MaybeConvertToReplaceLoad(nsDocShellLoadState* aLoadState,
8758 Document* aExtantDocument,
8759 bool aIdenticalURI,
8760 bool aHasActiveEntry) {
8761 // MaybeConvertToReplaceLoad implements steps 12 and 13 of #navigate, but
8762 // since we're not yet using historyBehavior for all types of loads and
8763 // configurations, we need to sometimes bail and revert to the old way of
8764 // handling push to replace load conversion. The different cases we can't
8765 // handle are:
8766 //
8767 // * When we don't have an active document
8768 // * When a document doesn't yet have a session history entry
8769 // * When we don't use historyBehavior
8770 if (!aExtantDocument || !aHasActiveEntry || !aLoadState->HistoryBehavior()) {
8771 aLoadState->ResetHistoryBehavior();
8772 return;
8773 }
8774
8775 bool convertToReplaceLoad = aLoadState->NeedsCompletelyLoadedDocument() &&
8776 !aExtantDocument->IsCompletelyLoaded();
8777 if (const auto& historyBehavior = aLoadState->HistoryBehavior();
8778 !convertToReplaceLoad && historyBehavior &&
8779 *historyBehavior == NavigationHistoryBehavior::Auto) {
8780 convertToReplaceLoad = aIdenticalURI;
8781 if (convertToReplaceLoad && aExtantDocument->GetPrincipal()) {
8782 aExtantDocument->GetPrincipal()->Equals(aLoadState->TriggeringPrincipal(),
8783 &convertToReplaceLoad);
8784 }
8785 } else if (aLoadState->HistoryBehavior() ==
8786 Some(NavigationHistoryBehavior::Replace)) {
8787 // This load is supposed to be a replace, regardless of completely loaded.
8788 // This can happen for form submissions since the planned form
8789 // navigation might be queued before the document is completely loaded
8790 // and then actually run after it is completely loaded:
8791 // https://html.spec.whatwg.org/#concept-form-submit
8792 convertToReplaceLoad = true;
8793 }
8794
8795 convertToReplaceLoad =
8796 convertToReplaceLoad || nsContentUtils::NavigationMustBeAReplace(
8797 *aLoadState->URI(), *aExtantDocument);
8798
8799 if (convertToReplaceLoad) {
8800 MOZ_LOG_FMT(gNavigationAPILog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8801 "Convert to replace when navigating from {} to {}, {}",do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8802 *aExtantDocument->GetDocumentURI(), *aLoadState->URI(),do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8803 (aLoadState->NeedsCompletelyLoadedDocument() &&do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8804 !nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI(),do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8805 *aExtantDocument))do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8806 ? "needs completely loaded document"do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
8807 : "navigation must be a replace")do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Convert to replace when navigating from {} to {}, {}"
, *aExtantDocument->GetDocumentURI(), *aLoadState->URI(
), (aLoadState->NeedsCompletelyLoadedDocument() &&
!nsContentUtils::NavigationMustBeAReplace(*aLoadState->URI
(), *aExtantDocument)) ? "needs completely loaded document" :
"navigation must be a replace"); } } while (0)
;
8808 // There is no replace variant for LOAD_LINK, so we convert it to
8809 // LOAD_NORMAL_REPLACE just like in nsDocShell::OnNewURI.
8810 if (aLoadState->LoadType() == LOAD_LINK) {
8811 aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
8812 } else {
8813 aLoadState->SetLoadType(
8814 MaybeAddLoadFlags(aLoadState->LoadType(),
8815 nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY));
8816 }
8817 aLoadState->SetHistoryBehavior(NavigationHistoryBehavior::Replace);
8818 } else {
8819 aLoadState->SetHistoryBehavior(NavigationHistoryBehavior::Push);
8820 }
8821}
8822
8823// InternalLoad performs several of the steps from
8824// https://html.spec.whatwg.org/#navigate.
8825nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
8826 Maybe<uint32_t> aCacheKey) {
8827 MOZ_ASSERT(aLoadState, "need a load state!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadState" " (" "need a load state!"
")", "./../../../docshell/base/nsDocShell.cpp", 8827); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState" ") (" "need a load state!" ")"
); do { MOZ_CrashSequence(__null, 8827); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8828 MOZ_ASSERT(aLoadState->TriggeringPrincipal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TriggeringPrincipal()" " (" "need a valid TriggeringPrincipal"
")", "./../../../docshell/base/nsDocShell.cpp", 8829); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TriggeringPrincipal()" ") ("
"need a valid TriggeringPrincipal" ")"); do { MOZ_CrashSequence
(__null, 8829); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8829 "need a valid TriggeringPrincipal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TriggeringPrincipal()" " (" "need a valid TriggeringPrincipal"
")", "./../../../docshell/base/nsDocShell.cpp", 8829); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TriggeringPrincipal()" ") ("
"need a valid TriggeringPrincipal" ")"); do { MOZ_CrashSequence
(__null, 8829); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8830
8831 if (!aLoadState->TriggeringPrincipal()) {
8832 MOZ_ASSERT(false, "InternalLoad needs a valid triggeringPrincipal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "InternalLoad needs a valid triggeringPrincipal"
")", "./../../../docshell/base/nsDocShell.cpp", 8832); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "InternalLoad needs a valid triggeringPrincipal"
")"); do { MOZ_CrashSequence(__null, 8832); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8833 return NS_ERROR_FAILURE;
8834 }
8835 if (NS_WARN_IF(mBrowsingContext->GetPendingInitialization())NS_warn_if_impl(mBrowsingContext->GetPendingInitialization
(), "mBrowsingContext->GetPendingInitialization()", "./../../../docshell/base/nsDocShell.cpp"
, 8835)
) {
8836 return NS_ERROR_NOT_AVAILABLE;
8837 }
8838
8839 const bool shouldTakeFocus = NavigationShouldTakeFocus(this, aLoadState);
8840
8841 mOriginalUriString.Truncate();
8842
8843 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p InternalLoad %s\n", this, aLoadState
->URI()->GetSpecOrDefault().get()); } } while (0)
8844 ("DOCSHELL %p InternalLoad %s\n", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p InternalLoad %s\n", this, aLoadState
->URI()->GetSpecOrDefault().get()); } } while (0)
8845 aLoadState->URI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellLeakLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOCSHELL %p InternalLoad %s\n", this, aLoadState
->URI()->GetSpecOrDefault().get()); } } while (0)
;
8846
8847 NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(IsValidLoadType(aLoadState->
LoadType()))), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"IsValidLoadType(aLoadState->LoadType())" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 8847); return NS_ERROR_INVALID_ARG
; } } while (false)
;
8848
8849 // Cancel loads coming from Docshells that are being destroyed.
8850 if (mIsBeingDestroyed) {
8851 return NS_ERROR_NOT_AVAILABLE;
8852 }
8853
8854 nsresult rv = EnsureScriptEnvironment();
8855 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8856 return rv;
8857 }
8858
8859 // If we have a target to move to, do that now.
8860 if (!aLoadState->Target().IsEmpty()) {
8861 return PerformRetargeting(aLoadState);
8862 }
8863
8864 // This is the non-retargeting load path, we've already set the right loadtype
8865 // for form submissions in nsDocShell::OnLinkClickSync.
8866 if (aLoadState->TargetBrowsingContext().IsNull()) {
8867 aLoadState->SetTargetBrowsingContext(GetBrowsingContext());
8868 }
8869
8870 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TargetBrowsingContext() == GetBrowsingContext
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aLoadState->TargetBrowsingContext() == GetBrowsingContext
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
" (" "Load must be targeting this BrowsingContext" ")", "./../../../docshell/base/nsDocShell.cpp"
, 8872); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
") (" "Load must be targeting this BrowsingContext" ")"); do
{ MOZ_CrashSequence(__null, 8872); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8871 aLoadState->TargetBrowsingContext() == GetBrowsingContext(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TargetBrowsingContext() == GetBrowsingContext
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aLoadState->TargetBrowsingContext() == GetBrowsingContext
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
" (" "Load must be targeting this BrowsingContext" ")", "./../../../docshell/base/nsDocShell.cpp"
, 8872); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
") (" "Load must be targeting this BrowsingContext" ")"); do
{ MOZ_CrashSequence(__null, 8872); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8872 "Load must be targeting this BrowsingContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TargetBrowsingContext() == GetBrowsingContext
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aLoadState->TargetBrowsingContext() == GetBrowsingContext
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
" (" "Load must be targeting this BrowsingContext" ")", "./../../../docshell/base/nsDocShell.cpp"
, 8872); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aLoadState->TargetBrowsingContext() == GetBrowsingContext()"
") (" "Load must be targeting this BrowsingContext" ")"); do
{ MOZ_CrashSequence(__null, 8872); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8873
8874 MOZ_TRY(CheckDisallowedJavascriptLoad(aLoadState))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(CheckDisallowedJavascriptLoad(aLoadState)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
8875
8876 // If we don't have a target, we're loading into ourselves, and our load
8877 // delegate may want to intercept that load.
8878 SameDocumentNavigationState sameDocumentNavigationState;
8879 bool sameDocument =
8880 IsSameDocumentNavigation(aLoadState, sameDocumentNavigationState) &&
8881 !aLoadState->GetPendingRedirectedChannel();
8882
8883 if (mLoadType != LOAD_ERROR_PAGE &&
8884 !aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL)) {
8885 MaybeConvertToReplaceLoad(aLoadState, GetExtantDocument(),
8886 sameDocumentNavigationState.mIdentical,
8887 !!mActiveEntry);
8888 }
8889
8890 // Note: We do this check both here and in BrowsingContext::
8891 // LoadURI/InternalLoad, since document-specific sandbox flags are only
8892 // available in the process triggering the load, and we don't want the target
8893 // process to have to trust the triggering process to do the appropriate
8894 // checks for the BrowsingContext's sandbox flags.
8895 MOZ_TRY(mBrowsingContext->EnsureSourceSandboxAllowsNavigation(aLoadState))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(mBrowsingContext->EnsureSourceSandboxAllowsNavigation(aLoadState
)); if ((__builtin_expect(!!(mozTryVarTempResult.isErr()), 0)
)) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult
.unwrap(); })
;
8896 MOZ_TRY(mBrowsingContext->CheckFramebusting(aLoadState))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(mBrowsingContext->CheckFramebusting(aLoadState)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
8897
8898 NS_ENSURE_STATE(!HasUnloadedParent())do { if ((__builtin_expect(!!(!(!HasUnloadedParent())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!HasUnloadedParent()"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 8898); return NS_ERROR_UNEXPECTED; } } while (false)
;
8899
8900 rv = CheckLoadingPermissions();
8901 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8902 return rv;
8903 }
8904
8905 if (mFiredUnloadEvent) {
8906 if (IsOKToLoadURI(aLoadState->URI())) {
8907 MOZ_ASSERT(aLoadState->Target().IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->Target().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->Target().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->Target().IsEmpty()" " (" "Shouldn't have a window target here!"
")", "./../../../docshell/base/nsDocShell.cpp", 8908); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->Target().IsEmpty()" ") (" "Shouldn't have a window target here!"
")"); do { MOZ_CrashSequence(__null, 8908); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8908 "Shouldn't have a window target here!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->Target().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->Target().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->Target().IsEmpty()" " (" "Shouldn't have a window target here!"
")", "./../../../docshell/base/nsDocShell.cpp", 8908); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->Target().IsEmpty()" ") (" "Shouldn't have a window target here!"
")"); do { MOZ_CrashSequence(__null, 8908); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8909
8910 // If this is a replace load, make whatever load triggered
8911 // the unload event also a replace load, so we don't
8912 // create extra history entries.
8913 if (LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
8914 LOAD_FLAGS_REPLACE_HISTORY)((aLoadState->LoadType()) & ((LOAD_FLAGS_REPLACE_HISTORY
) << 16))
) {
8915 mLoadType = LOAD_NORMAL_REPLACE;
8916 }
8917
8918 // Do this asynchronously
8919 RefPtr ev = MakeRefPtr<InternalLoadEvent>(this, aLoadState);
8920 return Dispatch(ev.forget());
8921 }
8922
8923 // Just ignore this load attempt
8924 return NS_OK;
8925 }
8926
8927 // If we are loading a URI that should inherit a security context (basically
8928 // javascript: at this point), and the caller has said that principal
8929 // inheritance is allowed, there are a few possible cases:
8930 //
8931 // 1) We are provided with the principal to inherit. In that case, we just use
8932 // it.
8933 //
8934 // 2) The load is coming from some other application. In this case we don't
8935 // want to inherit from whatever document we have loaded now, since the
8936 // load is unrelated to it.
8937 //
8938 // 3) It's a load from our application, but does not provide an explicit
8939 // principal to inherit. In that case, we want to inherit the principal of
8940 // our current document, or of our parent document (if any) if we don't
8941 // have a current document.
8942 {
8943 bool inherits;
8944
8945 if (!aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL) &&
8946 !aLoadState->PrincipalToInherit() &&
8947 (aLoadState->HasInternalLoadFlags(
8948 INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL)) &&
8949 NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::URIInheritsSecurityContext
( aLoadState->URI(), &inherits))), 1)))
8950 aLoadState->URI(), &inherits))((bool)(__builtin_expect(!!(!NS_FAILED_impl(nsContentUtils::URIInheritsSecurityContext
( aLoadState->URI(), &inherits))), 1)))
&&
8951 inherits) {
8952 aLoadState->SetPrincipalToInherit(GetInheritedPrincipal(true));
8953 }
8954 // If principalToInherit is still null (e.g. if some of the conditions of
8955 // were not satisfied), then no inheritance of any sort will happen: the
8956 // load will just get a principal based on the URI being loaded.
8957 }
8958
8959 // If this docshell is owned by a frameloader, make sure to cancel
8960 // possible frameloader initialization before loading a new page.
8961 nsCOMPtr<nsIDocShellTreeItem> parent = GetInProcessParentDocshell();
8962 if (parent) {
8963 RefPtr<Document> doc = parent->GetDocument();
8964 if (doc) {
8965 doc->TryCancelFrameLoaderInitialization(this);
8966 }
8967 }
8968
8969 // Before going any further vet loads initiated by external programs.
8970 if (aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL)) {
8971 MOZ_DIAGNOSTIC_ASSERT(aLoadState->LoadType() == LOAD_NORMAL)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->LoadType() == LOAD_NORMAL)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aLoadState->LoadType() == LOAD_NORMAL))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadState->LoadType() == LOAD_NORMAL"
, "./../../../docshell/base/nsDocShell.cpp", 8971); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "aLoadState->LoadType() == LOAD_NORMAL"
")"); do { MOZ_CrashSequence(__null, 8971); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8972
8973 // Disallow external chrome: loads targetted at content windows
8974 if (aLoadState->URI()->SchemeIs("chrome")) {
8975 NS_WARNING("blocked external chrome: url -- use '--chrome' option")NS_DebugBreak(NS_DEBUG_WARNING, "blocked external chrome: url -- use '--chrome' option"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 8975)
;
8976 return NS_ERROR_FAILURE;
8977 }
8978
8979 // clear the decks to prevent context bleed-through (bug 298255)
8980 rv = CreateAboutBlankDocumentViewer(nullptr, nullptr, nullptr, nullptr,
8981 /* aIsInitialDocument */ false);
8982 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8983 return NS_ERROR_FAILURE;
8984 }
8985
8986 if (Document* doc = GetDocument()) {
8987 doc->DisallowBFCaching();
8988 }
8989 }
8990
8991 mAllowKeywordFixup = aLoadState->HasInternalLoadFlags(
8992 INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
8993 mURIResultedInDocument = false; // reset the clock...
8994
8995 // If container is an iframe element and will lazy load element steps given
8996 // container returns true, then stop intersection-observing a lazy loading
8997 // element container and set container's lazy load resumption steps to null.
8998 if (IsSubframe()) {
8999 if (auto* iframe = HTMLIFrameElement::FromNodeOrNull(
9000 mBrowsingContext->GetEmbedderElement())) {
9001 // Per spec, reload doesn't cancel lazy loading iframes.
9002 if (!(aLoadState->LoadType() & LOAD_RELOAD_NORMAL)) {
9003 iframe->StopLazyLoading(HTMLIFrameElement::TriggerLoad::No);
9004 }
9005 }
9006 }
9007
9008 CallerType callerType = aLoadState->TriggeringPrincipal()->IsSystemPrincipal()
9009 ? CallerType::System
9010 : CallerType::NonSystem;
9011
9012 if (!aLoadState->LoadIsFromSessionHistory() &&
9013 !mBrowsingContext->CheckNavigationRateLimit(callerType)) {
9014 return NS_OK;
9015 }
9016
9017 // See if this is actually a load between two history entries for the same
9018 // document. If the process fails, or if we successfully navigate within the
9019 // same document, return.
9020 if (sameDocument) {
9021 nsresult rv =
9022 HandleSameDocumentNavigation(aLoadState, sameDocumentNavigationState);
9023 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9023); return rv; } } while (false)
;
9024 if (shouldTakeFocus) {
9025 mBrowsingContext->Focus(CallerType::System, IgnoreErrors());
9026 }
9027 if (aLoadState->LoadIsFromSessionHistory() &&
9028 (mLoadType & LOAD_CMD_HISTORY)) {
9029 // https://html.spec.whatwg.org/#apply-the-history-step
9030 // 14.10.1 Set navigable's ongoing navigation to null.
9031 SetOngoingNavigation(Nothing());
9032 }
9033 return rv;
9034 }
9035
9036 // mDocumentViewer->PermitUnload can destroy |this| docShell, which
9037 // causes the next call of CanSavePresentation to crash.
9038 // Hold onto |this| until we return, to prevent a crash from happening.
9039 // (bug#331040)
9040 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
9041
9042 // Don't init timing for javascript:, since it generally doesn't
9043 // actually start a load or anything. If it does, we'll init
9044 // timing then, from OnStateChange.
9045
9046 // XXXbz mTiming should know what channel it's for, so we don't
9047 // need this hackery.
9048 const bool isJavaScript = aLoadState->URI()->SchemeIs("javascript");
9049 const bool isExternalProtocol =
9050 nsContentUtils::IsExternalProtocol(aLoadState->URI());
9051 const bool isDownload = !aLoadState->FileName().IsVoid();
9052 const bool toBeReset = !isJavaScript && MaybeInitTiming();
9053
9054 // FIXME(emilio): Should this be done by javascript: uris? What about external
9055 // protocols?
9056 if (mTiming && !isDownload) {
9057 mTiming->NotifyBeforeUnload();
9058 }
9059
9060 // The following steps are from https://html.spec.whatwg.org/#navigate
9061 // 20. Set the ongoing navigation for navigable to navigationId.
9062 // Session history loads are history steps, not #navigate, and must not abort
9063 // the navigate event that was fired for them.
9064 if (aLoadState->LoadIsFromSessionHistory()) {
9065 SetOngoingNavigation(Some(OngoingNavigation::NavigationID));
9066 } else {
9067 ResetOngoingNavigation(Some(OngoingNavigation::NavigationID));
9068 }
9069
9070 // 21. If url's scheme is "javascript":
9071 if (isJavaScript) {
9072 // 21.1 Queue a global task on the navigation and traversal task source
9073 // given navigable's active window to navigate to a javascript: URL
9074 // given navigable, url, historyHandling, sourceSnapshotParams,
9075 // initiatorOriginSnapshot, userInvolvement, cspNavigationType,
9076 // initialInsertion, and navigationId.
9077 // 21.2 Return.
9078 //
9079 // Note: We don't queue a task, so instead we run step 3 of
9080 // https://html.spec.whatwg.org/#navigate-to-a-javascript:-url
9081 // 3. Set the ongoing navigation for targetNavigable to null.
9082 ResetOngoingNavigation(Nothing());
9083 }
9084
9085 // After firing the navigate event, we no longer need the source element.
9086 // So we take ownership of it here to avoid keeping it alive too long.
9087 RefPtr<Element> sourceElement = aLoadState->TakeSourceElement();
9088
9089 // 22. If all of the following are true:
9090 // * userInvolvement is not "browser UI";
9091 // * navigable's active document's origin is same origin-domain with
9092 // sourceDocument's origin;
9093 // * navigable's active document's is initial about:blank is false; and
9094 // * url's scheme is a fetch scheme,
9095 // then:
9096 if (RefPtr<Document> document = GetDocument();
9097 !isDownload && !aLoadState->LoadIsFromSessionHistory() && document &&
9098 aLoadState->UserNavigationInvolvement() !=
9099 UserNavigationInvolvement::BrowserUI &&
9100 !document->IsInitialDocument() &&
9101 !NS_IsAboutBlankAllowQueryAndFragment(document->GetDocumentURI()) &&
9102 NS_IsFetchScheme(aLoadState->URI()) &&
9103 document->NodePrincipal()->EqualsConsideringDomain(
9104 aLoadState->TriggeringPrincipal())) {
9105 if (nsCOMPtr<nsPIDOMWindowInner> window = document->GetInnerWindow()) {
9106 // 22.1 Let navigation be navigable's active window's navigation API.
9107 if (RefPtr<Navigation> navigation = window->Navigation()) {
9108 AutoJSAPI jsapi;
9109 if (jsapi.Init(window)) {
9110 // 22.2 Let entryListForFiring be formDataEntryList if
9111 // documentResource is a POST resource; otherwise, null.
9112 RefPtr<FormData> formData = aLoadState->GetFormDataEntryList();
9113
9114 // 22.3 Let navigationAPIStateForFiring be navigationAPIState if
9115 // navigationAPIState is not null; otherwise,
9116 // StructuredSerializeForStorage(undefined).
9117 RefPtr<nsIStructuredCloneContainer> navigationAPIStateForFiring =
9118 aLoadState->GetNavigationAPIState();
9119
9120 nsCOMPtr<nsIURI> destinationURL = aLoadState->URI();
9121 // 22.4 Let continue be the result of firing a push/replace/reload
9122 // navigate event at navigation with navigationType set to
9123 // historyHandling, isSameDocument set to false, userInvolvement
9124 // set to userInvolvement, sourceElement set to sourceElement,
9125 // formDataEntryList set to entryListForFiring, destinationURL
9126 // set to url, navigationAPIState set to
9127 // navigationAPIStateForFiring, and apiMethodTracker set to
9128 // apiMethodTracker.
9129 RefPtr apiMethodTracker = aLoadState->GetNavigationAPIMethodTracker();
9130 bool shouldContinue = navigation->FirePushReplaceReloadNavigateEvent(
9131 jsapi.cx(), aLoadState->GetNavigationType(), destinationURL,
9132 /* aIsSameDocument */ false,
9133 Some(aLoadState->UserNavigationInvolvement()), sourceElement,
9134 formData, navigationAPIStateForFiring,
9135 /* aClassicHistoryAPIState */ nullptr, apiMethodTracker);
9136
9137 // 22.5 If continue is false, then return.
9138 if (!shouldContinue) {
9139 return NS_OK;
9140 }
9141 }
9142 }
9143 }
9144 }
9145
9146 // Check if the page doesn't want to be unloaded. The javascript:
9147 // protocol handler deals with this for javascript: URLs.
9148 // NOTE(emilio): As of this writing, other browsers fire beforeunload for
9149 // external protocols, so keep doing that even though they don't return data
9150 // and thus we won't really unload this...
9151 if (!isJavaScript && !isDownload &&
9152 !aLoadState->NotifiedBeforeUnloadListeners() && mDocumentViewer) {
9153 // Check if request is exempted from HTTPSOnlyMode and if https-first is
9154 // enabled, if so it means:
9155 // * https-first failed to upgrade request to https
9156 // * we already asked for permission to unload and the user accepted
9157 // otherwise we wouldn't be here.
9158 const bool isPrivateWin = GetOriginAttributes().IsPrivateBrowsing();
9159 const uint32_t loadType = aLoadState->LoadType();
9160
9161 // Check if request is a reload.
9162 const bool isHistoryOrReload =
9163 loadType == LOAD_RELOAD_NORMAL ||
9164 loadType == LOAD_RELOAD_BYPASS_CACHE ||
9165 loadType == LOAD_RELOAD_BYPASS_PROXY ||
9166 loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
9167 loadType == LOAD_HISTORY;
9168
9169 // If it isn't a reload, the request already failed to be upgraded and
9170 // https-first is enabled then don't ask the user again for permission to
9171 // unload and just unload.
9172 bool okToUnload;
9173 if (!isHistoryOrReload && aLoadState->IsExemptFromHTTPSFirstMode() &&
9174 nsHTTPSOnlyUtils::GetUpgradeMode(isPrivateWin) ==
9175 nsHTTPSOnlyUtils::HTTPS_FIRST_MODE) {
9176 rv = mDocumentViewer->PermitUnload(
9177 nsIDocumentViewer::PermitUnloadAction::eDontPromptAndUnload,
9178 &okToUnload);
9179 } else {
9180 rv = mDocumentViewer->PermitUnload(&okToUnload);
9181 if (mIsBeingDestroyed) {
9182 // unload handler destroyed this docshell.
9183 return NS_ERROR_NOT_AVAILABLE;
9184 }
9185 }
9186
9187 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !okToUnload) {
9188 // The user chose not to unload the page, interrupt the
9189 // load.
9190 MaybeResetInitTiming(toBeReset);
9191 return NS_OK;
9192 }
9193 }
9194
9195 if (mTiming && !isDownload) {
9196 mTiming->NotifyUnloadAccepted(mCurrentURI);
9197 }
9198
9199 if (aLoadState->LoadType() == LOAD_HISTORY) {
9200 MaybeFireTraverseHistory(aLoadState);
9201
9202 if (mIsBeingDestroyed) {
9203 // navigate handler destroyed this docshell.
9204 return NS_ERROR_NOT_AVAILABLE;
9205 }
9206 }
9207
9208 // In e10s, in the parent process, we refuse to load anything other than
9209 // "safe" resources that we ship or trust enough to give "special" URLs.
9210 // Similar check will be performed by the ParentProcessDocumentChannel if in
9211 // use.
9212 if (XRE_IsE10sParentProcess() &&
9213 !DocumentChannel::CanUseDocumentChannel(aLoadState->URI()) &&
9214 !CanLoadInParentProcess(aLoadState->URI())) {
9215 return NS_ERROR_FAILURE;
9216 }
9217
9218 // Whenever a top-level browsing context is navigated, the user agent MUST
9219 // lock the orientation of the document to the document's default
9220 // orientation. We don't explicitly check for a top-level browsing context
9221 // here because orientation is only set on top-level browsing contexts.
9222 if (mBrowsingContext->GetOrientationLock() != hal::ScreenOrientation::None) {
9223 MOZ_ASSERT(mBrowsingContext->IsTop())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsTop()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mBrowsingContext->IsTop()", "./../../../docshell/base/nsDocShell.cpp"
, 9223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsTop()"
")"); do { MOZ_CrashSequence(__null, 9223); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9224 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation
::None))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation::None))"
, "./../../../docshell/base/nsDocShell.cpp", 9225); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation::None))"
")"); do { MOZ_CrashSequence(__null, 9225); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
9225 mBrowsingContext->SetOrientationLock(hal::ScreenOrientation::None))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation
::None))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation::None))"
, "./../../../docshell/base/nsDocShell.cpp", 9225); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetOrientationLock(hal::ScreenOrientation::None))"
")"); do { MOZ_CrashSequence(__null, 9225); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
9226 if (mBrowsingContext->IsActive()) {
9227 ScreenOrientation::UpdateActiveOrientationLock(
9228 hal::ScreenOrientation::None);
9229 }
9230 }
9231
9232 // Do a check so that we know if there are ongoing requests
9233 // before calling Stop() below.
9234 Document* document = GetDocument();
9235 uint32_t flags = 0;
9236 if (document && !document->CanSavePresentation(nullptr, flags, true)) {
9237 // This forces some flags into the WindowGlobalParent's mBFCacheStatus,
9238 // which we'll then use in CanonicalBrowsingContext::AllowedInBFCache,
9239 // and in particular we'll store BFCacheStatus::REQUEST if needed.
9240 // Also, we want to report all the flags to the parent process here (and
9241 // not just BFCacheStatus::NOT_ALLOWED), so that it can update the
9242 // telemetry data correctly.
9243 document->DisallowBFCaching(flags);
9244 }
9245
9246 if (aLoadState->LoadIsFromSessionHistory() &&
9247 (mLoadType & LOAD_CMD_HISTORY)) {
9248 SetOngoingNavigation(Nothing());
9249 }
9250
9251 if (aLoadState->LoadIsFromSessionHistory() &&
9252 (aLoadState->LoadType() & LOAD_CMD_HISTORY)) {
9253 ClearNavigationAPIOngoingNavigationForHistoryStep();
9254 }
9255
9256 // Don't stop current network activity for javascript: URL's since they might
9257 // not result in any data, and thus nothing should be stopped in those cases.
9258 // In the case where they do result in data, the javascript: URL channel takes
9259 // care of stopping current network activity. Similarly, downloads don't
9260 // unload this document...
9261 if (!isJavaScript && !isDownload && !isExternalProtocol) {
9262 // Stop any current network activity.
9263 // Also stop content if this is a zombie doc. otherwise
9264 // the onload will be delayed by other loads initiated in the
9265 // background by the first document that
9266 // didn't fully load before the next load was initiated.
9267 // If not a zombie, don't stop content until data
9268 // starts arriving from the new URI...
9269 if ((mDocumentViewer && mDocumentViewer->GetPreviousViewer()) ||
9270 LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(), LOAD_FLAGS_STOP_CONTENT)((aLoadState->LoadType()) & ((LOAD_FLAGS_STOP_CONTENT)
<< 16))
) {
9271 rv = StopInternal(nsIWebNavigation::STOP_ALL, UnsetOngoingNavigation::No);
9272 } else {
9273 rv = StopInternal(nsIWebNavigation::STOP_NETWORK,
9274 UnsetOngoingNavigation::No);
9275 }
9276
9277 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9278 return rv;
9279 }
9280 }
9281
9282 // StopInternal cleared the flag, but a traversal that starts again as a new
9283 // load already fired pageswap.
9284 if (aLoadState->PageSwapFired()) {
9285 mFiredCrossDocPageSwap = true;
9286 }
9287
9288 mLoadType = aLoadState->LoadType();
9289
9290 if (aLoadState->LoadIsFromSessionHistory() &&
9291 (mLoadType & LOAD_CMD_HISTORY)) {
9292 if (RefPtr window = GetActiveWindow()) {
9293 if (RefPtr navigation = window->Navigation()) {
9294 if (const LoadingSessionHistoryInfo* loadingInfo =
9295 GetLoadingSessionHistoryInfo()) {
9296 navigation->CreateNavigationActivationFrom(
9297 loadingInfo->mPreviousEntry,
9298 NavigationUtils::NavigationTypeFromLoadType(mLoadType));
9299 }
9300 }
9301 }
9302
9303 // https://html.spec.whatwg.org/#history-traversal:
9304 // To traverse the history
9305 // "If entry has a different Document object than the current entry, then
9306 // run the following substeps: Remove any tasks queued by the history
9307 // traversal task source..."
9308 // Same document object case was handled already above with
9309 // HandleSameDocumentNavigation call.
9310 RefPtr<ChildSHistory> shistory = GetRootSessionHistory();
9311 if (shistory) {
9312 shistory->RemovePendingHistoryNavigations();
9313 }
9314 }
9315
9316 bool isTopLevelDoc = mBrowsingContext->IsTopContent();
9317
9318 OriginAttributes attrs = GetOriginAttributes();
9319 attrs.SetFirstPartyDomain(isTopLevelDoc, aLoadState->URI());
9320
9321 nsCOMPtr<nsIRequest> req;
9322 rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req));
9323
9324 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
9325 if (shouldTakeFocus) {
9326 mBrowsingContext->Focus(CallerType::System, IgnoreErrors());
9327 }
9328 }
9329
9330 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9331 nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
9332 UnblockEmbedderLoadEventForFailure();
9333
9334 // The spec says no exception should be raised for pre-navigation check
9335 // failures.
9336 if (NS_ERROR_DOM_SECURITY_ERR == rv) {
9337 return NS_OK;
9338 }
9339
9340 nsCOMPtr<nsIURI> uri = aLoadState->URI();
9341 if (DisplayLoadError(rv, uri, nullptr, chan) &&
9342 // FIXME: At this point code was using internal load flags, but checking
9343 // non-internal load flags?
9344 aLoadState->HasLoadFlags(LOAD_FLAGS_ERROR_LOAD_CHANGES_RV)) {
9345 return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
9346 }
9347
9348 // We won't report any error if this is an unknown protocol error. The
9349 // reason behind this is that it will allow enumeration of external
9350 // protocols if we report an error for each unknown protocol.
9351 if (NS_ERROR_UNKNOWN_PROTOCOL == rv) {
9352 return NS_OK;
9353 }
9354 }
9355
9356 return rv;
9357}
9358
9359/* static */
9360bool nsDocShell::CanLoadInParentProcess(nsIURI* aURI) {
9361 nsCOMPtr<nsIURI> uri = aURI;
9362 // In e10s, in the parent process, we refuse to load anything other than
9363 // "safe" resources that we ship or trust enough to give "special" URLs.
9364 bool canLoadInParent = false;
9365 if (NS_SUCCEEDED(NS_URIChainHasFlags(((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_URIChainHasFlags
( uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &canLoadInParent
))), 1)))
9366 uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &canLoadInParent))((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_URIChainHasFlags
( uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &canLoadInParent
))), 1)))
&&
9367 canLoadInParent) {
9368 // We allow UI resources.
9369 return true;
9370 }
9371 // For about: and extension-based URIs, which don't get
9372 // URI_IS_UI_RESOURCE, first remove layers of view-source:, if present.
9373 while (uri && uri->SchemeIs("view-source")) {
9374 nsCOMPtr<nsINestedURI> nested = do_QueryInterface(uri);
9375 if (nested) {
9376 nested->GetInnerURI(getter_AddRefs(uri));
9377 } else {
9378 break;
9379 }
9380 }
9381 // Allow about: URIs, execept about:srcdoc, which can include arbitrary code.
9382 // And allow moz-extension ones if we're running extension content in the
9383 // parent process.
9384 if (!uri || (uri->SchemeIs("about") && !NS_IsAboutSrcdoc(uri)) ||
9385 (!StaticPrefs::extensions_webextensions_remote() &&
9386 uri->SchemeIs("moz-extension"))) {
9387 return true;
9388 }
9389#ifdef MOZ_THUNDERBIRD
9390 if (uri->SchemeIs("imap") || uri->SchemeIs("mailbox") ||
9391 uri->SchemeIs("news") || uri->SchemeIs("nntp") ||
9392 uri->SchemeIs("snews") || uri->SchemeIs("x-moz-ews") ||
9393 uri->SchemeIs("x-moz-graph")) {
9394 return true;
9395 }
9396#endif
9397 nsAutoCString scheme;
9398 uri->GetScheme(scheme);
9399 // Allow ext+foo URIs (extension-registered custom protocols). See
9400 // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/protocol_handlers
9401 if (StringBeginsWith(scheme, "ext+"_ns) &&
9402 !StaticPrefs::extensions_webextensions_remote()) {
9403 return true;
9404 }
9405 // Final exception for some legacy automated tests:
9406 if (xpc::IsInAutomation() &&
9407 StaticPrefs::security_allow_unsafe_parent_loads()) {
9408 return true;
9409 }
9410 return false;
9411}
9412
9413nsIPrincipal* nsDocShell::GetInheritedPrincipal(
9414 bool aConsiderCurrentDocument, bool aConsiderPartitionedPrincipal) {
9415 RefPtr<Document> document;
9416 bool inheritedFromCurrent = false;
9417
9418 if (aConsiderCurrentDocument && mDocumentViewer) {
9419 document = mDocumentViewer->GetDocument();
9420 inheritedFromCurrent = true;
9421 }
9422
9423 if (!document) {
9424 nsCOMPtr<nsIDocShellTreeItem> parentItem;
9425 GetInProcessSameTypeParent(getter_AddRefs(parentItem));
9426 if (parentItem) {
9427 document = parentItem->GetDocument();
9428 }
9429 }
9430
9431 if (!document) {
9432 if (!aConsiderCurrentDocument) {
9433 return nullptr;
9434 }
9435
9436 // Make sure we end up with _something_ as the principal no matter
9437 // what.If this fails, we'll just get a null docViewer and bail.
9438 if (!VerifyDocumentViewer()) {
9439 return nullptr;
9440 }
9441 document = mDocumentViewer->GetDocument();
9442 }
9443
9444 //-- Get the document's principal
9445 if (document) {
9446 nsIPrincipal* docPrincipal = aConsiderPartitionedPrincipal
9447 ? document->PartitionedPrincipal()
9448 : document->NodePrincipal();
9449
9450 // Don't allow loads in typeContent docShells to inherit the system
9451 // principal from existing documents.
9452 if (inheritedFromCurrent && mItemType == typeContent &&
9453 docPrincipal->IsSystemPrincipal()) {
9454 return nullptr;
9455 }
9456
9457 return docPrincipal;
9458 }
9459
9460 return nullptr;
9461}
9462
9463/* static */ nsresult nsDocShell::CreateRealChannelForDocument(
9464 nsIChannel** aChannel, nsIURI* aURI, nsILoadInfo* aLoadInfo,
9465 nsIInterfaceRequestor* aCallbacks, nsLoadFlags aLoadFlags,
9466 const nsAString& aSrcdoc, nsIURI* aBaseURI) {
9467 nsCOMPtr<nsIChannel> channel;
9468 if (aSrcdoc.IsVoid()) {
9469 MOZ_TRY(NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo
, nullptr, nullptr, aCallbacks, aLoadFlags)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
9470 nullptr, // PerformanceStorage__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo
, nullptr, nullptr, aCallbacks, aLoadFlags)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
9471 nullptr, // loadGroup__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo
, nullptr, nullptr, aCallbacks, aLoadFlags)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
9472 aCallbacks, aLoadFlags))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo
, nullptr, nullptr, aCallbacks, aLoadFlags)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
9473
9474 if (aBaseURI) {
9475 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
9476 if (vsc) {
9477 MOZ_ALWAYS_SUCCEEDS(vsc->SetBaseURI(aBaseURI))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(vsc->SetBaseURI(aBaseURI))), 1)))), 1))) { } else { do { do
{ } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(vsc->SetBaseURI(aBaseURI))"
, "./../../../docshell/base/nsDocShell.cpp", 9477); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(vsc->SetBaseURI(aBaseURI))" ")"
); do { MOZ_CrashSequence(__null, 9477); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
9478 }
9479 }
9480 } else if (aURI->SchemeIs("view-source")) {
9481 // Instantiate view source handler protocol, if it doesn't exist already.
9482 nsCOMPtr<nsIIOService> io(do_GetIOService());
9483 MOZ_ASSERT(io)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(io)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(io))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("io", "./../../../docshell/base/nsDocShell.cpp"
, 9483); AnnotateMozCrashReason("MOZ_ASSERT" "(" "io" ")"); do
{ MOZ_CrashSequence(__null, 9483); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9484 nsCOMPtr<nsIProtocolHandler> handler;
9485 nsresult rv =
9486 io->GetProtocolHandler("view-source", getter_AddRefs(handler));
9487 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9488 return rv;
9489 }
9490
9491 nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
9492 if (!vsh) {
9493 return NS_ERROR_FAILURE;
9494 }
9495
9496 MOZ_TRY(vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, aLoadInfo,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, aLoadInfo,
getter_AddRefs(channel))); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
9497 getter_AddRefs(channel)))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, aLoadInfo,
getter_AddRefs(channel))); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
;
9498 } else {
9499 MOZ_RELEASE_ASSERT(NS_IsAboutSrcdoc(aURI))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsAboutSrcdoc(aURI))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsAboutSrcdoc(aURI)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsAboutSrcdoc(aURI)"
, "./../../../docshell/base/nsDocShell.cpp", 9499); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "NS_IsAboutSrcdoc(aURI)" ")"); do {
MOZ_CrashSequence(__null, 9499); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9500
9501 MOZ_TRY(NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aURI,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aURI
, aSrcdoc, "text/html"_ns, aLoadInfo, true)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
9502 aSrcdoc, "text/html"_ns, aLoadInfo,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aURI
, aSrcdoc, "text/html"_ns, aLoadInfo, true)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
9503 true))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aURI
, aSrcdoc, "text/html"_ns, aLoadInfo, true)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
9504 nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
9505 MOZ_ASSERT(isc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(isc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("isc", "./../../../docshell/base/nsDocShell.cpp"
, 9505); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isc" ")"); do
{ MOZ_CrashSequence(__null, 9505); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9506 isc->SetBaseURI(aBaseURI);
9507 }
9508
9509 if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
9510 nsresult rv = channel->SetLoadFlags(aLoadFlags);
9511 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9511); return rv; } } while (false)
;
9512 }
9513
9514 channel.forget(aChannel);
9515 return NS_OK;
9516}
9517
9518/* static */ bool nsDocShell::CreateAndConfigureRealChannelForLoadState(
9519 BrowsingContext* aBrowsingContext, nsDocShellLoadState* aLoadState,
9520 LoadInfo* aLoadInfo, nsIInterfaceRequestor* aCallbacks,
9521 const OriginAttributes& aOriginAttributes, nsLoadFlags aLoadFlags,
9522 uint32_t aCacheKey, nsresult& aRv, nsIChannel** aChannel) {
9523 MOZ_ASSERT(aLoadInfo)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadInfo))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLoadInfo", "./../../../docshell/base/nsDocShell.cpp"
, 9523); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadInfo" ")"
); do { MOZ_CrashSequence(__null, 9523); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9524
9525 nsString srcdoc = VoidString();
9526 bool isSrcdoc =
9527 aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC);
9528 if (isSrcdoc) {
9529 srcdoc = aLoadState->SrcdocData();
9530 }
9531
9532 aLoadInfo->SetTriggeringRemoteType(
9533 aLoadState->GetEffectiveTriggeringRemoteType());
9534
9535 if (aLoadState->PrincipalToInherit()) {
9536 aLoadInfo->SetPrincipalToInherit(aLoadState->PrincipalToInherit());
9537 }
9538 aLoadInfo->SetLoadTriggeredFromExternal(
9539 aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL));
9540 aLoadInfo->SetForceAllowDataURI(aLoadState->HasInternalLoadFlags(
9541 INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
9542 aLoadInfo->SetOriginalFrameSrcLoad(
9543 aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC));
9544 aLoadInfo->SetIsNewWindowTarget(
9545 aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_FIRST_LOAD));
9546 aLoadInfo->SetForceMediaDocument(aLoadState->GetForceMediaDocument());
9547
9548 bool inheritAttrs = false;
9549 if (aLoadState->PrincipalToInherit()) {
9550 inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
9551 aLoadState->PrincipalToInherit(), aLoadState->URI(),
9552 true, // aInheritForAboutBlank
9553 isSrcdoc);
9554 }
9555
9556 // Strip the target query parameters before creating the channel.
9557 aLoadState->MaybeStripTrackerQueryStrings(aBrowsingContext);
9558
9559 OriginAttributes attrs;
9560
9561 // Inherit origin attributes from PrincipalToInherit if inheritAttrs is
9562 // true. Otherwise we just use the origin attributes from docshell.
9563 if (inheritAttrs) {
9564 MOZ_ASSERT(aLoadState->PrincipalToInherit(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->PrincipalToInherit())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->PrincipalToInherit
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->PrincipalToInherit()" " (" "We should have PrincipalToInherit here."
")", "./../../../docshell/base/nsDocShell.cpp", 9565); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->PrincipalToInherit()" ") ("
"We should have PrincipalToInherit here." ")"); do { MOZ_CrashSequence
(__null, 9565); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9565 "We should have PrincipalToInherit here.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->PrincipalToInherit())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->PrincipalToInherit
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->PrincipalToInherit()" " (" "We should have PrincipalToInherit here."
")", "./../../../docshell/base/nsDocShell.cpp", 9565); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->PrincipalToInherit()" ") ("
"We should have PrincipalToInherit here." ")"); do { MOZ_CrashSequence
(__null, 9565); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9566 attrs = aLoadState->PrincipalToInherit()->OriginAttributesRef();
9567 // If firstPartyIsolation is not enabled, then PrincipalToInherit should
9568 // have the same origin attributes with docshell.
9569 MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(),do { if (!OriginAttributes::IsFirstPartyEnabled()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(attrs ==
aOriginAttributes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(attrs == aOriginAttributes))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("attrs == aOriginAttributes"
, "./../../../docshell/base/nsDocShell.cpp", 9570); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "attrs == aOriginAttributes" ")"); do { MOZ_CrashSequence
(__null, 9570); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); } } while (false)
9570 attrs == aOriginAttributes)do { if (!OriginAttributes::IsFirstPartyEnabled()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(attrs ==
aOriginAttributes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(attrs == aOriginAttributes))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("attrs == aOriginAttributes"
, "./../../../docshell/base/nsDocShell.cpp", 9570); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "attrs == aOriginAttributes" ")"); do { MOZ_CrashSequence
(__null, 9570); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); } } while (false)
;
9571 } else {
9572 attrs = aOriginAttributes;
9573 attrs.SetFirstPartyDomain(IsTopLevelDoc(aBrowsingContext, aLoadInfo),
9574 aLoadState->URI());
9575 }
9576
9577 aRv = aLoadInfo->SetOriginAttributes(attrs);
9578 if (NS_WARN_IF(NS_FAILED(aRv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(aRv
)), 0))), "NS_FAILED(aRv)", "./../../../docshell/base/nsDocShell.cpp"
, 9578)
) {
9579 return false;
9580 }
9581
9582 if (aLoadState->GetIsFromProcessingFrameAttributes()) {
9583 aLoadInfo->SetIsFromProcessingFrameAttributes();
9584 }
9585
9586 // Propagate the IsFormSubmission flag to the loadInfo.
9587 if (aLoadState->IsFormSubmission()) {
9588 aLoadInfo->SetIsFormSubmission(true);
9589 }
9590
9591 aLoadInfo->SetUnstrippedURI(aLoadState->GetUnstrippedURI());
9592
9593 nsCOMPtr<nsIChannel> channel;
9594 aRv = CreateRealChannelForDocument(getter_AddRefs(channel), aLoadState->URI(),
9595 aLoadInfo, aCallbacks, aLoadFlags, srcdoc,
9596 aLoadState->BaseURI());
9597 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9597); return false; } } while (false)
;
9598
9599 if (!channel) {
9600 return false;
9601 }
9602
9603 // If the HTTPS-Only mode is enabled, every insecure request gets upgraded to
9604 // HTTPS by default. This behavior can be disabled through the loadinfo flag
9605 // HTTPS_ONLY_EXEMPT.
9606 nsHTTPSOnlyUtils::TestSitePermissionAndPotentiallyAddExemption(channel);
9607
9608 // hack
9609 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
9610 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
9611 do_QueryInterface(channel));
9612 nsCOMPtr<nsIURI> referrer;
9613 nsIReferrerInfo* referrerInfo = aLoadState->GetReferrerInfo();
9614 if (referrerInfo) {
9615 referrerInfo->GetOriginalReferrer(getter_AddRefs(referrer));
9616 }
9617 if (httpChannelInternal) {
9618 if (aLoadState->FirstParty()) {
9619 aRv = httpChannelInternal->SetDocumentURI(aLoadState->URI());
9620 MOZ_ASSERT(NS_SUCCEEDED(aRv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))", "./../../../docshell/base/nsDocShell.cpp"
, 9620); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 9620); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9621 } else {
9622 aRv = httpChannelInternal->SetDocumentURI(referrer);
9623 MOZ_ASSERT(NS_SUCCEEDED(aRv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))", "./../../../docshell/base/nsDocShell.cpp"
, 9623); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 9623); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9624 }
9625 aRv = httpChannelInternal->SetRedirectMode(
9626 nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
9627 MOZ_ASSERT(NS_SUCCEEDED(aRv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))", "./../../../docshell/base/nsDocShell.cpp"
, 9627); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 9627); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9628 }
9629
9630 if (httpChannel) {
9631 if (aLoadState->HeadersStream()) {
9632 aRv = AddHeadersToChannel(aLoadState->HeadersStream(), httpChannel);
9633 }
9634 // Set the referrer explicitly
9635 // Referrer is currenly only set for link clicks here.
9636 if (referrerInfo) {
9637 aRv = httpChannel->SetReferrerInfo(referrerInfo);
9638 MOZ_ASSERT(NS_SUCCEEDED(aRv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1
)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))", "./../../../docshell/base/nsDocShell.cpp"
, 9638); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 9638); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9639 }
9640
9641 // Mark the http channel as UrgentStart for top level document loading in
9642 // active tab.
9643 if (IsUrgentStart(aBrowsingContext, aLoadInfo, aLoadState->LoadType())) {
9644 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
9645 if (cos) {
9646 cos->AddClassFlags(nsIClassOfService::UrgentStart);
9647 if (StaticPrefs::dom_document_priority_incremental()) {
9648 cos->SetIncremental(true);
9649 }
9650 }
9651 }
9652 }
9653
9654 channel->SetOriginalURI(aLoadState->OriginalURI() ? aLoadState->OriginalURI()
9655 : aLoadState->URI());
9656
9657 const nsACString& typeHint = aLoadState->TypeHint();
9658 if (!typeHint.IsVoid()) {
9659 channel->SetContentType(typeHint);
9660 }
9661
9662 const nsAString& fileName = aLoadState->FileName();
9663 if (!fileName.IsVoid()) {
9664 aRv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
9665 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9665); return false; } } while (false)
;
9666 if (!fileName.IsEmpty()) {
9667 aRv = channel->SetContentDispositionFilename(fileName);
9668 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9668); return false; } } while (false)
;
9669 }
9670 }
9671
9672 if (nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel)) {
9673 nsCOMPtr<nsIURI> referrer;
9674 nsIReferrerInfo* referrerInfo = aLoadState->GetReferrerInfo();
9675 if (referrerInfo) {
9676 referrerInfo->GetOriginalReferrer(getter_AddRefs(referrer));
9677 }
9678 // save true referrer for those who need it (e.g. xpinstall whitelisting)
9679 // Currently only http and ftp channels support this.
9680 props->SetPropertyAsInterface(u"docshell.internalReferrer"_ns, referrer);
9681 }
9682
9683 nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
9684 auto loadType = aLoadState->LoadType();
9685
9686 if (loadType == LOAD_RELOAD_NORMAL &&
9687 StaticPrefs::
9688 browser_soft_reload_only_force_validate_top_level_document()) {
9689 nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(channel);
9690 if (cachingChannel) {
9691 cachingChannel->SetForceValidateCacheContent(true);
9692 }
9693 }
9694
9695 // figure out if we need to set the post data stream on the channel...
9696 if (aLoadState->PostDataStream()) {
9697 if (nsCOMPtr<nsIFormPOSTActionChannel> postChannel =
9698 do_QueryInterface(channel)) {
9699 // XXX it's a bit of a hack to rewind the postdata stream here but
9700 // it has to be done in case the post data is being reused multiple
9701 // times.
9702 nsCOMPtr<nsISeekableStream> postDataSeekable =
9703 do_QueryInterface(aLoadState->PostDataStream());
9704 if (postDataSeekable) {
9705 aRv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
9706 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9706); return false; } } while (false)
;
9707 }
9708
9709 // we really need to have a content type associated with this stream!!
9710 postChannel->SetUploadStream(aLoadState->PostDataStream(), ""_ns, -1);
9711
9712 // Ownership of the stream has transferred to the channel, clear our
9713 // reference.
9714 aLoadState->SetPostDataStream(nullptr);
9715 }
9716
9717 /* If there is a valid postdata *and* it is a History Load,
9718 * set up the cache key on the channel, to retrieve the
9719 * data *only* from the cache. If it is a normal reload, the
9720 * cache is free to go to the server for updated postdata.
9721 */
9722 if (cacheChannel && aCacheKey != 0) {
9723 if (loadType == LOAD_HISTORY || loadType == LOAD_RELOAD_CHARSET_CHANGE) {
9724 cacheChannel->SetCacheKey(aCacheKey);
9725 uint32_t loadFlags;
9726 if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))((bool)(__builtin_expect(!!(!NS_FAILED_impl(channel->GetLoadFlags
(&loadFlags))), 1)))
) {
9727 channel->SetLoadFlags(loadFlags |
9728 nsICachingChannel::LOAD_ONLY_FROM_CACHE);
9729 }
9730 } else if (loadType == LOAD_RELOAD_NORMAL) {
9731 cacheChannel->SetCacheKey(aCacheKey);
9732 }
9733 }
9734 } else {
9735 /* If there is no postdata, set the cache key on the channel, and
9736 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
9737 * will be free to get it from net if it is not found in cache.
9738 * New cache may use it creatively on CGI pages with GET
9739 * method and even on those that say "no-cache"
9740 */
9741 if (loadType == LOAD_HISTORY || loadType == LOAD_RELOAD_NORMAL ||
9742 loadType == LOAD_RELOAD_CHARSET_CHANGE ||
9743 loadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE ||
9744 loadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE) {
9745 if (cacheChannel && aCacheKey != 0) {
9746 cacheChannel->SetCacheKey(aCacheKey);
9747 }
9748 }
9749 }
9750
9751 if (nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel)) {
9752 // Allow execution against our context if the principals match
9753 scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
9754 }
9755
9756 if (nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(channel)) {
9757 nsString initiatorType;
9758 switch (aLoadInfo->InternalContentPolicyType()) {
9759 case nsIContentPolicy::TYPE_INTERNAL_EMBED:
9760 initiatorType = u"embed"_ns;
9761 break;
9762 case nsIContentPolicy::TYPE_INTERNAL_OBJECT:
9763 initiatorType = u"object"_ns;
9764 break;
9765 default: {
9766 const auto& embedderElementType =
9767 aBrowsingContext->GetEmbedderElementType();
9768 if (embedderElementType) {
9769 initiatorType = *embedderElementType;
9770 }
9771 break;
9772 }
9773 }
9774
9775 if (!initiatorType.IsEmpty()) {
9776 timedChannel->SetInitiatorType(initiatorType);
9777 }
9778 }
9779
9780 nsCOMPtr<nsIURI> rpURI;
9781 aLoadInfo->GetResultPrincipalURI(getter_AddRefs(rpURI));
9782 Maybe<nsCOMPtr<nsIURI>> originalResultPrincipalURI;
9783 aLoadState->GetMaybeResultPrincipalURI(originalResultPrincipalURI);
9784 if (originalResultPrincipalURI &&
9785 (!aLoadState->KeepResultPrincipalURIIfSet() || !rpURI)) {
9786 // Unconditionally override, we want the replay to be equal to what has
9787 // been captured.
9788 aLoadInfo->SetResultPrincipalURI(originalResultPrincipalURI.ref());
9789 }
9790
9791 if (aLoadState->OriginalURI() && aLoadState->LoadReplace()) {
9792 // The LOAD_REPLACE flag and its handling here will be removed as part
9793 // of bug 1319110. For now preserve its restoration here to not break
9794 // any code expecting it being set specially on redirected channels.
9795 // If the flag has originally been set to change result of
9796 // NS_GetFinalChannelURI it won't have any effect and also won't cause
9797 // any harm.
9798 uint32_t loadFlags;
9799 aRv = channel->GetLoadFlags(&loadFlags);
9800 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9800); return false; } } while (false)
;
9801 channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
9802 }
9803
9804 nsCOMPtr<nsIPolicyContainer> policyContainer = aLoadState->PolicyContainer();
9805 if (nsCOMPtr<nsIContentSecurityPolicy> csp =
9806 PolicyContainer::GetCSP(policyContainer)) {
9807 // Navigational requests that are same origin need to be upgraded in case
9808 // upgrade-insecure-requests is present. Please note that for document
9809 // navigations that bit is re-computed in case we encounter a server
9810 // side redirect so the navigation is not same-origin anymore.
9811 bool upgradeInsecureRequests = false;
9812 csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
9813 if (upgradeInsecureRequests) {
9814 // only upgrade if the navigation is same origin
9815 nsCOMPtr<nsIPrincipal> resultPrincipal;
9816 aRv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
9817 channel, getter_AddRefs(resultPrincipal));
9818 NS_ENSURE_SUCCESS(aRv, false)do { nsresult __rv = aRv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "aRv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9818); return false; } } while (false)
;
9819 if (nsContentSecurityUtils::IsConsideredSameOriginForUIR(
9820 aLoadState->TriggeringPrincipal(), resultPrincipal)) {
9821 aLoadInfo->SetUpgradeInsecureRequests(true);
9822 }
9823 }
9824 }
9825
9826 if (policyContainer) {
9827 // For document loads we store the policyContainer that potentially needs to
9828 // be inherited by the new document, e.g. in case we are loading
9829 // an opaque origin like a data: URI. The actual inheritance
9830 // check happens within Document::InitPolicyContainer().
9831 // Please create an actual copy of the policyContainer (do not share the
9832 // same reference) otherwise modifications done (such as the meta CSP of the
9833 // new doc) in an opaque origin will incorrectly be propagated to the
9834 // embedding document.
9835 RefPtr policyContainerToInherit = MakeRefPtr<PolicyContainer>();
9836 policyContainerToInherit->InitFromOther(
9837 PolicyContainer::Cast(policyContainer));
9838 aLoadInfo->SetPolicyContainerToInherit(policyContainerToInherit);
9839 }
9840
9841 channel.forget(aChannel);
9842 return true;
9843}
9844
9845bool nsDocShell::ShouldDoInitialAboutBlankSyncLoad(
9846 nsIURI* aURI, nsDocShellLoadState* aLoadState,
9847 nsIPrincipal* aPrincipalToInherit) {
9848 MOZ_ASSERT(mDocumentViewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentViewer))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mDocumentViewer"
, "./../../../docshell/base/nsDocShell.cpp", 9848); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer" ")"); do { MOZ_CrashSequence
(__null, 9848); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9849
9850 if (!NS_IsAboutBlankAllowQueryAndFragment(aURI)) {
9851 return false;
9852 }
9853
9854 if (aLoadState->IsInitialAboutBlankHandlingProhibited()) {
9855 return false;
9856 }
9857
9858 Document* doc = mDocumentViewer->GetDocument();
9859
9860 if (mHasStartedLoadingOtherThanInitialBlankURI || !mDocumentViewer || !doc ||
9861 !doc->IsUncommittedInitialDocument()) {
9862 return false;
9863 }
9864
9865 if (!aPrincipalToInherit) {
9866 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer->GetDocument()->NodePrincipal(
)->GetIsNullPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentViewer->GetDocument
()->NodePrincipal()->GetIsNullPrincipal()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
" (" "Load looks like first load but does not want principal inheritance."
")", "./../../../docshell/base/nsDocShell.cpp", 9868); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
") (" "Load looks like first load but does not want principal inheritance."
")"); do { MOZ_CrashSequence(__null, 9868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9867 mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer->GetDocument()->NodePrincipal(
)->GetIsNullPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentViewer->GetDocument
()->NodePrincipal()->GetIsNullPrincipal()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
" (" "Load looks like first load but does not want principal inheritance."
")", "./../../../docshell/base/nsDocShell.cpp", 9868); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
") (" "Load looks like first load but does not want principal inheritance."
")"); do { MOZ_CrashSequence(__null, 9868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9868 "Load looks like first load but does not want principal inheritance.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentViewer->GetDocument()->NodePrincipal(
)->GetIsNullPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentViewer->GetDocument
()->NodePrincipal()->GetIsNullPrincipal()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
" (" "Load looks like first load but does not want principal inheritance."
")", "./../../../docshell/base/nsDocShell.cpp", 9868); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal()"
") (" "Load looks like first load but does not want principal inheritance."
")"); do { MOZ_CrashSequence(__null, 9868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9869 } else {
9870 if (XRE_IsContentProcess()) {
9871 RefPtr<LoadedOriginSet> loadedOrigins = CurrentLoadedOriginSet();
9872 if (!loadedOrigins->ValidatePrincipal(aPrincipalToInherit)) {
9873 // We can't directly load this principal, so we need the normal load
9874 // path to do a process switch.
9875 return false;
9876 }
9877 }
9878
9879 // If a page opens about:blank, it will have a content principal.
9880 // If it is then restored after a restart, we might not have initialized
9881 // UsesOAC for it. If this is the case, do a normal load (bug 2004165).
9882 // XXX bug 2005205 tracks removing this workaround.
9883 if (aLoadState->LoadIsFromSessionHistory() &&
9884 !mBrowsingContext->Group()
9885 ->UsesOriginAgentCluster(aPrincipalToInherit)
9886 .isSome()) {
9887 return false;
9888 }
9889
9890 // Initial about:blank from SH is kind of broken.
9891 // - The IPC round-trip in MaybeHandleSubframeHistory will make the load
9892 // async, but CompleteInitialAboutBlankLoad might at least not replace
9893 // the document. See bug 2007894.
9894 // - If an xorigin iframe navigates itself to about:blank and is then
9895 // restored during a parent document reload / traversal, we get here with
9896 // an xorigin about:blank. See bug 2021375.
9897 // So at least block xorigin initial about:blank.
9898 if (aLoadState->LoadIsFromSessionHistory() &&
9899 !aPrincipalToInherit->Equals(doc->GetPrincipal())) {
9900 return false;
9901 }
9902 }
9903
9904 return true;
9905}
9906
9907void nsDocShell::UnsuppressPaintingIfNoNavigationAwayFromAboutBlank(
9908 mozilla::PresShell* aPresShell) {
9909 if (mHasStartedLoadingOtherThanInitialBlankURI || !mDocumentViewer) {
9910 return;
9911 }
9912 Document* doc = mDocumentViewer->GetDocument();
9913 if (!doc || !doc->IsInitialDocument()) {
9914 return;
9915 }
9916 if (mDocumentViewer->GetPresShell() != aPresShell) {
9917 return;
9918 }
9919 // Our surroundings appear to remain in the same state
9920 // as before posting the runnable.
9921 aPresShell->UnsuppressPainting();
9922 // The content viewer's mPresShell could have been removed now, see bug
9923 // 378682/421432
9924 if ((aPresShell = mDocumentViewer->GetPresShell())) {
9925 aPresShell->LoadComplete();
9926 }
9927}
9928
9929nsresult nsDocShell::PerformTrustedTypesPreNavigationCheck(
9930 nsDocShellLoadState* aLoadState, nsGlobalWindowInner* aWindow) const {
9931 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "./../../../docshell/base/nsDocShell.cpp"
, 9931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { MOZ_CrashSequence(__null, 9931); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9932 RefPtr<nsIContentSecurityPolicy> csp =
9933 PolicyContainer::GetCSP(aWindow->GetPolicyContainer());
9934 if (!csp || csp->GetRequireTrustedTypesForDirectiveState() ==
9935 RequireTrustedTypesForDirectiveState::NONE) {
9936 return NS_OK;
9937 }
9938
9939 // Exempt web extension content scripts from trusted types policies defined by
9940 // the page in which they are running.
9941 if (auto principal = BasePrincipal::Cast(aLoadState->TriggeringPrincipal())) {
9942 if (principal->ContentScriptAddonPolicyCore()) {
9943 return NS_OK;
9944 }
9945 }
9946
9947 // If disposion is enforce for require-trusted-types-for, then we return
9948 // errors in order to block navigation. If it's report-only, errors are
9949 // ignored and the URL is unchanged.
9950 bool shouldBlockOnError = csp->GetRequireTrustedTypesForDirectiveState() ==
9951 RequireTrustedTypesForDirectiveState::ENFORCE;
9952
9953 // 2. Let urlString be the result of running the URL serializer on
9954 // request’s url.
9955 nsAutoCString urlString;
9956 aLoadState->URI()->GetSpec(urlString);
9957
9958 // 3. Let encodedScriptSource be the result of removing the leading
9959 // "javascript:" from urlString.
9960 constexpr auto javascriptScheme = "javascript:"_ns;
9961 const nsDependentCSubstring encodedScriptSource =
9962 Substring(urlString, javascriptScheme.Length());
9963
9964 // 4. Let convertedScriptSource be the result of executing Process value
9965 // with a default policy algorithm
9966 Maybe<nsAutoString> compliantStringHolder;
9967 NS_ConvertUTF8toUTF16 encodedScriptSourceUTF16(encodedScriptSource);
9968 constexpr nsLiteralString sink = u"Location href"_ns;
9969 auto reportPreNavigationCheckViolations = [&csp, &sink,
9970 &encodedScriptSourceUTF16] {
9971 // Report violation the same way as for "Should sink type mismatch
9972 // violation be blocked by Content Security Policy", since that's what
9973 // other browsers do. See
9974 // https://github.com/w3c/trusted-types/issues/584.
9975 auto location = JSCallingLocation::Get();
9976 TrustedTypeUtils::ReportSinkTypeMismatchViolations(
9977 csp, nullptr /* aCSPEventListener */, location.FileName(),
9978 location.mLine, location.mColumn, sink, kTrustedTypesOnlySinkGroup,
9979 encodedScriptSourceUTF16);
9980 };
9981 ErrorResult error;
9982 auto convertedScriptSource =
9983 TrustedTypeUtils::GetConvertedScriptSourceForPreNavigationCheck(
9984 *aWindow, encodedScriptSourceUTF16, sink, compliantStringHolder,
9985 error);
9986 error.WouldReportJSException();
9987 if (error.Failed()) {
9988 reportPreNavigationCheckViolations();
9989 if (shouldBlockOnError) {
9990 RETURN_NSRESULT_ON_FAILURE(error)do { (error).WouldReportJSException(); if ((error).Failed()) {
NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "RETURN_NSRESULT_ON_FAILURE(%s) failed with result 0x%X"
, "error", (error).ErrorCodeAsInt()) .get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 9990); return (error).StealNSResult(); } } while (0)
;
9991 }
9992 error.SuppressException();
9993 return NS_OK;
9994 }
9995
9996 // 5. Set urlString to be the result of prepending "javascript:" to
9997 // stringified convertedScriptSource.
9998 urlString = javascriptScheme + NS_ConvertUTF16toUTF8(*convertedScriptSource);
9999
10000 // 6. Let newURL be the result of running the URL parser on urlString.
10001 nsCOMPtr<nsIURI> newURL;
10002 nsresult rv = NS_NewURI(getter_AddRefs(newURL), urlString);
10003 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10004 reportPreNavigationCheckViolations();
10005 return shouldBlockOnError ? rv : NS_OK;
10006 }
10007
10008 // 7. Set request’s url to newURL.
10009 aLoadState->SetURI(newURL);
10010 return NS_OK;
10011}
10012
10013nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
10014 Maybe<uint32_t> aCacheKey,
10015 nsIRequest** aRequest) {
10016 // Double-check that we're still around to load this URI.
10017 if (mIsBeingDestroyed) {
10018 // Return NS_OK despite not doing anything to avoid throwing exceptions
10019 // from nsLocation::SetHref if the unload handler of the existing page
10020 // tears us down.
10021 return NS_OK;
10022 }
10023
10024 MOZ_DIAGNOSTIC_ASSERT(mInitialized, "Need to initialize before load")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInitialized)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInitialized))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mInitialized" " ("
"Need to initialize before load" ")", "./../../../docshell/base/nsDocShell.cpp"
, 10024); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mInitialized"
") (" "Need to initialize before load" ")"); do { MOZ_CrashSequence
(__null, 10024); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10025 NS_ENSURE_TRUE(VerifyDocumentViewer(), NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(VerifyDocumentViewer())), 0))
) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "VerifyDocumentViewer()"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10025); return NS_ERROR_FAILURE; } } while (false)
;
10026
10027 nsCOMPtr<nsIURILoader> uriLoader = components::URILoader::Service();
10028 if (NS_WARN_IF(!uriLoader)NS_warn_if_impl(!uriLoader, "!uriLoader", "./../../../docshell/base/nsDocShell.cpp"
, 10028)
) {
10029 return NS_ERROR_UNEXPECTED;
10030 }
10031
10032 // Persist and sync layout history state before we load a new uri, as this
10033 // might be our last chance to do so, in the content process.
10034 PersistLayoutHistoryState();
10035 SynchronizeLayoutHistoryState();
10036
10037 nsresult rv;
10038 nsContentPolicyType contentPolicyType = DetermineContentType();
10039
10040 auto getSourceWindowContext = [this, &aLoadState] {
10041 const MaybeDiscardedBrowsingContext& sourceBC =
10042 aLoadState->SourceBrowsingContext();
10043 if (!sourceBC.IsNullOrDiscarded()) {
10044 if (WindowContext* wc = sourceBC.get()->GetCurrentWindowContext()) {
10045 return wc;
10046 }
10047 }
10048 return mBrowsingContext->GetParentWindowContext();
10049 };
10050
10051 if (StaticPrefs::dom_security_trusted_types_enabled() &&
10052 aLoadState->URI()->SchemeIs("javascript")) {
10053 if (WindowContext* sourceWindowContext = getSourceWindowContext()) {
10054 RefPtr<nsGlobalWindowInner> window =
10055 sourceWindowContext->GetInnerWindow();
10056 rv = PerformTrustedTypesPreNavigationCheck(aLoadState, window);
10057 // Default policy might destroy the whole docshell, so check that again.
10058 if (mIsBeingDestroyed) {
10059 return NS_OK;
10060 }
10061 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10062 return NS_ERROR_DOM_SECURITY_ERR;
10063 }
10064 }
10065 }
10066
10067 if (IsSubframe()) {
10068 MOZ_ASSERT(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
" (" "DoURILoad thinks this is a frame and InternalLoad does not"
")", "./../../../docshell/base/nsDocShell.cpp", 10070); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
") (" "DoURILoad thinks this is a frame and InternalLoad does not"
")"); do { MOZ_CrashSequence(__null, 10070); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10069 contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
" (" "DoURILoad thinks this is a frame and InternalLoad does not"
")", "./../../../docshell/base/nsDocShell.cpp", 10070); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
") (" "DoURILoad thinks this is a frame and InternalLoad does not"
")"); do { MOZ_CrashSequence(__null, 10070); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10070 "DoURILoad thinks this is a frame and InternalLoad does not")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME
|| contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
" (" "DoURILoad thinks this is a frame and InternalLoad does not"
")", "./../../../docshell/base/nsDocShell.cpp", 10070); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME"
") (" "DoURILoad thinks this is a frame and InternalLoad does not"
")"); do { MOZ_CrashSequence(__null, 10070); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10071 if (StaticPrefs::dom_block_external_protocol_in_iframes()) {
10072 // Only allow URLs able to return data in iframes.
10073 if (nsContentUtils::IsExternalProtocol(aLoadState->URI())) {
10074 // The context to check user-interaction with for the purposes of
10075 // popup-blocking.
10076 //
10077 // We generally want to check the context that initiated the navigation.
10078 WindowContext* sourceWindowContext = getSourceWindowContext();
10079 MOZ_ASSERT(sourceWindowContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sourceWindowContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sourceWindowContext))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("sourceWindowContext"
, "./../../../docshell/base/nsDocShell.cpp", 10079); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "sourceWindowContext" ")"); do { MOZ_CrashSequence
(__null, 10079); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10080
10081 // FIXME: We can't check user-interaction against an OOP window. This is
10082 // the next best thing we can really do. The load state keeps whether
10083 // the navigation had a user interaction in process
10084 // (aLoadState->HasValidUserGestureActivation()), but we can't really
10085 // consume it, which we want to prevent popup-spamming from the same
10086 // click event.
10087 WindowContext* context =
10088 sourceWindowContext->IsInProcess()
10089 ? sourceWindowContext
10090 : mBrowsingContext->GetCurrentWindowContext();
10091 const bool popupBlocked = [&] {
10092 const bool active = mBrowsingContext->IsActive();
10093
10094 // For same-origin-with-top windows, we grant a single free popup
10095 // without user activation, see bug 1680721.
10096 //
10097 // We consume the flag now even if there's no user activation.
10098 const bool hasFreePass = [&] {
10099 if (!active ||
10100 !(context->IsInProcess() && context->SameOriginWithTop())) {
10101 return false;
10102 }
10103 nsGlobalWindowInner* win =
10104 context->TopWindowContext()->GetInnerWindow();
10105 return win && win->TryOpenExternalProtocolIframe();
10106 }();
10107
10108 if (context->IsInProcess() &&
10109 context->ConsumeTransientUserGestureActivation()) {
10110 // If the user has interacted with the page, consume it.
10111 return false;
10112 }
10113
10114 // TODO(emilio): Can we remove this check? It seems like what prompted
10115 // this code (bug 1514547) should be covered by transient user
10116 // activation, see bug 1514547.
10117 if (active &&
10118 PopupBlocker::ConsumeTimerTokenForExternalProtocolIframe()) {
10119 return false;
10120 }
10121
10122 if (sourceWindowContext->CanShowPopup()) {
10123 return false;
10124 }
10125
10126 if (hasFreePass) {
10127 return false;
10128 }
10129
10130 return true;
10131 }();
10132
10133 // No error must be returned when iframes are blocked.
10134 if (popupBlocked) {
10135 nsAutoString message;
10136 nsresult rv = nsContentUtils::GetLocalizedString(
10137 PropertiesFile::DOM_PROPERTIES,
10138 "ExternalProtocolFrameBlockedNoUserActivation", message);
10139 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
10140 nsContentUtils::ReportToConsoleByWindowID(
10141 message, nsIScriptError::warningFlag, "DOM"_ns,
10142 context->InnerWindowId());
10143 }
10144 return NS_OK;
10145 }
10146 }
10147 }
10148
10149 // Only allow view-source scheme in top-level docshells. view-source is
10150 // the only scheme to which this applies at the moment due to potential
10151 // timing attacks to read data from cross-origin iframes. If this widens
10152 // we should add a protocol flag for whether the scheme is allowed in
10153 // frames and use something like nsNetUtil::NS_URIChainHasFlags.
10154 nsCOMPtr<nsIURI> tempURI = aLoadState->URI();
10155 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
10156 while (nestedURI) {
10157 // view-source should always be an nsINestedURI, loop and check the
10158 // scheme on this and all inner URIs that are also nested URIs.
10159 if (tempURI->SchemeIs("view-source")) {
10160 return NS_ERROR_UNKNOWN_PROTOCOL;
10161 }
10162 nestedURI->GetInnerURI(getter_AddRefs(tempURI));
10163 nestedURI = do_QueryInterface(tempURI);
10164 }
10165 } else {
10166 MOZ_ASSERT(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT" " (" "DoURILoad thinks this is a document and InternalLoad does not"
")", "./../../../docshell/base/nsDocShell.cpp", 10167); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT"
") (" "DoURILoad thinks this is a document and InternalLoad does not"
")"); do { MOZ_CrashSequence(__null, 10167); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10167 "DoURILoad thinks this is a document and InternalLoad does not")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT" " (" "DoURILoad thinks this is a document and InternalLoad does not"
")", "./../../../docshell/base/nsDocShell.cpp", 10167); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT"
") (" "DoURILoad thinks this is a document and InternalLoad does not"
")"); do { MOZ_CrashSequence(__null, 10167); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10168 }
10169
10170 nsCOMPtr<nsIURI> uri = aLoadState->URI();
10171 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1736570
10172 const bool doInitialSyncLoad = ShouldDoInitialAboutBlankSyncLoad(
10173 uri, aLoadState, aLoadState->PrincipalToInherit());
10174
10175 if (!doInitialSyncLoad && mBrowsingContext->IsContent()) {
10176 // https://wicg.github.io/document-picture-in-picture/#close-on-navigate
10177 // Two exceptions.
10178 // - The initial navigation is not per-spec and must complete.
10179 // - We also set IsDocumentPiP on chrome but the spec doesn't apply to it.
10180 if (Document* doc = GetExtantDocument()) {
10181 NS_DispatchToMainThread(NS_NewRunnableFunction(
10182 "Close PIP window on navigate",
10183 [doc = RefPtr(doc)]() MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
10184 doc->CloseAnyAssociatedDocumentPiPWindows();
10185 }));
10186 }
10187 if (mBrowsingContext->GetIsDocumentPiP()) {
10188 return NS_OK;
10189 }
10190 }
10191
10192 // FIXME We still have a ton of codepaths that don't pass through
10193 // DocumentLoadListener, so probably need to create session history info
10194 // in more places.
10195 if (aLoadState->GetLoadingSessionHistoryInfo()) {
10196 SetLoadingSessionHistoryInfo(*aLoadState->GetLoadingSessionHistoryInfo());
10197 } else if (doInitialSyncLoad) {
10198 // Materialize LoadingSessionHistoryInfo here, because DocumentChannel
10199 // loads have it, and later history behavior depends on it existing.
10200 auto entry = std::make_unique<SessionHistoryInfo>(
10201 uri, aLoadState->TriggeringPrincipal(),
10202 aLoadState->PrincipalToInherit(),
10203 aLoadState->PartitionedPrincipalToInherit(),
10204 aLoadState->PolicyContainer(), mContentTypeHint);
10205 entry->SetTransient();
10206 mozilla::dom::LoadingSessionHistoryInfo info(*entry);
10207 if (Navigation::IsAPIEnabled()) {
10208 info.mContiguousEntries.AppendElement(*entry);
10209 }
10210 SetLoadingSessionHistoryInfo(info, true);
10211 }
10212
10213 // open a channel for the url
10214
10215 // If we have a pending channel, use the channel we've already created here.
10216 // We don't need to set up load flags for our channel, as it has already been
10217 // created.
10218
10219 if (nsCOMPtr<nsIChannel> channel =
10220 aLoadState->GetPendingRedirectedChannel()) {
10221 // If we have a request outparameter, shove our channel into it.
10222 if (aRequest) {
10223 nsCOMPtr<nsIRequest> outRequest = channel;
10224 outRequest.forget(aRequest);
10225 }
10226
10227 mHasStartedLoadingOtherThanInitialBlankURI = true;
10228 return OpenRedirectedChannel(aLoadState);
10229 }
10230
10231 // There are two cases we care about:
10232 // * Top-level load: In this case, loadingNode is null, but loadingWindow
10233 // is our mScriptGlobal. We pass null for loadingPrincipal in this case.
10234 // * Subframe load: loadingWindow is null, but loadingNode is the frame
10235 // element for the load. loadingPrincipal is the NodePrincipal of the
10236 // frame element.
10237 nsCOMPtr<nsINode> loadingNode;
10238 nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
10239 nsCOMPtr<nsIPrincipal> loadingPrincipal;
10240 nsCOMPtr<nsISupports> topLevelLoadingContext;
10241
10242 if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
10243 loadingNode = nullptr;
10244 loadingPrincipal = nullptr;
10245 loadingWindow = mScriptGlobal;
10246 if (XRE_IsContentProcess()) {
10247 // In e10s the child process doesn't have access to the element that
10248 // contains the browsing context (because that element is in the chrome
10249 // process).
10250 nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild();
10251 topLevelLoadingContext = ToSupports(browserChild);
10252 } else {
10253 // This is for loading non-e10s tabs and toplevel windows of various
10254 // sorts.
10255 // For the toplevel window cases, requestingElement will be null.
10256 nsCOMPtr<Element> requestingElement =
10257 loadingWindow->GetFrameElementInternal();
10258 topLevelLoadingContext = requestingElement;
10259 }
10260 } else {
10261 loadingWindow = nullptr;
10262 loadingNode = mScriptGlobal->GetFrameElementInternal();
10263 if (loadingNode) {
10264 // If we have a loading node, then use that as our loadingPrincipal.
10265 loadingPrincipal = loadingNode->NodePrincipal();
10266#ifdef DEBUG1
10267 // Get the docshell type for requestingElement.
10268 RefPtr<Document> requestingDoc = loadingNode->OwnerDoc();
10269 nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
10270 // requestingElement docshell type = current docshell type.
10271 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mItemType == elementDocShell->ItemType())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mItemType == elementDocShell->ItemType()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mItemType == elementDocShell->ItemType()"
" (" "subframes should have the same docshell type as their parent"
")", "./../../../docshell/base/nsDocShell.cpp", 10273); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mItemType == elementDocShell->ItemType()"
") (" "subframes should have the same docshell type as their parent"
")"); do { MOZ_CrashSequence(__null, 10273); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10272 mItemType == elementDocShell->ItemType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mItemType == elementDocShell->ItemType())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mItemType == elementDocShell->ItemType()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mItemType == elementDocShell->ItemType()"
" (" "subframes should have the same docshell type as their parent"
")", "./../../../docshell/base/nsDocShell.cpp", 10273); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mItemType == elementDocShell->ItemType()"
") (" "subframes should have the same docshell type as their parent"
")"); do { MOZ_CrashSequence(__null, 10273); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10273 "subframes should have the same docshell type as their parent")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mItemType == elementDocShell->ItemType())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mItemType == elementDocShell->ItemType()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mItemType == elementDocShell->ItemType()"
" (" "subframes should have the same docshell type as their parent"
")", "./../../../docshell/base/nsDocShell.cpp", 10273); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mItemType == elementDocShell->ItemType()"
") (" "subframes should have the same docshell type as their parent"
")"); do { MOZ_CrashSequence(__null, 10273); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10274#endif
10275 } else {
10276 if (mIsBeingDestroyed) {
10277 // If this isn't a top-level load and mScriptGlobal's frame element is
10278 // null, then the element got removed from the DOM while we were trying
10279 // to load this resource. This docshell is scheduled for destruction
10280 // already, so bail out here.
10281 return NS_OK;
10282 }
10283 // If we are not being destroyed and we do not have access to the loading
10284 // node, then we are a remote subframe. Set the loading principal
10285 // to be a null principal and then set it correctly in the parent.
10286 loadingPrincipal = NullPrincipal::Create(GetOriginAttributes(), nullptr);
10287 }
10288 }
10289
10290 if (!aLoadState->TriggeringPrincipal()) {
10291 MOZ_ASSERT(false, "DoURILoad needs a valid triggeringPrincipal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "DoURILoad needs a valid triggeringPrincipal"
")", "./../../../docshell/base/nsDocShell.cpp", 10291); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "DoURILoad needs a valid triggeringPrincipal"
")"); do { MOZ_CrashSequence(__null, 10291); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10292 return NS_ERROR_FAILURE;
10293 }
10294
10295 const nsSecurityFlags securityFlags =
10296 DocumentLoadListener::SecurityFlagsForLoadInfo(aLoadState);
10297 const uint32_t sandboxFlags = DocumentLoadListener::EffectiveSandboxFlags(
10298 mBrowsingContext->GetSandboxFlags(), securityFlags);
10299
10300 // Must never have a parent for TYPE_DOCUMENT loads
10301 MOZ_ASSERT_IF(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,do { if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!mBrowsingContext->GetParent())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(!mBrowsingContext->GetParent()))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!mBrowsingContext->GetParent()"
, "./../../../docshell/base/nsDocShell.cpp", 10302); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mBrowsingContext->GetParent()" ")"); do
{ MOZ_CrashSequence(__null, 10302); __attribute__((nomerge))
::abort(); } while (false); } } while (false); } } while (false
)
10302 !mBrowsingContext->GetParent())do { if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!mBrowsingContext->GetParent())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(!mBrowsingContext->GetParent()))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!mBrowsingContext->GetParent()"
, "./../../../docshell/base/nsDocShell.cpp", 10302); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mBrowsingContext->GetParent()" ")"); do
{ MOZ_CrashSequence(__null, 10302); __attribute__((nomerge))
::abort(); } while (false); } } while (false); } } while (false
)
;
10303 // Subdocuments must have a parent
10304 MOZ_ASSERT_IF(contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT,do { if (contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mBrowsingContext->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->GetParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBrowsingContext->GetParent()", "./../../../docshell/base/nsDocShell.cpp"
, 10305); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->GetParent()"
")"); do { MOZ_CrashSequence(__null, 10305); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
10305 mBrowsingContext->GetParent())do { if (contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mBrowsingContext->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->GetParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBrowsingContext->GetParent()", "./../../../docshell/base/nsDocShell.cpp"
, 10305); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->GetParent()"
")"); do { MOZ_CrashSequence(__null, 10305); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
;
10306 mBrowsingContext->SetTriggeringAndInheritPrincipals(
10307 aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
10308 aLoadState->GetLoadIdentifier());
10309 RefPtr<LoadInfo> loadInfo;
10310 if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
10311 loadInfo = MakeRefPtr<LoadInfo>(
10312 loadingWindow, uri, aLoadState->TriggeringPrincipal(),
10313 topLevelLoadingContext, securityFlags, sandboxFlags);
10314 } else {
10315 loadInfo = MOZ_TRY(LoadInfo::Create(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(LoadInfo::Create( loadingPrincipal, aLoadState->TriggeringPrincipal
(), loadingNode, securityFlags, contentPolicyType, Maybe<mozilla
::dom::ClientInfo>(), Maybe<mozilla::dom::ServiceWorkerDescriptor
>(), sandboxFlags)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
10316 loadingPrincipal, aLoadState->TriggeringPrincipal(), loadingNode,__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(LoadInfo::Create( loadingPrincipal, aLoadState->TriggeringPrincipal
(), loadingNode, securityFlags, contentPolicyType, Maybe<mozilla
::dom::ClientInfo>(), Maybe<mozilla::dom::ServiceWorkerDescriptor
>(), sandboxFlags)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
10317 securityFlags, contentPolicyType, Maybe<mozilla::dom::ClientInfo>(),__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(LoadInfo::Create( loadingPrincipal, aLoadState->TriggeringPrincipal
(), loadingNode, securityFlags, contentPolicyType, Maybe<mozilla
::dom::ClientInfo>(), Maybe<mozilla::dom::ServiceWorkerDescriptor
>(), sandboxFlags)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
10318 Maybe<mozilla::dom::ServiceWorkerDescriptor>(), sandboxFlags))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(LoadInfo::Create( loadingPrincipal, aLoadState->TriggeringPrincipal
(), loadingNode, securityFlags, contentPolicyType, Maybe<mozilla
::dom::ClientInfo>(), Maybe<mozilla::dom::ServiceWorkerDescriptor
>(), sandboxFlags)); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
;
10319 }
10320 RefPtr<WindowContext> context = mBrowsingContext->GetCurrentWindowContext();
10321
10322 if (doInitialSyncLoad) {
10323 // Stay on the eagerly created document and adjust it to match what we would
10324 // be loading.
10325 return CompleteInitialAboutBlankLoad(aLoadState, loadInfo);
10326 }
10327 mHasStartedLoadingOtherThanInitialBlankURI = true;
10328
10329 if (mLoadType != LOAD_ERROR_PAGE && context && context->IsInProcess()) {
10330 if (context->HasValidTransientUserGestureActivation()) {
10331 aLoadState->SetHasValidUserGestureActivation(true);
10332 aLoadState->SetTextDirectiveUserActivation(true);
10333 }
10334 if (!aLoadState->TriggeringWindowId()) {
10335 aLoadState->SetTriggeringWindowId(context->Id());
10336 }
10337 }
10338
10339 // in case this docshell load was triggered by a valid transient user gesture,
10340 // or also the load originates from external, then we pass that information on
10341 // to the loadinfo, which allows e.g. setting Sec-Fetch-User request headers.
10342 if (aLoadState->HasValidUserGestureActivation() ||
10343 aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL)) {
10344 loadInfo->SetHasValidUserGestureActivation(true);
10345 aLoadState->SetTextDirectiveUserActivation(true);
10346 }
10347
10348 loadInfo->SetTextDirectiveUserActivation(
10349 aLoadState->GetTextDirectiveUserActivation());
10350
10351 loadInfo->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
10352 loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
10353 net::ClassificationFlags flags = aLoadState->TriggeringClassificationFlags();
10354 loadInfo->SetTriggeringFirstPartyClassificationFlags(flags.firstPartyFlags);
10355 loadInfo->SetTriggeringThirdPartyClassificationFlags(flags.thirdPartyFlags);
10356 loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh());
10357
10358 uint32_t cacheKey = 0;
10359 if (aCacheKey) {
10360 cacheKey = *aCacheKey;
10361 } else {
10362 if (mLoadingEntry) {
10363 cacheKey = mLoadingEntry->mInfo.GetCacheKey();
10364 } else if (mActiveEntry) { // for reload cases
10365 cacheKey = mActiveEntry->GetCacheKey();
10366 }
10367 }
10368
10369 bool uriModified;
10370 if (mLoadingEntry) {
10371 uriModified = mLoadingEntry->mInfo.GetURIWasModified();
10372 } else {
10373 uriModified = false;
10374 }
10375
10376 bool isEmbeddingBlockedError = false;
10377 if (mFailedChannel) {
10378 nsresult status;
10379 mFailedChannel->GetStatus(&status);
10380 isEmbeddingBlockedError = status == NS_ERROR_XFO_VIOLATION ||
10381 status == NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION;
10382 }
10383
10384 nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
10385 mBrowsingContext, uriModified, Some(isEmbeddingBlockedError));
10386
10387 nsCOMPtr<nsIChannel> channel;
10388 if (DocumentChannel::CanUseDocumentChannel(uri)) {
10389 // The parent decides during the load whether the old document delays the
10390 // commit for a view transition. Send it the current state first. The
10391 // DocumentChannel messages use the same IPC channel, so they arrive after.
10392 if (RefPtr<Document> doc = GetExtantDocument()) {
10393 doc->MaybeUpdateOutboundViewTransitionOptIn();
10394 }
10395 channel = DocumentChannel::CreateForDocument(
10396 aLoadState, loadInfo, loadFlags, this, cacheKey, uriModified,
10397 isEmbeddingBlockedError);
10398 MOZ_ASSERT(channel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(channel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(channel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("channel", "./../../../docshell/base/nsDocShell.cpp"
, 10398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "channel" ")"
); do { MOZ_CrashSequence(__null, 10398); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10399
10400 // Disable keyword fixup when using DocumentChannel, since
10401 // DocumentLoadListener will handle this for us (in the parent process).
10402 mAllowKeywordFixup = false;
10403 } else if (!CreateAndConfigureRealChannelForLoadState(
10404 mBrowsingContext, aLoadState, loadInfo, this,
10405 GetOriginAttributes(), loadFlags, cacheKey, rv,
10406 getter_AddRefs(channel))) {
10407 return rv;
10408 }
10409
10410 // Make sure to give the caller a channel if we managed to create one
10411 // This is important for correct error page/session history interaction
10412 if (aRequest) {
10413 NS_ADDREF(*aRequest = channel)(*aRequest = channel)->AddRef();
10414 }
10415
10416 const nsACString& typeHint = aLoadState->TypeHint();
10417 if (!typeHint.IsVoid()) {
10418 mContentTypeHint = typeHint;
10419 } else {
10420 mContentTypeHint.Truncate();
10421 }
10422
10423 // Load attributes depend on load type...
10424 if (mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
10425 // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we
10426 // only want to force cache load for this channel, not the whole
10427 // loadGroup.
10428 nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(channel);
10429 if (cachingChannel) {
10430 cachingChannel->SetAllowStaleCacheContent(true);
10431 }
10432 }
10433
10434 uint32_t openFlags =
10435 nsDocShell::ComputeURILoaderFlags(mBrowsingContext, mLoadType);
10436 return OpenInitializedChannel(channel, uriLoader, openFlags);
10437}
10438
10439nsresult nsDocShell::CompleteInitialAboutBlankLoad(
10440 nsDocShellLoadState* aLoadState, nsILoadInfo* aLoadInfo) {
10441 nsresult rv;
10442 // Match the DocumentChannel case where the default for third-partiness
10443 // differs from the default in LoadInfo construction here.
10444 BrowsingContext* top = mBrowsingContext->Top();
10445 if (top == mBrowsingContext) {
10446 aLoadInfo->SetIsThirdPartyContextToTopWindow(false);
10447 } else {
10448 bool thirdParty = true;
10449 if (Document* topDoc = top->GetExtantDocument();
10450 topDoc && aLoadState->PrincipalToInherit()) {
10451 (void)topDoc->GetPrincipal()->IsThirdPartyPrincipal(
10452 aLoadState->PrincipalToInherit(), &thirdParty);
10453 }
10454 aLoadInfo->SetIsThirdPartyContextToTopWindow(thirdParty);
10455 }
10456
10457 if (!mDocumentViewer) {
10458 MOZ_ASSERT(false, "How did the viewer go away?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "How did the viewer go away?"
")", "./../../../docshell/base/nsDocShell.cpp", 10458); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "How did the viewer go away?"
")"); do { MOZ_CrashSequence(__null, 10458); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10459 return NS_ERROR_FAILURE;
10460 }
10461 RefPtr<Document> doc = mDocumentViewer->GetDocument();
10462 MOZ_LOG(gDocShellLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::DoURILoad sync about:blank onto initial "
"about:blank. Document[%p]\n", this, doc.get()); } } while (
0)
10463 ("nsDocShell[%p]::DoURILoad sync about:blank onto initial "do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::DoURILoad sync about:blank onto initial "
"about:blank. Document[%p]\n", this, doc.get()); } } while (
0)
10464 "about:blank. Document[%p]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::DoURILoad sync about:blank onto initial "
"about:blank. Document[%p]\n", this, doc.get()); } } while (
0)
10465 this, doc.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::DoURILoad sync about:blank onto initial "
"about:blank. Document[%p]\n", this, doc.get()); } } while (
0)
;
10466 if (!doc) {
10467 MOZ_ASSERT(false, "How did the document go away?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "How did the document go away?"
")", "./../../../docshell/base/nsDocShell.cpp", 10467); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "false" ") (" "How did the document go away?"
")"); do { MOZ_CrashSequence(__null, 10467); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10468 return NS_ERROR_FAILURE;
10469 }
10470
10471 // Get the load event fired for the initial about:blank without starting
10472 // a real load from a channel. We still need a channel object even though
10473 // we don't care about reading from the channel.
10474 nsCOMPtr<nsIChannel> aboutBlankChannel;
10475 rv = NS_NewChannelInternal(getter_AddRefs(aboutBlankChannel),
10476 aLoadState->URI(), aLoadInfo, nullptr, mLoadGroup,
10477 nullptr, nsIChannel::LOAD_DOCUMENT_URI);
10478 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10479 return rv;
10480 }
10481 if (!aboutBlankChannel) {
10482 return NS_ERROR_FAILURE;
10483 }
10484
10485 nsCOMPtr<nsIPrincipal> expectedPrincipal = aLoadState->PrincipalToInherit();
10486 nsCOMPtr<nsIPrincipal> expectedPartitionedPrincipal = expectedPrincipal;
10487 // If we don't have a content principal, also use it as partitioned principal
10488 if (expectedPrincipal && expectedPrincipal->GetIsContentPrincipal()) {
10489 // The partitioned content principal is always isolated.
10490 StoragePrincipalHelper::Create(
10491 aboutBlankChannel, expectedPrincipal, /* aForceIsolation */ true,
10492 getter_AddRefs(expectedPartitionedPrincipal));
10493 }
10494
10495 const bool principalMismatch =
10496 expectedPrincipal && !expectedPrincipal->Equals(doc->GetPrincipal());
10497 MOZ_ASSERT_IF(!expectedPrincipal, doc->GetPrincipal()->GetIsNullPrincipal())do { if (!expectedPrincipal) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(doc->GetPrincipal()->
GetIsNullPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(doc->GetPrincipal()->GetIsNullPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("doc->GetPrincipal()->GetIsNullPrincipal()", "./../../../docshell/base/nsDocShell.cpp"
, 10497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc->GetPrincipal()->GetIsNullPrincipal()"
")"); do { MOZ_CrashSequence(__null, 10497); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
;
10498
10499 // The channel would sandbox aLoadState->PrincipalToInherit(). Even if
10500 // the document already has a null principal, we don't know if it's the right
10501 // sandboxed one. So be safe and clobber.
10502 const uint32_t sandboxFlags =
10503 mBrowsingContext->GetHasLoadedNonInitialDocument()
10504 ? mBrowsingContext->GetSandboxFlags()
10505 : mBrowsingContext->GetInitialSandboxFlags();
10506 const bool shouldBeSandboxed = sandboxFlags & SANDBOXED_ORIGIN;
10507 MOZ_ASSERT_IF(shouldBeSandboxed, expectedPrincipal)do { if (shouldBeSandboxed) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(expectedPrincipal)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(expectedPrincipal))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("expectedPrincipal", "./../../../docshell/base/nsDocShell.cpp"
, 10507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "expectedPrincipal"
")"); do { MOZ_CrashSequence(__null, 10507); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
;
10508
10509 // Clobber document before completing the synchronous load if it doesn't have
10510 // the right principal (bug 1979032)
10511 if (principalMismatch || shouldBeSandboxed) {
10512 // This will sandbox the principals as needed
10513 nsCOMPtr<nsIPolicyContainer> policyContainer =
10514 aLoadState->PolicyContainer();
10515 nsCOMPtr<nsIURI> base = doc->GetDocBaseURI();
10516 rv = CreateAboutBlankDocumentViewer(
10517 expectedPrincipal, expectedPartitionedPrincipal, policyContainer, base,
10518 /* aIsInitialDocument */ true);
10519 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10519); return rv; } } while (false)
;
10520
10521 doc = mDocumentViewer->GetDocument();
10522 MOZ_ASSERT(doc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(doc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("doc", "./../../../docshell/base/nsDocShell.cpp"
, 10522); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc" ")");
do { MOZ_CrashSequence(__null, 10522); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10523 MOZ_LOG(gDocShellLog, LogLevel::Warning,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Warning)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Warning, "nsDocShell[%p] sync about:blank principals don't match, create "
"new document. Document[%p] \n", this, doc.get()); } } while
(0)
10524 ("nsDocShell[%p] sync about:blank principals don't match, create "do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Warning)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Warning, "nsDocShell[%p] sync about:blank principals don't match, create "
"new document. Document[%p] \n", this, doc.get()); } } while
(0)
10525 "new document. Document[%p] \n",do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Warning)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Warning, "nsDocShell[%p] sync about:blank principals don't match, create "
"new document. Document[%p] \n", this, doc.get()); } } while
(0)
10526 this, doc.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Warning)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Warning, "nsDocShell[%p] sync about:blank principals don't match, create "
"new document. Document[%p] \n", this, doc.get()); } } while
(0)
;
10527 }
10528
10529 MOZ_ASSERT(doc->IsInitialDocument(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(doc->IsInitialDocument())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("doc->IsInitialDocument()"
" (" "How come the doc is no longer the initial one?" ")", "./../../../docshell/base/nsDocShell.cpp"
, 10530); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc->IsInitialDocument()"
") (" "How come the doc is no longer the initial one?" ")");
do { MOZ_CrashSequence(__null, 10530); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10530 "How come the doc is no longer the initial one?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(doc->IsInitialDocument())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("doc->IsInitialDocument()"
" (" "How come the doc is no longer the initial one?" ")", "./../../../docshell/base/nsDocShell.cpp"
, 10530); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc->IsInitialDocument()"
") (" "How come the doc is no longer the initial one?" ")");
do { MOZ_CrashSequence(__null, 10530); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10531
10532 MOZ_ASSERT(doc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(doc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"doc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE"
, "./../../../docshell/base/nsDocShell.cpp", 10532); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "doc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE"
")"); do { MOZ_CrashSequence(__null, 10532); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10533 MOZ_ASSERT(!mIsLoadingDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsLoadingDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsLoadingDocument))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mIsLoadingDocument"
, "./../../../docshell/base/nsDocShell.cpp", 10533); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsLoadingDocument" ")"); do { MOZ_CrashSequence
(__null, 10533); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10534
10535 if (nsIContentSecurityPolicy* csp =
10536 PolicyContainer::GetCSP(doc->GetPolicyContainer())) {
10537 // We do this here rather than when inheriting the CSP in
10538 // CreateAboutBlankDocumentViewer so that client source and parsed policies
10539 // use the parent's URI as self (bug 2021482, 2035423).
10540 MOZ_TRY(csp->SetRequestContextWithDocument(doc))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(csp->SetRequestContextWithDocument(doc)); if ((__builtin_expect
(!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult
.propagateErr(); } mozTryVarTempResult.unwrap(); })
;
10541 }
10542 doc->ApplyCspFromLoadInfo(aLoadInfo);
10543 doc->ApplySettingsFromCSP(false);
10544 doc->RecomputeResistFingerprinting();
10545
10546 rv = doc->GetWindowContext()->SetIsOriginalFrameSource(
10547 aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC));
10548 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10548); return rv; } } while (false)
;
10549
10550 nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow();
10551 if (innerWindow) {
10552 mozilla::dom::ClientSource* clientSource =
10553 nsGlobalWindowInner::Cast(innerWindow)->GetClientSource();
10554 // See if we don't have a controller but the parent has gained a
10555 // controller.
10556 if (clientSource && clientSource->GetController().isNothing()) {
10557 MaybeInheritController(
10558 clientSource,
10559 StoragePrincipalHelper::ShouldUsePartitionPrincipalForServiceWorker(
10560 this)
10561 ? doc->PartitionedPrincipal()
10562 : doc->GetPrincipal());
10563 }
10564 }
10565
10566 MOZ_ASSERT(!mIsLoadingDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsLoadingDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsLoadingDocument))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mIsLoadingDocument"
, "./../../../docshell/base/nsDocShell.cpp", 10566); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsLoadingDocument" ")"); do { MOZ_CrashSequence
(__null, 10566); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10567 MOZ_ASSERT(!mDocumentRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDocumentRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDocumentRequest))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mDocumentRequest"
, "./../../../docshell/base/nsDocShell.cpp", 10567); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocumentRequest" ")"); do { MOZ_CrashSequence
(__null, 10567); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10568
10569 // Call OnStartRequest so that nsDocLoader sets mIsLoadingDocument and fire
10570 // state start
10571 OnStartRequest(aboutBlankChannel);
10572
10573 MOZ_ASSERT(mIsLoadingDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIsLoadingDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIsLoadingDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mIsLoadingDocument"
, "./../../../docshell/base/nsDocShell.cpp", 10573); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mIsLoadingDocument" ")"); do { MOZ_CrashSequence
(__null, 10573); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10574 MOZ_ASSERT(mDocumentRequest == aboutBlankChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentRequest == aboutBlankChannel)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mDocumentRequest == aboutBlankChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mDocumentRequest == aboutBlankChannel"
, "./../../../docshell/base/nsDocShell.cpp", 10574); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDocumentRequest == aboutBlankChannel" ")"
); do { MOZ_CrashSequence(__null, 10574); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10575 MOZ_ASSERT(!doc->InitialAboutBlankLoadCompleting())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!doc->InitialAboutBlankLoadCompleting())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!doc->InitialAboutBlankLoadCompleting()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!doc->InitialAboutBlankLoadCompleting()"
, "./../../../docshell/base/nsDocShell.cpp", 10575); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!doc->InitialAboutBlankLoadCompleting()"
")"); do { MOZ_CrashSequence(__null, 10575); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10576
10577 doc->BeginInitialAboutBlankLoadCompleting(aboutBlankChannel);
10578 auto resetLoadCompleting =
10579 MakeScopeExit([&] { doc->EndInitialAboutBlankLoadCompleting(); });
10580
10581 mCurrentURI = aLoadState->URI();
10582 doc->SetDocumentURI(aLoadState->URI());
10583
10584 // Normal documents fire the location change at content viewer creation.
10585 // The initial about:blank does not do that at content viewer creation,
10586 // so that the UI isn't bothered about the initial about:blank if there's
10587 // immediate navigation away. However, now that the initial about:blank is
10588 // going to remain in this docshell, we need to let to the UI know about it
10589 // (at least in the top-level case).
10590 FireOnLocationChange(this, aboutBlankChannel, aLoadState->URI(), 0);
10591
10592 MoveLoadingToActiveEntry(false, 0, nullptr);
10593
10594 doc->BeginLoad();
10595
10596 nsContentUtils::AddScriptRunner(
10597 MakeAndAddRef<nsDocElementCreatedNotificationRunner>(doc));
10598 // When scripts are not blocked (are they ever blocked here?), the runnable
10599 // runs immediately, so let's check if this docshell got destroyed or the
10600 // document got swapped. Unclear if this ever happens; this is a defensive
10601 // check.
10602 if (mIsBeingDestroyed || !mDocumentViewer ||
10603 doc != mDocumentViewer->GetDocument()) {
10604 return NS_OK;
10605 }
10606
10607 // Initialize the presShell here in the window.open() case.
10608 RefPtr<PresShell> presShell = doc->GetPresShell();
10609 if (presShell && !presShell->DidInitialize()) {
10610 rv = presShell->Initialize();
10611 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10611); return rv; } } while (false)
;
10612 }
10613
10614 doc->SetScrollToRef(doc->GetDocumentURI());
10615
10616 OnStopRequest(aboutBlankChannel, NS_OK);
10617
10618 // Mechanisms in Document will force a load from EndLoad()
10619 // even if there are still blockers.
10620 doc->EndLoad(/* aFireDOMContentLoadedSync = */ true);
10621 // Can't assert any postcondition, because the load event
10622 // handler may have started loading something new in this
10623 // docshell.
10624
10625 return NS_OK;
10626}
10627
10628static nsresult AppendSegmentToString(nsIInputStream* /*aIn*/, void* aClosure,
10629 const char* aFromRawSegment,
10630 uint32_t /*aToOffset*/, uint32_t aCount,
10631 uint32_t* aWriteCount) {
10632 // aFromSegment now contains aCount bytes of data.
10633
10634 nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure);
10635 buf->Append(aFromRawSegment, aCount);
10636
10637 // Indicate that we have consumed all of aFromSegment
10638 *aWriteCount = aCount;
10639 return NS_OK;
10640}
10641
10642/* static */ nsresult nsDocShell::AddHeadersToChannel(
10643 nsIInputStream* aHeadersData, nsIChannel* aGenericChannel) {
10644 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
10645 NS_ENSURE_STATE(httpChannel)do { if ((__builtin_expect(!!(!(httpChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "httpChannel" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 10645);
return NS_ERROR_UNEXPECTED; } } while (false)
;
10646
10647 uint32_t numRead;
10648 nsAutoCString headersString;
10649 nsresult rv = aHeadersData->ReadSegments(
10650 AppendSegmentToString, &headersString, UINT32_MAX(4294967295U), &numRead);
10651 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10651); return rv; } } while (false)
;
10652
10653 // used during the manipulation of the String from the InputStream
10654 nsAutoCString headerName;
10655 nsAutoCString headerValue;
10656 int32_t crlf;
10657 int32_t colon;
10658
10659 //
10660 // Iterate over the headersString: for each "\r\n" delimited chunk,
10661 // add the value as a header to the nsIHttpChannel
10662 //
10663
10664 static const char kWhitespace[] = "\b\t\r\n ";
10665 while (true) {
10666 crlf = headersString.Find("\r\n");
10667 if (crlf == kNotFound) {
10668 return NS_OK;
10669 }
10670
10671 const nsACString& oneHeader = StringHead(headersString, crlf);
10672
10673 colon = oneHeader.FindChar(':');
10674 if (colon == kNotFound) {
10675 return NS_ERROR_UNEXPECTED;
10676 }
10677
10678 headerName = StringHead(oneHeader, colon);
10679 headerValue = Substring(oneHeader, colon + 1);
10680
10681 headerName.Trim(kWhitespace);
10682 headerValue.Trim(kWhitespace);
10683
10684 headersString.Cut(0, crlf + 2);
10685
10686 //
10687 // FINALLY: we can set the header!
10688 //
10689
10690 rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
10691 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10691); return rv; } } while (false)
;
10692 }
10693
10694 MOZ_ASSERT_UNREACHABLE("oops")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"oops" ")", "./../../../docshell/base/nsDocShell.cpp", 10694
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: "
"oops" ")"); do { MOZ_CrashSequence(__null, 10694); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
10695 return NS_ERROR_UNEXPECTED;
10696}
10697
10698/* static */ uint32_t nsDocShell::ComputeURILoaderFlags(
10699 BrowsingContext* aBrowsingContext, uint32_t aLoadType,
10700 bool aIsDocumentLoad) {
10701 MOZ_ASSERT(aBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowsingContext))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowsingContext"
, "./../../../docshell/base/nsDocShell.cpp", 10701); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aBrowsingContext" ")"); do { MOZ_CrashSequence
(__null, 10701); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10702
10703 uint32_t openFlags = 0;
10704 if (aLoadType == LOAD_LINK) {
10705 openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
10706 }
10707 if (!aBrowsingContext->GetAllowContentRetargeting()) {
10708 openFlags |= nsIURILoader::DONT_RETARGET;
10709 }
10710
10711 if (!aIsDocumentLoad) {
10712 openFlags |= nsIURILoader::IS_OBJECT_EMBED;
10713
10714 // Unless the pref is set, object/embed loads always specify DONT_RETARGET.
10715 // See bug 1868001 for details.
10716 if (!StaticPrefs::dom_navigation_object_embed_allow_retargeting()) {
10717 openFlags |= nsIURILoader::DONT_RETARGET;
10718 }
10719 }
10720
10721 return openFlags;
10722}
10723
10724nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
10725 nsIURILoader* aURILoader,
10726 uint32_t aOpenFlags) {
10727 nsresult rv = NS_OK;
10728
10729 // If anything fails here, make sure to clear our initial ClientSource.
10730 auto cleanupInitialClient =
10731 MakeScopeExit([&] { mInitialClientSource.reset(); });
10732
10733 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10734 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(win)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "win" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10734); return NS_ERROR_FAILURE; } } while (false)
;
10735
10736 MaybeCreateInitialClientSource();
10737
10738 // Let the client channel helper know if we are using DocumentChannel,
10739 // since redirects get handled in the parent process in that case.
10740 RefPtr<net::DocumentChannel> docChannel = do_QueryObject(aChannel);
10741 if (docChannel && XRE_IsContentProcess()) {
10742 // Tell the content process nsDocumentOpenInfo to not try to do
10743 // any sort of targeting.
10744 aOpenFlags |= nsIURILoader::DONT_RETARGET;
10745 }
10746
10747 // Since we are loading a document we need to make sure the proper reserved
10748 // and initial client data is stored on the nsILoadInfo. The
10749 // ClientChannelHelper does this and ensures that it is propagated properly
10750 // on redirects. We pass no reserved client here so that the helper will
10751 // create the reserved ClientSource if necessary.
10752 Maybe<ClientInfo> noReservedClient;
10753 if (docChannel) {
10754 // When using DocumentChannel, all redirect handling is done in the parent,
10755 // so we just need the child variant to watch for the internal redirect
10756 // to the final channel.
10757 rv = AddClientChannelHelperInChild(aChannel,
10758 GetMainThreadSerialEventTarget());
10759 docChannel->SetInitialClientInfo(GetInitialClientInfo());
10760 } else {
10761 rv = AddClientChannelHelper(aChannel, std::move(noReservedClient),
10762 GetInitialClientInfo(),
10763 GetMainThreadSerialEventTarget());
10764 }
10765 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10765); return rv; } } while (false)
;
10766
10767 rv = aURILoader->OpenURI(aChannel, aOpenFlags, this);
10768 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10768); return rv; } } while (false)
;
10769
10770 // We're about to load a new page and it may take time before necko
10771 // gives back any data, so main thread might have a chance to process a
10772 // collector slice
10773 nsJSContext::MaybeRunNextCollectorSlice(this, JS::GCReason::DOCSHELL);
10774
10775 // Success. Keep the initial ClientSource if it exists.
10776 cleanupInitialClient.release();
10777
10778 return NS_OK;
10779}
10780
10781nsresult nsDocShell::OpenRedirectedChannel(nsDocShellLoadState* aLoadState) {
10782 nsCOMPtr<nsIChannel> channel = aLoadState->GetPendingRedirectedChannel();
10783 MOZ_ASSERT(channel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(channel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(channel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("channel", "./../../../docshell/base/nsDocShell.cpp"
, 10783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "channel" ")"
); do { MOZ_CrashSequence(__null, 10783); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10784
10785 // If anything fails here, make sure to clear our initial ClientSource.
10786 auto cleanupInitialClient =
10787 MakeScopeExit([&] { mInitialClientSource.reset(); });
10788
10789 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10790 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(win)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "win" ") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10790); return NS_ERROR_FAILURE; } } while (false)
;
10791
10792 MaybeCreateInitialClientSource();
10793
10794 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
10795
10796 LoadInfo* li = static_cast<LoadInfo*>(loadInfo.get());
10797 if (loadInfo->GetExternalContentPolicyType() ==
10798 ExtContentPolicy::TYPE_DOCUMENT) {
10799 li->UpdateBrowsingContextID(mBrowsingContext->Id());
10800 } else if (loadInfo->GetExternalContentPolicyType() ==
10801 ExtContentPolicy::TYPE_SUBDOCUMENT) {
10802 li->UpdateFrameBrowsingContextID(mBrowsingContext->Id());
10803 }
10804
10805 // If we did a process switch, then we should have an existing allocated
10806 // ClientInfo, so we just need to allocate a corresponding ClientSource.
10807 CreateReservedSourceIfNeeded(channel, GetMainThreadSerialEventTarget());
10808
10809 uint32_t documentOpenInfoFlags = nsIURILoader::DONT_RETARGET;
10810 if (loadInfo->GetExternalContentPolicyType() ==
10811 ExtContentPolicy::TYPE_OBJECT) {
10812 documentOpenInfoFlags |= nsIURILoader::IS_OBJECT_EMBED;
10813 }
10814
10815 RefPtr loader =
10816 MakeRefPtr<nsDocumentOpenInfo>(this, documentOpenInfoFlags, nullptr);
10817 channel->SetLoadGroup(mLoadGroup);
10818
10819 MOZ_ALWAYS_SUCCEEDS(loader->Prepare())do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(loader->Prepare())), 1)))), 1))) { } else { do { do { } while
(false); MOZ_ReportCrash("" "NS_SUCCEEDED(loader->Prepare())"
, "./../../../docshell/base/nsDocShell.cpp", 10819); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(loader->Prepare())" ")"); do {
MOZ_CrashSequence(__null, 10819); __attribute__((nomerge)) ::
abort(); } while (false); } while (false); } } while (false)
;
10820
10821 nsresult rv = NS_OK;
10822 if (XRE_IsParentProcess()) {
10823 // If we're in the parent, the we don't have an nsIChildChannel, just
10824 // the original channel, which is already open in this process.
10825
10826 // DocumentLoadListener expects to get an nsIParentChannel, so
10827 // we create a wrapper around the channel and nsIStreamListener
10828 // that forwards functionality as needed, and then we register
10829 // it under the provided identifier.
10830 RefPtr wrapper = MakeRefPtr<ParentChannelWrapper>(channel, loader);
10831 // We're in the parent process, so the redirect is owned by the parent
10832 // process (ContentParentId 0).
10833 wrapper->Register(aLoadState->GetPendingRedirectChannelRegistrarId(), 0);
10834
10835 mLoadGroup->AddRequest(channel, nullptr);
10836 } else if (nsCOMPtr<nsIChildChannel> childChannel =
10837 do_QueryInterface(channel)) {
10838 // Our channel was redirected from another process, so doesn't need to
10839 // be opened again. However, it does need its listener hooked up
10840 // correctly.
10841 rv = childChannel->CompleteRedirectSetup(loader);
10842 } else {
10843 // It's possible for the redirected channel to not implement
10844 // nsIChildChannel and be entirely local (like srcdoc). In that case we
10845 // can just open the local instance and it will work.
10846 rv = channel->AsyncOpen(loader);
10847 }
10848 if (rv == NS_ERROR_NO_CONTENT) {
10849 return NS_OK;
10850 }
10851 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10851); return rv; } } while (false)
;
10852
10853 // Success. Keep the initial ClientSource if it exists.
10854 cleanupInitialClient.release();
10855 return NS_OK;
10856}
10857
10858// https://html.spec.whatwg.org/#scrolling-to-a-fragment
10859nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
10860 nsACString& aNewHash, uint32_t aLoadType) {
10861 if (!mCurrentURI) {
10862 return NS_OK;
10863 }
10864
10865 RefPtr<PresShell> presShell = GetPresShell();
10866 if (!presShell) {
10867 // If we failed to get the shell, or if there is no shell,
10868 // nothing left to do here.
10869 return NS_OK;
10870 }
10871
10872 ScrollContainerFrame* rootScroll = presShell->GetRootScrollContainerFrame();
10873 if (rootScroll) {
10874 rootScroll->ClearDidHistoryRestore();
10875 }
10876
10877 // If it's a load from history, we don't have any anchor jumping to do.
10878 // Scrollbar position will be restored by the caller based on positions stored
10879 // in session history.
10880 bool scroll = aLoadType != LOAD_HISTORY && aLoadType != LOAD_RELOAD_NORMAL;
10881 // If the load contains text directives, try to apply them. This may fail if
10882 // the load is a same-document load that was initiated before the document was
10883 // fully loaded and the target is not yet included in the DOM tree.
10884 // For this case, the `uninvokedTextDirectives` are not cleared, so that
10885 // `Document::ScrollToRef()` can re-apply the text directive.
10886 // `Document::ScrollToRef()` is (presumably) the second "async" call mentioned
10887 // in sec. 7.4.2.3.3 in the HTML spec, "Fragment navigations":
10888 // https://html.spec.whatwg.org/#scroll-to-fragid:~:text=This%20algorithm%20will%20be%20called%20twice
10889
10890 const RefPtr fragmentDirective = GetDocument()->FragmentDirective();
10891 const nsTArray<RefPtr<dom::Range>> textDirectiveRanges =
10892 fragmentDirective->FindTextFragmentsInDocument();
10893 fragmentDirective->HighlightTextDirectives(textDirectiveRanges);
10894 const bool scrollToTextDirective =
10895 !textDirectiveRanges.IsEmpty() &&
10896 fragmentDirective->IsTextDirectiveAllowedToBeScrolledTo();
10897 const RefPtr<dom::Range> textDirectiveToScroll =
10898 scrollToTextDirective ? textDirectiveRanges[0] : nullptr;
10899
10900 // If we have no new anchor, we do not want to scroll, unless there is a
10901 // current anchor and we are doing a history load. So return if we have no
10902 // new anchor, and there is no current anchor or the load is not a history
10903 // load.
10904 if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef &&
10905 !scrollToTextDirective) {
10906 return NS_OK;
10907 }
10908
10909 // Both the new and current URIs refer to the same page. We can now
10910 // browse to the hash stored in the new URI.
10911
10912 if (aNewHash.IsEmpty() && !scrollToTextDirective) {
10913 // 2. If fragment is the empty string, then return the special value top of
10914 // the document.
10915 //
10916 // Tell the shell it's at an anchor without scrolling.
10917 presShell->GoToAnchor(u""_ns, nullptr, false);
10918
10919 if (scroll) {
10920 // Scroll to the top of the page. Ignore the return value; failure to
10921 // scroll here (e.g. if there is no root scrollframe) is not grounds for
10922 // canceling the load!
10923 SetCurScrollPosEx(0, 0);
10924 }
10925
10926 return NS_OK;
10927 }
10928
10929 // 3. Let potentialIndicatedElement be the result of finding a potential
10930 // indicated element given document and fragment.
10931 NS_ConvertUTF8toUTF16 uStr(aNewHash);
10932
10933 MOZ_ASSERT(!uStr.IsEmpty() || scrollToTextDirective)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!uStr.IsEmpty() || scrollToTextDirective)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!uStr.IsEmpty() || scrollToTextDirective))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!uStr.IsEmpty() || scrollToTextDirective"
, "./../../../docshell/base/nsDocShell.cpp", 10933); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!uStr.IsEmpty() || scrollToTextDirective" ")"
); do { MOZ_CrashSequence(__null, 10933); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10934
10935 auto rv = presShell->GoToAnchor(uStr, textDirectiveToScroll, scroll,
10936 ScrollFlags::ScrollSmoothAuto);
10937
10938 // 4. If potentialIndicatedElement is not null, then return
10939 // potentialIndicatedElement.
10940 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
10941 return NS_OK;
10942 }
10943
10944 // 5. Let fragmentBytes be the result of percent-decoding fragment.
10945 nsAutoCString fragmentBytes;
10946 const bool unescaped = NS_UnescapeURL(aNewHash.Data(), aNewHash.Length(),
10947 /* aFlags = */ 0, fragmentBytes);
10948
10949 if (!unescaped) {
10950 // Another attempt is only necessary if characters were unescaped.
10951 return NS_OK;
10952 }
10953
10954 if (fragmentBytes.IsEmpty()) {
10955 // When aNewHash contains "%00", the unescaped string may be empty, and
10956 // GoToAnchor asserts if we ask it to scroll to an empty ref.
10957 presShell->GoToAnchor(u""_ns, nullptr, false);
10958 return NS_OK;
10959 }
10960
10961 // 6. Let decodedFragment be the result of running UTF-8 decode without BOM on
10962 // fragmentBytes.
10963 nsAutoString decodedFragment;
10964 rv = UTF_8_ENCODING->DecodeWithoutBOMHandling(fragmentBytes, decodedFragment);
10965 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 10965); return rv; } } while (false)
;
10966
10967 // 7. Set potentialIndicatedElement to the result of finding a potential
10968 // indicated element given document and decodedFragment.
10969 //
10970 // Ignore the return value of GoToAnchor, since it will return an error if
10971 // there is no such anchor in the document, which is actually a success
10972 // condition for us (we want to update the session history with the new URI no
10973 // matter whether we actually scrolled somewhere).
10974 presShell->GoToAnchor(decodedFragment, nullptr, scroll,
10975 ScrollFlags::ScrollSmoothAuto);
10976
10977 return NS_OK;
10978}
10979
10980bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
10981 nsIPrincipal* aTriggeringPrincipal,
10982 nsIPrincipal* aPrincipalToInherit,
10983 bool aAddToGlobalHistory, bool aCloneSHChildren) {
10984 MOZ_ASSERT(aURI, "uri is null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "uri is null" ")", "./../../../docshell/base/nsDocShell.cpp"
, 10984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") ("
"uri is null" ")"); do { MOZ_CrashSequence(__null, 10984); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
10985 MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChannel || !aTriggeringPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChannel || !aTriggeringPrincipal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChannel || !aTriggeringPrincipal" " (" "Shouldn't have both set"
")", "./../../../docshell/base/nsDocShell.cpp", 10985); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aChannel || !aTriggeringPrincipal" ") (" "Shouldn't have both set"
")"); do { MOZ_CrashSequence(__null, 10985); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10986
10987 MOZ_ASSERT(!aPrincipalToInherit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPrincipalToInherit || (aPrincipalToInherit &&
aTriggeringPrincipal))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aPrincipalToInherit || (aPrincipalToInherit
&& aTriggeringPrincipal)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal)"
, "./../../../docshell/base/nsDocShell.cpp", 10988); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal)"
")"); do { MOZ_CrashSequence(__null, 10988); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10988 (aPrincipalToInherit && aTriggeringPrincipal))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPrincipalToInherit || (aPrincipalToInherit &&
aTriggeringPrincipal))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aPrincipalToInherit || (aPrincipalToInherit
&& aTriggeringPrincipal)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal)"
, "./../../../docshell/base/nsDocShell.cpp", 10988); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal)"
")"); do { MOZ_CrashSequence(__null, 10988); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10989
10990#if defined(DEBUG1)
10991 if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellLog, LogLevel
::Debug)), 0))
) {
10992 nsAutoCString chanName;
10993 if (aChannel) {
10994 aChannel->GetName(chanName);
10995 } else {
10996 chanName.AssignLiteral("<no channel>");
10997 }
10998
10999 MOZ_LOG(gDocShellLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n"
, this, aURI->GetSpecOrDefault().get(), chanName.get(), mLoadType
); } } while (0)
11000 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n"
, this, aURI->GetSpecOrDefault().get(), chanName.get(), mLoadType
); } } while (0)
11001 aURI->GetSpecOrDefault().get(), chanName.get(), mLoadType))do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n"
, this, aURI->GetSpecOrDefault().get(), chanName.get(), mLoadType
); } } while (0)
;
11002 }
11003#endif
11004
11005 bool equalUri = false;
11006
11007 // Get the post data and the HTTP response code from the channel.
11008 uint32_t responseStatus = 0;
11009 nsCOMPtr<nsIInputStream> inputStream;
11010 if (aChannel) {
11011 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11012
11013 // Check if the HTTPChannel is hiding under a multiPartChannel
11014 if (!httpChannel) {
11015 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11016 }
11017
11018 if (httpChannel) {
11019 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11020 if (uploadChannel) {
11021 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11022 }
11023 }
11024 }
11025
11026 // Determine if this type of load should update history.
11027 bool updateGHistory = ShouldUpdateGlobalHistory(mLoadType);
11028
11029 // We don't update session history on reload unless we're loading
11030 // an iframe in shift-reload case.
11031 [[maybe_unused]] bool updateSHistory =
11032 mBrowsingContext->ShouldUpdateSessionHistory(mLoadType);
11033
11034 // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
11035 // root browsing context.
11036 // FIXME If session history in the parent is enabled then we only do this if
11037 // the session history object is in process, otherwise we can't really
11038 // use the mLSHE anyway. Once session history is only stored in the
11039 // parent then this code will probably be removed anyway.
11040 RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
11041 if (!rootSH) {
11042 updateSHistory = false;
11043 updateGHistory = false; // XXX Why global history too?
11044 }
11045
11046 // Check if the url to be loaded is the same as the one already loaded.
11047 if (mCurrentURI) {
11048 aURI->Equals(mCurrentURI, &equalUri);
11049 }
11050
11051#ifdef DEBUG1
11052 bool shAvailable = (rootSH != nullptr);
11053
11054 // XXX This log message is almost useless because |updateSHistory|
11055 // and |updateGHistory| are not correct at this point.
11056
11057 MOZ_LOG(gDocShellLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, " shAvailable=%i updateSHistory=%i updateGHistory=%i"
" equalURI=%i\n", shAvailable, updateSHistory, updateGHistory
, equalUri); } } while (0)
11058 (" shAvailable=%i updateSHistory=%i updateGHistory=%i"do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, " shAvailable=%i updateSHistory=%i updateGHistory=%i"
" equalURI=%i\n", shAvailable, updateSHistory, updateGHistory
, equalUri); } } while (0)
11059 " equalURI=%i\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, " shAvailable=%i updateSHistory=%i updateGHistory=%i"
" equalURI=%i\n", shAvailable, updateSHistory, updateGHistory
, equalUri); } } while (0)
11060 shAvailable, updateSHistory, updateGHistory, equalUri))do { const ::mozilla::LogModule* moz_real_module = gDocShellLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, " shAvailable=%i updateSHistory=%i updateGHistory=%i"
" equalURI=%i\n", shAvailable, updateSHistory, updateGHistory
, equalUri); } } while (0)
;
11061#endif
11062
11063 /* If the url to be loaded is the same as the one already there,
11064 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
11065 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
11066 * AddToSessionHistory() won't mess with the current SHEntry and
11067 * if this page has any frame children, it also will be handled
11068 * properly. see bug 83684
11069 *
11070 * NB: If mOSHE is null but we have a current URI, then it probably
11071 * means that we must be at the transient about:blank content viewer;
11072 * we should let the normal load continue, since there's nothing to
11073 * replace. Sometimes this happens after a session restore (eg process
11074 * switch) and mCurrentURI is not about:blank; we assume we can let the load
11075 * continue (Bug 1301399).
11076 *
11077 * XXX Hopefully changing the loadType at this time will not hurt
11078 * anywhere. The other way to take care of sequentially repeating
11079 * frameset pages is to add new methods to nsIDocShellTreeItem.
11080 * Hopefully I don't have to do that.
11081 */
11082 if (equalUri && mActiveEntry &&
11083 (mLoadType == LOAD_NORMAL || mLoadType == LOAD_LINK ||
11084 mLoadType == LOAD_STOP_CONTENT) &&
11085 !inputStream) {
11086 mLoadType = LOAD_NORMAL_REPLACE;
11087 }
11088
11089 /* If the user pressed shift-reload, cache will create a new cache key
11090 * for the page. Save the new cacheKey in Session History.
11091 * see bug 90098
11092 */
11093 if (aChannel && IsForceReloadType(mLoadType)) {
11094 MOZ_ASSERT(!updateSHistory || IsSubframe(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!updateSHistory || IsSubframe())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!updateSHistory || IsSubframe
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!updateSHistory || IsSubframe()" " (" "We shouldn't be updating session history for forced"
" reloads unless we're in a newly created iframe!" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!updateSHistory || IsSubframe()"
") (" "We shouldn't be updating session history for forced" " reloads unless we're in a newly created iframe!"
")"); do { MOZ_CrashSequence(__null, 11096); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11095 "We shouldn't be updating session history for forced"do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!updateSHistory || IsSubframe())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!updateSHistory || IsSubframe
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!updateSHistory || IsSubframe()" " (" "We shouldn't be updating session history for forced"
" reloads unless we're in a newly created iframe!" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!updateSHistory || IsSubframe()"
") (" "We shouldn't be updating session history for forced" " reloads unless we're in a newly created iframe!"
")"); do { MOZ_CrashSequence(__null, 11096); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11096 " reloads unless we're in a newly created iframe!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!updateSHistory || IsSubframe())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!updateSHistory || IsSubframe
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!updateSHistory || IsSubframe()" " (" "We shouldn't be updating session history for forced"
" reloads unless we're in a newly created iframe!" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!updateSHistory || IsSubframe()"
") (" "We shouldn't be updating session history for forced" " reloads unless we're in a newly created iframe!"
")"); do { MOZ_CrashSequence(__null, 11096); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11097
11098 nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel));
11099 uint32_t cacheKey = 0;
11100 // Get the Cache Key and store it in SH.
11101 if (cacheChannel) {
11102 cacheChannel->GetCacheKey(&cacheKey);
11103 }
11104 // If we already have a loading history entry, store the new cache key
11105 // in it. Otherwise, since we're doing a reload and won't be updating
11106 // our history entry, store the cache key in our current history entry.
11107 SetCacheKeyOnHistoryEntry(cacheKey);
11108 }
11109
11110 if (ShouldAddURIVisit(aChannel) && updateGHistory && aAddToGlobalHistory) {
11111 nsCOMPtr<nsIURI> previousURI;
11112 uint32_t previousFlags = 0;
11113
11114 if (mLoadType & LOAD_CMD_RELOAD) {
11115 // On a reload request, we don't set redirecting flags.
11116 previousURI = aURI;
11117 } else {
11118 ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags);
11119 }
11120
11121 AddURIVisit(aURI, previousURI, previousFlags, responseStatus,
11122 net::ChannelIsPost(aChannel));
11123 }
11124
11125 // aCloneSHChildren exactly means "we are not loading a new document".
11126 uint32_t locationFlags =
11127 aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
11128
11129 bool onLocationChangeNeeded =
11130 SetCurrentURI(aURI, aChannel, false,
11131 /* aIsInitialAboutBlank */ false, locationFlags);
11132 // Make sure to store the referrer from the channel, if any
11133 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11134 if (httpChannel) {
11135 mReferrerInfo = httpChannel->GetReferrerInfo();
11136 }
11137 return onLocationChangeNeeded;
11138}
11139
11140Maybe<Wireframe> nsDocShell::GetWireframe() {
11141 const bool collectWireFrame =
11142 StaticPrefs::browser_history_collectWireframes() &&
11143 mBrowsingContext->IsTopContent() && mActiveEntry;
11144
11145 if (!collectWireFrame) {
11146 return Nothing();
11147 }
11148
11149 RefPtr<Document> doc = mDocumentViewer->GetDocument();
11150 Nullable<Wireframe> wireframe;
11151 doc->GetWireframeWithoutFlushing(false, wireframe);
11152 if (wireframe.IsNull()) {
11153 return Nothing();
11154 }
11155 return Some(wireframe.Value());
11156}
11157
11158bool nsDocShell::CollectWireframe() {
11159 Maybe<Wireframe> wireframe = GetWireframe();
11160 if (wireframe.isNothing()) {
11161 return false;
11162 }
11163
11164 if (XRE_IsParentProcess()) {
11165 SessionHistoryEntry* entry =
11166 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
11167 if (entry) {
11168 entry->SetWireframe(wireframe);
11169 }
11170 } else {
11171 (void)ContentChild::GetSingleton()->SendSessionHistoryEntryWireframe(
11172 mBrowsingContext, wireframe.ref());
11173 }
11174
11175 return true;
11176}
11177
11178//*****************************************************************************
11179// nsDocShell: Session History
11180//*****************************************************************************
11181
11182nsresult nsDocShell::AddState(JS::Handle<JS::Value> aData,
11183 const nsAString& aTitle, const nsAString& aURL,
11184 CallerType aCallerType, bool aReplace,
11185 JSContext* aCx) {
11186 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: AddState(..., %s, %s, %d)"
, this, NS_ConvertUTF16toUTF8(aTitle).get(), NS_ConvertUTF16toUTF8
(aURL).get(), aReplace); } } while (0)
11187 ("nsDocShell[%p]: AddState(..., %s, %s, %d)", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: AddState(..., %s, %s, %d)"
, this, NS_ConvertUTF16toUTF8(aTitle).get(), NS_ConvertUTF16toUTF8
(aURL).get(), aReplace); } } while (0)
11188 NS_ConvertUTF16toUTF8(aTitle).get(),do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: AddState(..., %s, %s, %d)"
, this, NS_ConvertUTF16toUTF8(aTitle).get(), NS_ConvertUTF16toUTF8
(aURL).get(), aReplace); } } while (0)
11189 NS_ConvertUTF16toUTF8(aURL).get(), aReplace))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell[%p]: AddState(..., %s, %s, %d)"
, this, NS_ConvertUTF16toUTF8(aTitle).get(), NS_ConvertUTF16toUTF8
(aURL).get(), aReplace); } } while (0)
;
11190 // Implements History.pushState and History.replaceState
11191
11192 // Here's what we do, roughly in the order specified by HTML5. The specific
11193 // steps we are executing are at
11194 // <https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate>,
11195 // <https://html.spec.whatwg.org/#shared-history-push/replace-state-steps>,
11196 // and
11197 // <https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps>.
11198 // This function basically implements #dom-history-pushstate and
11199 // UpdateURLAndHistory implements #url-and-history-update-steps.
11200 //
11201 // A. Serialize aData using structured clone. This is #dom-history-pushstate
11202 // step 5.
11203 // B. If the third argument is present, #dom-history-pushstate step 7.
11204 // 7.1. Resolve the url, relative to our document.
11205 // 7.2. If (a) fails, raise a SECURITY_ERR
11206 // 7.4. Compare the resulting absolute URL to the document's address. If
11207 // any part of the URLs difer other than the <path>, <query>, and
11208 // <fragment> components, raise a SECURITY_ERR and abort.
11209 // C. If !aReplace, #url-and-history-update-steps steps 2.1-2.3:
11210 // Remove from the session history all entries after the current entry,
11211 // as we would after a regular navigation, and save the current
11212 // entry's scroll position (bug 590573).
11213 // D. #url-and-history-update-steps step 2.4 or step 3. As apropriate,
11214 // either add a state object entry to the session history after the
11215 // current entry with the following properties, or modify the current
11216 // session history entry to set
11217 // a. cloned data as the state object,
11218 // b. if the third argument was present, the absolute URL found in
11219 // step 2
11220 // Also clear the new history entry's POST data (see bug 580069).
11221 // E. If aReplace is false (i.e. we're doing a pushState instead of a
11222 // replaceState), notify bfcache that we've navigated to a new page.
11223 // F. If the third argument is present, set the document's current address
11224 // to the absolute URL found in step B. This is
11225 // #url-and-history-update-steps step 4.
11226 //
11227 // It's important that this function not run arbitrary scripts after step A
11228 // and before completing step E. For example, if a script called
11229 // history.back() before we completed step E, bfcache might destroy an
11230 // active content viewer. Since EvictOutOfRangeDocumentViewers at the end of
11231 // step E might run script, we can't just put a script blocker around the
11232 // critical section.
11233 //
11234 // Note that we completely ignore the aTitle parameter.
11235
11236 nsresult rv;
11237
11238 RefPtr<Document> document = GetDocument();
11239 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(document)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "document" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 11239); return NS_ERROR_FAILURE
; } } while (false)
;
11240
11241 // Don't clobber the load type of an existing network load.
11242 Maybe<AutoRestore<uint32_t>> loadTypeResetter;
11243 if (StaticPrefs::
11244 docshell_shistory_sameDocumentNavigationOverridesLoadType() &&
11245 !document->NodePrincipal()->IsURIInPrefList(
11246 "docshell.shistory.sameDocumentNavigationOverridesLoadType."
11247 "forceDisable")) {
11248 loadTypeResetter.emplace(mLoadType);
11249 }
11250
11251 // pushState effectively becomes replaceState when we've started a network
11252 // load but haven't adopted its document yet. This mirrors what we do with
11253 // changes to the hash at this stage of the game.
11254 if (JustStartedNetworkLoad()) {
11255 if (!loadTypeResetter.isSome()) {
11256 loadTypeResetter.emplace(mLoadType);
11257 }
11258 aReplace = true;
11259 }
11260
11261 // Step A: Serialize aData using structured clone.
11262 // https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate
11263 // step 5.
11264 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
11265
11266 // scContainer->Init might cause arbitrary JS to run, and this code might
11267 // navigate the page we're on, potentially to a different origin! (bug
11268 // 634834) To protect against this, we abort if our principal changes due
11269 // to the InitFromJSVal() call.
11270 {
11271 RefPtr<Document> origDocument = GetDocument();
11272 if (!origDocument) {
11273 return NS_ERROR_DOM_SECURITY_ERR;
11274 }
11275 nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
11276
11277 scContainer = new nsStructuredCloneContainer();
11278 rv = scContainer->InitFromJSVal(aData, aCx);
11279 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 11279); return rv; } } while (false)
;
11280
11281 RefPtr<Document> newDocument = GetDocument();
11282 if (!newDocument) {
11283 return NS_ERROR_DOM_SECURITY_ERR;
11284 }
11285 nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
11286
11287 bool principalsEqual = false;
11288 origPrincipal->Equals(newPrincipal, &principalsEqual);
11289 NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR)do { if ((__builtin_expect(!!(!(principalsEqual)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "principalsEqual" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 11289);
return NS_ERROR_DOM_SECURITY_ERR; } } while (false)
;
11290 }
11291
11292 // Check that the state object isn't too long.
11293 int32_t maxStateObjSize = StaticPrefs::browser_history_maxStateObjectSize();
11294 if (maxStateObjSize < 0) {
11295 maxStateObjSize = 0;
11296 }
11297
11298 uint64_t scSize;
11299 rv = scContainer->GetSerializedNBytes(&scSize);
11300 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 11300); return rv; } } while (false)
;
11301
11302 NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE)do { if ((__builtin_expect(!!(!(scSize <= (uint32_t)maxStateObjSize
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "scSize <= (uint32_t)maxStateObjSize"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 11302); return NS_ERROR_ILLEGAL_VALUE; } } while (false)
;
11303
11304 // Step B: Resolve aURL.
11305 // https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate
11306 // step 7.
11307 bool equalURIs = true;
11308 nsCOMPtr<nsIURI> currentURI;
11309 if (mCurrentURI) {
11310 currentURI = nsIOService::CreateExposableURI(mCurrentURI);
11311 } else {
11312 currentURI = mCurrentURI;
11313 }
11314 nsCOMPtr<nsIURI> newURI;
11315 if (aURL.Length() == 0) {
11316 newURI = currentURI;
11317 } else {
11318 // 7.1: Resolve aURL relative to mURI
11319
11320 nsIURI* docBaseURI = document->GetDocBaseURI();
11321 if (!docBaseURI) {
11322 return NS_ERROR_FAILURE;
11323 }
11324
11325 nsAutoCString spec;
11326 docBaseURI->GetSpec(spec);
11327
11328 rv = NS_NewURI(getter_AddRefs(newURI), aURL,
11329 document->GetDocumentCharacterSet(), docBaseURI);
11330
11331 // 7.2: If 2a fails, raise a SECURITY_ERR
11332 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
11333 return NS_ERROR_DOM_SECURITY_ERR;
11334 }
11335
11336 if (!document->CanRewriteURL(newURI)) {
11337 return NS_ERROR_DOM_SECURITY_ERR;
11338 }
11339
11340 if (currentURI) {
11341 currentURI->Equals(newURI, &equalURIs);
11342 } else {
11343 equalURIs = false;
11344 }
11345
11346 } // end of same-origin check
11347
11348 if (!mBrowsingContext->CheckNavigationRateLimit(aCallerType)) {
11349 return NS_OK;
11350 }
11351
11352 // https://html.spec.whatwg.org/#shared-history-push/replace-state-steps
11353 // Step 8
11354 if (nsCOMPtr<nsPIDOMWindowInner> window = document->GetInnerWindow()) {
11355 if (RefPtr<Navigation> navigation = window->Navigation()) {
11356 bool shouldContinue = navigation->FirePushReplaceReloadNavigateEvent(
11357 aCx, aReplace ? NavigationType::Replace : NavigationType::Push,
11358 newURI,
11359 /* aIsSameDocument */ true,
11360 /* aUserInvolvement */ Nothing(),
11361 /* aSourceElement */ nullptr, /* aFormDataEntryList */ nullptr,
11362 /* aNavigationAPIState */ nullptr, scContainer);
11363
11364 // Step 9
11365 if (!shouldContinue) {
11366 return NS_OK;
11367 }
11368 }
11369 }
11370
11371 // Step 10
11372 // Run #url-and-history-update-steps
11373 rv = UpdateURLAndHistory(document, newURI, scContainer,
11374 aReplace ? NavigationHistoryBehavior::Replace
11375 : NavigationHistoryBehavior::Push,
11376 currentURI, equalURIs);
11377 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 11377); return rv; } } while (false)
;
11378
11379 return NS_OK;
11380}
11381
11382nsresult nsDocShell::UpdateURLAndHistory(
11383 Document* aDocument, nsIURI* aNewURI, nsIStructuredCloneContainer* aData,
11384 NavigationHistoryBehavior aHistoryHandling, nsIURI* aCurrentURI,
11385 bool aEqualURIs, bool aFiredNavigateEvent) {
11386 MOZ_LOG_FMT(gNavigationAPILog, LogLevel::Debug, "UpdateURLAndHistory {}",do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "UpdateURLAndHistory {}", aHistoryHandling
); } } while (0)
11387 aHistoryHandling)do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "UpdateURLAndHistory {}", aHistoryHandling
); } } while (0)
;
11388
11389 // Implements
11390 // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
11391 MOZ_ASSERT(aHistoryHandling != NavigationHistoryBehavior::Auto)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aHistoryHandling != NavigationHistoryBehavior::Auto)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aHistoryHandling != NavigationHistoryBehavior::Auto)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aHistoryHandling != NavigationHistoryBehavior::Auto"
, "./../../../docshell/base/nsDocShell.cpp", 11391); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aHistoryHandling != NavigationHistoryBehavior::Auto"
")"); do { MOZ_CrashSequence(__null, 11391); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11392 bool isReplace = aHistoryHandling == NavigationHistoryBehavior::Replace;
11393
11394 // If we have a pending title change, handle it before creating a new entry.
11395 aDocument->DoNotifyPossibleTitleChange();
11396
11397 // Step 2, if aReplace is false: Create a new entry in the session
11398 // history. This will erase all SHEntries after the new entry and make this
11399 // entry the current one.
11400 NS_ENSURE_TRUE(mActiveEntry || isReplace, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mActiveEntry || isReplace)), 0
))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mActiveEntry || isReplace"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 11400); return NS_ERROR_FAILURE; } } while (false)
;
11401
11402 // If this push/replaceState changed the document's current URI and the new
11403 // URI differs from the old URI in more than the hash, or if the old
11404 // SHEntry's URI was modified in this way by a push/replaceState call
11405 // set URIWasModified to true for the current SHEntry (bug 669671).
11406 bool sameExceptHashes = true;
11407 aNewURI->EqualsExceptRef(aCurrentURI, &sameExceptHashes);
11408 bool uriWasModified;
11409 if (sameExceptHashes) {
11410 uriWasModified = mActiveEntry && mActiveEntry->GetURIWasModified();
11411 } else {
11412 uriWasModified = true;
11413 }
11414
11415 mLoadType = LOAD_PUSHSTATE;
11416
11417 RefPtr<SessionHistoryEntry> newSHEntry;
11418 if (!isReplace) {
11419 // Step 2.
11420
11421 // Step 2.2, "Remove any tasks queued by the history traversal task
11422 // source that are associated with any Document objects in the
11423 // top-level browsing context's document family." This is very hard in
11424 // SessionHistoryInParent since we can't synchronously access the
11425 // pending navigations that are already sent to the parent. We can
11426 // abort any AsyncGo navigations that are waiting to be sent. If we
11427 // send a message to the parent, it would be processed after any
11428 // navigations previously sent. So long as we consider the "history
11429 // traversal task source" to be the list in this process we match the
11430 // spec. If we move the entire list to the parent, we can handle the
11431 // aborting of loads there, but we don't have a way to synchronously
11432 // remove entries as we do here for non-SHIP.
11433 RefPtr<ChildSHistory> shistory = GetRootSessionHistory();
11434 if (shistory) {
11435 shistory->RemovePendingHistoryNavigations();
11436 }
11437
11438 nsPoint scrollPos = GetCurScrollPos();
11439
11440 bool scrollRestorationIsManual;
11441 // FIXME Need to save the current scroll position on mActiveEntry.
11442 scrollRestorationIsManual = mActiveEntry->GetScrollRestorationIsManual();
11443
11444 nsCOMPtr<nsIPolicyContainer> policyContainer =
11445 aDocument->GetPolicyContainer();
11446
11447 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p UpdateActiveEntry (not replacing)"
, this); } } while (0)
11448 ("nsDocShell %p UpdateActiveEntry (not replacing)", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p UpdateActiveEntry (not replacing)"
, this); } } while (0)
;
11449
11450 nsString title(mActiveEntry->GetTitle());
11451 nsCOMPtr<nsIReferrerInfo> referrerInfo = mActiveEntry->GetReferrerInfo();
11452
11453 UpdateActiveEntry(false,
11454 /* aPreviousScrollPos = */ Some(scrollPos), aNewURI,
11455 /* aReferrerInfo = */ referrerInfo,
11456 /* aTriggeringPrincipal = */ aDocument->NodePrincipal(),
11457 policyContainer, title, scrollRestorationIsManual, aData,
11458 uriWasModified);
11459 } else {
11460 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p UpdateActiveEntry (replacing) mActiveEntry %p"
, this, mActiveEntry.get()); } } while (0)
11461 ("nsDocShell %p UpdateActiveEntry (replacing) mActiveEntry %p",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p UpdateActiveEntry (replacing) mActiveEntry %p"
, this, mActiveEntry.get()); } } while (0)
11462 this, mActiveEntry.get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p UpdateActiveEntry (replacing) mActiveEntry %p"
, this, mActiveEntry.get()); } } while (0)
;
11463 // We don't use aTitle here, see bug 544535.
11464 nsString title;
11465 nsCOMPtr<nsIReferrerInfo> referrerInfo;
11466 if (mActiveEntry) {
11467 title = mActiveEntry->GetTitle();
11468 referrerInfo = mActiveEntry->GetReferrerInfo();
11469 } else {
11470 referrerInfo = nullptr;
11471 }
11472 UpdateActiveEntry(
11473 true, /* aPreviousScrollPos = */ Nothing(), aNewURI,
11474 /* aReferrerInfo = */ referrerInfo, aDocument->NodePrincipal(),
11475 aDocument->GetPolicyContainer(), title,
11476 mActiveEntry && mActiveEntry->GetScrollRestorationIsManual(), aData,
11477 uriWasModified);
11478 }
11479
11480 // Step 4: If the document's URI changed, update document's URI and update
11481 // global history.
11482 //
11483 // We need to call FireOnLocationChange so that the browser's address bar
11484 // gets updated and the back button is enabled, but we only need to
11485 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
11486 // since SetCurrentURI will call FireOnLocationChange for us.
11487 //
11488 // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
11489 // nullptr for aRequest param to FireOnLocationChange(...). Such an update
11490 // notification is allowed only when we know docshell is not loading a new
11491 // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
11492 // FireOnLocationChange(...) breaks security UI.
11493 //
11494 // If the docshell is shutting down, don't update the document URI, as we
11495 // can't load into a docshell that is being destroyed.
11496 if (!aEqualURIs && !mIsBeingDestroyed) {
11497 aDocument->SetDocumentURI(aNewURI);
11498 SetCurrentURI(aNewURI, nullptr, /* aFireLocationChange */ true,
11499 /* aIsInitialAboutBlank */ false,
11500 GetSameDocumentNavigationFlags(aNewURI));
11501
11502 AddURIVisit(aNewURI, aCurrentURI, 0);
11503
11504 // AddURIVisit doesn't set the title for the new URI in global history,
11505 // so do that here.
11506 UpdateGlobalHistoryTitle(aNewURI);
11507
11508 // Inform the favicon service that our old favicon applies to this new
11509 // URI.
11510 CopyFavicon(aCurrentURI, aNewURI, UsePrivateBrowsing());
11511 } else {
11512 FireDummyOnLocationChange();
11513 }
11514 aDocument->SetStateObject(aData);
11515
11516 if (RefPtr navigation = aDocument->GetInnerWindow()->Navigation()) {
11517 MOZ_LOG(gNavigationAPILog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event for a same-document "
"navigation from UpdateURLAndHistory -> isReplace: %s", this
, isReplace ? "true" : "false"); } } while (0)
11518 ("nsDocShell %p triggering a navigation event for a same-document "do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event for a same-document "
"navigation from UpdateURLAndHistory -> isReplace: %s", this
, isReplace ? "true" : "false"); } } while (0)
11519 "navigation from UpdateURLAndHistory -> isReplace: %s",do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event for a same-document "
"navigation from UpdateURLAndHistory -> isReplace: %s", this
, isReplace ? "true" : "false"); } } while (0)
11520 this, isReplace ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p triggering a navigation event for a same-document "
"navigation from UpdateURLAndHistory -> isReplace: %s", this
, isReplace ? "true" : "false"); } } while (0)
;
11521 // Step 11: Update the navigation API entries for a same-document
11522 // navigation given document's relevant global object's navigation API,
11523 // newEntry, and historyHandling.
11524 navigation->UpdateEntriesForSameDocumentNavigation(
11525 mActiveEntry.get(),
11526 isReplace ? NavigationType::Replace : NavigationType::Push,
11527 aFiredNavigateEvent);
11528 }
11529
11530 return NS_OK;
11531}
11532
11533NS_IMETHODIMPnsresult
11534nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual) {
11535 *aIsManual = mActiveEntry && mActiveEntry->GetScrollRestorationIsManual();
11536 return NS_OK;
11537}
11538
11539NS_IMETHODIMPnsresult
11540nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual) {
11541 SetScrollRestorationIsManualOnHistoryEntry(aIsManual);
11542
11543 return NS_OK;
11544}
11545
11546void nsDocShell::SetScrollRestorationIsManualOnHistoryEntry(bool aIsManual) {
11547 if (mActiveEntry && mBrowsingContext) {
11548 mActiveEntry->SetScrollRestorationIsManual(aIsManual);
11549 if (XRE_IsParentProcess()) {
11550 SessionHistoryEntry* entry =
11551 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
11552 if (entry) {
11553 entry->SetScrollRestorationIsManual(aIsManual);
11554 }
11555 } else {
11556 (void)ContentChild::GetSingleton()
11557 ->SendSessionHistoryEntryScrollRestorationIsManual(mBrowsingContext,
11558 aIsManual);
11559 }
11560 }
11561}
11562
11563void nsDocShell::SetCacheKeyOnHistoryEntry(uint32_t aCacheKey) {
11564 if (mActiveEntry && mBrowsingContext) {
11565 mActiveEntry->SetCacheKey(aCacheKey);
11566 if (XRE_IsParentProcess()) {
11567 SessionHistoryEntry* entry =
11568 mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
11569 if (entry) {
11570 entry->SetCacheKey(aCacheKey);
11571 }
11572 } else {
11573 (void)ContentChild::GetSingleton()->SendSessionHistoryEntryCacheKey(
11574 mBrowsingContext, aCacheKey);
11575 }
11576 }
11577}
11578
11579void nsDocShell::UpdateActiveEntry(
11580 bool aReplace, const Maybe<nsPoint>& aPreviousScrollPos, nsIURI* aURI,
11581 nsIReferrerInfo* aReferrerInfo, nsIPrincipal* aTriggeringPrincipal,
11582 nsIPolicyContainer* aPolicyContainer, const nsAString& aTitle,
11583 bool aScrollRestorationIsManual, nsIStructuredCloneContainer* aData,
11584 bool aURIWasModified) {
11585 MOZ_ASSERT(aURI, "uri is null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "uri is null" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11585); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") ("
"uri is null" ")"); do { MOZ_CrashSequence(__null, 11585); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
11586 MOZ_ASSERT(mLoadType == LOAD_PUSHSTATE,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLoadType == LOAD_PUSHSTATE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mLoadType == LOAD_PUSHSTATE)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mLoadType == LOAD_PUSHSTATE"
" (" "This code only deals with pushState" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mLoadType == LOAD_PUSHSTATE"
") (" "This code only deals with pushState" ")"); do { MOZ_CrashSequence
(__null, 11587); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
11587 "This code only deals with pushState")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLoadType == LOAD_PUSHSTATE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mLoadType == LOAD_PUSHSTATE)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mLoadType == LOAD_PUSHSTATE"
" (" "This code only deals with pushState" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mLoadType == LOAD_PUSHSTATE"
") (" "This code only deals with pushState" ")"); do { MOZ_CrashSequence
(__null, 11587); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11588 MOZ_ASSERT_IF(aPreviousScrollPos.isSome(), !aReplace)do { if (aPreviousScrollPos.isSome()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(!aReplace)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aReplace))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aReplace", "./../../../docshell/base/nsDocShell.cpp", 11588
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aReplace" ")"); do
{ MOZ_CrashSequence(__null, 11588); __attribute__((nomerge))
::abort(); } while (false); } } while (false); } } while (false
)
;
11589
11590 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, aURI->GetSpecOrDefault().get()); } } while (0)
11591 ("Creating an active entry on nsDocShell %p to %s", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, aURI->GetSpecOrDefault().get()); } } while (0)
11592 aURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Creating an active entry on nsDocShell %p to %s"
, this, aURI->GetSpecOrDefault().get()); } } while (0)
;
11593
11594 // Even if we're replacing an existing entry we create new a
11595 // SessionHistoryInfo. In the parent process we'll keep the existing
11596 // SessionHistoryEntry, but just replace its SessionHistoryInfo, that way the
11597 // entry keeps identity but its data is replaced.
11598 bool replace = aReplace && mActiveEntry;
11599
11600 if (!replace) {
11601 CollectWireframe();
11602 }
11603
11604 UniquePtr<SessionHistoryInfo> previousActiveEntry(mActiveEntry.release());
11605 if (previousActiveEntry) {
11606 // Link this entry to the previous active entry.
11607 mActiveEntry =
11608 std::make_unique<SessionHistoryInfo>(*previousActiveEntry, aURI);
11609 } else {
11610 Document* doc = GetDocument();
11611 MOZ_ASSERT(doc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(doc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(doc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("doc", "./../../../docshell/base/nsDocShell.cpp"
, 11611); AnnotateMozCrashReason("MOZ_ASSERT" "(" "doc" ")");
do { MOZ_CrashSequence(__null, 11611); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11612 mActiveEntry = std::make_unique<SessionHistoryInfo>(
11613 aURI, aTriggeringPrincipal, doc->NodePrincipal(), nullptr,
11614 aPolicyContainer, mContentTypeHint);
11615 }
11616 mActiveEntry->SetUnstrippedURI(nullptr);
11617 mActiveEntry->SetReferrerInfo(aReferrerInfo);
11618 mActiveEntry->SetTitle(aTitle);
11619 mActiveEntry->SetStateData(static_cast<nsStructuredCloneContainer*>(aData));
11620 mActiveEntry->SetURIWasModified(aURIWasModified);
11621 mActiveEntry->SetScrollRestorationIsManual(aScrollRestorationIsManual);
11622
11623 if (replace) {
11624 mActiveEntry->NavigationKey() = previousActiveEntry->NavigationKey();
11625 mBrowsingContext->ReplaceActiveSessionHistoryEntry(mActiveEntry.get());
11626 } else {
11627 mBrowsingContext->IncrementHistoryEntryCountForBrowsingContext();
11628 // FIXME We should probably just compute mChildOffset in the parent
11629 // instead of passing it over IPC here.
11630 mBrowsingContext->SetActiveSessionHistoryEntry(
11631 aPreviousScrollPos, mActiveEntry.get(), previousActiveEntry.get(),
11632 mLoadType,
11633 /* aCacheKey = */ 0);
11634 // FIXME Do we need to update mPreviousEntryIndex and mLoadedEntryIndex?
11635 }
11636}
11637
11638nsresult nsDocShell::LoadHistoryEntry(const LoadingSessionHistoryInfo& aEntry,
11639 uint32_t aLoadType, bool aUserActivation,
11640 bool aNotifiedBeforeUnloadListeners,
11641 bool aIsResumingInterceptedNavigation,
11642 bool aPageSwapFired) {
11643 RefPtr<nsDocShellLoadState> loadState = aEntry.CreateLoadInfo();
11644 loadState->SetHasValidUserGestureActivation(
11645 loadState->HasValidUserGestureActivation() || aUserActivation);
11646
11647 loadState->SetTextDirectiveUserActivation(
11648 loadState->GetTextDirectiveUserActivation() || aUserActivation);
11649
11650 loadState->SetNotifiedBeforeUnloadListeners(aNotifiedBeforeUnloadListeners);
11651
11652 loadState->SetIsResumingInterceptedNavigation(
11653 aIsResumingInterceptedNavigation);
11654
11655 loadState->SetPageSwapFired(aPageSwapFired);
11656
11657 return LoadHistoryEntry(loadState, aLoadType);
11658}
11659
11660void nsDocShell::MaybeFireTraverseHistory(nsDocShellLoadState* aLoadState) {
11661 if (!Navigation::IsAPIEnabled()) {
11662 return;
11663 }
11664
11665 BrowsingContext* browsingContext = GetBrowsingContext();
11666 if (!browsingContext || browsingContext->IsTop()) {
11667 return;
11668 }
11669
11670 if (!mActiveEntry || !aLoadState->GetLoadingSessionHistoryInfo() ||
11671 aLoadState->IsResumingInterceptedNavigation()) {
11672 return;
11673 }
11674 if (mActiveEntry->NavigationKey() ==
11675 aLoadState->GetLoadingSessionHistoryInfo()->mInfo.NavigationKey()) {
11676 return;
11677 }
11678
11679 nsCOMPtr activeURI = mActiveEntry->GetURIOrInheritedForAboutBlankOrSrcdoc();
11680 nsCOMPtr<nsIURI> loadingURI =
11681 aLoadState->GetLoadingSessionHistoryInfo()
11682 ->mInfo.GetURIOrInheritedForAboutBlankOrSrcdoc();
11683 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( activeURI, loadingURI, false, false
))), 0)))
11684 activeURI, loadingURI,((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( activeURI, loadingURI, false, false
))), 0)))
11685 /*reportError=*/false,((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( activeURI, loadingURI, false, false
))), 0)))
11686 /*fromPrivateWindow=*/false))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckSameOriginURI( activeURI, loadingURI, false, false
))), 0)))
) {
11687 return;
11688 }
11689
11690 if (RefPtr window = GetActiveWindow()) {
11691 if (RefPtr navigation = window->Navigation()) {
11692 if (AutoJSAPI jsapi; jsapi.Init(window)) {
11693 // This should send the correct user involvment. See bug 1903552.
11694 navigation->FireTraverseNavigateEvent(jsapi.cx(), aLoadState,
11695 Nothing());
11696 }
11697 }
11698 }
11699}
11700
11701nsIDocumentViewer::PermitUnloadResult
11702nsDocShell::MaybeFireTraversableTraverseHistory(
11703 nsDocShellLoadState* aLoadState,
11704 Maybe<UserNavigationInvolvement> aUserInvolvement) {
11705 MOZ_DIAGNOSTIC_ASSERT(GetBrowsingContext())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetBrowsingContext())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(GetBrowsingContext()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("GetBrowsingContext()"
, "./../../../docshell/base/nsDocShell.cpp", 11705); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "GetBrowsingContext()" ")"); do {
MOZ_CrashSequence(__null, 11705); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
11706 MOZ_DIAGNOSTIC_ASSERT(GetBrowsingContext()->IsTop())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetBrowsingContext()->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(GetBrowsingContext()->IsTop
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("GetBrowsingContext()->IsTop()", "./../../../docshell/base/nsDocShell.cpp"
, 11706); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "GetBrowsingContext()->IsTop()"
")"); do { MOZ_CrashSequence(__null, 11706); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11707
11708 SetOngoingNavigation(Some(OngoingNavigation::Traversal));
11709
11710 nsIDocumentViewer::PermitUnloadResult finalStatus =
11711 nsIDocumentViewer::eContinue;
11712 if (RefPtr<nsPIDOMWindowInner> activeWindow = GetActiveWindow()) {
11713 if (RefPtr navigation = activeWindow->Navigation()) {
11714 if (AutoJSAPI jsapi; jsapi.Init(activeWindow)) {
11715 switch (navigation->FireTraverseNavigateEvent(jsapi.cx(), aLoadState,
11716 aUserInvolvement)) {
11717 case Navigation::FinalStatus::Continue:
11718 break;
11719 case Navigation::FinalStatus::Intercept:
11720 finalStatus = nsIDocumentViewer::eInterceptedByNavigate;
11721 break;
11722 case Navigation::FinalStatus::Prevent:
11723 finalStatus = nsIDocumentViewer::eCanceledByNavigate;
11724 break;
11725 }
11726 }
11727 }
11728 }
11729
11730 return finalStatus;
11731}
11732
11733nsresult nsDocShell::LoadHistoryEntry(nsDocShellLoadState* aLoadState,
11734 uint32_t aLoadType) {
11735 if (!IsNavigationAllowed()) {
11736 return NS_OK;
11737 }
11738
11739 // https://html.spec.whatwg.org/#navigate-to-a-javascript:-url
11740 // Step 13: historyEntry should store entryToReplace's URL.
11741 if (aLoadState->URI()->SchemeIs("javascript")) {
11742 MOZ_ASSERT_UNREACHABLE("javascript: URIs should not enter session history")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"javascript: URIs should not enter session history" ")", "./../../../docshell/base/nsDocShell.cpp"
, 11742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "javascript: URIs should not enter session history"
")"); do { MOZ_CrashSequence(__null, 11742); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11743 return NS_ERROR_FAILURE;
11744 }
11745
11746 // XXX FillLoadInfo doesn't copy mLoadType, so the load state arrives here
11747 // without a load type set.
11748 aLoadState->SetLoadType(aLoadType);
11749
11750 SetOngoingNavigation(Some(OngoingNavigation::Traversal));
11751
11752 /* If there is a valid postdata *and* the user pressed
11753 * reload or shift-reload, take user's permission before we
11754 * repost the data to the server.
11755 */
11756 if ((aLoadType & LOAD_CMD_RELOAD) && aLoadState->PostDataStream()) {
11757 bool repost;
11758 nsresult rv = ConfirmRepost(&repost);
11759 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
11760 return rv;
11761 }
11762
11763 // If the user pressed cancel in the dialog, return. We're done here.
11764 if (!repost) {
11765 return NS_BINDING_ABORTED;
11766 }
11767 }
11768
11769 // If there is no valid triggeringPrincipal, we deny the load
11770 MOZ_ASSERT(aLoadState->TriggeringPrincipal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TriggeringPrincipal()" " (" "need a valid triggeringPrincipal to load from history"
")", "./../../../docshell/base/nsDocShell.cpp", 11771); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TriggeringPrincipal()" ") ("
"need a valid triggeringPrincipal to load from history" ")")
; do { MOZ_CrashSequence(__null, 11771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
11771 "need a valid triggeringPrincipal to load from history")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->TriggeringPrincipal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadState->TriggeringPrincipal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLoadState->TriggeringPrincipal()" " (" "need a valid triggeringPrincipal to load from history"
")", "./../../../docshell/base/nsDocShell.cpp", 11771); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->TriggeringPrincipal()" ") ("
"need a valid triggeringPrincipal to load from history" ")")
; do { MOZ_CrashSequence(__null, 11771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11772 if (!aLoadState->TriggeringPrincipal()) {
11773 return NS_ERROR_FAILURE;
11774 }
11775
11776 return InternalLoad(aLoadState); // No nsIRequest
11777}
11778
11779NS_IMETHODIMPnsresult
11780nsDocShell::PersistLayoutHistoryState() {
11781 nsresult rv = NS_OK;
11782
11783 if (mActiveEntry) {
11784 bool scrollRestorationIsManual =
11785 mActiveEntry->GetScrollRestorationIsManual();
11786 nsCOMPtr<nsILayoutHistoryState> layoutState;
11787 if (RefPtr<PresShell> presShell = GetPresShell()) {
11788 rv = presShell->CaptureHistoryState(getter_AddRefs(layoutState));
11789 } else if (scrollRestorationIsManual) {
11790 // Even if we don't have layout anymore, we may want to reset the
11791 // current scroll state in layout history.
11792 GetLayoutHistoryState(getter_AddRefs(layoutState));
11793 }
11794
11795 if (scrollRestorationIsManual && layoutState) {
11796 layoutState->ResetScrollState();
11797 }
11798 }
11799
11800 return rv;
11801}
11802
11803already_AddRefed<ChildSHistory> nsDocShell::GetRootSessionHistory() {
11804 RefPtr<ChildSHistory> childSHistory =
11805 mBrowsingContext->Top()->GetChildSessionHistory();
11806 return childSHistory.forget();
11807}
11808
11809nsresult nsDocShell::GetHttpChannel(nsIChannel* aChannel,
11810 nsIHttpChannel** aReturn) {
11811 NS_ENSURE_ARG_POINTER(aReturn)do { if ((__builtin_expect(!!(!(aReturn)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aReturn" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 11811); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
11812 if (!aChannel) {
11813 return NS_ERROR_FAILURE;
11814 }
11815
11816 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
11817 if (multiPartChannel) {
11818 nsCOMPtr<nsIChannel> baseChannel;
11819 multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
11820 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
11821 *aReturn = httpChannel;
11822 NS_IF_ADDREF(*aReturn)ns_if_addref(*aReturn);
11823 }
11824 return NS_OK;
11825}
11826
11827bool nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel) {
11828 // By default layout State will be saved.
11829 if (!aChannel) {
11830 return false;
11831 }
11832
11833 // figure out if SH should be saving layout state
11834 bool noStore = false;
11835 (void)aChannel->IsNoStoreResponse(&noStore);
11836 return noStore;
11837}
11838
11839NS_IMETHODIMPnsresult
11840nsDocShell::GetEditor(nsIEditor** aEditor) {
11841 NS_ENSURE_ARG_POINTER(aEditor)do { if ((__builtin_expect(!!(!(aEditor)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEditor" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 11841); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
11842 RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorInternal();
11843 htmlEditor.forget(aEditor);
11844 return NS_OK;
11845}
11846
11847NS_IMETHODIMPnsresult
11848nsDocShell::SetEditor(nsIEditor* aEditor) {
11849 HTMLEditor* htmlEditor = aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
11850 // If TextEditor comes, throw an error.
11851 if (aEditor && !htmlEditor) {
11852 return NS_ERROR_INVALID_ARG;
11853 }
11854 return SetHTMLEditorInternal(htmlEditor);
11855}
11856
11857HTMLEditor* nsDocShell::GetHTMLEditorInternal() {
11858 return mEditorData ? mEditorData->GetHTMLEditor() : nullptr;
11859}
11860
11861nsresult nsDocShell::SetHTMLEditorInternal(HTMLEditor* aHTMLEditor) {
11862 if (!aHTMLEditor && !mEditorData) {
11863 return NS_OK;
11864 }
11865
11866 nsresult rv = EnsureEditorData();
11867 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
11868 return rv;
11869 }
11870
11871 return mEditorData->SetHTMLEditor(aHTMLEditor);
11872}
11873
11874NS_IMETHODIMPnsresult
11875nsDocShell::GetEditable(bool* aEditable) {
11876 NS_ENSURE_ARG_POINTER(aEditable)do { if ((__builtin_expect(!!(!(aEditable)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEditable" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 11876); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
11877 *aEditable = mEditorData && mEditorData->GetEditable();
11878 return NS_OK;
11879}
11880
11881NS_IMETHODIMPnsresult
11882nsDocShell::GetHasEditingSession(bool* aHasEditingSession) {
11883 NS_ENSURE_ARG_POINTER(aHasEditingSession)do { if ((__builtin_expect(!!(!(aHasEditingSession)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aHasEditingSession" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 11883);
return NS_ERROR_INVALID_POINTER; } } while (false)
;
11884
11885 if (mEditorData) {
11886 *aHasEditingSession = !!mEditorData->GetEditingSession();
11887 } else {
11888 *aHasEditingSession = false;
11889 }
11890
11891 return NS_OK;
11892}
11893
11894NS_IMETHODIMPnsresult
11895nsDocShell::MakeEditable(bool aInWaitForUriLoad) {
11896 nsresult rv = EnsureEditorData();
11897 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
11898 return rv;
11899 }
11900
11901 return mEditorData->MakeEditable(aInWaitForUriLoad);
11902}
11903
11904/* static */ bool nsDocShell::ShouldAddURIVisit(nsIChannel* aChannel) {
11905 bool needToAddURIVisit = true;
11906 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
11907 if (props) {
11908 (void)props->GetPropertyAsBool(u"docshell.needToAddURIVisit"_ns,
11909 &needToAddURIVisit);
11910 }
11911
11912 return needToAddURIVisit;
11913}
11914
11915/* static */ void nsDocShell::ExtractLastVisit(
11916 nsIChannel* aChannel, nsIURI** aURI, uint32_t* aChannelRedirectFlags) {
11917 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
11918 if (!props) {
11919 return;
11920 }
11921
11922 nsresult rv;
11923 nsCOMPtr<nsIURI> uri(do_GetProperty(props, u"docshell.previousURI"_ns, &rv));
11924 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
11925 uri.forget(aURI);
11926
11927 rv = props->GetPropertyAsUint32(u"docshell.previousFlags"_ns,
11928 aChannelRedirectFlags);
11929
11930 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Could not fetch previous flags, URI will be treated like referrer"
, "NS_SUCCEEDED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 11932); } } while (false)
11931 NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Could not fetch previous flags, URI will be treated like referrer"
, "NS_SUCCEEDED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 11932); } } while (false)
11932 "Could not fetch previous flags, URI will be treated like referrer")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Could not fetch previous flags, URI will be treated like referrer"
, "NS_SUCCEEDED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 11932); } } while (false)
;
11933
11934 } else {
11935 // There is no last visit for this channel, so this must be the first
11936 // link. Link the visit to the referrer of this request, if any.
11937 // Treat referrer as null if there is an error getting it.
11938 NS_GetReferrerFromChannel(aChannel, aURI);
11939 }
11940}
11941
11942void nsDocShell::SaveLastVisit(nsIChannel* aChannel, nsIURI* aURI,
11943 uint32_t aChannelRedirectFlags) {
11944 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
11945 if (!props || !aURI) {
11946 return;
11947 }
11948
11949 props->SetPropertyAsInterface(u"docshell.previousURI"_ns, aURI);
11950 props->SetPropertyAsUint32(u"docshell.previousFlags"_ns,
11951 aChannelRedirectFlags);
11952}
11953
11954/* static */ void nsDocShell::InternalAddURIVisit(
11955 nsIURI* aURI, nsIURI* aPreviousURI, uint32_t aChannelRedirectFlags,
11956 uint32_t aResponseStatus, BrowsingContext* aBrowsingContext,
11957 nsIWidget* aWidget, uint32_t aLoadType, bool aWasUpgraded, bool aIsPost) {
11958 MOZ_ASSERT(aURI, "Visited URI is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "Visited URI is null!"
")", "./../../../docshell/base/nsDocShell.cpp", 11958); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aURI" ") (" "Visited URI is null!" ")"); do
{ MOZ_CrashSequence(__null, 11958); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
;
11959 MOZ_ASSERT(aLoadType != LOAD_ERROR_PAGE && aLoadType != LOAD_BYPASS_HISTORY,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadType != LOAD_ERROR_PAGE && aLoadType !=
LOAD_BYPASS_HISTORY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadType != LOAD_ERROR_PAGE
&& aLoadType != LOAD_BYPASS_HISTORY))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadType != LOAD_ERROR_PAGE && aLoadType != LOAD_BYPASS_HISTORY"
" (" "Do not add error or bypass pages to global history" ")"
, "./../../../docshell/base/nsDocShell.cpp", 11960); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadType != LOAD_ERROR_PAGE && aLoadType != LOAD_BYPASS_HISTORY"
") (" "Do not add error or bypass pages to global history" ")"
); do { MOZ_CrashSequence(__null, 11960); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
11960 "Do not add error or bypass pages to global history")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadType != LOAD_ERROR_PAGE && aLoadType !=
LOAD_BYPASS_HISTORY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadType != LOAD_ERROR_PAGE
&& aLoadType != LOAD_BYPASS_HISTORY))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLoadType != LOAD_ERROR_PAGE && aLoadType != LOAD_BYPASS_HISTORY"
" (" "Do not add error or bypass pages to global history" ")"
, "./../../../docshell/base/nsDocShell.cpp", 11960); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadType != LOAD_ERROR_PAGE && aLoadType != LOAD_BYPASS_HISTORY"
") (" "Do not add error or bypass pages to global history" ")"
); do { MOZ_CrashSequence(__null, 11960); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11961
11962 bool usePrivateBrowsing = false;
11963 aBrowsingContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
11964
11965 // Only content-type docshells save URI visits. Also don't do
11966 // anything here if we're not supposed to use global history.
11967 if (!aBrowsingContext->IsContent() ||
11968 !aBrowsingContext->GetUseGlobalHistory() || usePrivateBrowsing) {
11969 return;
11970 }
11971
11972 nsCOMPtr<IHistory> history = components::History::Service();
11973
11974 if (history) {
11975 uint32_t visitURIFlags = 0;
11976
11977 if (aBrowsingContext->IsTop()) {
11978 visitURIFlags |= IHistory::TOP_LEVEL;
11979 }
11980
11981 if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
11982 visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
11983 } else if (aChannelRedirectFlags &
11984 nsIChannelEventSink::REDIRECT_PERMANENT) {
11985 visitURIFlags |= IHistory::REDIRECT_PERMANENT;
11986 } else {
11987 MOZ_ASSERT(!aChannelRedirectFlags,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChannelRedirectFlags)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChannelRedirectFlags))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aChannelRedirectFlags"
" (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")", "./../../../docshell/base/nsDocShell.cpp"
, 11989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChannelRedirectFlags"
") (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")"); do { MOZ_CrashSequence
(__null, 11989); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
11988 "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChannelRedirectFlags)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChannelRedirectFlags))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aChannelRedirectFlags"
" (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")", "./../../../docshell/base/nsDocShell.cpp"
, 11989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChannelRedirectFlags"
") (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")"); do { MOZ_CrashSequence
(__null, 11989); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
11989 "if any flags in aChannelRedirectFlags is set.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChannelRedirectFlags)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChannelRedirectFlags))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aChannelRedirectFlags"
" (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")", "./../../../docshell/base/nsDocShell.cpp"
, 11989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChannelRedirectFlags"
") (" "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
"if any flags in aChannelRedirectFlags is set." ")"); do { MOZ_CrashSequence
(__null, 11989); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11990 }
11991
11992 if (aResponseStatus >= 300 && aResponseStatus < 400) {
11993 visitURIFlags |= IHistory::REDIRECT_SOURCE;
11994 if (aResponseStatus == 301 || aResponseStatus == 308) {
11995 visitURIFlags |= IHistory::REDIRECT_SOURCE_PERMANENT;
11996 }
11997 }
11998 // Errors 400-501 and 505 are considered unrecoverable, in the sense a
11999 // simple retry attempt by the user is unlikely to solve them.
12000 // 408 is special cased, since may actually indicate a temporary
12001 // connection problem.
12002 else if (aResponseStatus != 408 &&
12003 ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
12004 aResponseStatus == 505)) {
12005 visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
12006 }
12007
12008 if (aWasUpgraded) {
12009 visitURIFlags |=
12010 IHistory::REDIRECT_SOURCE | IHistory::REDIRECT_SOURCE_UPGRADED;
12011 }
12012
12013 if (aIsPost) {
12014 visitURIFlags |= IHistory::SOURCE_IS_POST_RESPONSE;
12015 }
12016
12017 (void)history->VisitURI(
12018 aWidget, aURI, aPreviousURI, visitURIFlags,
12019 aBrowsingContext->BrowserId(),
12020 aBrowsingContext->OriginAttributesRef().mUserContextId);
12021 }
12022}
12023
12024void nsDocShell::AddURIVisit(nsIURI* aURI, nsIURI* aPreviousURI,
12025 uint32_t aChannelRedirectFlags,
12026 uint32_t aResponseStatus, bool aIsPost) {
12027 nsPIDOMWindowOuter* outer = GetWindow();
12028 nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget(outer);
12029
12030 InternalAddURIVisit(aURI, aPreviousURI, aChannelRedirectFlags,
12031 aResponseStatus, mBrowsingContext, widget, mLoadType,
12032 false, aIsPost);
12033}
12034
12035//*****************************************************************************
12036// nsDocShell: Helper Routines
12037//*****************************************************************************
12038
12039NS_IMETHODIMPnsresult
12040nsDocShell::SetLoadType(uint32_t aLoadType) {
12041 mLoadType = aLoadType;
12042 return NS_OK;
12043}
12044
12045NS_IMETHODIMPnsresult
12046nsDocShell::GetLoadType(uint32_t* aLoadType) {
12047 *aLoadType = mLoadType;
12048 return NS_OK;
12049}
12050
12051nsresult nsDocShell::ConfirmRepost(bool* aRepost) {
12052 if (StaticPrefs::dom_confirm_repost_testing_always_accept()) {
12053 *aRepost = true;
12054 return NS_OK;
12055 }
12056
12057 nsCOMPtr<nsIPromptCollection> prompter =
12058 do_GetService("@mozilla.org/embedcomp/prompt-collection;1");
12059 if (!prompter) {
12060 return NS_ERROR_NOT_AVAILABLE;
12061 }
12062
12063 return prompter->ConfirmRepost(mBrowsingContext, aRepost);
12064}
12065
12066nsresult nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
12067 nsIStringBundle** aStringBundle) {
12068 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt),do { nsresult __rv = GetInterface((nsIPrompt::kIID), (void**)
aPrompt); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv
)), 0)))) { const char* name = mozilla::GetStaticErrorName(__rv
); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInterface((nsIPrompt::kIID), (void**)aPrompt)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12069); return NS_ERROR_FAILURE; } } while (false)
12069 NS_ERROR_FAILURE)do { nsresult __rv = GetInterface((nsIPrompt::kIID), (void**)
aPrompt); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv
)), 0)))) { const char* name = mozilla::GetStaticErrorName(__rv
); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetInterface((nsIPrompt::kIID), (void**)aPrompt)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12069); return NS_ERROR_FAILURE; } } while (false)
;
12070
12071 nsCOMPtr<nsIStringBundleService> stringBundleService =
12072 mozilla::components::StringBundle::Service();
12073 NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(stringBundleService)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "stringBundleService"
") failed", nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12073); return NS_ERROR_FAILURE; } } while (false)
;
12074
12075 NS_ENSURE_SUCCESS(do { nsresult __rv = stringBundleService->CreateBundle(kAppstringsBundleURL
, aStringBundle); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12077); return NS_ERROR_FAILURE; } } while (false)
12076 stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle),do { nsresult __rv = stringBundleService->CreateBundle(kAppstringsBundleURL
, aStringBundle); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12077); return NS_ERROR_FAILURE; } } while (false)
12077 NS_ERROR_FAILURE)do { nsresult __rv = stringBundleService->CreateBundle(kAppstringsBundleURL
, aStringBundle); if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12077); return NS_ERROR_FAILURE; } } while (false)
;
12078
12079 return NS_OK;
12080}
12081
12082ScrollContainerFrame* nsDocShell::GetRootScrollContainerFrame() {
12083 PresShell* presShell = GetPresShell();
12084 NS_ENSURE_TRUE(presShell, nullptr)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12084); return nullptr
; } } while (false)
;
12085
12086 return presShell->GetRootScrollContainerFrame();
12087}
12088
12089nsresult nsDocShell::EnsureScriptEnvironment() {
12090 if (mScriptGlobal) {
12091 return NS_OK;
12092 }
12093
12094 if (mIsBeingDestroyed) {
12095 return NS_ERROR_NOT_AVAILABLE;
12096 }
12097
12098#ifdef DEBUG1
12099 NS_ASSERTION(!mInEnsureScriptEnv,do { if (!(!mInEnsureScriptEnv)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Infinite loop! Calling EnsureScriptEnvironment() from " "within EnsureScriptEnvironment()!"
, "!mInEnsureScriptEnv", "./../../../docshell/base/nsDocShell.cpp"
, 12101); MOZ_PretendNoReturn(); } } while (0)
12100 "Infinite loop! Calling EnsureScriptEnvironment() from "do { if (!(!mInEnsureScriptEnv)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Infinite loop! Calling EnsureScriptEnvironment() from " "within EnsureScriptEnvironment()!"
, "!mInEnsureScriptEnv", "./../../../docshell/base/nsDocShell.cpp"
, 12101); MOZ_PretendNoReturn(); } } while (0)
12101 "within EnsureScriptEnvironment()!")do { if (!(!mInEnsureScriptEnv)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Infinite loop! Calling EnsureScriptEnvironment() from " "within EnsureScriptEnvironment()!"
, "!mInEnsureScriptEnv", "./../../../docshell/base/nsDocShell.cpp"
, 12101); MOZ_PretendNoReturn(); } } while (0)
;
12102
12103 // Yeah, this isn't re-entrant safe, but that's ok since if we
12104 // re-enter this method, we'll infinitely loop...
12105 AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
12106 mInEnsureScriptEnv = true;
12107#endif
12108
12109 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
12110 NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(browserChrome)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "browserChrome" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 12110);
return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
12111
12112 uint32_t chromeFlags;
12113 browserChrome->GetChromeFlags(&chromeFlags);
12114
12115 // If our window is modal and we're not opened as chrome, make
12116 // this window a modal content window.
12117 mScriptGlobal = nsGlobalWindowOuter::Create(this, mItemType == typeChrome);
12118 MOZ_ASSERT(mScriptGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mScriptGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mScriptGlobal))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mScriptGlobal",
"./../../../docshell/base/nsDocShell.cpp", 12118); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mScriptGlobal" ")"); do { MOZ_CrashSequence
(__null, 12118); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
12119
12120 // Ensure the script object is set up to run script.
12121 return mScriptGlobal->EnsureScriptEnvironment();
12122}
12123
12124nsresult nsDocShell::EnsureEditorData() {
12125 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 12125); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 12125); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
12126
12127 bool openDocHasDetachedEditor = false;
12128 if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
12129 // We shouldn't recreate the editor data if it already exists, or
12130 // we're shutting down, or we already have a detached editor data
12131 // stored in the session history. We should only have one editordata
12132 // per docshell.
12133 mEditorData = std::make_unique<nsDocShellEditorData>(this);
12134 }
12135
12136 return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
12137}
12138
12139nsresult nsDocShell::EnsureFind() {
12140 if (!mFind) {
12141 mFind = MakeRefPtr<nsWebBrowserFind>();
12142 }
12143
12144 // we promise that the nsIWebBrowserFind that we return has been set
12145 // up to point to the focused, or content window, so we have to
12146 // set that up each time.
12147
12148 nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
12149 NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(scriptGO)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "scriptGO" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12149); return NS_ERROR_UNEXPECTED
; } } while (false)
;
12150
12151 // default to our window
12152 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO);
12153 nsCOMPtr<nsPIDOMWindowOuter> windowToSearch;
12154 nsFocusManager::GetFocusedDescendant(ourWindow,
12155 nsFocusManager::eIncludeAllDescendants,
12156 getter_AddRefs(windowToSearch));
12157
12158 nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
12159 if (!findInFrames) {
12160 return NS_ERROR_NO_INTERFACE;
12161 }
12162
12163 nsresult rv = findInFrames->SetRootSearchFrame(ourWindow);
12164 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
12165 return rv;
12166 }
12167 rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
12168 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
12169 return rv;
12170 }
12171
12172 return NS_OK;
12173}
12174
12175NS_IMETHODIMPnsresult
12176nsDocShell::IsBeingDestroyed(bool* aDoomed) {
12177 NS_ENSURE_ARG(aDoomed)do { if ((__builtin_expect(!!(!(aDoomed)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDoomed" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12177); return NS_ERROR_INVALID_ARG
; } } while (false)
;
12178 *aDoomed = mIsBeingDestroyed;
12179 return NS_OK;
12180}
12181
12182NS_IMETHODIMPnsresult
12183nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult) {
12184 NS_ENSURE_ARG(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12184); return NS_ERROR_INVALID_ARG
; } } while (false)
;
12185 *aResult = mIsExecutingOnLoadHandler;
12186 return NS_OK;
12187}
12188
12189NS_IMETHODIMPnsresult
12190nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState) {
12191 nsCOMPtr<nsILayoutHistoryState> state;
12192 if (mActiveEntry) {
12193 state = mActiveEntry->GetLayoutHistoryState();
12194 }
12195 state.forget(aLayoutHistoryState);
12196 return NS_OK;
12197}
12198
12199NS_IMETHODIMPnsresult
12200nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState) {
12201 if (mActiveEntry) {
12202 mActiveEntry->SetLayoutHistoryState(aLayoutHistoryState);
12203 }
12204 return NS_OK;
12205}
12206
12207nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
12208 nsIInterfaceRequestor* aRequestor) {
12209 if (aRequestor) {
12210 mWeakPtr = do_GetWeakReference(aRequestor);
12211 }
12212}
12213
12214nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy() {
12215 mWeakPtr = nullptr;
12216}
12217
12218NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)MozExternalRefCountType nsDocShell::InterfaceRequestorProxy::
AddRef(void) { static_assert(!std::is_destructible_v<nsDocShell
::InterfaceRequestorProxy>, "Reference-counted class " "nsDocShell::InterfaceRequestorProxy"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../docshell/base/nsDocShell.cpp"
, 12218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 12218
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsDocShell::InterfaceRequestorProxy" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsDocShell::InterfaceRequestorProxy" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsDocShell::InterfaceRequestorProxy\" != nullptr"
" (" "Must specify a name" ")", "./../../../docshell/base/nsDocShell.cpp"
, 12218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsDocShell::InterfaceRequestorProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 12218); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsDocShell::InterfaceRequestorProxy" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"nsDocShell::InterfaceRequestorProxy"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType nsDocShell::InterfaceRequestorProxy
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../docshell/base/nsDocShell.cpp"
, 12218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 12218
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsDocShell::InterfaceRequestorProxy" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsDocShell::InterfaceRequestorProxy" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsDocShell::InterfaceRequestorProxy\" != nullptr"
" (" "Must specify a name" ")", "./../../../docshell/base/nsDocShell.cpp"
, 12218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsDocShell::InterfaceRequestorProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 12218); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsDocShell::InterfaceRequestorProxy" " not thread-safe"
); const char* const nametmp = "nsDocShell::InterfaceRequestorProxy"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult nsDocShell::InterfaceRequestorProxy
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../docshell/base/nsDocShell.cpp", 12218); MOZ_PretendNoReturn
(); } } while (0); nsresult rv = NS_ERROR_FAILURE; static_assert
(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"); static
const QITableEntry table[] = { {&mozilla::detail::kImplementedIID
<nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsDocShell::InterfaceRequestorProxy*)0x1000)) - reinterpret_cast
<char*>((nsDocShell::InterfaceRequestorProxy*)0x1000))}
, {&mozilla::detail::kImplementedIID<nsDocShell::InterfaceRequestorProxy
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIInterfaceRequestor*>
((nsDocShell::InterfaceRequestorProxy*)0x1000))) - reinterpret_cast
<char*>((nsDocShell::InterfaceRequestorProxy*)0x1000))}
, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
12219
12220NS_IMETHODIMPnsresult
12221nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID,
12222 void** aSink) {
12223 NS_ENSURE_ARG_POINTER(aSink)do { if ((__builtin_expect(!!(!(aSink)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aSink" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12223); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
12224 nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
12225 if (ifReq) {
12226 return ifReq->GetInterface(aIID, aSink);
12227 }
12228 *aSink = nullptr;
12229 return NS_NOINTERFACE;
12230}
12231
12232//*****************************************************************************
12233// nsDocShell::nsIAuthPromptProvider
12234//*****************************************************************************
12235
12236NS_IMETHODIMPnsresult
12237nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID,
12238 void** aResult) {
12239 // a priority prompt request will override a false mAllowAuth setting
12240 bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
12241
12242 if (!mAllowAuth && !priorityPrompt) {
12243 return NS_ERROR_NOT_AVAILABLE;
12244 }
12245
12246 // we're either allowing auth, or it's a proxy request
12247 nsresult rv;
12248 nsCOMPtr<nsIPromptFactory> wwatch =
12249 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
12250 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12250); return rv; } } while (false)
;
12251
12252 rv = EnsureScriptEnvironment();
12253 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12253); return rv; } } while (false)
;
12254
12255 // Get the an auth prompter for our window so that the parenting
12256 // of the dialogs works as it should when using tabs.
12257
12258 return wwatch->GetPrompt(mScriptGlobal, aIID,
12259 reinterpret_cast<void**>(aResult));
12260}
12261
12262//*****************************************************************************
12263// nsDocShell::nsILoadContext
12264//*****************************************************************************
12265
12266NS_IMETHODIMPnsresult
12267nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow) {
12268 CallGetInterface(this, aWindow);
12269 return NS_OK;
12270}
12271
12272NS_IMETHODIMPnsresult
12273nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow) {
12274 return mBrowsingContext->GetTopWindow(aWindow);
12275}
12276
12277NS_IMETHODIMPnsresult
12278nsDocShell::GetTopFrameElement(Element** aElement) {
12279 return mBrowsingContext->GetTopFrameElement(aElement);
12280}
12281
12282NS_IMETHODIMPnsresult
12283nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection) {
12284 return mBrowsingContext->GetUseTrackingProtection(aUseTrackingProtection);
12285}
12286
12287NS_IMETHODIMPnsresult
12288nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection) {
12289 return mBrowsingContext->SetUseTrackingProtection(aUseTrackingProtection);
12290}
12291
12292NS_IMETHODIMPnsresult
12293nsDocShell::GetIsContent(bool* aIsContent) {
12294 *aIsContent = (mItemType == typeContent);
12295 return NS_OK;
12296}
12297
12298bool nsDocShell::IsOKToLoadURI(nsIURI* aURI) {
12299 MOZ_ASSERT(aURI, "Must have a URI!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "Must have a URI!" ")"
, "./../../../docshell/base/nsDocShell.cpp", 12299); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aURI" ") (" "Must have a URI!" ")"); do { MOZ_CrashSequence
(__null, 12299); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
12300
12301 if (!mFiredUnloadEvent) {
12302 return true;
12303 }
12304
12305 if (!mLoadingURI) {
12306 return false;
12307 }
12308
12309 bool isPrivateWin = false;
12310 Document* doc = GetDocument();
12311 if (doc) {
12312 isPrivateWin =
12313 doc->NodePrincipal()->OriginAttributesRef().IsPrivateBrowsing();
12314 }
12315
12316 nsCOMPtr<nsIScriptSecurityManager> secMan =
12317 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID"@mozilla.org/scriptsecuritymanager;1");
12318 return secMan && NS_SUCCEEDED(secMan->CheckSameOriginURI(((bool)(__builtin_expect(!!(!NS_FAILED_impl(secMan->CheckSameOriginURI
( aURI, mLoadingURI, false, isPrivateWin))), 1)))
12319 aURI, mLoadingURI, false, isPrivateWin))((bool)(__builtin_expect(!!(!NS_FAILED_impl(secMan->CheckSameOriginURI
( aURI, mLoadingURI, false, isPrivateWin))), 1)))
;
12320}
12321
12322//
12323// Routines for selection and clipboard
12324//
12325nsresult nsDocShell::GetControllerForCommand(const char* aCommand,
12326 nsIController** aResult) {
12327 NS_ENSURE_ARG_POINTER(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12327); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
12328 *aResult = nullptr;
12329
12330 NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mScriptGlobal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mScriptGlobal" ") failed"
, nullptr, "./../../../docshell/base/nsDocShell.cpp", 12330);
return NS_ERROR_FAILURE; } } while (false)
;
12331
12332 nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
12333 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12333); return NS_ERROR_FAILURE
; } } while (false)
;
12334
12335 return root->GetControllerForCommand(aCommand, false /* for any window */,
12336 aResult);
12337}
12338
12339NS_IMETHODIMPnsresult
12340nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult) {
12341 NS_ENSURE_ARG_POINTER(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../docshell/base/nsDocShell.cpp", 12341); return NS_ERROR_INVALID_POINTER
; } } while (false)
;
12342 *aResult = false;
12343
12344 nsresult rv = NS_ERROR_FAILURE;
12345
12346 nsCOMPtr<nsIController> controller;
12347 rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12348 if (controller) {
12349 rv = controller->IsCommandEnabled(aCommand, aResult);
12350 }
12351
12352 return rv;
12353}
12354
12355NS_IMETHODIMPnsresult
12356nsDocShell::DoCommand(const char* aCommand) {
12357 nsresult rv = NS_ERROR_FAILURE;
12358
12359 nsCOMPtr<nsIController> controller;
12360 rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12361 if (controller) {
12362 rv = controller->DoCommand(aCommand);
12363 }
12364
12365 return rv;
12366}
12367
12368NS_IMETHODIMPnsresult
12369nsDocShell::DoCommandWithParams(const char* aCommand,
12370 nsICommandParams* aParams) {
12371 nsCOMPtr<nsIController> controller;
12372 nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12373 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 12373)
) {
12374 return rv;
12375 }
12376
12377 nsCOMPtr<nsICommandController> commandController =
12378 do_QueryInterface(controller, &rv);
12379 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../docshell/base/nsDocShell.cpp"
, 12379)
) {
12380 return rv;
12381 }
12382
12383 return commandController->DoCommandWithParams(aCommand, aParams);
12384}
12385
12386nsresult nsDocShell::EnsureCommandHandler() {
12387 if (!mCommandManager) {
12388 if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow()) {
12389 mCommandManager = MakeRefPtr<nsCommandManager>(domWindow);
12390 }
12391 }
12392 return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
12393}
12394
12395// link handling
12396
12397class OnLinkClickEvent : public CancelableRunnable, public SupportsWeakPtr {
12398 public:
12399 OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
12400 nsDocShellLoadState* aLoadState, bool aNoOpenerImplied,
12401 nsIPrincipal* aTriggeringPrincipal);
12402
12403 NS_IMETHODvirtual nsresult Run() override {
12404 if (mCancelled) {
12405 return NS_OK;
12406 }
12407
12408 // We need to set up an AutoJSAPI here for the following reason: When we
12409 // do OnLinkClickSync we'll eventually end up in
12410 // nsGlobalWindow::OpenInternal which only does popup blocking if
12411 // !LegacyIsCallerChromeOrNativeCode(). So we need to fake things so that
12412 // we don't look like native code as far as LegacyIsCallerNativeCode() is
12413 // concerned. (Bug 1930445)
12414 AutoJSAPI jsapi;
12415 if (jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
12416 // For form submissions, the source element is set to the submitter,
12417 // and we don't want to overwrite it with the <form> element here.
12418 if (!mLoadState->HasSourceElement()) {
12419 mLoadState->SetSourceElement(mContent->AsElement());
12420 }
12421 mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied,
12422 mTriggeringPrincipal);
12423 }
12424 return NS_OK;
12425 }
12426
12427 nsresult Cancel() override final {
12428 mCancelled = true;
12429 // Don't clear mLoadState, etc. here since this can be called
12430 // from the OnLinkClickSync() above, and we might be holding
12431 // the last references to them.
12432 return NS_OK;
12433 }
12434
12435 private:
12436 RefPtr<nsDocShell> mHandler;
12437 nsCOMPtr<nsIContent> mContent;
12438 RefPtr<nsDocShellLoadState> mLoadState;
12439 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
12440 bool mNoOpenerImplied;
12441 bool mCancelled = false;
12442};
12443
12444OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
12445 nsDocShellLoadState* aLoadState,
12446 bool aNoOpenerImplied,
12447 nsIPrincipal* aTriggeringPrincipal)
12448 : mozilla::CancelableRunnable("OnLinkClickEvent"),
12449 mHandler(aHandler),
12450 mContent(aContent),
12451 mLoadState(aLoadState),
12452 mTriggeringPrincipal(aTriggeringPrincipal),
12453 mNoOpenerImplied(aNoOpenerImplied) {}
12454
12455nsresult nsDocShell::OnFormSubmit(HTMLFormElement* aForm,
12456 nsDocShellLoadState* aLoadState) {
12457 // Need to do this here, since it's ordinarily done in OnLinkClick.
12458 if (ShouldBlockLoadingForBackButton()) {
12459 return NS_OK;
12460 }
12461 if (!StaticPrefs::dom_forms_submit_async_navigation()) {
12462 return OnLinkClickSync(aForm, aLoadState, false, aForm->NodePrincipal());
12463 }
12464
12465 // Determine BC to target synchronously, for consistency with other browsers
12466 ComputeNamedTargetBrowsingContext(aLoadState);
12467
12468 // https://html.spec.whatwg.org/#form-submission-algorithm
12469 // 25. If form document equals targetNavigable's active document, and form
12470 // document has not yet completely loaded, then set historyHandling to
12471 // "replace".
12472 const MaybeDiscarded<BrowsingContext>& targetBC =
12473 aLoadState->TargetBrowsingContext();
12474 Document* formDocument = aForm->OwnerDoc();
12475 if ((targetBC.IsNull() || targetBC == formDocument->GetBrowsingContext()) &&
12476 !formDocument->IsCompletelyLoaded()) {
12477 aLoadState->SetHistoryBehavior(NavigationHistoryBehavior::Replace);
12478 }
12479
12480 RefPtr ev = MakeRefPtr<OnLinkClickEvent>(this, aForm, aLoadState, false,
12481 aForm->NodePrincipal());
12482 RefPtr<nsIRunnable> runnable = ev;
12483 nsresult rv = Dispatch(runnable.forget());
12484 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12484); return rv; } } while (false)
;
12485
12486 nsDocShell* targetDocShell = this;
12487 if (!aLoadState->Target().IsEmpty()) {
12488 targetDocShell =
12489 targetBC.IsNullOrDiscarded()
12490 ? nullptr
12491 : static_cast<nsDocShell*>(targetBC.get()->GetDocShell());
12492 }
12493 if (targetDocShell) {
12494 targetDocShell->CancelPlannedFormNavigation();
12495 // Chrome stops pending javascript: navigations here.
12496 // https://github.com/whatwg/html/issues/12607
12497 targetDocShell->StopPendingJavascriptURLNavigations();
12498 targetDocShell->mPlannedFormNavigation = ev.get();
12499 }
12500 return NS_OK;
12501}
12502
12503nsresult nsDocShell::CancelPlannedFormNavigation() {
12504 if (mPlannedFormNavigation) {
12505 mPlannedFormNavigation->Cancel();
12506 mPlannedFormNavigation = nullptr;
12507 }
12508 return NS_OK;
12509}
12510
12511nsresult nsDocShell::OnLinkClick(
12512 nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
12513 const nsAString& aFileName, nsIInputStream* aPostDataStream,
12514 nsIInputStream* aHeadersDataStream, bool aIsUserTriggered,
12515 UserNavigationInvolvement aUserInvolvement,
12516 nsIPrincipal* aTriggeringPrincipal, nsIPolicyContainer* aPolicyContainer) {
12517#ifndef ANDROID
12518 MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTriggeringPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTriggeringPrincipal))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aTriggeringPrincipal"
" (" "Need a valid triggeringPrincipal" ")", "./../../../docshell/base/nsDocShell.cpp"
, 12518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTriggeringPrincipal"
") (" "Need a valid triggeringPrincipal" ")"); do { MOZ_CrashSequence
(__null, 12518); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
12519#endif
12520 NS_ASSERTION(NS_IsMainThread(), "wrong thread")do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "wrong thread", "NS_IsMainThread()", "./../../../docshell/base/nsDocShell.cpp"
, 12520); MOZ_PretendNoReturn(); } } while (0)
;
12521
12522 if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
12523 return NS_OK;
12524 }
12525
12526 // On history navigation through Back/Forward buttons, don't execute
12527 // automatic JavaScript redirection such as |anchorElement.click()| or
12528 // |formElement.submit()|.
12529 //
12530 // XXX |formElement.submit()| bypasses this checkpoint because it calls
12531 // nsDocShell::OnLinkClickSync(...) instead.
12532 if (ShouldBlockLoadingForBackButton()) {
12533 return NS_OK;
12534 }
12535
12536 if (aContent->IsEditable()) {
12537 return NS_OK;
12538 }
12539
12540 RefPtr<Document> ownerDoc = aContent->OwnerDoc();
12541 if (nsContentUtils::IsExternalProtocol(aURI)) {
12542 ownerDoc->EnsureNotEnteringAndExitFullscreen();
12543 }
12544
12545 bool noOpenerImplied = false;
12546 nsAutoString target(aTargetSpec);
12547 if (aFileName.IsVoid() &&
12548 ShouldOpenInBlankTarget(aTargetSpec, aURI, aContent, aIsUserTriggered)) {
12549 target = u"_blank";
12550 if (!aTargetSpec.Equals(target)) {
12551 noOpenerImplied = true;
12552 }
12553 }
12554
12555 // https://html.spec.whatwg.org/#downloading-hyperlinks
12556 // Step 6, step 6.1, step 6.2
12557 // aFileName not being void implies a download attribute, since we've already
12558 // checked if the attribute is present in `nsContentUtils::TriggerLinkClick`
12559 // and made it void otherwise.
12560 if (!aFileName.IsVoid() &&
12561 aUserInvolvement != UserNavigationInvolvement::BrowserUI) {
12562 if (nsCOMPtr<nsPIDOMWindowInner> window = ownerDoc->GetInnerWindow()) {
12563 if (RefPtr<Navigation> navigation = window->Navigation()) {
12564 AutoJSAPI jsapi;
12565 if (jsapi.Init(window)) {
12566 RefPtr element = aContent->AsElement();
12567 // Step 6.4
12568 bool shouldContinue = navigation->FireDownloadRequestNavigateEvent(
12569 jsapi.cx(), aURI, aUserInvolvement, element, aFileName);
12570
12571 // Step 6.5
12572 if (!shouldContinue) {
12573 return NS_OK;
12574 }
12575 }
12576 }
12577 }
12578 }
12579
12580 RefPtr loadState = MakeRefPtr<nsDocShellLoadState>(aURI);
12581 loadState->SetTarget(target);
12582 loadState->SetFileName(aFileName);
12583 loadState->SetPostDataStream(aPostDataStream);
12584 loadState->SetHeadersStream(aHeadersDataStream);
12585 loadState->SetFirstParty(true);
12586 loadState->SetTriggeringPrincipal(
12587 aTriggeringPrincipal ? aTriggeringPrincipal : aContent->NodePrincipal());
12588 loadState->SetPrincipalToInherit(aContent->NodePrincipal());
12589 loadState->SetPolicyContainer(
12590 aPolicyContainer ? aPolicyContainer : aContent->GetPolicyContainer());
12591 loadState->SetAllowFocusMove(UserActivation::IsHandlingUserInput());
12592
12593 const bool hasValidUserGestureActivation =
12594 ownerDoc->HasValidTransientUserGestureActivation();
12595 loadState->SetHasValidUserGestureActivation(hasValidUserGestureActivation);
12596
12597 // For protocols that would launch without a prompt (e.g. mailto), consume the
12598 // transient user gesture activation so a single gesture can't chain multiple
12599 // launches. Do this here, at the same point the activation value is captured
12600 // on the load state, rather than later in OnLinkClickSync: that runs
12601 // asynchronously, and consuming there would be inconsistent with the scripted
12602 // navigation path (see BrowsingContext::Navigate). The pre-consume value is
12603 // already recorded on the load state above. See bug 299116.
12604 if (nsAutoCString scheme; NS_SUCCEEDED(aURI->GetScheme(scheme))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aURI->GetScheme
(scheme))), 1)))
) {
12605 nsExternalHelperAppService::MaybeConsumeUserActivationForExternalScheme(
12606 ownerDoc->GetWindowContext(), loadState->TriggeringPrincipal(), scheme);
12607 }
12608
12609 loadState->SetTextDirectiveUserActivation(
12610 ownerDoc->ConsumeTextDirectiveUserActivation() ||
12611 hasValidUserGestureActivation);
12612 loadState->SetUserNavigationInvolvement(aUserInvolvement);
12613 loadState->SetTriggeringClassificationFlags(
12614 ownerDoc->GetScriptTrackingFlags());
12615 loadState->SetHistoryBehavior(NavigationHistoryBehavior::Auto);
12616
12617 ComputeNamedTargetBrowsingContext(loadState);
12618
12619 RefPtr ev = MakeRefPtr<OnLinkClickEvent>(
12620 this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal);
12621
12622 // https://html.spec.whatwg.org/#navigate step 8 only queues a task when the
12623 // navigation crosses agents.
12624 if (StaticPrefs::dom_links_sync_fragment_navigation()) {
12625 SameDocumentNavigationState state;
12626 if ((loadState->Target().IsEmpty() ||
12627 loadState->TargetBrowsingContext() == GetBrowsingContext()) &&
12628 IsSameDocumentNavigation(loadState, state)) {
12629 ev->Run();
12630 return NS_OK;
12631 }
12632 }
12633
12634 RefPtr<nsIRunnable> runnable = ev;
12635 return Dispatch(runnable.forget());
12636}
12637
12638bool nsDocShell::ShouldOpenInBlankTarget(const nsAString& aOriginalTarget,
12639 nsIURI* aLinkURI, nsIContent* aContent,
12640 bool aIsUserTriggered) {
12641 if (aLinkURI->SchemeIs("javascript")) {
12642 return false;
12643 }
12644
12645 // External links from within app tabs should always open in new tabs
12646 // instead of replacing the app tab's page (Bug 575561)
12647 // nsIURI.host can throw for non-nsStandardURL nsIURIs. If we fail to
12648 // get either host, just return false to use the original target.
12649 nsAutoCString linkHost;
12650 if (NS_FAILED(aLinkURI->GetHost(linkHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(aLinkURI->GetHost
(linkHost))), 0)))
) {
12651 return false;
12652 }
12653
12654 // The targetTopLevelLinkClicksToBlank property on BrowsingContext allows
12655 // privileged code to change the default targeting behaviour. In particular,
12656 // if a user-initiated link click for the (or targetting the) top-level frame
12657 // is detected, we default the target to "_blank" to give it a new
12658 // top-level BrowsingContext.
12659 if (mBrowsingContext->TargetTopLevelLinkClicksToBlank() && aIsUserTriggered &&
12660 ((aOriginalTarget.IsEmpty() && mBrowsingContext->IsTop()) ||
12661 aOriginalTarget == u"_top"_ns)) {
12662 return true;
12663 }
12664
12665 // Don't modify non-default targets.
12666 if (!aOriginalTarget.IsEmpty()) {
12667 return false;
12668 }
12669
12670 // Only check targets that are in extension panels or app tabs.
12671 // (isAppTab will be false for app tab subframes).
12672 nsString mmGroup = mBrowsingContext->Top()->GetMessageManagerGroup();
12673 if (!mmGroup.EqualsLiteral("webext-browsers") &&
12674 !mBrowsingContext->IsAppTab()) {
12675 return false;
12676 }
12677
12678 nsCOMPtr<nsIURI> docURI = aContent->OwnerDoc()->GetDocumentURIObject();
12679 if (!docURI) {
12680 return false;
12681 }
12682
12683 nsAutoCString docHost;
12684 if (NS_FAILED(docURI->GetHost(docHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(docURI->GetHost
(docHost))), 0)))
) {
12685 return false;
12686 }
12687
12688 if (linkHost.Equals(docHost)) {
12689 return false;
12690 }
12691
12692 // Special case: ignore "www" prefix if it is part of host string
12693 return linkHost.Length() < docHost.Length()
12694 ? !docHost.Equals("www."_ns + linkHost)
12695 : !linkHost.Equals("www."_ns + docHost);
12696}
12697
12698static bool ElementCanHaveNoopener(nsIContent* aContent) {
12699 return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area,
12700 nsGkAtoms::form) ||
12701 aContent->IsSVGElement(nsGkAtoms::a) ||
12702 (aContent->IsMathMLElement(nsGkAtoms::a) &&
12703 StaticPrefs::mathml_a_element_enabled());
12704}
12705
12706nsresult nsDocShell::OnLinkClickSync(nsIContent* aContent,
12707 nsDocShellLoadState* aLoadState,
12708 bool aNoOpenerImplied,
12709 nsIPrincipal* aTriggeringPrincipal) {
12710 if (!IsNavigationAllowed() || !IsOKToLoadURI(aLoadState->URI())) {
12711 return NS_OK;
12712 }
12713
12714 if (aContent->IsEditable()) {
12715 return NS_OK;
12716 }
12717
12718 // if the triggeringPrincipal is not passed explicitly, then we
12719 // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
12720 nsCOMPtr<nsIPrincipal> triggeringPrincipal =
12721 aTriggeringPrincipal ? aTriggeringPrincipal : aContent->NodePrincipal();
12722
12723 {
12724 // defer to an external protocol handler if necessary...
12725 nsCOMPtr<nsIExternalProtocolService> extProtService =
12726 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID"@mozilla.org/uriloader/external-protocol-service;1");
12727 if (extProtService) {
12728 nsAutoCString scheme;
12729 aLoadState->URI()->GetScheme(scheme);
12730 if (!scheme.IsEmpty()) {
12731 // if the URL scheme does not correspond to an exposed protocol, then
12732 // we need to hand this link click over to the external protocol
12733 // handler.
12734 bool isExposed;
12735 nsresult rv =
12736 extProtService->IsExposedProtocol(scheme.get(), &isExposed);
12737 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !isExposed) {
12738 // Use the activation captured on the load state at click/submit time
12739 // (OnLinkClick, HTMLFormElement::SubmitSubmission), rather than
12740 // re-reading from the document here: this runs asynchronously, by
12741 // which point the transient activation may have expired. Consumption
12742 // of the activation (for gated schemes like mailto) also happens at
12743 // that capture point. See bug 299116.
12744 bool hasValidUserGestureActivation =
12745 aLoadState->HasValidUserGestureActivation();
12746 return extProtService->LoadURI(aLoadState->URI(), triggeringPrincipal,
12747 nullptr, mBrowsingContext,
12748 /* aTriggeredExternally */
12749 false, hasValidUserGestureActivation,
12750 /* aNewWindowTarget */ false);
12751 }
12752 }
12753 }
12754 }
12755 uint32_t triggeringSandboxFlags = 0;
12756 uint64_t triggeringWindowId = 0;
12757 if (mBrowsingContext) {
12758 triggeringSandboxFlags = aContent->OwnerDoc()->GetSandboxFlags();
12759 triggeringWindowId = aContent->OwnerDoc()->InnerWindowID();
12760 }
12761
12762 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
12763 bool elementCanHaveNoopener = ElementCanHaveNoopener(aContent);
12764 bool triggeringPrincipalIsSystemPrincipal =
12765 aLoadState->TriggeringPrincipal()->IsSystemPrincipal();
12766 if (elementCanHaveNoopener) {
12767 nsAutoString relString;
12768 aContent->AsElement()->GetAttr(nsGkAtoms::rel, relString);
12769 nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
12770 relString);
12771
12772 bool targetBlank = aLoadState->Target().LowerCaseEqualsLiteral("_blank");
12773 bool explicitOpenerSet = false;
12774
12775 // The opener behaviour follows a hierarchy, such that if a higher
12776 // priority behaviour is specified, it always takes priority. That
12777 // priority is currently: norefrerer > noopener > opener > default
12778
12779 while (tok.hasMoreTokens()) {
12780 const nsAString& token = tok.nextToken();
12781 if (token.LowerCaseEqualsLiteral("noreferrer")) {
12782 flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
12783 INTERNAL_LOAD_FLAGS_NO_OPENER;
12784 // noreferrer cannot be overwritten by a 'rel=opener'.
12785 explicitOpenerSet = true;
12786 break;
12787 }
12788
12789 if (token.LowerCaseEqualsLiteral("noopener")) {
12790 flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
12791 explicitOpenerSet = true;
12792 }
12793
12794 if (targetBlank && StaticPrefs::dom_targetBlankNoOpener_enabled() &&
12795 token.LowerCaseEqualsLiteral("opener") && !explicitOpenerSet) {
12796 explicitOpenerSet = true;
12797 }
12798 }
12799
12800 if (targetBlank && StaticPrefs::dom_targetBlankNoOpener_enabled() &&
12801 !explicitOpenerSet && !triggeringPrincipalIsSystemPrincipal) {
12802 flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
12803 }
12804
12805 if (aNoOpenerImplied) {
12806 flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
12807 }
12808 }
12809
12810 // Get the owner document of the link that was clicked, this will be
12811 // the document that the link is in, or the last document that the
12812 // link was in. From that document, we'll get the URI to use as the
12813 // referrer, since the current URI in this docshell may be a
12814 // new document that we're in the process of loading.
12815 RefPtr<Document> referrerDoc = aContent->OwnerDoc();
12816
12817 // Now check that the referrerDoc's inner window is the current inner
12818 // window for mScriptGlobal. If it's not, then we don't want to
12819 // follow this link.
12820 nsPIDOMWindowInner* referrerInner = referrerDoc->GetInnerWindow();
12821 if (!mScriptGlobal || !referrerInner ||
12822 mScriptGlobal->GetCurrentInnerWindow() != referrerInner) {
12823 // We're no longer the current inner window
12824 return NS_OK;
12825 }
12826
12827 // referrer could be null here in some odd cases, but that's ok,
12828 // we'll just load the link w/o sending a referrer in those cases.
12829
12830 uint32_t loadType = LOAD_LINK;
12831 if (aLoadState->IsFormSubmission()) {
12832 if (aLoadState->Target().IsEmpty()) {
12833 // We set the right load type here for form submissions with an empty
12834 // target. Form submission with a non-empty target are handled in
12835 // nsDocShell::PerformRetargeting after we've selected the correct target
12836 // BC.
12837 loadType = GetLoadTypeForFormSubmission(GetBrowsingContext(), aLoadState);
12838 }
12839 }
12840
12841 RefPtr referrerInfo = elementCanHaveNoopener
12842 ? MakeRefPtr<ReferrerInfo>(*aContent->AsElement())
12843 : MakeRefPtr<ReferrerInfo>(*referrerDoc);
12844
12845 aLoadState->SetTriggeringSandboxFlags(triggeringSandboxFlags);
12846 aLoadState->SetTriggeringWindowId(triggeringWindowId);
12847 aLoadState->SetReferrerInfo(referrerInfo);
12848 aLoadState->SetInternalLoadFlags(flags);
12849 aLoadState->SetLoadType(loadType);
12850 aLoadState->SetSourceBrowsingContext(mBrowsingContext);
12851
12852 nsresult rv = InternalLoad(aLoadState);
12853
12854 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
12855 nsPingListener::DispatchPings(this, aContent, aLoadState->URI(),
12856 referrerInfo);
12857 }
12858
12859 return rv;
12860}
12861
12862nsresult nsDocShell::OnOverLink(nsIContent* aContent, nsIURI* aURI) {
12863 if (aContent->IsEditable()) {
12864 return NS_OK;
12865 }
12866
12867 nsresult rv = NS_ERROR_FAILURE;
12868
12869 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(mTreeOwner);
12870 if (!browserChrome) {
12871 return rv;
12872 }
12873
12874 nsCOMPtr<nsIURI> exposableURI = nsIOService::CreateExposableURI(aURI);
12875 nsAutoCString spec;
12876 rv = exposableURI->GetDisplaySpec(spec);
12877 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12877); return rv; } } while (false)
;
12878
12879 NS_ConvertUTF8toUTF16 uStr(spec);
12880
12881 // The speculative connect used to go through the predictor, but we don't
12882 // need all that just to initiate a speculative connect.
12883 if ((StaticPrefs::network_predictor_enable_hover_on_ssl() &&
12884 mCurrentURI->SchemeIs("https")) ||
12885 mCurrentURI->SchemeIs("http")) {
12886 if (nsCOMPtr<nsISpeculativeConnect> specService =
12887 mozilla::components::IO::Service()) {
12888 // This would be a navigation, so if this is cross origin the speculative
12889 // connection needs to have the origin of the URL not the current page.
12890 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
12891 aURI, aContent->NodePrincipal()->OriginAttributesRef());
12892
12893 specService->SpeculativeConnect(aURI, principal, this, false);
12894 }
12895 }
12896
12897 rv = browserChrome->SetLinkStatus(uStr);
12898 return rv;
12899}
12900
12901nsresult nsDocShell::OnLeaveLink() {
12902 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
12903 nsresult rv = NS_ERROR_FAILURE;
12904
12905 if (browserChrome) {
12906 rv = browserChrome->SetLinkStatus(u""_ns);
12907 }
12908 return rv;
12909}
12910
12911bool nsDocShell::ShouldBlockLoadingForBackButton() {
12912 if (!(mLoadType & LOAD_CMD_HISTORY) ||
12913 UserActivation::IsHandlingUserInput() ||
12914 !Preferences::GetBool("accessibility.blockjsredirection")) {
12915 return false;
12916 }
12917
12918 bool canGoForward = false;
12919 GetCanGoForward(&canGoForward);
12920 return canGoForward;
12921}
12922
12923//----------------------------------------------------------------------
12924// Web Shell Services API
12925
12926// This functions is only called when a new charset is detected in loading a
12927// document.
12928nsresult nsDocShell::CharsetChangeReloadDocument(
12929 mozilla::NotNull<const mozilla::Encoding*> aEncoding, int32_t aSource) {
12930 // XXX hack. keep the aCharset and aSource wait to pick it up
12931 nsCOMPtr<nsIDocumentViewer> viewer;
12932 NS_ENSURE_SUCCESS(GetDocViewer(getter_AddRefs(viewer)), NS_ERROR_FAILURE)do { nsresult __rv = GetDocViewer(getter_AddRefs(viewer)); if
(((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv)), 0)))) { const
char* name = mozilla::GetStaticErrorName(__rv); mozilla::SmprintfPointer
msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "GetDocViewer(getter_AddRefs(viewer))"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../docshell/base/nsDocShell.cpp"
, 12932); return NS_ERROR_FAILURE; } } while (false)
;
12933 if (viewer) {
12934 int32_t source;
12935 (void)viewer->GetReloadEncodingAndSource(&source);
12936 if (aSource > source) {
12937 viewer->SetReloadEncodingAndSource(aEncoding, aSource);
12938 if (eCharsetReloadRequested != mCharsetReloadState) {
12939 mCharsetReloadState = eCharsetReloadRequested;
12940 switch (mLoadType) {
12941 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
12942 return Reload(LOAD_FLAGS_CHARSET_CHANGE | LOAD_FLAGS_BYPASS_CACHE |
12943 LOAD_FLAGS_BYPASS_PROXY);
12944 case LOAD_RELOAD_BYPASS_CACHE:
12945 return Reload(LOAD_FLAGS_CHARSET_CHANGE | LOAD_FLAGS_BYPASS_CACHE);
12946 default:
12947 return Reload(LOAD_FLAGS_CHARSET_CHANGE);
12948 }
12949 }
12950 }
12951 }
12952 // return failure if this request is not accepted due to mCharsetReloadState
12953 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
12954}
12955
12956nsresult nsDocShell::CharsetChangeStopDocumentLoad() {
12957 if (eCharsetReloadRequested != mCharsetReloadState) {
12958 Stop(nsIWebNavigation::STOP_ALL);
12959 return NS_OK;
12960 }
12961 // return failer if this request is not accepted due to mCharsetReloadState
12962 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
12963}
12964
12965NS_IMETHODIMPnsresult nsDocShell::ExitPrintPreview() {
12966 nsCOMPtr<nsIWebBrowserPrint> viewer = do_QueryInterface(mDocumentViewer);
12967 MOZ_TRY(viewer->ExitPrintPreview())__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult
(viewer->ExitPrintPreview()); if ((__builtin_expect(!!(mozTryVarTempResult
.isErr()), 0))) { return mozTryVarTempResult.propagateErr(); }
mozTryVarTempResult.unwrap(); })
;
12968 return NS_OK;
12969}
12970
12971/* [infallible] */
12972NS_IMETHODIMPnsresult nsDocShell::GetIsTopLevelContentDocShell(
12973 bool* aIsTopLevelContentDocShell) {
12974 *aIsTopLevelContentDocShell = false;
12975
12976 if (mItemType == typeContent) {
12977 *aIsTopLevelContentDocShell = mBrowsingContext->IsTopContent();
12978 }
12979
12980 return NS_OK;
12981}
12982
12983// Implements nsILoadContext.originAttributes
12984NS_IMETHODIMPnsresult
12985nsDocShell::GetScriptableOriginAttributes(JSContext* aCx,
12986 JS::MutableHandle<JS::Value> aVal) {
12987 return mBrowsingContext->GetScriptableOriginAttributes(aCx, aVal);
12988}
12989
12990// Implements nsIDocShell.GetOriginAttributes()
12991NS_IMETHODIMPnsresult
12992nsDocShell::GetOriginAttributes(JSContext* aCx,
12993 JS::MutableHandle<JS::Value> aVal) {
12994 return mBrowsingContext->GetScriptableOriginAttributes(aCx, aVal);
12995}
12996
12997bool nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal,
12998 nsIURI* aURI) {
12999 MOZ_ASSERT(aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal", "./../../../docshell/base/nsDocShell.cpp"
, 12999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
")"); do { MOZ_CrashSequence(__null, 12999); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
13000 MOZ_ASSERT(aURI)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI", "./../../../docshell/base/nsDocShell.cpp"
, 13000); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ")")
; do { MOZ_CrashSequence(__null, 13000); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13001
13002 if (UsePrivateBrowsing() || mBrowsingContext->GetSandboxFlags()) {
13003 return false;
13004 }
13005
13006 nsCOMPtr<nsIDocShellTreeItem> parent;
13007 GetInProcessSameTypeParent(getter_AddRefs(parent));
13008 nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
13009 nsPIDOMWindowInner* parentInner =
13010 parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
13011
13012 StorageAccess storage =
13013 StorageAllowedForNewWindow(aPrincipal, aURI, parentInner);
13014
13015 // A service worker is allowed to control the window if partition is enabled.
13016 if (parentInner) {
13017 RefPtr<Document> doc = parentInner->GetExtantDoc();
13018
13019 if (doc && StoragePartitioningEnabled(storage, doc->CookieJarSettings())) {
13020 return true;
13021 }
13022 }
13023
13024 return storage == StorageAccess::eAllow;
13025}
13026
13027nsresult nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs) {
13028 MOZ_ASSERT(!mIsBeingDestroyed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsBeingDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsBeingDestroyed))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 13028); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mIsBeingDestroyed" ")"); do { MOZ_CrashSequence
(__null, 13028); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
13029 return mBrowsingContext->SetOriginAttributes(aAttrs);
13030}
13031
13032NS_IMETHODIMPnsresult
13033nsDocShell::ResumeRedirectedLoad(uint64_t aIdentifier) {
13034 RefPtr<nsDocShell> self = this;
13035 RefPtr<ChildProcessChannelListener> cpcl =
13036 ChildProcessChannelListener::GetSingleton();
13037
13038 // Call into InternalLoad with the pending channel when it is received.
13039 cpcl->RegisterCallback(
13040 aIdentifier, [self](nsDocShellLoadState* aLoadState,
13041 nsTArray<Endpoint<extensions::PStreamFilterParent>>&&
13042 aStreamFilterEndpoints,
13043 nsDOMNavigationTiming* aTiming) {
13044 MOZ_ASSERT(aLoadState->GetPendingRedirectedChannel())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadState->GetPendingRedirectedChannel())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aLoadState->GetPendingRedirectedChannel()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aLoadState->GetPendingRedirectedChannel()"
, "./../../../docshell/base/nsDocShell.cpp", 13044); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aLoadState->GetPendingRedirectedChannel()"
")"); do { MOZ_CrashSequence(__null, 13044); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
13045 if (NS_WARN_IF(self->mIsBeingDestroyed)NS_warn_if_impl(self->mIsBeingDestroyed, "self->mIsBeingDestroyed"
, "./../../../docshell/base/nsDocShell.cpp", 13045)
) {
13046 aLoadState->GetPendingRedirectedChannel()->CancelWithReason(
13047 NS_BINDING_ABORTED, "nsDocShell::mIsBeingDestroyed"_ns);
13048 return NS_BINDING_ABORTED;
13049 }
13050
13051 self->mLoadType = aLoadState->LoadType();
13052 nsCOMPtr<nsIURI> previousURI;
13053 uint32_t previousFlags = 0;
13054 ExtractLastVisit(aLoadState->GetPendingRedirectedChannel(),
13055 getter_AddRefs(previousURI), &previousFlags);
13056 self->SaveLastVisit(aLoadState->GetPendingRedirectedChannel(),
13057 previousURI, previousFlags);
13058
13059 if (aTiming) {
13060 self->mTiming = new nsDOMNavigationTiming(self, aTiming);
13061 self->mBlankTiming = false;
13062 }
13063
13064 // Prohibit initial about:blank handling e.g. for when a cross-process
13065 // iframe loads about:blank and becomes same-process. Conceptually, the
13066 // browsing context isn't new despite the docshell being newly created.
13067 aLoadState->ProhibitInitialAboutBlankHandling();
13068
13069 self->InternalLoad(aLoadState);
13070
13071 if (aLoadState->GetOriginalURIString().isSome()) {
13072 // Save URI string in case it's needed later when
13073 // sending to search engine service in EndPageLoad()
13074 self->mOriginalUriString = *aLoadState->GetOriginalURIString();
13075 }
13076
13077 for (auto& endpoint : aStreamFilterEndpoints) {
13078 extensions::StreamFilterParent::Attach(
13079 aLoadState->GetPendingRedirectedChannel(), std::move(endpoint));
13080 }
13081
13082 // If the channel isn't pending, then it means that InternalLoad
13083 // never connected it, and we shouldn't try to continue. This
13084 // can happen even if InternalLoad returned NS_OK.
13085 bool pending = false;
13086 aLoadState->GetPendingRedirectedChannel()->IsPending(&pending);
13087 NS_ASSERTION(pending, "We should have connected the pending channel!")do { if (!(pending)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "We should have connected the pending channel!"
, "pending", "./../../../docshell/base/nsDocShell.cpp", 13087
); MOZ_PretendNoReturn(); } } while (0)
;
13088 if (!pending) {
13089 return NS_BINDING_ABORTED;
13090 }
13091 return NS_OK;
13092 });
13093 return NS_OK;
13094}
13095
13096NS_IMETHODIMPnsresult
13097nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
13098 JSContext* aCx) {
13099 OriginAttributes attrs;
13100 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
13101 return NS_ERROR_INVALID_ARG;
13102 }
13103
13104 return SetOriginAttributes(attrs);
13105}
13106
13107NS_IMETHODIMPnsresult
13108nsDocShell::GetAsyncPanZoomEnabled(bool* aOut) {
13109 if (PresShell* presShell = GetPresShell()) {
13110 *aOut = presShell->AsyncPanZoomEnabled();
13111 return NS_OK;
13112 }
13113
13114 // If we don't have a presShell, fall back to the default platform value of
13115 // whether or not APZ is enabled.
13116 *aOut = gfxPlatform::AsyncPanZoomEnabled();
13117 return NS_OK;
13118}
13119
13120bool nsDocShell::HasUnloadedParent() {
13121 for (WindowContext* wc = GetBrowsingContext()->GetParentWindowContext(); wc;
13122 wc = wc->GetParentWindowContext()) {
13123 if (!wc->IsCurrent() || wc->IsDiscarded() ||
13124 wc->GetBrowsingContext()->IsDiscarded()) {
13125 // If a parent is OOP and the parent WindowContext is no
13126 // longer current, we can assume the parent was unloaded.
13127 return true;
13128 }
13129
13130 if (wc->GetBrowsingContext()->IsInProcess() &&
13131 (!wc->GetBrowsingContext()->GetDocShell() ||
13132 wc->GetBrowsingContext()->GetDocShell()->GetIsInUnload())) {
13133 return true;
13134 }
13135 }
13136 return false;
13137}
13138
13139/* static */
13140bool nsDocShell::ShouldUpdateGlobalHistory(uint32_t aLoadType) {
13141 return !(aLoadType == LOAD_BYPASS_HISTORY || aLoadType == LOAD_ERROR_PAGE ||
13142 aLoadType & LOAD_CMD_HISTORY);
13143}
13144
13145void nsDocShell::UpdateGlobalHistoryTitle(nsIURI* aURI) {
13146 if (!mBrowsingContext->GetUseGlobalHistory() || UsePrivateBrowsing()) {
13147 return;
13148 }
13149
13150 // Global history is interested into sub-frame visits only for link-coloring
13151 // purposes, thus title updates are skipped for those.
13152 //
13153 // Moreover, some iframe documents (such as the ones created via
13154 // document.open()) inherit the document uri of the caller, which would cause
13155 // us to override a previously set page title with one from the subframe.
13156 if (IsSubframe()) {
13157 return;
13158 }
13159
13160 if (nsCOMPtr<IHistory> history = components::History::Service()) {
13161 history->SetURITitle(aURI, mTitle);
13162 }
13163}
13164
13165bool nsDocShell::IsInvisible() { return mInvisible; }
13166
13167void nsDocShell::SetInvisible(bool aInvisible) { mInvisible = aInvisible; }
13168
13169/* static */
13170void nsDocShell::MaybeNotifyKeywordSearchLoading(nsIURIFixupInfo* aInfo) {
13171 if (!aInfo) {
13172 return;
13173 }
13174 nsAutoString providerId;
13175 aInfo->GetKeywordProviderId(providerId);
13176 if (providerId.IsEmpty()) {
13177 return;
13178 }
13179 nsAutoString keyword;
13180 aInfo->GetKeywordAsSent(keyword);
13181
13182 nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
13183 if (obsSvc) {
13184 // Note that "keyword-search" refers to a search via the url
13185 // bar, not a bookmarks keyword search.
13186 obsSvc->NotifyObservers(aInfo, "keyword-search", keyword.get());
13187 }
13188}
13189
13190NS_IMETHODIMPnsresult
13191nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, nsIChannel* aChannel,
13192 bool* aShouldIntercept) {
13193 return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel,
13194 aShouldIntercept);
13195}
13196
13197NS_IMETHODIMPnsresult
13198nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel) {
13199 return mInterceptController->ChannelIntercepted(aChannel);
13200}
13201
13202bool nsDocShell::InFrameSwap() {
13203 RefPtr<nsDocShell> shell = this;
13204 do {
13205 if (shell->mInFrameSwap) {
13206 return true;
13207 }
13208 shell = shell->GetInProcessParentDocshell();
13209 } while (shell);
13210 return false;
13211}
13212
13213UniquePtr<ClientSource> nsDocShell::TakeInitialClientSource() {
13214 return std::move(mInitialClientSource);
13215}
13216
13217NS_IMETHODIMPnsresult
13218nsDocShell::GetEditingSession(nsIEditingSession** aEditSession) {
13219 if (!NS_SUCCEEDED(EnsureEditorData())((bool)(__builtin_expect(!!(!NS_FAILED_impl(EnsureEditorData(
))), 1)))
) {
13220 return NS_ERROR_FAILURE;
13221 }
13222
13223 *aEditSession = do_AddRef(mEditorData->GetEditingSession()).take();
13224 return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
13225}
13226
13227NS_IMETHODIMPnsresult
13228nsDocShell::GetScriptableBrowserChild(nsIBrowserChild** aBrowserChild) {
13229 *aBrowserChild = GetBrowserChild().take();
13230 return *aBrowserChild ? NS_OK : NS_ERROR_FAILURE;
13231}
13232
13233already_AddRefed<nsIBrowserChild> nsDocShell::GetBrowserChild() {
13234 nsCOMPtr<nsIBrowserChild> tc = do_QueryReferent(mBrowserChild);
13235 return tc.forget();
13236}
13237
13238nsCommandManager* nsDocShell::GetCommandManager() {
13239 NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr)do { nsresult __rv = EnsureCommandHandler(); if (((bool)(__builtin_expect
(!!(NS_FAILED_impl(__rv)), 0)))) { const char* name = mozilla
::GetStaticErrorName(__rv); mozilla::SmprintfPointer msg = mozilla
::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%"
"X" "%s%s%s", "EnsureCommandHandler()", "nullptr", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../docshell/base/nsDocShell.cpp", 13239); return nullptr
; } } while (false)
;
13240 return mCommandManager;
13241}
13242
13243NS_IMETHODIMP_(void)void
13244nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) {
13245 mBrowsingContext->GetOriginAttributes(aAttrs);
13246}
13247
13248HTMLEditor* nsIDocShell::GetHTMLEditor() {
13249 nsDocShell* docShell = static_cast<nsDocShell*>(this);
13250 return docShell->GetHTMLEditorInternal();
13251}
13252
13253nsresult nsIDocShell::SetHTMLEditor(HTMLEditor* aHTMLEditor) {
13254 nsDocShell* docShell = static_cast<nsDocShell*>(this);
13255 return docShell->SetHTMLEditorInternal(aHTMLEditor);
13256}
13257
13258#define MATRIX_LENGTH 20
13259
13260NS_IMETHODIMPnsresult
13261nsDocShell::SetColorMatrix(const nsTArray<float>& aMatrix) {
13262 if (aMatrix.Length() == MATRIX_LENGTH) {
13263 mColorMatrix = std::make_unique<gfx::Matrix5x4>();
13264 static_assert(
13265 MATRIX_LENGTH * sizeof(float) == sizeof(mColorMatrix->components),
13266 "Size mismatch for our memcpy");
13267 memcpy(mColorMatrix->components, aMatrix.Elements(),
13268 sizeof(mColorMatrix->components));
13269 } else if (aMatrix.Length() == 0) {
13270 mColorMatrix.reset();
13271 } else {
13272 return NS_ERROR_INVALID_ARG;
13273 }
13274
13275 PresShell* presShell = GetPresShell();
13276 if (!presShell) {
13277 return NS_ERROR_FAILURE;
13278 }
13279
13280 nsIFrame* frame = presShell->GetRootFrame();
13281 if (!frame) {
13282 return NS_ERROR_FAILURE;
13283 }
13284
13285 frame->SchedulePaint();
13286
13287 return NS_OK;
13288}
13289
13290NS_IMETHODIMPnsresult
13291nsDocShell::GetColorMatrix(nsTArray<float>& aMatrix) {
13292 if (mColorMatrix) {
13293 aMatrix.SetLength(MATRIX_LENGTH);
13294 static_assert(
13295 MATRIX_LENGTH * sizeof(float) == sizeof(mColorMatrix->components),
13296 "Size mismatch for our memcpy");
13297 memcpy(aMatrix.Elements(), mColorMatrix->components,
13298 MATRIX_LENGTH * sizeof(float));
13299 }
13300
13301 return NS_OK;
13302}
13303
13304#undef MATRIX_LENGTH
13305
13306NS_IMETHODIMPnsresult
13307nsDocShell::GetIsForceReloading(bool* aForceReload) {
13308 *aForceReload = IsForceReloading();
13309 return NS_OK;
13310}
13311
13312bool nsDocShell::IsForceReloading() { return IsForceReloadType(mLoadType); }
13313
13314NS_IMETHODIMPnsresult
13315nsDocShell::GetBrowsingContextXPCOM(BrowsingContext** aBrowsingContext) {
13316 *aBrowsingContext = do_AddRef(mBrowsingContext).take();
13317 return NS_OK;
13318}
13319
13320BrowsingContext* nsDocShell::GetBrowsingContext() { return mBrowsingContext; }
13321
13322bool nsDocShell::GetIsAttemptingToNavigate() {
13323 // XXXbz the document.open spec says to abort even if there's just a
13324 // queued navigation task, sort of. It's not clear whether browsers
13325 // actually do that, and we didn't use to do it, so for now let's
13326 // not do that.
13327 // https://github.com/whatwg/html/issues/3447 tracks the spec side of this.
13328 if (mDocumentRequest) {
13329 // There's definitely a navigation in progress.
13330 return true;
13331 }
13332
13333 // javascript: channels have slightly weird behavior: they're LOAD_BACKGROUND
13334 // until the script runs, which means they're not sending loadgroup
13335 // notifications and hence not getting set as mDocumentRequest. Look through
13336 // our loadgroup for document-level javascript: loads.
13337 if (!mLoadGroup) {
13338 return false;
13339 }
13340
13341 nsCOMPtr<nsISimpleEnumerator> requests;
13342 mLoadGroup->GetRequests(getter_AddRefs(requests));
13343 bool hasMore = false;
13344 while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(requests->HasMoreElements
(&hasMore))), 1)))
&& hasMore) {
13345 nsCOMPtr<nsISupports> elem;
13346 requests->GetNext(getter_AddRefs(elem));
13347 nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(elem));
13348 if (!scriptChannel) {
13349 continue;
13350 }
13351
13352 if (scriptChannel->GetIsDocumentLoad()) {
13353 // This is a javascript: load that might lead to a new document,
13354 // hence a navigation.
13355 return true;
13356 }
13357 }
13358
13359 if (mOngoingNavigation == Some(OngoingNavigation::NavigationID)) {
13360 return true;
13361 }
13362
13363 return mCheckingSessionHistory;
13364}
13365
13366mozilla::dom::SessionHistoryInfo* nsDocShell::GetActiveSessionHistoryInfo()
13367 const {
13368 return mActiveEntry.get();
13369}
13370
13371void nsDocShell::SetLoadingSessionHistoryInfo(
13372 const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo,
13373 bool aNeedToReportActiveAfterLoadingBecomesActive) {
13374 // FIXME Would like to assert this, but can't yet.
13375 // MOZ_ASSERT(!mLoadingEntry);
13376 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Setting the loading entry on nsDocShell %p to %s"
, this, aLoadingInfo.mInfo.GetURI()->GetSpecOrDefault().get
()); } } while (0)
13377 ("Setting the loading entry on nsDocShell %p to %s", this,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Setting the loading entry on nsDocShell %p to %s"
, this, aLoadingInfo.mInfo.GetURI()->GetSpecOrDefault().get
()); } } while (0)
13378 aLoadingInfo.mInfo.GetURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Setting the loading entry on nsDocShell %p to %s"
, this, aLoadingInfo.mInfo.GetURI()->GetSpecOrDefault().get
()); } } while (0)
;
13379 mLoadingEntry = std::make_unique<LoadingSessionHistoryInfo>(aLoadingInfo);
13380 mNeedToReportActiveAfterLoadingBecomesActive =
13381 aNeedToReportActiveAfterLoadingBecomesActive;
13382}
13383
13384void nsDocShell::MoveLoadingToActiveEntry(bool aExpired, uint32_t aCacheKey,
13385 nsIURI* aPreviousURI) {
13386 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p MoveLoadingToActiveEntry", this
); } } while (0)
13387 ("nsDocShell %p MoveLoadingToActiveEntry", this))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsDocShell %p MoveLoadingToActiveEntry", this
); } } while (0)
;
13388
13389 UniquePtr<SessionHistoryInfo> previousActiveEntry(mActiveEntry.release());
13390 mozilla::UniquePtr<mozilla::dom::LoadingSessionHistoryInfo> loadingEntry;
13391 mActiveEntryIsLoadingFromSessionHistory =
13392 mLoadingEntry && mLoadingEntry->mLoadIsFromSessionHistory;
13393 if (mLoadingEntry) {
13394 MOZ_LOG(gSHLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p "
"to %s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
13395 ("Moving the loading entry to the active entry on nsDocShell %p "do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p "
"to %s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
13396 "to %s",do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p "
"to %s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
13397 this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gSHLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Moving the loading entry to the active entry on nsDocShell %p "
"to %s", this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault
().get()); } } while (0)
;
13398 mActiveEntry = std::make_unique<SessionHistoryInfo>(mLoadingEntry->mInfo);
13399 mLoadingEntry.swap(loadingEntry);
13400 if (!mActiveEntryIsLoadingFromSessionHistory) {
13401 if (mNeedToReportActiveAfterLoadingBecomesActive) {
13402 // Needed to pass various history length WPTs.
13403 mBrowsingContext->SetActiveSessionHistoryEntry(
13404 mozilla::Nothing(), mActiveEntry.get(), previousActiveEntry.get(),
13405 mLoadType,
13406 /* aUpdatedCacheKey = */ 0,
13407 // Of the loads getting here, only initial about:blank is transient.
13408 // Keep it from updating the length as before, though it probably
13409 // should, see bug 2091545.
13410 /* aUpdateLength = */ !mActiveEntry->IsTransient());
13411 }
13412 if (loadingEntry->mReplacesActiveEntry) {
13413 MOZ_ASSERT(previousActiveEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(previousActiveEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(previousActiveEntry))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("previousActiveEntry"
, "./../../../docshell/base/nsDocShell.cpp", 13413); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "previousActiveEntry" ")"); do { MOZ_CrashSequence
(__null, 13413); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
13414 mBrowsingContext->ReplaceActiveSessionHistoryEntry(mActiveEntry.get());
13415 } else if (!(previousActiveEntry && previousActiveEntry->IsTransient())) {
13416 mBrowsingContext->IncrementHistoryEntryCountForBrowsingContext();
13417 }
13418 }
13419 }
13420 mNeedToReportActiveAfterLoadingBecomesActive = false;
13421
13422 if (mActiveEntry) {
13423 if (aCacheKey != 0) {
13424 mActiveEntry->SetCacheKey(aCacheKey);
13425 }
13426
13427 MOZ_ASSERT(loadingEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(loadingEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loadingEntry))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("loadingEntry", "./../../../docshell/base/nsDocShell.cpp"
, 13427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "loadingEntry"
")"); do { MOZ_CrashSequence(__null, 13427); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
13428 uint32_t loadType =
13429 mLoadType == LOAD_ERROR_PAGE ? mFailedLoadType : mLoadType;
13430
13431 if (loadingEntry->mLoadId != UINT64_MAX(18446744073709551615UL)) {
13432 // We're passing in mCurrentURI, which could be null. SessionHistoryCommit
13433 // does require a non-null uri if this is for a refresh load of the same
13434 // URI, but in that case mCurrentURI won't be null here.
13435 mBrowsingContext->SessionHistoryCommit(
13436 *loadingEntry, loadType, aPreviousURI, previousActiveEntry.get(),
13437 false, aExpired, aCacheKey);
13438 }
13439
13440 // Only update navigation if the new entry will be persisted (i.e., is not
13441 // an about: page).
13442 if (!loadingEntry->mInfo.IsTransient() && GetWindow() &&
13443 GetWindow()->GetCurrentInnerWindow()) {
13444 if (RefPtr navigation =
13445 GetWindow()->GetCurrentInnerWindow()->Navigation()) {
13446 navigation->InitializeHistoryEntries(loadingEntry->mContiguousEntries,
13447 mActiveEntry.get());
13448
13449 MOZ_LOG_FMT(gNavigationAPILog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13450 "Before creating NavigationActivation, "do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13451 "triggeringEntry={}, triggeringType={}",do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13452 fmt::ptr(loadingEntry->mPreviousEntrydo { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13453 .map([](auto& entry) { return &entry; })do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13454 .valueOr(nullptr)),do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13455 loadingEntry->mTriggeringNavigationTypedo { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13456 .map([](NavigationType type) {do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13457 return fmt::format("{}", type);do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13458 })do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
13459 .valueOr("none"))do { const ::mozilla::LogModule* moz_real_module = gNavigationAPILog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print_fmt(moz_real_module
, LogLevel::Debug, "Before creating NavigationActivation, " "triggeringEntry={}, triggeringType={}"
, fmt::ptr(loadingEntry->mPreviousEntry .map([](auto& entry
) { return &entry; }) .valueOr(nullptr)), loadingEntry->
mTriggeringNavigationType .map([](NavigationType type) { return
fmt::format("{}", type); }) .valueOr("none")); } } while (0)
;
13460 navigation->CreateNavigationActivationFrom(
13461 loadingEntry->mPreviousEntry,
13462 loadingEntry->mTriggeringNavigationType);
13463 }
13464 }
13465 }
13466}
13467
13468static bool IsFaviconLoad(nsIRequest* aRequest) {
13469 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
13470 if (!channel) {
13471 return false;
13472 }
13473
13474 nsCOMPtr<nsILoadInfo> li = channel->LoadInfo();
13475 return li && li->InternalContentPolicyType() ==
13476 nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON;
13477}
13478
13479void nsDocShell::RecordSingleChannelId(bool aStartRequest,
13480 nsIRequest* aRequest) {
13481 // Ignore favicon loads, they don't need to block caching.
13482 if (IsFaviconLoad(aRequest)) {
13483 return;
13484 }
13485
13486 MOZ_ASSERT_IF(!aStartRequest, mRequestForBlockingFromBFCacheCount > 0)do { if (!aStartRequest) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(mRequestForBlockingFromBFCacheCount
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mRequestForBlockingFromBFCacheCount > 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRequestForBlockingFromBFCacheCount > 0"
, "./../../../docshell/base/nsDocShell.cpp", 13486); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mRequestForBlockingFromBFCacheCount > 0"
")"); do { MOZ_CrashSequence(__null, 13486); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
;
13487
13488 mRequestForBlockingFromBFCacheCount += aStartRequest ? 1 : -1;
13489
13490 if (mBrowsingContext->GetCurrentWindowContext()) {
13491 // We have three states: no request, one request with an id and
13492 // eiher one request without an id or multiple requests. Nothing() is no
13493 // request, Some(non-zero) is one request with an id and Some(0) is one
13494 // request without an id or multiple requests.
13495 Maybe<uint64_t> singleChannelId;
13496 if (mRequestForBlockingFromBFCacheCount > 1) {
13497 singleChannelId = Some(0);
13498 } else if (mRequestForBlockingFromBFCacheCount == 1) {
13499 nsCOMPtr<nsIIdentChannel> identChannel;
13500 if (aStartRequest) {
13501 identChannel = do_QueryInterface(aRequest);
13502 } else {
13503 // aChannel is the channel that's being removed, but we need to check if
13504 // the remaining channel in the loadgroup has an id.
13505 nsCOMPtr<nsISimpleEnumerator> requests;
13506 mLoadGroup->GetRequests(getter_AddRefs(requests));
13507 for (const auto& request : SimpleEnumerator<nsIRequest>(requests)) {
13508 if (!IsFaviconLoad(request) &&
13509 !!(identChannel = do_QueryInterface(request))) {
13510 break;
13511 }
13512 }
13513 }
13514
13515 if (identChannel) {
13516 singleChannelId = Some(identChannel->ChannelId());
13517 } else {
13518 singleChannelId = Some(0);
13519 }
13520 } else {
13521 MOZ_ASSERT(mRequestForBlockingFromBFCacheCount == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestForBlockingFromBFCacheCount == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mRequestForBlockingFromBFCacheCount == 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mRequestForBlockingFromBFCacheCount == 0"
, "./../../../docshell/base/nsDocShell.cpp", 13521); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mRequestForBlockingFromBFCacheCount == 0" ")"
); do { MOZ_CrashSequence(__null, 13521); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13522 singleChannelId = Nothing();
13523 }
13524
13525 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Verbose))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gSHIPBFCacheLog, LogLevel::Verbose)), 0))), 0))
) {
13526 nsAutoCString uri("[no uri]");
13527 if (mCurrentURI) {
13528 uri = mCurrentURI->GetSpecOrDefault();
13529 }
13530 if (singleChannelId.isNothing()) {
13531 MOZ_LOG(gSHIPBFCacheLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s doesn't have any requests relevant for "
"blocking BFCache", uri.get()); } } while (0)
13532 ("Loadgroup for %s doesn't have any requests relevant for "do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s doesn't have any requests relevant for "
"blocking BFCache", uri.get()); } } while (0)
13533 "blocking BFCache",do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s doesn't have any requests relevant for "
"blocking BFCache", uri.get()); } } while (0)
13534 uri.get()))do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s doesn't have any requests relevant for "
"blocking BFCache", uri.get()); } } while (0)
;
13535 } else if (singleChannelId.value() == 0) {
13536 MOZ_LOG(gSHIPBFCacheLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has multiple requests relevant for blocking "
"BFCache", uri.get()); } } while (0)
13537 ("Loadgroup for %s has multiple requests relevant for blocking "do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has multiple requests relevant for blocking "
"BFCache", uri.get()); } } while (0)
13538 "BFCache",do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has multiple requests relevant for blocking "
"BFCache", uri.get()); } } while (0)
13539 uri.get()))do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has multiple requests relevant for blocking "
"BFCache", uri.get()); } } while (0)
;
13540 } else {
13541 MOZ_LOG(gSHIPBFCacheLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has one request with id %"
"l" "u" " relevant for blocking BFCache", uri.get(), singleChannelId
.value()); } } while (0)
13542 ("Loadgroup for %s has one request with id %" PRIu64do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has one request with id %"
"l" "u" " relevant for blocking BFCache", uri.get(), singleChannelId
.value()); } } while (0)
13543 " relevant for blocking BFCache",do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has one request with id %"
"l" "u" " relevant for blocking BFCache", uri.get(), singleChannelId
.value()); } } while (0)
13544 uri.get(), singleChannelId.value()))do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Loadgroup for %s has one request with id %"
"l" "u" " relevant for blocking BFCache", uri.get(), singleChannelId
.value()); } } while (0)
;
13545 }
13546 }
13547
13548 if (mSingleChannelId != singleChannelId) {
13549 mSingleChannelId = singleChannelId;
13550 WindowGlobalChild* wgc =
13551 mBrowsingContext->GetCurrentWindowContext()->GetWindowGlobalChild();
13552 if (wgc) {
13553 wgc->SendSetSingleChannelId(singleChannelId);
13554 }
13555 }
13556 }
13557}
13558
13559NS_IMETHODIMPnsresult
13560nsDocShell::OnStartRequest(nsIRequest* aRequest) {
13561 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Verbose))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gSHIPBFCacheLog, LogLevel::Verbose)), 0))), 0))
) {
13562 nsAutoCString uri("[no uri]");
13563 if (mCurrentURI) {
13564 uri = mCurrentURI->GetSpecOrDefault();
13565 }
13566 nsAutoCString name;
13567 aRequest->GetName(name);
13568 MOZ_LOG(gSHIPBFCacheLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Adding request %s to loadgroup for %s",
name.get(), uri.get()); } } while (0)
13569 ("Adding request %s to loadgroup for %s", name.get(), uri.get()))do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Adding request %s to loadgroup for %s",
name.get(), uri.get()); } } while (0)
;
13570 }
13571 RecordSingleChannelId(true, aRequest);
13572 return nsDocLoader::OnStartRequest(aRequest);
13573}
13574
13575NS_IMETHODIMPnsresult
13576nsDocShell::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
13577 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Verbose))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gSHIPBFCacheLog, LogLevel::Verbose)), 0))), 0))
) {
13578 nsAutoCString uri("[no uri]");
13579 if (mCurrentURI) {
13580 uri = mCurrentURI->GetSpecOrDefault();
13581 }
13582 nsAutoCString name;
13583 aRequest->GetName(name);
13584 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Removing request %s from loadgroup for %s"
, name.get(), uri.get()); } } while (0)
13585 gSHIPBFCacheLog, LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Removing request %s from loadgroup for %s"
, name.get(), uri.get()); } } while (0)
13586 ("Removing request %s from loadgroup for %s", name.get(), uri.get()))do { const ::mozilla::LogModule* moz_real_module = gSHIPBFCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Removing request %s from loadgroup for %s"
, name.get(), uri.get()); } } while (0)
;
13587 }
13588 RecordSingleChannelId(false, aRequest);
13589 return nsDocLoader::OnStopRequest(aRequest, aStatusCode);
13590}
13591
13592void nsDocShell::MaybeDisconnectChildListenersOnPageHide() {
13593 MOZ_RELEASE_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
, "./../../../docshell/base/nsDocShell.cpp", 13593); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "XRE_IsContentProcess()" ")"); do {
MOZ_CrashSequence(__null, 13593); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
13594
13595 if (mChannelToDisconnectOnPageHide != 0 && mLoadGroup) {
13596 nsCOMPtr<nsISimpleEnumerator> requests;
13597 mLoadGroup->GetRequests(getter_AddRefs(requests));
13598 for (const auto& request : SimpleEnumerator<nsIRequest>(requests)) {
13599 RefPtr<DocumentChannel> channel = do_QueryObject(request);
13600 if (channel && channel->ChannelId() == mChannelToDisconnectOnPageHide) {
13601 static_cast<DocumentChannelChild*>(channel.get())
13602 ->DisconnectChildListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED);
13603 }
13604 }
13605 mChannelToDisconnectOnPageHide = 0;
13606 }
13607}
13608
13609bool nsDocShell::IsSameDocumentAsActiveEntry(
13610 const mozilla::dom::SessionHistoryInfo& aSHInfo) {
13611 return mActiveEntry ? mActiveEntry->SharesDocumentWith(aSHInfo) : false;
13612}
13613
13614// https://html.spec.whatwg.org/#nav-window
13615nsPIDOMWindowInner* nsDocShell::GetActiveWindow() {
13616 nsPIDOMWindowOuter* outer = GetWindow();
13617 return outer ? outer->GetCurrentInnerWindow() : nullptr;
13618}
13619
13620// https://html.spec.whatwg.org/#inform-the-navigation-api-about-aborting-navigation
13621void nsDocShell::InformNavigationAPIAboutAbortingNavigation() {
13622 // Step 1
13623 // We really have no idea what this means.
13624
13625 // No ongoing navigations if we don't have a window.
13626 RefPtr<nsPIDOMWindowInner> window = GetActiveWindow();
13627 if (!window) {
13628 return;
13629 }
13630
13631 // Step 2
13632 RefPtr<Navigation> navigation = window->Navigation();
13633 if (!navigation) {
13634 return;
13635 }
13636
13637 AutoJSAPI jsapi;
13638 if (!jsapi.Init(navigation->GetRelevantGlobal())) {
13639 return;
13640 }
13641
13642 // Steps 3 & 4
13643 // See https://github.com/whatwg/html/issues/11579
13644 navigation->InnerInformAboutAbortingNavigation(jsapi.cx());
13645}
13646
13647// https://html.spec.whatwg.org/#inform-the-navigation-api-about-child-navigable-destruction
13648void nsDocShell::InformNavigationAPIAboutChildNavigableDestruction() {
13649 // Step 1
13650 InformNavigationAPIAboutAbortingNavigation();
13651
13652 // No ongoing navigations if we don't have a window.
13653 RefPtr<nsPIDOMWindowInner> window = GetActiveWindow();
13654 if (!window) {
13655 return;
13656 }
13657
13658 // Step 2
13659 RefPtr<Navigation> navigation = window->Navigation();
13660 if (!navigation) {
13661 return;
13662 }
13663
13664 AutoJSAPI jsapi;
13665 if (!jsapi.Init(navigation->GetRelevantGlobal())) {
13666 return;
13667 }
13668
13669 navigation->InformAboutChildNavigableDestruction(jsapi.cx());
13670}
13671
13672// https://html.spec.whatwg.org/#apply-the-history-step step 8.3, for a history
13673// step that moves this navigable away from its active document.
13674void nsDocShell::ClearNavigationAPIOngoingNavigationForHistoryStep() {
13675 if (RefPtr<Navigation> navigation =
13676 NavigationOfDocument(GetExtantDocument())) {
13677 navigation->ClearOngoingNavigationForHistoryStep();
13678 }
13679}
13680
13681// https://html.spec.whatwg.org/#set-the-ongoing-navigation
13682void nsDocShell::ResetOngoingNavigation(
13683 const Maybe<OngoingNavigation>& aOngoingNavigation) {
13684 // We currently only use #set-the-ongoing-navigation to call,
13685 // #inform-the-navigation-api-about-aborting-navigation, but really it should
13686 // be used for more. The spec keeps a piece of state on the navigable:
13687 // https://html.spec.whatwg.org/#ongoing-navigation. Spec uses it for several
13688 // things, for example right here in #set-the-ongoing-navigation to make sure
13689 // that we don't call #inform-the-navigation-api-about-aborting-navigation if
13690 // we're setting it to the same value. We currently only care about aborting
13691 // the currently firing navigate event. Also, in reality, this is very much
13692 // related to nsDocShell::GetIsAttemptingToNavigate() which is what we
13693 // currently use to determine if we need to stop an ongoing navigation in
13694 // Document::Open, whereas the spec checks if the ongoing navigation is a
13695 // NavigationID.
13696
13697 // Step 1, with the exception that we assume setting the ongoing navigation to
13698 // an id always means a fresh id.
13699 if (aOngoingNavigation == mOngoingNavigation &&
13700 aOngoingNavigation != Some(OngoingNavigation::NavigationID)) {
13701 return;
13702 }
13703
13704 // Step 2
13705 InformNavigationAPIAboutAbortingNavigation();
13706
13707 // Step 3
13708 mOngoingNavigation = aOngoingNavigation;
13709}
13710
13711void nsDocShell::StopPendingJavascriptURLNavigations() {
13712 nsCOMPtr<nsISimpleEnumerator> requests;
13713 mLoadGroup->GetRequests(getter_AddRefs(requests));
13714 bool hasMore;
13715 while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(requests->HasMoreElements
(&hasMore))), 1)))
&& hasMore) {
13716 nsCOMPtr<nsISupports> elem;
13717 requests->GetNext(getter_AddRefs(elem));
13718 nsCOMPtr<nsIScriptChannel> script = do_QueryInterface(elem);
13719 if (script) {
13720 nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
13721 MOZ_ASSERT(request)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(request)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(request))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("request", "./../../../docshell/base/nsDocShell.cpp"
, 13721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "request" ")"
); do { MOZ_CrashSequence(__null, 13721); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13722 mLoadGroup->CancelRequest(
13723 request, "nsDocShell::StopPendingJavascriptNavigations"_ns,
13724 NS_BINDING_ABORTED);
13725 }
13726 }
13727}