1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "nsDocShell.h"
8
9 #include <algorithm>
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 "mozilla/ArrayUtils.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/AutoRestore.h"
21 #include "mozilla/BasePrincipal.h"
22 #include "mozilla/Casting.h"
23 #include "mozilla/Encoding.h"
24 #include "mozilla/EventStateManager.h"
25 #include "mozilla/HTMLEditor.h"
26 #include "mozilla/LoadInfo.h"
27 #include "mozilla/Logging.h"
28 #include "mozilla/MediaFeatureChange.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/ResultExtensions.h"
31 #include "mozilla/Services.h"
32 #include "mozilla/StartupTimeline.h"
33 #include "mozilla/Telemetry.h"
34 #include "mozilla/Unused.h"
35
36 #include "mozilla/dom/ClientChannelHelper.h"
37 #include "mozilla/dom/ClientHandle.h"
38 #include "mozilla/dom/ClientInfo.h"
39 #include "mozilla/dom/ClientManager.h"
40 #include "mozilla/dom/ClientSource.h"
41 #include "mozilla/dom/ContentChild.h"
42 #include "mozilla/dom/DocGroup.h"
43 #include "mozilla/dom/Element.h"
44 #include "mozilla/dom/HTMLAnchorElement.h"
45 #include "mozilla/dom/PerformanceNavigation.h"
46 #include "mozilla/dom/PermissionMessageUtils.h"
47 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
48 #include "mozilla/dom/ScreenOrientation.h"
49 #include "mozilla/dom/ScriptSettings.h"
50 #include "mozilla/dom/ServiceWorkerInterceptController.h"
51 #include "mozilla/dom/ServiceWorkerManager.h"
52 #include "mozilla/dom/ServiceWorkerUtils.h"
53 #include "mozilla/dom/TabChild.h"
54 #include "mozilla/dom/TabGroup.h"
55 #include "mozilla/dom/ToJSValue.h"
56
57 #include "mozilla/net/ReferrerPolicy.h"
58
59 #include "nsIApplicationCacheChannel.h"
60 #include "nsIApplicationCacheContainer.h"
61 #include "nsIAppShell.h"
62 #include "nsIAsyncVerifyRedirectCallback.h"
63 #include "nsIAuthPrompt.h"
64 #include "nsIAuthPrompt2.h"
65 #include "nsICachingChannel.h"
66 #include "nsICaptivePortalService.h"
67 #include "nsIChannel.h"
68 #include "nsIChannelEventSink.h"
69 #include "nsIClassOfService.h"
70 #include "nsICommandManager.h"
71 #include "nsIConsoleReportCollector.h"
72 #include "nsIContent.h"
73 #include "nsIContentInlines.h"
74 #include "nsIContentSecurityPolicy.h"
75 #include "nsIContentViewer.h"
76 #include "nsIController.h"
77 #include "nsICookieService.h"
78 #include "nsIDocShellTreeItem.h"
79 #include "nsIDocShellTreeOwner.h"
80 #include "nsIDocument.h"
81 #include "nsIDocumentLoaderFactory.h"
82 #include "nsIDOMDocument.h"
83 #include "nsIDOMElement.h"
84 #include "nsIDOMNode.h"
85 #include "nsIDOMStorage.h"
86 #include "nsIDOMWindow.h"
87 #include "nsIEditingSession.h"
88 #include "nsIExternalProtocolService.h"
89 #include "nsIFormPOSTActionChannel.h"
90 #include "nsIFrame.h"
91 #include "nsIGlobalHistory2.h"
92 #include "nsIGlobalObject.h"
93 #include "nsIHttpChannel.h"
94 #include "nsIHttpChannelInternal.h"
95 #include "nsIIDNService.h"
96 #include "nsIInputStreamChannel.h"
97 #include "nsIInterfaceRequestorUtils.h"
98 #include "nsIJARChannel.h"
99 #include "nsILayoutHistoryState.h"
100 #include "nsILoadInfo.h"
101 #include "nsIMultiPartChannel.h"
102 #include "nsINestedURI.h"
103 #include "nsINetworkPredictor.h"
104 #include "nsINode.h"
105 #include "nsINSSErrorsService.h"
106 #include "nsIObserverService.h"
107 #include "nsIOService.h"
108 #include "nsIPrincipal.h"
109 #include "nsIPrivacyTransitionObserver.h"
110 #include "nsIPrompt.h"
111 #include "nsIPromptFactory.h"
112 #include "nsIReflowObserver.h"
113 #include "nsIScriptChannel.h"
114 #include "nsIScriptError.h"
115 #include "nsIScriptObjectPrincipal.h"
116 #include "nsIScriptSecurityManager.h"
117 #include "nsIScrollableFrame.h"
118 #include "nsIScrollObserver.h"
119 #include "nsISecureBrowserUI.h"
120 #include "nsISecurityUITelemetry.h"
121 #include "nsISeekableStream.h"
122 #include "nsISelectionDisplay.h"
123 #include "nsISHContainer.h"
124 #include "nsISHEntry.h"
125 #include "nsISHistory.h"
126 #include "nsISHistoryInternal.h"
127 #include "nsISiteSecurityService.h"
128 #include "nsISocketProvider.h"
129 #include "nsIStringBundle.h"
130 #include "nsIStructuredCloneContainer.h"
131 #include "nsISupportsPrimitives.h"
132 #include "nsITabChild.h"
133 #include "nsITextToSubURI.h"
134 #include "nsITimedChannel.h"
135 #include "nsITimer.h"
136 #include "nsITransportSecurityInfo.h"
137 #include "nsIUploadChannel.h"
138 #include "nsIURIFixup.h"
139 #include "nsIURILoader.h"
140 #include "nsIURIMutator.h"
141 #include "nsIURL.h"
142 #include "nsIViewSourceChannel.h"
143 #include "nsIWebBrowserChrome.h"
144 #include "nsIWebBrowserChrome3.h"
145 #include "nsIWebBrowserChromeFocus.h"
146 #include "nsIWebBrowserFind.h"
147 #include "nsIWebProgress.h"
148 #include "nsIWidget.h"
149 #include "nsIWindowWatcher.h"
150 #include "nsIWritablePropertyBag2.h"
151 #include "nsIWyciwygChannel.h"
152
153 #include "nsPICommandUpdater.h"
154 #include "nsPIDOMWindow.h"
155 #include "nsPILoadGroupInternal.h"
156 #include "nsPIWindowRoot.h"
157
158 #include "IHistory.h"
159 #include "IUrlClassifierUITelemetry.h"
160
161 #include "mozIThirdPartyUtil.h"
162
163 #include "nsArray.h"
164 #include "nsArrayUtils.h"
165 #include "nsAutoPtr.h"
166 #include "nsCDefaultURIFixup.h"
167 #include "nsCExternalHandlerService.h"
168 #include "nsContentDLF.h"
169 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
170 #include "nsContentSecurityManager.h"
171 #include "nsContentUtils.h"
172 #include "nsCURILoader.h"
173 #include "nsDocShellCID.h"
174 #include "nsDocShellEditorData.h"
175 #include "nsDocShellEnumerator.h"
176 #include "nsDocShellLoadInfo.h"
177 #include "nsDocShellLoadTypes.h"
178 #include "nsDocShellTransferableHooks.h"
179 #include "nsDOMCID.h"
180 #include "nsDOMNavigationTiming.h"
181 #include "nsDSURIContentListener.h"
182 #include "nsError.h"
183 #include "nsEscape.h"
184 #include "nsFocusManager.h"
185 #include "nsGlobalWindow.h"
186 #include "nsJSEnvironment.h"
187 #include "nsNetCID.h"
188 #include "nsNetUtil.h"
189 #include "nsObjectLoadingContent.h"
190 #include "nsPingListener.h"
191 #include "nsPoint.h"
192 #include "nsQueryObject.h"
193 #include "nsRect.h"
194 #include "nsRefreshTimer.h"
195 #include "nsSandboxFlags.h"
196 #include "nsIServiceWorkerManager.h"
197 #include "nsSHistory.h"
198 #include "nsStructuredCloneContainer.h"
199 #include "nsSubDocumentFrame.h"
200 #include "nsView.h"
201 #include "nsViewManager.h"
202 #include "nsViewSourceHandler.h"
203 #include "nsWhitespaceTokenizer.h"
204 #include "nsWidgetsCID.h"
205 #include "nsXULAppAPI.h"
206
207 #include "GeckoProfiler.h"
208 #include "Navigator.h"
209 #include "NullPrincipal.h"
210 #include "prenv.h"
211 #include "URIUtils.h"
212
213 #include "timeline/JavascriptTimelineMarker.h"
214
215 #ifdef MOZ_PLACES
216 #include "nsIFaviconService.h"
217 #include "mozIPlacesPendingOperation.h"
218 #include "mozIAsyncFavicons.h"
219 #endif
220
221 #if NS_PRINT_PREVIEW
222 #include "nsIDocumentViewerPrint.h"
223 #include "nsIWebBrowserPrint.h"
224 #endif
225
226 #ifdef MOZ_TOOLKIT_SEARCH
227 #include "nsIBrowserSearchService.h"
228 #endif
229
230 using namespace mozilla;
231 using namespace mozilla::dom;
232
233 // Threshold value in ms for META refresh based redirects
234 #define REFRESH_REDIRECT_TIMER 15000
235
236 // Hint for native dispatch of events on how long to delay after
237 // all documents have loaded in milliseconds before favoring normal
238 // native event dispatch priorites over performance
239 // Can be overridden with docshell.event_starvation_delay_hint pref.
240 #define NS_EVENT_STARVATION_DELAY_HINT 2000
241
242 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
243
244 // True means sUseErrorPages has been added to
245 // preferences var cache.
246 static bool gAddedPreferencesVarCache = false;
247
248 // Number of documents currently loading
249 static int32_t gNumberOfDocumentsLoading = 0;
250
251 // Global count of existing docshells.
252 static int32_t gDocShellCount = 0;
253
254 // Global count of docshells with the private attribute set
255 static uint32_t gNumberOfPrivateDocShells = 0;
256
257 // True means we validate window targets to prevent frameset
258 // spoofing. Initialize this to a non-bolean value so we know to check
259 // the pref on the creation of the first docshell.
260 static uint32_t gValidateOrigin = 0xffffffff;
261
262 #ifdef DEBUG
263 static mozilla::LazyLogModule gDocShellLog("nsDocShell");
264 #endif
265 static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");
266 ;
267
268 const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
269 const char kAppstringsBundleURL[] =
270 "chrome://global/locale/appstrings.properties";
271
272 bool nsDocShell::sUseErrorPages = false;
273
274 // Global reference to the URI fixup service.
275 nsIURIFixup* nsDocShell::sURIFixup = nullptr;
276
FavorPerformanceHint(bool aPerfOverStarvation)277 static void FavorPerformanceHint(bool aPerfOverStarvation) {
278 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
279 if (appShell) {
280 appShell->FavorPerformanceHint(
281 aPerfOverStarvation,
282 Preferences::GetUint("docshell.event_starvation_delay_hint",
283 NS_EVENT_STARVATION_DELAY_HINT));
284 }
285 }
286
IncreasePrivateDocShellCount()287 static void IncreasePrivateDocShellCount() {
288 gNumberOfPrivateDocShells++;
289 if (gNumberOfPrivateDocShells > 1 || !XRE_IsContentProcess()) {
290 return;
291 }
292
293 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
294 cc->SendPrivateDocShellsExist(true);
295 }
296
DecreasePrivateDocShellCount()297 static void DecreasePrivateDocShellCount() {
298 MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
299 gNumberOfPrivateDocShells--;
300 if (!gNumberOfPrivateDocShells) {
301 if (XRE_IsContentProcess()) {
302 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
303 cc->SendPrivateDocShellsExist(false);
304 return;
305 }
306
307 nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
308 if (obsvc) {
309 obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
310 }
311 }
312 }
313
nsDocShell()314 nsDocShell::nsDocShell()
315 : nsDocLoader(),
316 mForcedCharset(nullptr),
317 mParentCharset(nullptr),
318 mTreeOwner(nullptr),
319 mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
320 mCharsetReloadState(eCharsetReloadInit),
321 mOrientationLock(eScreenOrientation_None),
322 mParentCharsetSource(0),
323 mMarginWidth(-1),
324 mMarginHeight(-1),
325 mItemType(typeContent),
326 mPreviousTransIndex(-1),
327 mLoadedTransIndex(-1),
328 mChildOffset(0),
329 mSandboxFlags(0),
330 mBusyFlags(BUSY_FLAGS_NONE),
331 mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
332 mLoadType(0),
333 mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
334 mReferrerPolicy(0),
335 mFailedLoadType(0),
336 mFrameType(FRAME_TYPE_REGULAR),
337 mPrivateBrowsingId(0),
338 mDisplayMode(nsIDocShell::DISPLAY_MODE_BROWSER),
339 mJSRunToCompletionDepth(0),
340 mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE),
341 mFullscreenAllowed(CHECK_ATTRIBUTES),
342 mCreatingDocument(false)
343 #ifdef DEBUG
344 ,
345 mInEnsureScriptEnv(false)
346 #endif
347 ,
348 mCreated(false),
349 mAllowSubframes(true),
350 mAllowPlugins(true),
351 mAllowJavascript(true),
352 mAllowMetaRedirects(true),
353 mAllowImages(true),
354 mAllowMedia(true),
355 mAllowDNSPrefetch(true),
356 mAllowWindowControl(true),
357 mAllowContentRetargeting(true),
358 mAllowContentRetargetingOnChildren(true),
359 mUseErrorPages(false),
360 mObserveErrorPages(true),
361 mAllowAuth(true),
362 mAllowKeywordFixup(false),
363 mIsOffScreenBrowser(false),
364 mIsActive(true),
365 mDisableMetaRefreshWhenInactive(false),
366 mIsAppTab(false),
367 mUseGlobalHistory(false),
368 mUseRemoteTabs(false),
369 mUseTrackingProtection(false),
370 mDeviceSizeIsPageSize(false),
371 mWindowDraggingAllowed(false),
372 mInFrameSwap(false),
373 mInheritPrivateBrowsingId(true),
374 mCanExecuteScripts(false),
375 mFiredUnloadEvent(false),
376 mEODForCurrentDocument(false),
377 mURIResultedInDocument(false),
378 mIsBeingDestroyed(false),
379 mIsExecutingOnLoadHandler(false),
380 mIsPrintingOrPP(false),
381 mSavingOldViewer(false),
382 mDynamicallyCreated(false),
383 mAffectPrivateSessionLifetime(true),
384 mInvisible(false),
385 mHasLoadedNonBlankURI(false),
386 mBlankTiming(false) {
387 AssertOriginAttributesMatchPrivateBrowsing();
388
389 nsContentUtils::GenerateUUIDInPlace(mHistoryID);
390
391 if (gDocShellCount++ == 0) {
392 NS_ASSERTION(sURIFixup == nullptr,
393 "Huh, sURIFixup not null in first nsDocShell ctor!");
394
395 CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
396 }
397
398 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
399
400 #ifdef DEBUG
401 // We're counting the number of |nsDocShells| to help find leaks
402 ++gNumberOfDocShells;
403 if (!PR_GetEnv("MOZ_QUIET")) {
404 printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n", (void*)this,
405 gNumberOfDocShells, getpid(),
406 nsIDToCString(mHistoryID).get());
407 }
408 #endif
409 }
410
~nsDocShell()411 nsDocShell::~nsDocShell() {
412 MOZ_ASSERT(!mObserved);
413
414 // Avoid notifying observers while we're in the dtor.
415 mIsBeingDestroyed = true;
416
417 Destroy();
418
419 nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory));
420 if (shPrivate) {
421 shPrivate->SetRootDocShell(nullptr);
422 }
423
424 if (--gDocShellCount == 0) {
425 NS_IF_RELEASE(sURIFixup);
426 }
427
428 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this));
429
430 #ifdef DEBUG
431 // We're counting the number of |nsDocShells| to help find leaks
432 --gNumberOfDocShells;
433 if (!PR_GetEnv("MOZ_QUIET")) {
434 printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %s]\n", (void*)this,
435 gNumberOfDocShells, getpid(),
436 nsIDToCString(mHistoryID).get());
437 }
438 #endif
439 }
440
Init()441 nsresult nsDocShell::Init() {
442 MOZ_ASSERT(!mIsBeingDestroyed);
443
444 nsresult rv = nsDocLoader::Init();
445 NS_ENSURE_SUCCESS(rv, rv);
446
447 NS_ASSERTION(mLoadGroup, "Something went wrong!");
448
449 mContentListener = new nsDSURIContentListener(this);
450 rv = mContentListener->Init();
451 NS_ENSURE_SUCCESS(rv, rv);
452
453 // If parent intercept is not enabled then we must forward to
454 // the network controller from docshell. We also enable if we're
455 // in the parent process in order to support non-e10s configurations.
456 if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
457 mInterceptController = new ServiceWorkerInterceptController();
458 }
459
460 // We want to hold a strong ref to the loadgroup, so it better hold a weak
461 // ref to us... use an InterfaceRequestorProxy to do this.
462 nsCOMPtr<nsIInterfaceRequestor> proxy =
463 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
464 mLoadGroup->SetNotificationCallbacks(proxy);
465
466 rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
467 NS_ENSURE_SUCCESS(rv, rv);
468
469 // Add as |this| a progress listener to itself. A little weird, but
470 // simpler than reproducing all the listener-notification logic in
471 // overrides of the various methods via which nsDocLoader can be
472 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
473 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
474 nsIWebProgress::NOTIFY_STATE_NETWORK);
475 }
476
DestroyChildren()477 void nsDocShell::DestroyChildren() {
478 nsCOMPtr<nsIDocShellTreeItem> shell;
479 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
480 while (iter.HasMore()) {
481 shell = do_QueryObject(iter.GetNext());
482 NS_ASSERTION(shell, "docshell has null child");
483
484 if (shell) {
485 shell->SetTreeOwner(nullptr);
486 }
487 }
488
489 nsDocLoader::DestroyChildren();
490 }
491
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell,nsDocLoader,mSessionStorageManager,mScriptGlobal,mInitialClientSource,mChromeEventHandler)492 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell, nsDocLoader,
493 mSessionStorageManager, mScriptGlobal,
494 mInitialClientSource, mChromeEventHandler)
495
496 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
497 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
498
499 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
500 NS_INTERFACE_MAP_ENTRY(nsIDocShell)
501 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
502 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
503 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
504 NS_INTERFACE_MAP_ENTRY(nsIScrollable)
505 NS_INTERFACE_MAP_ENTRY(nsITextScroll)
506 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
507 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
508 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
509 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
510 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
511 NS_INTERFACE_MAP_ENTRY(nsILoadContext)
512 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
513 NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
514 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
515 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
516 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,
517 mInterceptController)
518 NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
519 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
520
521 NS_IMETHODIMP
522 nsDocShell::GetInterface(const nsIID& aIID, void** aSink) {
523 NS_PRECONDITION(aSink, "null out param");
524
525 *aSink = nullptr;
526
527 if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
528 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
529 *aSink = mCommandManager;
530 } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
531 *aSink = mContentListener;
532 } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
533 aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
534 aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
535 aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
536 aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
537 NS_SUCCEEDED(EnsureScriptEnvironment())) {
538 return mScriptGlobal->QueryInterface(aIID, aSink);
539 } else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
540 NS_SUCCEEDED(EnsureContentViewer())) {
541 nsCOMPtr<nsIDOMDocument> doc =
542 do_QueryInterface(mContentViewer->GetDocument());
543 doc.forget(aSink);
544 return *aSink ? NS_OK : NS_NOINTERFACE;
545 } else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
546 NS_SUCCEEDED(EnsureContentViewer())) {
547 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
548 doc.forget(aSink);
549 return *aSink ? NS_OK : NS_NOINTERFACE;
550 } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
551 *aSink = nullptr;
552
553 // Return application cache associated with this docshell, if any
554
555 nsCOMPtr<nsIContentViewer> contentViewer;
556 GetContentViewer(getter_AddRefs(contentViewer));
557 if (!contentViewer) {
558 return NS_ERROR_NO_INTERFACE;
559 }
560
561 nsCOMPtr<nsIDocument> doc = contentViewer->GetDocument();
562 NS_ASSERTION(doc, "Should have a document.");
563 if (!doc) {
564 return NS_ERROR_NO_INTERFACE;
565 }
566
567 #if defined(DEBUG)
568 MOZ_LOG(
569 gDocShellLog, LogLevel::Debug,
570 ("nsDocShell[%p]: returning app cache container %p", this, doc.get()));
571 #endif
572 return doc->QueryInterface(aIID, aSink);
573 } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
574 NS_SUCCEEDED(EnsureScriptEnvironment())) {
575 nsresult rv;
576 nsCOMPtr<nsIWindowWatcher> wwatch =
577 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
578 NS_ENSURE_SUCCESS(rv, rv);
579
580 // Get the an auth prompter for our window so that the parenting
581 // of the dialogs works as it should when using tabs.
582 nsIPrompt* prompt;
583 rv = wwatch->GetNewPrompter(mScriptGlobal->AsOuter(), &prompt);
584 NS_ENSURE_SUCCESS(rv, rv);
585
586 *aSink = prompt;
587 return NS_OK;
588 } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
589 aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
590 return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink))
591 ? NS_OK
592 : NS_NOINTERFACE;
593 } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
594 nsCOMPtr<nsISHistory> shistory;
595 nsresult rv = GetSessionHistory(getter_AddRefs(shistory));
596 if (NS_SUCCEEDED(rv) && shistory) {
597 shistory.forget(aSink);
598 return NS_OK;
599 }
600 return NS_NOINTERFACE;
601 } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
602 nsresult rv = EnsureFind();
603 if (NS_FAILED(rv)) {
604 return rv;
605 }
606
607 *aSink = mFind;
608 NS_ADDREF((nsISupports*)*aSink);
609 return NS_OK;
610 } else if (aIID.Equals(NS_GET_IID(nsIEditingSession))) {
611 nsCOMPtr<nsIEditingSession> es;
612 GetEditingSession(getter_AddRefs(es));
613 es.forget(aSink);
614 return *aSink ? NS_OK : NS_NOINTERFACE;
615 } else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) &&
616 NS_SUCCEEDED(EnsureTransferableHookData())) {
617 *aSink = mTransferableHookData;
618 NS_ADDREF((nsISupports*)*aSink);
619 return NS_OK;
620 } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
621 nsIPresShell* shell = GetPresShell();
622 if (shell) {
623 return shell->QueryInterface(aIID, aSink);
624 }
625 } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
626 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
627 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
628 if (NS_SUCCEEDED(rv) && treeOwner) {
629 return treeOwner->QueryInterface(aIID, aSink);
630 }
631 } else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
632 *aSink = GetTabChild().take();
633 return *aSink ? NS_OK : NS_ERROR_FAILURE;
634 } else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
635 nsCOMPtr<nsITabChild> tabChild =
636 do_GetInterface(static_cast<nsIDocShell*>(this));
637 nsCOMPtr<nsIContentFrameMessageManager> mm;
638 if (tabChild) {
639 tabChild->GetMessageManager(getter_AddRefs(mm));
640 } else {
641 if (nsPIDOMWindowOuter* win = GetWindow()) {
642 mm = do_QueryInterface(win->GetParentTarget());
643 }
644 }
645 *aSink = mm.get();
646 } else {
647 return nsDocLoader::GetInterface(aIID, aSink);
648 }
649
650 NS_IF_ADDREF(((nsISupports*)*aSink));
651 return *aSink ? NS_OK : NS_NOINTERFACE;
652 }
653
654 NS_IMETHODIMP
LoadURI(nsIURI * aURI,nsIDocShellLoadInfo * aLoadInfo,uint32_t aLoadFlags,bool aFirstParty)655 nsDocShell::LoadURI(nsIURI* aURI, nsIDocShellLoadInfo* aLoadInfo,
656 uint32_t aLoadFlags, bool aFirstParty) {
657 NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
658 "Unexpected flags");
659 NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
660
661 // Note: we allow loads to get through here even if mFiredUnloadEvent is
662 // true; that case will get handled in LoadInternal or LoadHistoryEntry,
663 // so we pass false as the second parameter to IsNavigationAllowed.
664 // However, we don't allow the page to change location *in the middle of*
665 // firing beforeunload, so we do need to check if *beforeunload* is currently
666 // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
667 if (!IsNavigationAllowed(true, false)) {
668 return NS_OK; // JS may not handle returning of an error code
669 }
670
671 nsCOMPtr<nsIURI> referrer;
672 nsCOMPtr<nsIURI> originalURI;
673 Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
674 bool keepResultPrincipalURIIfSet = false;
675 bool loadReplace = false;
676 bool isFromProcessingFrameAttributes = false;
677 nsCOMPtr<nsIInputStream> postStream;
678 nsCOMPtr<nsIInputStream> headersStream;
679 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
680 bool inheritPrincipal = false;
681 bool principalIsExplicit = false;
682 bool sendReferrer = true;
683 uint32_t referrerPolicy = mozilla::net::RP_Unset;
684 bool isSrcdoc = false;
685 nsCOMPtr<nsISHEntry> shEntry;
686 nsString target;
687 nsAutoString srcdoc;
688 bool forceAllowDataURI = false;
689 bool originalFrameSrc = false;
690 nsCOMPtr<nsIDocShell> sourceDocShell;
691 nsCOMPtr<nsIURI> baseURI;
692
693 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
694
695 NS_ENSURE_ARG(aURI);
696
697 if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
698 mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
699 StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
700 }
701
702 // Extract the info from the DocShellLoadInfo struct...
703 if (aLoadInfo) {
704 aLoadInfo->GetReferrer(getter_AddRefs(referrer));
705 aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
706 GetMaybeResultPrincipalURI(aLoadInfo, resultPrincipalURI);
707 aLoadInfo->GetKeepResultPrincipalURIIfSet(&keepResultPrincipalURIIfSet);
708 aLoadInfo->GetLoadReplace(&loadReplace);
709 aLoadInfo->GetIsFromProcessingFrameAttributes(
710 &isFromProcessingFrameAttributes);
711 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
712 aLoadInfo->GetLoadType(<);
713 // Get the appropriate loadType from nsIDocShellLoadInfo type
714 loadType = ConvertDocShellInfoLoadTypeToLoadType(lt);
715
716 aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
717 aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
718 aLoadInfo->GetPrincipalIsExplicit(&principalIsExplicit);
719 aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
720 aLoadInfo->GetTarget(getter_Copies(target));
721 aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
722 aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
723 aLoadInfo->GetSendReferrer(&sendReferrer);
724 aLoadInfo->GetReferrerPolicy(&referrerPolicy);
725 aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
726 aLoadInfo->GetSrcdocData(srcdoc);
727 aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
728 aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
729 aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI);
730 aLoadInfo->GetOriginalFrameSrc(&originalFrameSrc);
731 }
732
733 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
734 ("nsDocShell[%p]: loading %s with flags 0x%08x", this,
735 aURI->GetSpecOrDefault().get(), aLoadFlags));
736
737 if (!shEntry && !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
738 // First verify if this is a subframe.
739 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
740 GetSameTypeParent(getter_AddRefs(parentAsItem));
741 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
742 uint32_t parentLoadType;
743
744 if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) {
745 /* OK. It is a subframe. Checkout the
746 * parent's loadtype. If the parent was loaded thro' a history
747 * mechanism, then get the SH entry for the child from the parent.
748 * This is done to restore frameset navigation while going back/forward.
749 * If the parent was loaded through any other loadType, set the
750 * child's loadType too accordingly, so that session history does not
751 * get confused.
752 */
753
754 // Get the parent's load type
755 parentDS->GetLoadType(&parentLoadType);
756
757 // Get the ShEntry for the child from the parent
758 nsCOMPtr<nsISHEntry> currentSH;
759 bool oshe = false;
760 parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
761 bool dynamicallyAddedChild = mDynamicallyCreated;
762 if (!dynamicallyAddedChild && !oshe && currentSH) {
763 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
764 }
765 if (!dynamicallyAddedChild) {
766 // Only use the old SHEntry, if we're sure enough that
767 // it wasn't originally for some other frame.
768 parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
769 }
770
771 // Make some decisions on the child frame's loadType based on the
772 // parent's loadType, if the subframe hasn't loaded anything into it.
773 //
774 // In some cases privileged scripts may try to get the DOMWindow
775 // reference of this docshell before the loading starts, causing the
776 // initial about:blank content viewer being created and mCurrentURI being
777 // set. To handle this case we check if mCurrentURI is about:blank and
778 // currentSHEntry is null.
779 nsCOMPtr<nsISHEntry> currentChildEntry;
780 GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);
781 if (!mCurrentURI ||
782 (NS_IsAboutBlank(mCurrentURI) && !currentChildEntry)) {
783 // This is a newly created frame. Check for exception cases first.
784 // By default the subframe will inherit the parent's loadType.
785 if (shEntry &&
786 (parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK ||
787 parentLoadType == LOAD_NORMAL_EXTERNAL)) {
788 // The parent was loaded normally. In this case, this *brand new*
789 // child really shouldn't have a SHEntry. If it does, it could be
790 // because the parent is replacing an existing frame with a new frame,
791 // in the onLoadHandler. We don't want this url to get into session
792 // history. Clear off shEntry, and set load type to
793 // LOAD_BYPASS_HISTORY.
794 bool inOnLoadHandler = false;
795 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
796 if (inOnLoadHandler) {
797 loadType = LOAD_NORMAL_REPLACE;
798 shEntry = nullptr;
799 }
800 } else if (parentLoadType == LOAD_REFRESH) {
801 // Clear shEntry. For refresh loads, we have to load
802 // what comes thro' the pipe, not what's in history.
803 shEntry = nullptr;
804 } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
805 (shEntry &&
806 ((parentLoadType & LOAD_CMD_HISTORY) ||
807 (parentLoadType == LOAD_RELOAD_NORMAL) ||
808 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
809 (parentLoadType ==
810 LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
811 (parentLoadType ==
812 LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
813 // If the parent url, bypassed history or was loaded from
814 // history, pass on the parent's loadType to the new child
815 // frame too, so that the child frame will also
816 // avoid getting into history.
817 loadType = parentLoadType;
818 } else if (parentLoadType == LOAD_ERROR_PAGE) {
819 // If the parent document is an error page, we don't
820 // want to update global/session history. However,
821 // this child frame is not an error page.
822 loadType = LOAD_BYPASS_HISTORY;
823 } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
824 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
825 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
826 // the new frame should inherit the parent's load type so that it also
827 // bypasses the cache and/or proxy
828 loadType = parentLoadType;
829 }
830 } else {
831 // This is a pre-existing subframe. If
832 // 1. The load of this frame was not originally initiated by session
833 // history directly (i.e. (!shEntry) condition succeeded, but it can
834 // still be a history load on parent which causes this frame being
835 // loaded), and
836 // 2. mCurrentURI is not null, nor the initial about:blank,
837 // it is possible that a parent's onLoadHandler or even self's
838 // onLoadHandler is loading a new page in this child. Check parent's and
839 // self's busy flag and if it is set, we don't want this onLoadHandler
840 // load to get in to session history.
841 uint32_t parentBusy = BUSY_FLAGS_NONE;
842 uint32_t selfBusy = BUSY_FLAGS_NONE;
843 parentDS->GetBusyFlags(&parentBusy);
844 GetBusyFlags(&selfBusy);
845 if (parentBusy & BUSY_FLAGS_BUSY || selfBusy & BUSY_FLAGS_BUSY) {
846 loadType = LOAD_NORMAL_REPLACE;
847 shEntry = nullptr;
848 }
849 }
850 } // parentDS
851 else {
852 // This is the root docshell. If we got here while
853 // executing an onLoad Handler,this load will not go
854 // into session history.
855 bool inOnLoadHandler = false;
856 GetIsExecutingOnLoadHandler(&inOnLoadHandler);
857 if (inOnLoadHandler) {
858 loadType = LOAD_NORMAL_REPLACE;
859 }
860 }
861 } // !shEntry
862
863 if (shEntry) {
864 #ifdef DEBUG
865 MOZ_LOG(gDocShellLog, LogLevel::Debug,
866 ("nsDocShell[%p]: loading from session history", this));
867 #endif
868
869 return LoadHistoryEntry(shEntry, loadType);
870 }
871
872 // On history navigation via Back/Forward buttons, don't execute
873 // automatic JavaScript redirection such as |location.href = ...| or
874 // |window.open()|
875 //
876 // LOAD_NORMAL: window.open(...) etc.
877 // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
878 if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
879 ShouldBlockLoadingForBackButton()) {
880 return NS_OK;
881 }
882
883 // Perform the load...
884
885 // We need a principalToInherit.
886 //
887 // If principalIsExplicit is not set there are 4 possibilities:
888 // (1) If the system principal or an expanded principal was passed
889 // in and we're a typeContent docshell, inherit the principal
890 // from the current document instead.
891 // (2) In all other cases when the principal passed in is not null,
892 // use that principal.
893 // (3) If the caller has allowed inheriting from the current document,
894 // or if we're being called from system code (eg chrome JS or pure
895 // C++) then inheritPrincipal should be true and InternalLoad will get
896 // a principal from the current document. If none of these things are
897 // true, then
898 // (4) we don't pass a principal into the channel, and a principal will be
899 // created later from the channel's internal data.
900 //
901 // If principalIsExplicit *is* set, there are 4 possibilities
902 // (1) If the system principal or an expanded principal was passed in
903 // and we're a typeContent docshell, return an error.
904 // (2) In all other cases when the principal passed in is not null,
905 // use that principal.
906 // (3) If the caller has allowed inheriting from the current document,
907 // then inheritPrincipal should be true and InternalLoad will get
908 // a principal from the current document. If none of these things are
909 // true, then
910 // (4) we dont' pass a principal into the channel, and a principal will be
911 // created later from the channel's internal data.
912 nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal;
913 if (principalToInherit && mItemType != typeChrome) {
914 if (nsContentUtils::IsSystemPrincipal(principalToInherit)) {
915 if (principalIsExplicit) {
916 return NS_ERROR_DOM_SECURITY_ERR;
917 }
918 principalToInherit = nullptr;
919 inheritPrincipal = true;
920 } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) {
921 if (principalIsExplicit) {
922 return NS_ERROR_DOM_SECURITY_ERR;
923 }
924 // Don't inherit from the current page. Just do the safe thing
925 // and pretend that we were loaded by a nullprincipal.
926 //
927 // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
928 // have origin attributes.
929 principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this);
930 inheritPrincipal = false;
931 }
932 }
933 if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) {
934 // See if there's system or chrome JS code running
935 inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
936 }
937
938 if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
939 inheritPrincipal = false;
940 // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
941 // enabled, we will set firstPartyDomain on the origin attributes.
942 principalToInherit =
943 NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
944 }
945
946 // If the triggeringPrincipal is not passed explicitly, we first try to create
947 // a principal from the referrer, since the referrer URI reflects the web
948 // origin that triggered the load. If there is no referrer URI, we fall back
949 // to using the SystemPrincipal. It's safe to assume that no provided
950 // triggeringPrincipal and no referrer simulate a load that was triggered by
951 // the system. It's important to note that this block of code needs to appear
952 // *after* the block where we munge the principalToInherit, because otherwise
953 // we would never enter code blocks checking if the principalToInherit is null
954 // and we will end up with a wrong inheritPrincipal flag.
955 if (!triggeringPrincipal) {
956 if (referrer) {
957 nsresult rv = CreatePrincipalFromReferrer(
958 referrer, getter_AddRefs(triggeringPrincipal));
959 NS_ENSURE_SUCCESS(rv, rv);
960 } else {
961 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
962 }
963 }
964
965 uint32_t flags = 0;
966
967 if (inheritPrincipal) {
968 flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
969 }
970
971 if (!sendReferrer) {
972 flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
973 }
974
975 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
976 flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
977 }
978
979 if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) {
980 flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
981 }
982
983 if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) {
984 flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
985 }
986
987 if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
988 flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
989 }
990
991 if (isSrcdoc) {
992 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
993 }
994
995 if (forceAllowDataURI) {
996 flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
997 }
998
999 if (originalFrameSrc) {
1000 flags |= INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
1001 }
1002
1003 return InternalLoad(aURI, originalURI, resultPrincipalURI,
1004 keepResultPrincipalURIIfSet, loadReplace,
1005 isFromProcessingFrameAttributes, referrer, referrerPolicy,
1006 triggeringPrincipal, principalToInherit, flags, target,
1007 nullptr, // No type hint
1008 VoidString(), // No forced download
1009 postStream,
1010 -1, // XXXbaku
1011 headersStream, loadType,
1012 nullptr, // No SHEntry
1013 aFirstParty, srcdoc, sourceDocShell, baseURI,
1014 nullptr, // No nsIDocShell
1015 nullptr); // No nsIRequest
1016 }
1017
1018 NS_IMETHODIMP
LoadStream(nsIInputStream * aStream,nsIURI * aURI,const nsACString & aContentType,const nsACString & aContentCharset,nsIDocShellLoadInfo * aLoadInfo)1019 nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
1020 const nsACString& aContentType,
1021 const nsACString& aContentCharset,
1022 nsIDocShellLoadInfo* aLoadInfo) {
1023 NS_ENSURE_ARG(aStream);
1024
1025 mAllowKeywordFixup = false;
1026
1027 // if the caller doesn't pass in a URI we need to create a dummy URI. necko
1028 // currently requires a URI in various places during the load. Some consumers
1029 // do as well.
1030 nsCOMPtr<nsIURI> uri = aURI;
1031 if (!uri) {
1032 // HACK ALERT
1033 nsresult rv = NS_OK;
1034 // Make sure that the URI spec "looks" like a protocol and path...
1035 // For now, just use a bogus protocol called "internal"
1036 rv = NS_MutateURI(NS_SIMPLEURIMUTATOR_CONTRACTID)
1037 .SetSpec(NS_LITERAL_CSTRING("internal:load-stream"))
1038 .Finalize(uri);
1039 if (NS_FAILED(rv)) {
1040 return rv;
1041 }
1042 }
1043
1044 uint32_t loadType = LOAD_NORMAL;
1045 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
1046 if (aLoadInfo) {
1047 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
1048 (void)aLoadInfo->GetLoadType(<);
1049 // Get the appropriate LoadType from nsIDocShellLoadInfo type
1050 loadType = ConvertDocShellInfoLoadTypeToLoadType(lt);
1051 aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
1052 }
1053
1054 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
1055
1056 mLoadType = loadType;
1057
1058 if (!triggeringPrincipal) {
1059 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
1060 }
1061
1062 // build up a channel for this stream.
1063 nsCOMPtr<nsIChannel> channel;
1064 nsCOMPtr<nsIInputStream> stream = aStream;
1065 nsresult rv = NS_NewInputStreamChannel(
1066 getter_AddRefs(channel), uri, stream.forget(), triggeringPrincipal,
1067 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1068 nsIContentPolicy::TYPE_OTHER, aContentType, aContentCharset);
1069 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1070
1071 nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
1072 NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
1073
1074 NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false), NS_ERROR_FAILURE);
1075 return NS_OK;
1076 }
1077
1078 NS_IMETHODIMP
CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)1079 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo) {
1080 nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
1081 nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
1082
1083 localRef.forget(aLoadInfo);
1084 return NS_OK;
1085 }
1086
1087 /*
1088 * Reset state to a new content model within the current document and the
1089 * document viewer. Called by the document before initiating an out of band
1090 * document.write().
1091 */
1092 NS_IMETHODIMP
PrepareForNewContentModel()1093 nsDocShell::PrepareForNewContentModel() {
1094 mEODForCurrentDocument = false;
1095 return NS_OK;
1096 }
1097
1098 NS_IMETHODIMP
FirePageHideNotification(bool aIsUnload)1099 nsDocShell::FirePageHideNotification(bool aIsUnload) {
1100 FirePageHideNotificationInternal(aIsUnload, false);
1101 return NS_OK;
1102 }
1103
FirePageHideNotificationInternal(bool aIsUnload,bool aSkipCheckingDynEntries)1104 void nsDocShell::FirePageHideNotificationInternal(
1105 bool aIsUnload, bool aSkipCheckingDynEntries) {
1106 if (mContentViewer && !mFiredUnloadEvent) {
1107 // Keep an explicit reference since calling PageHide could release
1108 // mContentViewer
1109 nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer);
1110 mFiredUnloadEvent = true;
1111
1112 if (mTiming) {
1113 mTiming->NotifyUnloadEventStart();
1114 }
1115
1116 contentViewer->PageHide(aIsUnload);
1117
1118 if (mTiming) {
1119 mTiming->NotifyUnloadEventEnd();
1120 }
1121
1122 AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
1123 uint32_t n = mChildList.Length();
1124 kids.SetCapacity(n);
1125 for (uint32_t i = 0; i < n; i++) {
1126 kids.AppendElement(do_QueryInterface(ChildAt(i)));
1127 }
1128
1129 n = kids.Length();
1130 for (uint32_t i = 0; i < n; ++i) {
1131 RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get());
1132 if (child) {
1133 // Skip checking dynamic subframe entries in our children.
1134 child->FirePageHideNotificationInternal(aIsUnload, true);
1135 }
1136 }
1137
1138 // If the document is unloading, remove all dynamic subframe entries.
1139 if (aIsUnload && !aSkipCheckingDynEntries) {
1140 nsCOMPtr<nsISHistory> rootSH;
1141 GetRootSessionHistory(getter_AddRefs(rootSH));
1142 nsCOMPtr<nsISHistoryInternal> shPrivate = do_QueryInterface(rootSH);
1143 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE));
1144 if (shPrivate && container) {
1145 int32_t index = -1;
1146 rootSH->GetIndex(&index);
1147 shPrivate->RemoveDynEntries(index, container);
1148 }
1149 }
1150
1151 // Now make sure our editor, if any, is detached before we go
1152 // any farther.
1153 DetachEditorFromWindow();
1154 }
1155 }
1156
DispatchToTabGroup(TaskCategory aCategory,already_AddRefed<nsIRunnable> && aRunnable)1157 nsresult nsDocShell::DispatchToTabGroup(
1158 TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
1159 // Hold the ref so we won't forget to release it.
1160 nsCOMPtr<nsIRunnable> runnable(aRunnable);
1161 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
1162 if (!win) {
1163 // Window should only be unavailable after destroyed.
1164 MOZ_ASSERT(mIsBeingDestroyed);
1165 return NS_ERROR_FAILURE;
1166 }
1167
1168 if (win->GetDocGroup()) {
1169 return win->GetDocGroup()->Dispatch(aCategory, runnable.forget());
1170 }
1171 RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
1172 return tabGroup->Dispatch(aCategory, runnable.forget());
1173 }
1174
1175 NS_IMETHODIMP
DispatchLocationChangeEvent()1176 nsDocShell::DispatchLocationChangeEvent() {
1177 return DispatchToTabGroup(
1178 TaskCategory::Other,
1179 NewRunnableMethod("nsDocShell::FireDummyOnLocationChange", this,
1180 &nsDocShell::FireDummyOnLocationChange));
1181 }
1182
MaybeInitTiming()1183 bool nsDocShell::MaybeInitTiming() {
1184 if (mTiming && !mBlankTiming) {
1185 return false;
1186 }
1187
1188 bool canBeReset = false;
1189
1190 if (mScriptGlobal && mBlankTiming) {
1191 nsPIDOMWindowInner* innerWin =
1192 mScriptGlobal->AsOuter()->GetCurrentInnerWindow();
1193 if (innerWin && innerWin->GetPerformance()) {
1194 mTiming = innerWin->GetPerformance()->GetDOMTiming();
1195 mBlankTiming = false;
1196 }
1197 }
1198
1199 if (!mTiming) {
1200 mTiming = new nsDOMNavigationTiming(this);
1201 canBeReset = true;
1202 }
1203
1204 mTiming->NotifyNavigationStart(
1205 mIsActive ? nsDOMNavigationTiming::DocShellState::eActive
1206 : nsDOMNavigationTiming::DocShellState::eInactive);
1207
1208 return canBeReset;
1209 }
1210
MaybeResetInitTiming(bool aReset)1211 void nsDocShell::MaybeResetInitTiming(bool aReset) {
1212 if (aReset) {
1213 mTiming = nullptr;
1214 }
1215 }
1216
GetNavigationTiming() const1217 nsDOMNavigationTiming* nsDocShell::GetNavigationTiming() const {
1218 return mTiming;
1219 }
1220
1221 //
1222 // Bug 13871: Prevent frameset spoofing
1223 //
1224 // This routine answers: 'Is origin's document from same domain as
1225 // target's document?'
1226 //
1227 // file: uris are considered the same domain for the purpose of
1228 // frame navigation regardless of script accessibility (bug 420425)
1229 //
ValidateOrigin(nsIDocShellTreeItem * aOriginTreeItem,nsIDocShellTreeItem * aTargetTreeItem)1230 /* static */ bool nsDocShell::ValidateOrigin(
1231 nsIDocShellTreeItem* aOriginTreeItem,
1232 nsIDocShellTreeItem* aTargetTreeItem) {
1233 // We want to bypass this check for chrome callers, but only if there's
1234 // JS on the stack. System callers still need to do it.
1235 if (nsContentUtils::GetCurrentJSContext() &&
1236 nsContentUtils::IsCallerChrome()) {
1237 return true;
1238 }
1239
1240 MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells");
1241
1242 // Get origin document principal
1243 nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument();
1244 NS_ENSURE_TRUE(originDocument, false);
1245
1246 // Get target principal
1247 nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument();
1248 NS_ENSURE_TRUE(targetDocument, false);
1249
1250 bool equal;
1251 nsresult rv = originDocument->NodePrincipal()->Equals(
1252 targetDocument->NodePrincipal(), &equal);
1253 if (NS_SUCCEEDED(rv) && equal) {
1254 return true;
1255 }
1256
1257 // Not strictly equal, special case if both are file: uris
1258 bool originIsFile = false;
1259 bool targetIsFile = false;
1260 nsCOMPtr<nsIURI> originURI;
1261 nsCOMPtr<nsIURI> targetURI;
1262 nsCOMPtr<nsIURI> innerOriginURI;
1263 nsCOMPtr<nsIURI> innerTargetURI;
1264
1265 rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
1266 if (NS_SUCCEEDED(rv) && originURI) {
1267 innerOriginURI = NS_GetInnermostURI(originURI);
1268 }
1269
1270 rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
1271 if (NS_SUCCEEDED(rv) && targetURI) {
1272 innerTargetURI = NS_GetInnermostURI(targetURI);
1273 }
1274
1275 return innerOriginURI && innerTargetURI &&
1276 NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
1277 NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
1278 originIsFile && targetIsFile;
1279 }
1280
GetEldestPresContext(nsPresContext ** aPresContext)1281 nsresult nsDocShell::GetEldestPresContext(nsPresContext** aPresContext) {
1282 NS_ENSURE_ARG_POINTER(aPresContext);
1283 *aPresContext = nullptr;
1284
1285 nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
1286 while (viewer) {
1287 nsCOMPtr<nsIContentViewer> prevViewer;
1288 viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1289 if (!prevViewer) {
1290 return viewer->GetPresContext(aPresContext);
1291 }
1292 viewer = prevViewer;
1293 }
1294
1295 return NS_OK;
1296 }
1297
1298 NS_IMETHODIMP
GetPresContext(nsPresContext ** aPresContext)1299 nsDocShell::GetPresContext(nsPresContext** aPresContext) {
1300 NS_ENSURE_ARG_POINTER(aPresContext);
1301 *aPresContext = nullptr;
1302
1303 if (!mContentViewer) {
1304 return NS_OK;
1305 }
1306
1307 return mContentViewer->GetPresContext(aPresContext);
1308 }
1309
NS_IMETHODIMP_(nsIPresShell *)1310 NS_IMETHODIMP_(nsIPresShell*)
1311 nsDocShell::GetPresShell() {
1312 RefPtr<nsPresContext> presContext;
1313 (void)GetPresContext(getter_AddRefs(presContext));
1314 return presContext ? presContext->GetPresShell() : nullptr;
1315 }
1316
1317 NS_IMETHODIMP
GetEldestPresShell(nsIPresShell ** aPresShell)1318 nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell) {
1319 nsresult rv = NS_OK;
1320
1321 NS_ENSURE_ARG_POINTER(aPresShell);
1322 *aPresShell = nullptr;
1323
1324 RefPtr<nsPresContext> presContext;
1325 (void)GetEldestPresContext(getter_AddRefs(presContext));
1326
1327 if (presContext) {
1328 NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
1329 }
1330
1331 return rv;
1332 }
1333
1334 NS_IMETHODIMP
GetContentViewer(nsIContentViewer ** aContentViewer)1335 nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer) {
1336 NS_ENSURE_ARG_POINTER(aContentViewer);
1337
1338 *aContentViewer = mContentViewer;
1339 NS_IF_ADDREF(*aContentViewer);
1340 return NS_OK;
1341 }
1342
1343 NS_IMETHODIMP
SetChromeEventHandler(nsIDOMEventTarget * aChromeEventHandler)1344 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler) {
1345 mChromeEventHandler = do_QueryInterface(aChromeEventHandler);
1346
1347 if (mScriptGlobal) {
1348 mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
1349 }
1350
1351 return NS_OK;
1352 }
1353
1354 NS_IMETHODIMP
GetChromeEventHandler(nsIDOMEventTarget ** aChromeEventHandler)1355 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler) {
1356 NS_ENSURE_ARG_POINTER(aChromeEventHandler);
1357 nsCOMPtr<EventTarget> handler = mChromeEventHandler;
1358 handler.forget(aChromeEventHandler);
1359 return NS_OK;
1360 }
1361
1362 NS_IMETHODIMP
SetCurrentURI(nsIURI * aURI)1363 nsDocShell::SetCurrentURI(nsIURI* aURI) {
1364 // Note that securityUI will set STATE_IS_INSECURE, even if
1365 // the scheme of |aURI| is "https".
1366 SetCurrentURI(aURI, nullptr, true, 0);
1367 return NS_OK;
1368 }
1369
SetCurrentURI(nsIURI * aURI,nsIRequest * aRequest,bool aFireOnLocationChange,uint32_t aLocationFlags)1370 bool nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
1371 bool aFireOnLocationChange,
1372 uint32_t aLocationFlags) {
1373 MOZ_ASSERT(!mIsBeingDestroyed);
1374
1375 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
1376 ("DOCSHELL %p SetCurrentURI %s\n", this,
1377 aURI ? aURI->GetSpecOrDefault().get() : ""));
1378
1379 // We don't want to send a location change when we're displaying an error
1380 // page, and we don't want to change our idea of "current URI" either
1381 if (mLoadType == LOAD_ERROR_PAGE) {
1382 return false;
1383 }
1384
1385 mCurrentURI = NS_TryToMakeImmutable(aURI);
1386
1387 if (!NS_IsAboutBlank(mCurrentURI)) {
1388 mHasLoadedNonBlankURI = true;
1389 }
1390
1391 bool isRoot = false; // Is this the root docshell
1392 bool isSubFrame = false; // Is this a subframe navigation?
1393
1394 nsCOMPtr<nsIDocShellTreeItem> root;
1395
1396 GetSameTypeRootTreeItem(getter_AddRefs(root));
1397 if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
1398 // This is the root docshell
1399 isRoot = true;
1400 }
1401 if (mLSHE) {
1402 mLSHE->GetIsSubFrame(&isSubFrame);
1403 }
1404
1405 if (!isSubFrame && !isRoot) {
1406 /*
1407 * We don't want to send OnLocationChange notifications when
1408 * a subframe is being loaded for the first time, while
1409 * visiting a frameset page
1410 */
1411 return false;
1412 }
1413
1414 if (aFireOnLocationChange) {
1415 FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
1416 }
1417 return !aFireOnLocationChange;
1418 }
1419
1420 NS_IMETHODIMP
GetCharset(nsACString & aCharset)1421 nsDocShell::GetCharset(nsACString& aCharset) {
1422 aCharset.Truncate();
1423
1424 nsIPresShell* presShell = GetPresShell();
1425 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
1426 nsIDocument* doc = presShell->GetDocument();
1427 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
1428 doc->GetDocumentCharacterSet()->Name(aCharset);
1429 return NS_OK;
1430 }
1431
1432 NS_IMETHODIMP
GatherCharsetMenuTelemetry()1433 nsDocShell::GatherCharsetMenuTelemetry() {
1434 nsCOMPtr<nsIContentViewer> viewer;
1435 GetContentViewer(getter_AddRefs(viewer));
1436 if (!viewer) {
1437 return NS_OK;
1438 }
1439
1440 nsIDocument* doc = viewer->GetDocument();
1441 if (!doc || doc->WillIgnoreCharsetOverride()) {
1442 return NS_OK;
1443 }
1444
1445 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
1446
1447 bool isFileURL = false;
1448 nsIURI* url = doc->GetOriginalURI();
1449 if (url) {
1450 url->SchemeIs("file", &isFileURL);
1451 }
1452
1453 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
1454 switch (charsetSource) {
1455 case kCharsetFromTopLevelDomain:
1456 // Unlabeled doc on a domain that we map to a fallback encoding
1457 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7);
1458 break;
1459 case kCharsetFromFallback:
1460 case kCharsetFromDocTypeDefault:
1461 case kCharsetFromCache:
1462 case kCharsetFromParentFrame:
1463 case kCharsetFromHintPrevDoc:
1464 // Changing charset on an unlabeled doc.
1465 if (isFileURL) {
1466 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
1467 } else {
1468 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
1469 }
1470 break;
1471 case kCharsetFromAutoDetection:
1472 // Changing charset on unlabeled doc where chardet fired
1473 if (isFileURL) {
1474 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
1475 } else {
1476 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
1477 }
1478 break;
1479 case kCharsetFromMetaPrescan:
1480 case kCharsetFromMetaTag:
1481 case kCharsetFromChannel:
1482 // Changing charset on a doc that had a charset label.
1483 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
1484 break;
1485 case kCharsetFromParentForced:
1486 case kCharsetFromUserForced:
1487 // Changing charset on a document that already had an override.
1488 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
1489 break;
1490 case kCharsetFromIrreversibleAutoDetection:
1491 case kCharsetFromOtherComponent:
1492 case kCharsetFromByteOrderMark:
1493 case kCharsetUninitialized:
1494 default:
1495 // Bug. This isn't supposed to happen.
1496 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
1497 break;
1498 }
1499 return NS_OK;
1500 }
1501
1502 NS_IMETHODIMP
SetCharset(const nsACString & aCharset)1503 nsDocShell::SetCharset(const nsACString& aCharset) {
1504 // set the charset override
1505 return SetForcedCharset(aCharset);
1506 }
1507
1508 NS_IMETHODIMP
SetForcedCharset(const nsACString & aCharset)1509 nsDocShell::SetForcedCharset(const nsACString& aCharset) {
1510 if (aCharset.IsEmpty()) {
1511 mForcedCharset = nullptr;
1512 return NS_OK;
1513 }
1514 const Encoding* encoding = Encoding::ForLabel(aCharset);
1515 if (!encoding) {
1516 // Reject unknown labels
1517 return NS_ERROR_INVALID_ARG;
1518 }
1519 if (!encoding->IsAsciiCompatible() && encoding != ISO_2022_JP_ENCODING) {
1520 // Reject XSS hazards
1521 return NS_ERROR_INVALID_ARG;
1522 }
1523 mForcedCharset = encoding;
1524 return NS_OK;
1525 }
1526
1527 NS_IMETHODIMP
GetForcedCharset(nsACString & aResult)1528 nsDocShell::GetForcedCharset(nsACString& aResult) {
1529 if (mForcedCharset) {
1530 mForcedCharset->Name(aResult);
1531 } else {
1532 aResult.Truncate();
1533 }
1534 return NS_OK;
1535 }
1536
SetParentCharset(const Encoding * & aCharset,int32_t aCharsetSource,nsIPrincipal * aPrincipal)1537 void nsDocShell::SetParentCharset(const Encoding*& aCharset,
1538 int32_t aCharsetSource,
1539 nsIPrincipal* aPrincipal) {
1540 mParentCharset = aCharset;
1541 mParentCharsetSource = aCharsetSource;
1542 mParentCharsetPrincipal = aPrincipal;
1543 }
1544
GetParentCharset(const Encoding * & aCharset,int32_t * aCharsetSource,nsIPrincipal ** aPrincipal)1545 void nsDocShell::GetParentCharset(const Encoding*& aCharset,
1546 int32_t* aCharsetSource,
1547 nsIPrincipal** aPrincipal) {
1548 aCharset = mParentCharset;
1549 *aCharsetSource = mParentCharsetSource;
1550 NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
1551 }
1552
1553 NS_IMETHODIMP
GetChannelIsUnsafe(bool * aUnsafe)1554 nsDocShell::GetChannelIsUnsafe(bool* aUnsafe) {
1555 *aUnsafe = false;
1556
1557 nsIChannel* channel = GetCurrentDocChannel();
1558 if (!channel) {
1559 return NS_OK;
1560 }
1561
1562 nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
1563 if (!jarChannel) {
1564 return NS_OK;
1565 }
1566
1567 return jarChannel->GetIsUnsafe(aUnsafe);
1568 }
1569
1570 NS_IMETHODIMP
GetHasMixedActiveContentLoaded(bool * aHasMixedActiveContentLoaded)1571 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded) {
1572 nsCOMPtr<nsIDocument> doc(GetDocument());
1573 *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
1574 return NS_OK;
1575 }
1576
1577 NS_IMETHODIMP
GetHasMixedActiveContentBlocked(bool * aHasMixedActiveContentBlocked)1578 nsDocShell::GetHasMixedActiveContentBlocked(
1579 bool* aHasMixedActiveContentBlocked) {
1580 nsCOMPtr<nsIDocument> doc(GetDocument());
1581 *aHasMixedActiveContentBlocked =
1582 doc && doc->GetHasMixedActiveContentBlocked();
1583 return NS_OK;
1584 }
1585
1586 NS_IMETHODIMP
GetHasMixedDisplayContentLoaded(bool * aHasMixedDisplayContentLoaded)1587 nsDocShell::GetHasMixedDisplayContentLoaded(
1588 bool* aHasMixedDisplayContentLoaded) {
1589 nsCOMPtr<nsIDocument> doc(GetDocument());
1590 *aHasMixedDisplayContentLoaded =
1591 doc && doc->GetHasMixedDisplayContentLoaded();
1592 return NS_OK;
1593 }
1594
1595 NS_IMETHODIMP
GetHasMixedDisplayContentBlocked(bool * aHasMixedDisplayContentBlocked)1596 nsDocShell::GetHasMixedDisplayContentBlocked(
1597 bool* aHasMixedDisplayContentBlocked) {
1598 nsCOMPtr<nsIDocument> doc(GetDocument());
1599 *aHasMixedDisplayContentBlocked =
1600 doc && doc->GetHasMixedDisplayContentBlocked();
1601 return NS_OK;
1602 }
1603
1604 NS_IMETHODIMP
GetHasTrackingContentBlocked(bool * aHasTrackingContentBlocked)1605 nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked) {
1606 nsCOMPtr<nsIDocument> doc(GetDocument());
1607 *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked();
1608 return NS_OK;
1609 }
1610
1611 NS_IMETHODIMP
GetHasTrackingContentLoaded(bool * aHasTrackingContentLoaded)1612 nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded) {
1613 nsCOMPtr<nsIDocument> doc(GetDocument());
1614 *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded();
1615 return NS_OK;
1616 }
1617
1618 NS_IMETHODIMP
GetAllowPlugins(bool * aAllowPlugins)1619 nsDocShell::GetAllowPlugins(bool* aAllowPlugins) {
1620 NS_ENSURE_ARG_POINTER(aAllowPlugins);
1621
1622 *aAllowPlugins = mAllowPlugins;
1623 if (!mAllowPlugins) {
1624 return NS_OK;
1625 }
1626
1627 bool unsafe;
1628 *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
1629 return NS_OK;
1630 }
1631
1632 NS_IMETHODIMP
SetAllowPlugins(bool aAllowPlugins)1633 nsDocShell::SetAllowPlugins(bool aAllowPlugins) {
1634 mAllowPlugins = aAllowPlugins;
1635 // XXX should enable or disable a plugin host
1636 return NS_OK;
1637 }
1638
1639 NS_IMETHODIMP
GetAllowJavascript(bool * aAllowJavascript)1640 nsDocShell::GetAllowJavascript(bool* aAllowJavascript) {
1641 NS_ENSURE_ARG_POINTER(aAllowJavascript);
1642
1643 *aAllowJavascript = mAllowJavascript;
1644 return NS_OK;
1645 }
1646
1647 NS_IMETHODIMP
SetAllowJavascript(bool aAllowJavascript)1648 nsDocShell::SetAllowJavascript(bool aAllowJavascript) {
1649 mAllowJavascript = aAllowJavascript;
1650 RecomputeCanExecuteScripts();
1651 return NS_OK;
1652 }
1653
1654 NS_IMETHODIMP
GetUsePrivateBrowsing(bool * aUsePrivateBrowsing)1655 nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) {
1656 NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
1657 AssertOriginAttributesMatchPrivateBrowsing();
1658 *aUsePrivateBrowsing = mPrivateBrowsingId > 0;
1659 return NS_OK;
1660 }
1661
1662 NS_IMETHODIMP
SetUsePrivateBrowsing(bool aUsePrivateBrowsing)1663 nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) {
1664 nsContentUtils::ReportToConsoleNonLocalized(
1665 NS_LITERAL_STRING("Only internal code is allowed to set the "
1666 "usePrivateBrowsing attribute"),
1667 nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Internal API Used"),
1668 mContentViewer ? mContentViewer->GetDocument() : nullptr);
1669
1670 if (!CanSetOriginAttributes()) {
1671 bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
1672
1673 return changed ? NS_ERROR_FAILURE : NS_OK;
1674 }
1675
1676 return SetPrivateBrowsing(aUsePrivateBrowsing);
1677 }
1678
1679 NS_IMETHODIMP
SetPrivateBrowsing(bool aUsePrivateBrowsing)1680 nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing) {
1681 MOZ_ASSERT(!mIsBeingDestroyed);
1682
1683 bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
1684 if (changed) {
1685 mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0;
1686
1687 if (mItemType != typeChrome) {
1688 mOriginAttributes.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing);
1689 }
1690
1691 if (mAffectPrivateSessionLifetime) {
1692 if (aUsePrivateBrowsing) {
1693 IncreasePrivateDocShellCount();
1694 } else {
1695 DecreasePrivateDocShellCount();
1696 }
1697 }
1698 }
1699
1700 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
1701 while (iter.HasMore()) {
1702 nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
1703 if (shell) {
1704 shell->SetPrivateBrowsing(aUsePrivateBrowsing);
1705 }
1706 }
1707
1708 if (changed) {
1709 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
1710 while (iter.HasMore()) {
1711 nsWeakPtr ref = iter.GetNext();
1712 nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
1713 if (!obs) {
1714 mPrivacyObservers.RemoveElement(ref);
1715 } else {
1716 obs->PrivateModeChanged(aUsePrivateBrowsing);
1717 }
1718 }
1719 }
1720
1721 AssertOriginAttributesMatchPrivateBrowsing();
1722 return NS_OK;
1723 }
1724
1725 NS_IMETHODIMP
GetHasLoadedNonBlankURI(bool * aResult)1726 nsDocShell::GetHasLoadedNonBlankURI(bool* aResult) {
1727 NS_ENSURE_ARG_POINTER(aResult);
1728
1729 *aResult = mHasLoadedNonBlankURI;
1730 return NS_OK;
1731 }
1732
1733 NS_IMETHODIMP
GetUseRemoteTabs(bool * aUseRemoteTabs)1734 nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) {
1735 NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
1736
1737 *aUseRemoteTabs = mUseRemoteTabs;
1738 return NS_OK;
1739 }
1740
1741 NS_IMETHODIMP
SetRemoteTabs(bool aUseRemoteTabs)1742 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) {
1743 if (aUseRemoteTabs) {
1744 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
1745 NS_LITERAL_CSTRING("1"));
1746 }
1747
1748 mUseRemoteTabs = aUseRemoteTabs;
1749 return NS_OK;
1750 }
1751
1752 NS_IMETHODIMP
SetAffectPrivateSessionLifetime(bool aAffectLifetime)1753 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime) {
1754 MOZ_ASSERT(!mIsBeingDestroyed);
1755
1756 bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
1757 if (change && UsePrivateBrowsing()) {
1758 AssertOriginAttributesMatchPrivateBrowsing();
1759 if (aAffectLifetime) {
1760 IncreasePrivateDocShellCount();
1761 } else {
1762 DecreasePrivateDocShellCount();
1763 }
1764 }
1765 mAffectPrivateSessionLifetime = aAffectLifetime;
1766
1767 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
1768 while (iter.HasMore()) {
1769 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
1770 if (shell) {
1771 shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
1772 }
1773 }
1774 return NS_OK;
1775 }
1776
1777 NS_IMETHODIMP
GetAffectPrivateSessionLifetime(bool * aAffectLifetime)1778 nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime) {
1779 *aAffectLifetime = mAffectPrivateSessionLifetime;
1780 return NS_OK;
1781 }
1782
1783 NS_IMETHODIMP
AddWeakPrivacyTransitionObserver(nsIPrivacyTransitionObserver * aObserver)1784 nsDocShell::AddWeakPrivacyTransitionObserver(
1785 nsIPrivacyTransitionObserver* aObserver) {
1786 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
1787 if (!weakObs) {
1788 return NS_ERROR_NOT_AVAILABLE;
1789 }
1790 return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
1791 }
1792
1793 NS_IMETHODIMP
AddWeakReflowObserver(nsIReflowObserver * aObserver)1794 nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver) {
1795 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
1796 if (!weakObs) {
1797 return NS_ERROR_FAILURE;
1798 }
1799 return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
1800 }
1801
1802 NS_IMETHODIMP
RemoveWeakReflowObserver(nsIReflowObserver * aObserver)1803 nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver) {
1804 nsWeakPtr obs = do_GetWeakReference(aObserver);
1805 return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
1806 }
1807
1808 NS_IMETHODIMP
NotifyReflowObservers(bool aInterruptible,DOMHighResTimeStamp aStart,DOMHighResTimeStamp aEnd)1809 nsDocShell::NotifyReflowObservers(bool aInterruptible,
1810 DOMHighResTimeStamp aStart,
1811 DOMHighResTimeStamp aEnd) {
1812 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
1813 while (iter.HasMore()) {
1814 nsWeakPtr ref = iter.GetNext();
1815 nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
1816 if (!obs) {
1817 mReflowObservers.RemoveElement(ref);
1818 } else if (aInterruptible) {
1819 obs->ReflowInterruptible(aStart, aEnd);
1820 } else {
1821 obs->Reflow(aStart, aEnd);
1822 }
1823 }
1824 return NS_OK;
1825 }
1826
1827 NS_IMETHODIMP
GetAllowMetaRedirects(bool * aReturn)1828 nsDocShell::GetAllowMetaRedirects(bool* aReturn) {
1829 NS_ENSURE_ARG_POINTER(aReturn);
1830
1831 *aReturn = mAllowMetaRedirects;
1832 if (!mAllowMetaRedirects) {
1833 return NS_OK;
1834 }
1835
1836 bool unsafe;
1837 *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
1838 return NS_OK;
1839 }
1840
1841 NS_IMETHODIMP
SetAllowMetaRedirects(bool aValue)1842 nsDocShell::SetAllowMetaRedirects(bool aValue) {
1843 mAllowMetaRedirects = aValue;
1844 return NS_OK;
1845 }
1846
1847 NS_IMETHODIMP
GetAllowSubframes(bool * aAllowSubframes)1848 nsDocShell::GetAllowSubframes(bool* aAllowSubframes) {
1849 NS_ENSURE_ARG_POINTER(aAllowSubframes);
1850
1851 *aAllowSubframes = mAllowSubframes;
1852 return NS_OK;
1853 }
1854
1855 NS_IMETHODIMP
SetAllowSubframes(bool aAllowSubframes)1856 nsDocShell::SetAllowSubframes(bool aAllowSubframes) {
1857 mAllowSubframes = aAllowSubframes;
1858 return NS_OK;
1859 }
1860
1861 NS_IMETHODIMP
GetAllowImages(bool * aAllowImages)1862 nsDocShell::GetAllowImages(bool* aAllowImages) {
1863 NS_ENSURE_ARG_POINTER(aAllowImages);
1864
1865 *aAllowImages = mAllowImages;
1866 return NS_OK;
1867 }
1868
1869 NS_IMETHODIMP
SetAllowImages(bool aAllowImages)1870 nsDocShell::SetAllowImages(bool aAllowImages) {
1871 mAllowImages = aAllowImages;
1872 return NS_OK;
1873 }
1874
1875 NS_IMETHODIMP
GetAllowMedia(bool * aAllowMedia)1876 nsDocShell::GetAllowMedia(bool* aAllowMedia) {
1877 *aAllowMedia = mAllowMedia;
1878 return NS_OK;
1879 }
1880
1881 NS_IMETHODIMP
SetAllowMedia(bool aAllowMedia)1882 nsDocShell::SetAllowMedia(bool aAllowMedia) {
1883 mAllowMedia = aAllowMedia;
1884
1885 // Mute or unmute audio contexts attached to the inner window.
1886 if (mScriptGlobal) {
1887 if (nsPIDOMWindowInner* innerWin =
1888 mScriptGlobal->AsOuter()->GetCurrentInnerWindow()) {
1889 if (aAllowMedia) {
1890 innerWin->UnmuteAudioContexts();
1891 } else {
1892 innerWin->MuteAudioContexts();
1893 }
1894 }
1895 }
1896
1897 return NS_OK;
1898 }
1899
1900 NS_IMETHODIMP
GetAllowDNSPrefetch(bool * aAllowDNSPrefetch)1901 nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch) {
1902 *aAllowDNSPrefetch = mAllowDNSPrefetch;
1903 return NS_OK;
1904 }
1905
1906 NS_IMETHODIMP
SetAllowDNSPrefetch(bool aAllowDNSPrefetch)1907 nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch) {
1908 mAllowDNSPrefetch = aAllowDNSPrefetch;
1909 return NS_OK;
1910 }
1911
1912 NS_IMETHODIMP
GetAllowWindowControl(bool * aAllowWindowControl)1913 nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl) {
1914 *aAllowWindowControl = mAllowWindowControl;
1915 return NS_OK;
1916 }
1917
1918 NS_IMETHODIMP
SetAllowWindowControl(bool aAllowWindowControl)1919 nsDocShell::SetAllowWindowControl(bool aAllowWindowControl) {
1920 mAllowWindowControl = aAllowWindowControl;
1921 return NS_OK;
1922 }
1923
1924 NS_IMETHODIMP
GetAllowContentRetargeting(bool * aAllowContentRetargeting)1925 nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting) {
1926 *aAllowContentRetargeting = mAllowContentRetargeting;
1927 return NS_OK;
1928 }
1929
1930 NS_IMETHODIMP
SetAllowContentRetargeting(bool aAllowContentRetargeting)1931 nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting) {
1932 mAllowContentRetargetingOnChildren = aAllowContentRetargeting;
1933 mAllowContentRetargeting = aAllowContentRetargeting;
1934 return NS_OK;
1935 }
1936
1937 NS_IMETHODIMP
GetAllowContentRetargetingOnChildren(bool * aAllowContentRetargetingOnChildren)1938 nsDocShell::GetAllowContentRetargetingOnChildren(
1939 bool* aAllowContentRetargetingOnChildren) {
1940 *aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren;
1941 return NS_OK;
1942 }
1943
1944 NS_IMETHODIMP
SetAllowContentRetargetingOnChildren(bool aAllowContentRetargetingOnChildren)1945 nsDocShell::SetAllowContentRetargetingOnChildren(
1946 bool aAllowContentRetargetingOnChildren) {
1947 mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren;
1948 return NS_OK;
1949 }
1950
1951 NS_IMETHODIMP
GetInheritPrivateBrowsingId(bool * aInheritPrivateBrowsingId)1952 nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId) {
1953 *aInheritPrivateBrowsingId = mInheritPrivateBrowsingId;
1954 return NS_OK;
1955 }
1956
1957 NS_IMETHODIMP
SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId)1958 nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId) {
1959 mInheritPrivateBrowsingId = aInheritPrivateBrowsingId;
1960 return NS_OK;
1961 }
1962
1963 NS_IMETHODIMP
GetFullscreenAllowed(bool * aFullscreenAllowed)1964 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) {
1965 NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
1966
1967 // Browsers and apps have their mFullscreenAllowed retrieved from their
1968 // corresponding iframe in their parent upon creation.
1969 if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
1970 *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
1971 return NS_OK;
1972 }
1973
1974 // Assume false until we determine otherwise...
1975 *aFullscreenAllowed = false;
1976
1977 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
1978 if (!win) {
1979 return NS_OK;
1980 }
1981 if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
1982 if (frameElement->IsXULElement()) {
1983 if (frameElement->HasAttr(kNameSpaceID_None,
1984 nsGkAtoms::disablefullscreen)) {
1985 // Document inside this frame is explicitly disabled.
1986 return NS_OK;
1987 }
1988 } else {
1989 // We do not allow document inside any containing element other
1990 // than iframe to enter fullscreen.
1991 if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
1992 // If any ancestor iframe does not have allowfullscreen attribute
1993 // set, then fullscreen is not allowed.
1994 if (!frameElement->HasAttr(kNameSpaceID_None,
1995 nsGkAtoms::allowfullscreen) &&
1996 !frameElement->HasAttr(kNameSpaceID_None,
1997 nsGkAtoms::mozallowfullscreen)) {
1998 return NS_OK;
1999 }
2000 } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
2001 // Respect allowfullscreen only if this is a rewritten YouTube embed.
2002 nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
2003 do_QueryInterface(frameElement);
2004 if (!objectLoadingContent) {
2005 return NS_OK;
2006 }
2007 nsObjectLoadingContent* olc =
2008 static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
2009 if (!olc->IsRewrittenYoutubeEmbed()) {
2010 return NS_OK;
2011 }
2012 // We don't have to check prefixed attributes because Flash does not
2013 // support them.
2014 if (!frameElement->HasAttr(kNameSpaceID_None,
2015 nsGkAtoms::allowfullscreen)) {
2016 return NS_OK;
2017 }
2018 } else {
2019 // neither iframe nor embed
2020 return NS_OK;
2021 }
2022 }
2023 }
2024
2025 // If we have no parent then we're the root docshell; no ancestor of the
2026 // original docshell doesn't have a allowfullscreen attribute, so
2027 // report fullscreen as allowed.
2028 RefPtr<nsDocShell> parent = GetParentDocshell();
2029 if (!parent) {
2030 *aFullscreenAllowed = true;
2031 return NS_OK;
2032 }
2033
2034 // Otherwise, we have a parent, continue the checking for
2035 // mozFullscreenAllowed in the parent docshell's ancestors.
2036 return parent->GetFullscreenAllowed(aFullscreenAllowed);
2037 }
2038
2039 NS_IMETHODIMP
SetFullscreenAllowed(bool aFullscreenAllowed)2040 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed) {
2041 if (!nsIDocShell::GetIsMozBrowser()) {
2042 // Only allow setting of fullscreenAllowed on content/process boundaries.
2043 // At non-boundaries the fullscreenAllowed attribute is calculated based on
2044 // whether all enclosing frames have the "mozFullscreenAllowed" attribute
2045 // set to "true". fullscreenAllowed is set at the process boundaries to
2046 // propagate the value of the parent's "mozFullscreenAllowed" attribute
2047 // across process boundaries.
2048 return NS_ERROR_UNEXPECTED;
2049 }
2050 mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
2051 return NS_OK;
2052 }
2053
OrientationLock()2054 ScreenOrientationInternal nsDocShell::OrientationLock() {
2055 return mOrientationLock;
2056 }
2057
SetOrientationLock(ScreenOrientationInternal aOrientationLock)2058 void nsDocShell::SetOrientationLock(
2059 ScreenOrientationInternal aOrientationLock) {
2060 mOrientationLock = aOrientationLock;
2061 }
2062
2063 NS_IMETHODIMP
GetMayEnableCharacterEncodingMenu(bool * aMayEnableCharacterEncodingMenu)2064 nsDocShell::GetMayEnableCharacterEncodingMenu(
2065 bool* aMayEnableCharacterEncodingMenu) {
2066 *aMayEnableCharacterEncodingMenu = false;
2067 if (!mContentViewer) {
2068 return NS_OK;
2069 }
2070 nsIDocument* doc = mContentViewer->GetDocument();
2071 if (!doc) {
2072 return NS_OK;
2073 }
2074 if (doc->WillIgnoreCharsetOverride()) {
2075 return NS_OK;
2076 }
2077
2078 *aMayEnableCharacterEncodingMenu = true;
2079 return NS_OK;
2080 }
2081
2082 NS_IMETHODIMP
GetDocShellEnumerator(int32_t aItemType,int32_t aDirection,nsISimpleEnumerator ** aResult)2083 nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection,
2084 nsISimpleEnumerator** aResult) {
2085 NS_ENSURE_ARG_POINTER(aResult);
2086 *aResult = nullptr;
2087
2088 RefPtr<nsDocShellEnumerator> docShellEnum;
2089 if (aDirection == ENUMERATE_FORWARDS) {
2090 docShellEnum = new nsDocShellForwardsEnumerator;
2091 } else {
2092 docShellEnum = new nsDocShellBackwardsEnumerator;
2093 }
2094
2095 nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
2096 if (NS_FAILED(rv)) {
2097 return rv;
2098 }
2099
2100 rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
2101 if (NS_FAILED(rv)) {
2102 return rv;
2103 }
2104
2105 rv = docShellEnum->First();
2106 if (NS_FAILED(rv)) {
2107 return rv;
2108 }
2109
2110 rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
2111 (void**)aResult);
2112
2113 return rv;
2114 }
2115
2116 NS_IMETHODIMP
GetAppType(uint32_t * aAppType)2117 nsDocShell::GetAppType(uint32_t* aAppType) {
2118 *aAppType = mAppType;
2119 return NS_OK;
2120 }
2121
2122 NS_IMETHODIMP
SetAppType(uint32_t aAppType)2123 nsDocShell::SetAppType(uint32_t aAppType) {
2124 mAppType = aAppType;
2125 return NS_OK;
2126 }
2127
2128 NS_IMETHODIMP
GetAllowAuth(bool * aAllowAuth)2129 nsDocShell::GetAllowAuth(bool* aAllowAuth) {
2130 *aAllowAuth = mAllowAuth;
2131 return NS_OK;
2132 }
2133
2134 NS_IMETHODIMP
SetAllowAuth(bool aAllowAuth)2135 nsDocShell::SetAllowAuth(bool aAllowAuth) {
2136 mAllowAuth = aAllowAuth;
2137 return NS_OK;
2138 }
2139
2140 NS_IMETHODIMP
GetZoom(float * aZoom)2141 nsDocShell::GetZoom(float* aZoom) {
2142 NS_ENSURE_ARG_POINTER(aZoom);
2143 *aZoom = 1.0f;
2144 return NS_OK;
2145 }
2146
2147 NS_IMETHODIMP
SetZoom(float aZoom)2148 nsDocShell::SetZoom(float aZoom) { return NS_ERROR_NOT_IMPLEMENTED; }
2149
2150 NS_IMETHODIMP
GetMarginWidth(int32_t * aWidth)2151 nsDocShell::GetMarginWidth(int32_t* aWidth) {
2152 NS_ENSURE_ARG_POINTER(aWidth);
2153
2154 *aWidth = mMarginWidth;
2155 return NS_OK;
2156 }
2157
2158 NS_IMETHODIMP
SetMarginWidth(int32_t aWidth)2159 nsDocShell::SetMarginWidth(int32_t aWidth) {
2160 mMarginWidth = aWidth;
2161 return NS_OK;
2162 }
2163
2164 NS_IMETHODIMP
GetMarginHeight(int32_t * aHeight)2165 nsDocShell::GetMarginHeight(int32_t* aHeight) {
2166 NS_ENSURE_ARG_POINTER(aHeight);
2167
2168 *aHeight = mMarginHeight;
2169 return NS_OK;
2170 }
2171
2172 NS_IMETHODIMP
SetMarginHeight(int32_t aHeight)2173 nsDocShell::SetMarginHeight(int32_t aHeight) {
2174 mMarginHeight = aHeight;
2175 return NS_OK;
2176 }
2177
2178 NS_IMETHODIMP
GetBusyFlags(uint32_t * aBusyFlags)2179 nsDocShell::GetBusyFlags(uint32_t* aBusyFlags) {
2180 NS_ENSURE_ARG_POINTER(aBusyFlags);
2181
2182 *aBusyFlags = mBusyFlags;
2183 return NS_OK;
2184 }
2185
2186 NS_IMETHODIMP
TabToTreeOwner(bool aForward,bool aForDocumentNavigation,bool * aTookFocus)2187 nsDocShell::TabToTreeOwner(bool aForward, bool aForDocumentNavigation,
2188 bool* aTookFocus) {
2189 NS_ENSURE_ARG_POINTER(aTookFocus);
2190
2191 nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
2192 if (chromeFocus) {
2193 if (aForward) {
2194 *aTookFocus =
2195 NS_SUCCEEDED(chromeFocus->FocusNextElement(aForDocumentNavigation));
2196 } else {
2197 *aTookFocus =
2198 NS_SUCCEEDED(chromeFocus->FocusPrevElement(aForDocumentNavigation));
2199 }
2200 } else {
2201 *aTookFocus = false;
2202 }
2203
2204 return NS_OK;
2205 }
2206
2207 NS_IMETHODIMP
GetSecurityUI(nsISecureBrowserUI ** aSecurityUI)2208 nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI) {
2209 NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
2210 return NS_OK;
2211 }
2212
2213 NS_IMETHODIMP
SetSecurityUI(nsISecureBrowserUI * aSecurityUI)2214 nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI) {
2215 MOZ_ASSERT(!mIsBeingDestroyed);
2216
2217 mSecurityUI = aSecurityUI;
2218 mSecurityUI->SetDocShell(this);
2219 return NS_OK;
2220 }
2221
2222 NS_IMETHODIMP
GetLoadURIDelegate(nsILoadURIDelegate ** aLoadURIDelegate)2223 nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate** aLoadURIDelegate) {
2224 NS_IF_ADDREF(*aLoadURIDelegate = mLoadURIDelegate);
2225 return NS_OK;
2226 }
2227
2228 NS_IMETHODIMP
SetLoadURIDelegate(nsILoadURIDelegate * aLoadURIDelegate)2229 nsDocShell::SetLoadURIDelegate(nsILoadURIDelegate* aLoadURIDelegate) {
2230 mLoadURIDelegate = aLoadURIDelegate;
2231 return NS_OK;
2232 }
2233
2234 NS_IMETHODIMP
GetUseErrorPages(bool * aUseErrorPages)2235 nsDocShell::GetUseErrorPages(bool* aUseErrorPages) {
2236 *aUseErrorPages = UseErrorPages();
2237 return NS_OK;
2238 }
2239
2240 NS_IMETHODIMP
SetUseErrorPages(bool aUseErrorPages)2241 nsDocShell::SetUseErrorPages(bool aUseErrorPages) {
2242 // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
2243 if (mObserveErrorPages) {
2244 mObserveErrorPages = false;
2245 }
2246 mUseErrorPages = aUseErrorPages;
2247 return NS_OK;
2248 }
2249
2250 NS_IMETHODIMP
GetPreviousTransIndex(int32_t * aPreviousTransIndex)2251 nsDocShell::GetPreviousTransIndex(int32_t* aPreviousTransIndex) {
2252 *aPreviousTransIndex = mPreviousTransIndex;
2253 return NS_OK;
2254 }
2255
2256 NS_IMETHODIMP
GetLoadedTransIndex(int32_t * aLoadedTransIndex)2257 nsDocShell::GetLoadedTransIndex(int32_t* aLoadedTransIndex) {
2258 *aLoadedTransIndex = mLoadedTransIndex;
2259 return NS_OK;
2260 }
2261
2262 NS_IMETHODIMP
HistoryPurged(int32_t aNumEntries)2263 nsDocShell::HistoryPurged(int32_t aNumEntries) {
2264 // These indices are used for fastback cache eviction, to determine
2265 // which session history entries are candidates for content viewer
2266 // eviction. We need to adjust by the number of entries that we
2267 // just purged from history, so that we look at the right session history
2268 // entries during eviction.
2269 mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
2270 mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
2271
2272 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2273 while (iter.HasMore()) {
2274 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2275 if (shell) {
2276 shell->HistoryPurged(aNumEntries);
2277 }
2278 }
2279
2280 return NS_OK;
2281 }
2282
HistoryTransactionRemoved(int32_t aIndex)2283 nsresult nsDocShell::HistoryTransactionRemoved(int32_t aIndex) {
2284 // These indices are used for fastback cache eviction, to determine
2285 // which session history entries are candidates for content viewer
2286 // eviction. We need to adjust by the number of entries that we
2287 // just purged from history, so that we look at the right session history
2288 // entries during eviction.
2289 if (aIndex == mPreviousTransIndex) {
2290 mPreviousTransIndex = -1;
2291 } else if (aIndex < mPreviousTransIndex) {
2292 --mPreviousTransIndex;
2293 }
2294 if (mLoadedTransIndex == aIndex) {
2295 mLoadedTransIndex = 0;
2296 } else if (aIndex < mLoadedTransIndex) {
2297 --mLoadedTransIndex;
2298 }
2299
2300 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2301 while (iter.HasMore()) {
2302 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2303 if (shell) {
2304 static_cast<nsDocShell*>(shell.get())->HistoryTransactionRemoved(aIndex);
2305 }
2306 }
2307
2308 return NS_OK;
2309 }
2310
2311 NS_IMETHODIMP
SetRecordProfileTimelineMarkers(bool aValue)2312 nsDocShell::SetRecordProfileTimelineMarkers(bool aValue) {
2313 bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
2314 if (currentValue == aValue) {
2315 return NS_OK;
2316 }
2317
2318 RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
2319 if (!timelines) {
2320 return NS_OK;
2321 }
2322
2323 if (aValue) {
2324 MOZ_ASSERT(!timelines->HasConsumer(this));
2325 timelines->AddConsumer(this);
2326 MOZ_ASSERT(timelines->HasConsumer(this));
2327 UseEntryScriptProfiling();
2328 } else {
2329 MOZ_ASSERT(timelines->HasConsumer(this));
2330 timelines->RemoveConsumer(this);
2331 MOZ_ASSERT(!timelines->HasConsumer(this));
2332 UnuseEntryScriptProfiling();
2333 }
2334
2335 return NS_OK;
2336 }
2337
2338 NS_IMETHODIMP
GetRecordProfileTimelineMarkers(bool * aValue)2339 nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue) {
2340 *aValue = !!mObserved;
2341 return NS_OK;
2342 }
2343
PopProfileTimelineMarkers(JSContext * aCx,JS::MutableHandle<JS::Value> aOut)2344 nsresult nsDocShell::PopProfileTimelineMarkers(
2345 JSContext* aCx, JS::MutableHandle<JS::Value> aOut) {
2346 RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
2347 if (!timelines) {
2348 return NS_OK;
2349 }
2350
2351 nsTArray<dom::ProfileTimelineMarker> store;
2352 SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
2353
2354 timelines->PopMarkers(this, aCx, store);
2355
2356 if (!ToJSValue(aCx, store, aOut)) {
2357 JS_ClearPendingException(aCx);
2358 return NS_ERROR_UNEXPECTED;
2359 }
2360
2361 return NS_OK;
2362 }
2363
Now(DOMHighResTimeStamp * aWhen)2364 nsresult nsDocShell::Now(DOMHighResTimeStamp* aWhen) {
2365 *aWhen = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
2366 return NS_OK;
2367 }
2368
2369 NS_IMETHODIMP
SetWindowDraggingAllowed(bool aValue)2370 nsDocShell::SetWindowDraggingAllowed(bool aValue) {
2371 RefPtr<nsDocShell> parent = GetParentDocshell();
2372 if (!aValue && mItemType == typeChrome && !parent) {
2373 // Window dragging is always allowed for top level
2374 // chrome docshells.
2375 return NS_ERROR_FAILURE;
2376 }
2377 mWindowDraggingAllowed = aValue;
2378 return NS_OK;
2379 }
2380
2381 NS_IMETHODIMP
GetWindowDraggingAllowed(bool * aValue)2382 nsDocShell::GetWindowDraggingAllowed(bool* aValue) {
2383 // window dragging regions in CSS (-moz-window-drag:drag)
2384 // can be slow. Default behavior is to only allow it for
2385 // chrome top level windows.
2386 RefPtr<nsDocShell> parent = GetParentDocshell();
2387 if (mItemType == typeChrome && !parent) {
2388 // Top level chrome window
2389 *aValue = true;
2390 } else {
2391 *aValue = mWindowDraggingAllowed;
2392 }
2393 return NS_OK;
2394 }
2395
TopSessionStorageManager()2396 nsIDOMStorageManager* nsDocShell::TopSessionStorageManager() {
2397 nsresult rv;
2398
2399 nsCOMPtr<nsIDocShellTreeItem> topItem;
2400 rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
2401 if (NS_FAILED(rv)) {
2402 return nullptr;
2403 }
2404
2405 if (!topItem) {
2406 return nullptr;
2407 }
2408
2409 nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
2410 if (topDocShell != this) {
2411 return topDocShell->TopSessionStorageManager();
2412 }
2413
2414 if (!mSessionStorageManager) {
2415 mSessionStorageManager =
2416 do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
2417 }
2418
2419 return mSessionStorageManager;
2420 }
2421
2422 NS_IMETHODIMP
GetCurrentDocumentChannel(nsIChannel ** aResult)2423 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult) {
2424 NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
2425 return NS_OK;
2426 }
2427
GetCurrentDocChannel()2428 nsIChannel* nsDocShell::GetCurrentDocChannel() {
2429 if (mContentViewer) {
2430 nsIDocument* doc = mContentViewer->GetDocument();
2431 if (doc) {
2432 return doc->GetChannel();
2433 }
2434 }
2435 return nullptr;
2436 }
2437
2438 NS_IMETHODIMP
AddWeakScrollObserver(nsIScrollObserver * aObserver)2439 nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver) {
2440 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2441 if (!weakObs) {
2442 return NS_ERROR_FAILURE;
2443 }
2444 return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
2445 }
2446
2447 NS_IMETHODIMP
RemoveWeakScrollObserver(nsIScrollObserver * aObserver)2448 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver) {
2449 nsWeakPtr obs = do_GetWeakReference(aObserver);
2450 return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
2451 }
2452
NotifyAsyncPanZoomStarted()2453 void nsDocShell::NotifyAsyncPanZoomStarted() {
2454 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2455 while (iter.HasMore()) {
2456 nsWeakPtr ref = iter.GetNext();
2457 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2458 if (obs) {
2459 obs->AsyncPanZoomStarted();
2460 } else {
2461 mScrollObservers.RemoveElement(ref);
2462 }
2463 }
2464 }
2465
NotifyAsyncPanZoomStopped()2466 void nsDocShell::NotifyAsyncPanZoomStopped() {
2467 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2468 while (iter.HasMore()) {
2469 nsWeakPtr ref = iter.GetNext();
2470 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2471 if (obs) {
2472 obs->AsyncPanZoomStopped();
2473 } else {
2474 mScrollObservers.RemoveElement(ref);
2475 }
2476 }
2477 }
2478
2479 NS_IMETHODIMP
NotifyScrollObservers()2480 nsDocShell::NotifyScrollObservers() {
2481 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2482 while (iter.HasMore()) {
2483 nsWeakPtr ref = iter.GetNext();
2484 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2485 if (obs) {
2486 obs->ScrollPositionChanged();
2487 } else {
2488 mScrollObservers.RemoveElement(ref);
2489 }
2490 }
2491 return NS_OK;
2492 }
2493
2494 //*****************************************************************************
2495 // nsDocShell::nsIDocShellTreeItem
2496 //*****************************************************************************
2497
2498 NS_IMETHODIMP
GetName(nsAString & aName)2499 nsDocShell::GetName(nsAString& aName) {
2500 aName = mName;
2501 return NS_OK;
2502 }
2503
2504 NS_IMETHODIMP
SetName(const nsAString & aName)2505 nsDocShell::SetName(const nsAString& aName) {
2506 mName = aName;
2507 return NS_OK;
2508 }
2509
2510 NS_IMETHODIMP
NameEquals(const nsAString & aName,bool * aResult)2511 nsDocShell::NameEquals(const nsAString& aName, bool* aResult) {
2512 NS_ENSURE_ARG_POINTER(aResult);
2513 *aResult = mName.Equals(aName);
2514 return NS_OK;
2515 }
2516
2517 NS_IMETHODIMP
GetCustomUserAgent(nsAString & aCustomUserAgent)2518 nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent) {
2519 aCustomUserAgent = mCustomUserAgent;
2520 return NS_OK;
2521 }
2522
2523 NS_IMETHODIMP
SetCustomUserAgent(const nsAString & aCustomUserAgent)2524 nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent) {
2525 mCustomUserAgent = aCustomUserAgent;
2526 RefPtr<nsGlobalWindowInner> win =
2527 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
2528 if (win) {
2529 Navigator* navigator = win->Navigator();
2530 if (navigator) {
2531 navigator->ClearUserAgentCache();
2532 }
2533 }
2534
2535 uint32_t childCount = mChildList.Length();
2536 for (uint32_t i = 0; i < childCount; ++i) {
2537 nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
2538 if (childShell) {
2539 childShell->SetCustomUserAgent(aCustomUserAgent);
2540 }
2541 }
2542 return NS_OK;
2543 }
2544
2545 NS_IMETHODIMP
GetTouchEventsOverride(uint32_t * aTouchEventsOverride)2546 nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride) {
2547 NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
2548
2549 *aTouchEventsOverride = mTouchEventsOverride;
2550 return NS_OK;
2551 }
2552
2553 NS_IMETHODIMP
SetTouchEventsOverride(uint32_t aTouchEventsOverride)2554 nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride) {
2555 if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE ||
2556 aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED ||
2557 aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) {
2558 return NS_ERROR_INVALID_ARG;
2559 }
2560
2561 mTouchEventsOverride = aTouchEventsOverride;
2562
2563 uint32_t childCount = mChildList.Length();
2564 for (uint32_t i = 0; i < childCount; ++i) {
2565 nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
2566 if (childShell) {
2567 childShell->SetTouchEventsOverride(aTouchEventsOverride);
2568 }
2569 }
2570 return NS_OK;
2571 }
2572
ItemType()2573 /* virtual */ int32_t nsDocShell::ItemType() { return mItemType; }
2574
2575 NS_IMETHODIMP
GetItemType(int32_t * aItemType)2576 nsDocShell::GetItemType(int32_t* aItemType) {
2577 NS_ENSURE_ARG_POINTER(aItemType);
2578
2579 *aItemType = ItemType();
2580 return NS_OK;
2581 }
2582
2583 NS_IMETHODIMP
SetItemType(int32_t aItemType)2584 nsDocShell::SetItemType(int32_t aItemType) {
2585 NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
2586
2587 // Only allow setting the type on root docshells. Those would be the ones
2588 // that have the docloader service as mParent or have no mParent at all.
2589 nsCOMPtr<nsIDocumentLoader> docLoaderService =
2590 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
2591 NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
2592
2593 NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
2594
2595 mItemType = aItemType;
2596
2597 // disable auth prompting for anything but content
2598 mAllowAuth = mItemType == typeContent;
2599
2600 RefPtr<nsPresContext> presContext = nullptr;
2601 GetPresContext(getter_AddRefs(presContext));
2602 if (presContext) {
2603 presContext->UpdateIsChrome();
2604 }
2605
2606 return NS_OK;
2607 }
2608
2609 NS_IMETHODIMP
GetParent(nsIDocShellTreeItem ** aParent)2610 nsDocShell::GetParent(nsIDocShellTreeItem** aParent) {
2611 if (!mParent) {
2612 *aParent = nullptr;
2613 } else {
2614 CallQueryInterface(mParent, aParent);
2615 }
2616 // Note that in the case when the parent is not an nsIDocShellTreeItem we
2617 // don't want to throw; we just want to return null.
2618 return NS_OK;
2619 }
2620
GetParentDocshell()2621 already_AddRefed<nsDocShell> nsDocShell::GetParentDocshell() {
2622 nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
2623 return docshell.forget().downcast<nsDocShell>();
2624 }
2625
MaybeCreateInitialClientSource(nsIPrincipal * aPrincipal)2626 void nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal) {
2627 MOZ_ASSERT(!mIsBeingDestroyed);
2628
2629 // If there is an existing document then there is no need to create
2630 // a client for a future initial about:blank document.
2631 if (mScriptGlobal && mScriptGlobal->GetCurrentInnerWindowInternal() &&
2632 mScriptGlobal->GetCurrentInnerWindowInternal()->GetExtantDoc()) {
2633 MOZ_DIAGNOSTIC_ASSERT(mScriptGlobal->GetCurrentInnerWindowInternal()
2634 ->GetClientInfo()
2635 .isSome());
2636 MOZ_DIAGNOSTIC_ASSERT(!mInitialClientSource);
2637 return;
2638 }
2639
2640 // Don't recreate the initial client source. We call this multiple times
2641 // when DoChannelLoad() is called before CreateAboutBlankContentViewer.
2642 if (mInitialClientSource) {
2643 return;
2644 }
2645
2646 // Don't pre-allocate the client when we are sandboxed. The inherited
2647 // principal does not take sandboxing into account.
2648 // TODO: Refactor sandboxing principal code out so we can use it here.
2649 if (!aPrincipal && mSandboxFlags) {
2650 return;
2651 }
2652
2653 nsIPrincipal* principal =
2654 aPrincipal ? aPrincipal : GetInheritedPrincipal(false);
2655
2656 // Sometimes there is no principal available when we are called from
2657 // CreateAboutBlankContentViewer. For example, sometimes the principal
2658 // is only extracted from the load context after the document is created
2659 // in nsDocument::ResetToURI(). Ideally we would do something similar
2660 // here, but for now lets just avoid the issue by not preallocating the
2661 // client.
2662 if (!principal) {
2663 return;
2664 }
2665
2666 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
2667 if (!win) {
2668 return;
2669 }
2670
2671 mInitialClientSource = ClientManager::CreateSource(
2672 ClientType::Window, win->EventTargetFor(TaskCategory::Other), principal);
2673 MOZ_DIAGNOSTIC_ASSERT(mInitialClientSource);
2674
2675 // Mark the initial client as execution ready, but owned by the docshell.
2676 // If the client is actually used this will cause ClientSource to force
2677 // the creation of the initial about:blank by calling
2678 // nsDocShell::GetDocument().
2679 mInitialClientSource->DocShellExecutionReady(this);
2680
2681 // Next, check to see if the parent is controlled.
2682 nsCOMPtr<nsIDocShell> parent = GetParentDocshell();
2683 nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
2684 nsPIDOMWindowInner* parentInner =
2685 parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
2686 if (!parentInner) {
2687 return;
2688 }
2689
2690 nsCOMPtr<nsIURI> uri;
2691 MOZ_ALWAYS_SUCCEEDS(
2692 NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank")));
2693
2694 // We're done if there is no parent controller or if this docshell
2695 // is not permitted to control for some reason.
2696 Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
2697 if (controller.isNothing() ||
2698 !ServiceWorkerAllowedToControlWindow(principal, uri)) {
2699 return;
2700 }
2701
2702 nsCOMPtr<nsIServiceWorkerManager> swm =
2703 mozilla::services::GetServiceWorkerManager();
2704 if (!swm) {
2705 return;
2706 }
2707
2708 // If the parent is controlled then propagate that controller to the
2709 // initial about:blank client as well. This will set the controller
2710 // in the ClientManagerService in the parent.
2711 //
2712 // Note: If the registration is missing from the SWM we avoid setting
2713 // the controller on the client. We can do this synchronously
2714 // for now since SWM is in the child process. In the future
2715 // when SWM is in the parent process we will probably have to
2716 // always set the initial client source and then somehow clear
2717 // it if we find the registration is acutally gone. Its also
2718 // possible this race only occurs in cases where the resulting
2719 // window is no longer exposed. For example, in theory the SW
2720 // should not go away if our parent window is controlled.
2721 if (!swm->StartControlling(mInitialClientSource->Info(), controller.ref())) {
2722 return;
2723 }
2724
2725 // Also mark the ClientSource as controlled directly in case script
2726 // immediately accesses navigator.serviceWorker.controller.
2727 mInitialClientSource->SetController(controller.ref());
2728 }
2729
GetInitialClientInfo() const2730 Maybe<ClientInfo> nsDocShell::GetInitialClientInfo() const {
2731 if (mInitialClientSource) {
2732 Maybe<ClientInfo> result;
2733 result.emplace(mInitialClientSource->Info());
2734 return Move(result);
2735 }
2736
2737 nsGlobalWindowInner* innerWindow =
2738 mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
2739 nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
2740
2741 if (!doc || !doc->IsInitialDocument()) {
2742 return Maybe<ClientInfo>();
2743 }
2744
2745 return innerWindow->GetClientInfo();
2746 }
2747
RecomputeCanExecuteScripts()2748 void nsDocShell::RecomputeCanExecuteScripts() {
2749 bool old = mCanExecuteScripts;
2750 RefPtr<nsDocShell> parent = GetParentDocshell();
2751
2752 // If we have no tree owner, that means that we've been detached from the
2753 // docshell tree (this is distinct from having no parent dochshell, which
2754 // is the case for root docshells). It would be nice to simply disallow
2755 // script in detached docshells, but bug 986542 demonstrates that this
2756 // behavior breaks at least one website.
2757 //
2758 // So instead, we use our previous value, unless mAllowJavascript has been
2759 // explicitly set to false.
2760 if (!mTreeOwner) {
2761 mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
2762 // If scripting has been explicitly disabled on our docshell, we're done.
2763 } else if (!mAllowJavascript) {
2764 mCanExecuteScripts = false;
2765 // If we have a parent, inherit.
2766 } else if (parent) {
2767 mCanExecuteScripts = parent->mCanExecuteScripts;
2768 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2769 // script. Allow.
2770 } else {
2771 mCanExecuteScripts = true;
2772 }
2773
2774 // Inform our active DOM window.
2775 //
2776 // This will pass the outer, which will be in the scope of the active inner.
2777 if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
2778 xpc::Scriptability& scriptability =
2779 xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
2780 scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
2781 }
2782
2783 // If our value has changed, our children might be affected. Recompute their
2784 // value as well.
2785 if (old != mCanExecuteScripts) {
2786 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2787 while (iter.HasMore()) {
2788 static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
2789 }
2790 }
2791 }
2792
SetDocLoaderParent(nsDocLoader * aParent)2793 nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
2794 bool wasFrame = IsFrame();
2795 #ifdef DEBUG
2796 bool wasPrivate = UsePrivateBrowsing();
2797 #endif
2798
2799 nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
2800 NS_ENSURE_SUCCESS(rv, rv);
2801
2802 nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
2803 if (wasFrame != IsFrame() && priorityGroup) {
2804 priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
2805 }
2806
2807 // Curse ambiguous nsISupports inheritance!
2808 nsISupports* parent = GetAsSupports(aParent);
2809
2810 // If parent is another docshell, we inherit all their flags for
2811 // allowing plugins, scripting etc.
2812 bool value;
2813 nsString customUserAgent;
2814 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
2815 if (parentAsDocShell) {
2816 if (mAllowPlugins &&
2817 NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
2818 SetAllowPlugins(value);
2819 }
2820 if (mAllowJavascript &&
2821 NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
2822 SetAllowJavascript(value);
2823 }
2824 if (mAllowMetaRedirects &&
2825 NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
2826 SetAllowMetaRedirects(value);
2827 }
2828 if (mAllowSubframes &&
2829 NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
2830 SetAllowSubframes(value);
2831 }
2832 if (mAllowImages &&
2833 NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
2834 SetAllowImages(value);
2835 }
2836 SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
2837 if (mAllowWindowControl &&
2838 NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
2839 SetAllowWindowControl(value);
2840 }
2841 SetAllowContentRetargeting(
2842 mAllowContentRetargeting &&
2843 parentAsDocShell->GetAllowContentRetargetingOnChildren());
2844 if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
2845 SetIsActive(value);
2846 }
2847 if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
2848 !customUserAgent.IsEmpty()) {
2849 SetCustomUserAgent(customUserAgent);
2850 }
2851 if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
2852 value = false;
2853 }
2854 SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
2855 if (mInheritPrivateBrowsingId) {
2856 value = parentAsDocShell->GetAffectPrivateSessionLifetime();
2857 SetAffectPrivateSessionLifetime(value);
2858 }
2859 uint32_t flags;
2860 if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
2861 SetDefaultLoadFlags(flags);
2862 }
2863 uint32_t touchEventsOverride;
2864 if (NS_SUCCEEDED(
2865 parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) {
2866 SetTouchEventsOverride(touchEventsOverride);
2867 }
2868 }
2869
2870 nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
2871 if (parentAsLoadContext && mInheritPrivateBrowsingId &&
2872 NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
2873 SetPrivateBrowsing(value);
2874 }
2875
2876 nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
2877 if (parentURIListener) {
2878 mContentListener->SetParentContentListener(parentURIListener);
2879 }
2880
2881 // Our parent has changed. Recompute scriptability.
2882 RecomputeCanExecuteScripts();
2883
2884 NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(),
2885 "Private browsing state changed while inheritance was disabled");
2886
2887 return NS_OK;
2888 }
2889
2890 NS_IMETHODIMP
GetSameTypeParent(nsIDocShellTreeItem ** aParent)2891 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent) {
2892 NS_ENSURE_ARG_POINTER(aParent);
2893 *aParent = nullptr;
2894
2895 if (nsIDocShell::GetIsMozBrowser()) {
2896 return NS_OK;
2897 }
2898
2899 nsCOMPtr<nsIDocShellTreeItem> parent =
2900 do_QueryInterface(GetAsSupports(mParent));
2901 if (!parent) {
2902 return NS_OK;
2903 }
2904
2905 if (parent->ItemType() == mItemType) {
2906 parent.swap(*aParent);
2907 }
2908 return NS_OK;
2909 }
2910
2911 NS_IMETHODIMP
GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell ** aParent)2912 nsDocShell::GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell** aParent) {
2913 NS_ENSURE_ARG_POINTER(aParent);
2914 *aParent = nullptr;
2915
2916 nsCOMPtr<nsIDocShellTreeItem> parent =
2917 do_QueryInterface(GetAsSupports(mParent));
2918 if (!parent) {
2919 return NS_OK;
2920 }
2921
2922 if (parent->ItemType() == mItemType) {
2923 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
2924 parentDS.forget(aParent);
2925 }
2926 return NS_OK;
2927 }
2928
2929 NS_IMETHODIMP
GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)2930 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) {
2931 NS_ENSURE_ARG_POINTER(aRootTreeItem);
2932
2933 RefPtr<nsDocShell> root = this;
2934 RefPtr<nsDocShell> parent = root->GetParentDocshell();
2935 while (parent) {
2936 root = parent;
2937 parent = root->GetParentDocshell();
2938 }
2939
2940 root.forget(aRootTreeItem);
2941 return NS_OK;
2942 }
2943
2944 NS_IMETHODIMP
GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)2945 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) {
2946 NS_ENSURE_ARG_POINTER(aRootTreeItem);
2947 *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
2948
2949 nsCOMPtr<nsIDocShellTreeItem> parent;
2950 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
2951 NS_ERROR_FAILURE);
2952 while (parent) {
2953 *aRootTreeItem = parent;
2954 NS_ENSURE_SUCCESS(
2955 (*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)),
2956 NS_ERROR_FAILURE);
2957 }
2958 NS_ADDREF(*aRootTreeItem);
2959 return NS_OK;
2960 }
2961
2962 NS_IMETHODIMP
GetSameTypeRootTreeItemIgnoreBrowserBoundaries(nsIDocShell ** aRootTreeItem)2963 nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserBoundaries(
2964 nsIDocShell** aRootTreeItem) {
2965 NS_ENSURE_ARG_POINTER(aRootTreeItem);
2966 *aRootTreeItem = static_cast<nsIDocShell*>(this);
2967
2968 nsCOMPtr<nsIDocShell> parent;
2969 NS_ENSURE_SUCCESS(
2970 GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
2971 NS_ERROR_FAILURE);
2972 while (parent) {
2973 *aRootTreeItem = parent;
2974 NS_ENSURE_SUCCESS(
2975 (*aRootTreeItem)
2976 ->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
2977 NS_ERROR_FAILURE);
2978 }
2979 NS_ADDREF(*aRootTreeItem);
2980 return NS_OK;
2981 }
2982
2983 /* static */
CanAccessItem(nsIDocShellTreeItem * aTargetItem,nsIDocShellTreeItem * aAccessingItem,bool aConsiderOpener)2984 bool nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
2985 nsIDocShellTreeItem* aAccessingItem,
2986 bool aConsiderOpener) {
2987 NS_PRECONDITION(aTargetItem, "Must have target item!");
2988
2989 if (!gValidateOrigin || !aAccessingItem) {
2990 // Good to go
2991 return true;
2992 }
2993
2994 // XXXbz should we care if aAccessingItem or the document therein is
2995 // chrome? Should those get extra privileges?
2996
2997 // For historical context, see:
2998 //
2999 // Bug 13871: Prevent frameset spoofing
3000 // Bug 103638: Targets with same name in different windows open in wrong
3001 // window with javascript
3002 // Bug 408052: Adopt "ancestor" frame navigation policy
3003
3004 // Now do a security check.
3005 //
3006 // Disallow navigation if the two frames are not part of the same app, or if
3007 // they have different is-in-browser-element states.
3008 //
3009 // Allow navigation if
3010 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
3011 // the frame hierarchy or
3012 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
3013 // 3) aTargetItem is a top-level frame and aAccessingItem can target
3014 // its opener per rule (1) or (2).
3015
3016 if (aTargetItem == aAccessingItem) {
3017 // A frame is allowed to navigate itself.
3018 return true;
3019 }
3020
3021 nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
3022 nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
3023 if (!targetDS || !accessingDS) {
3024 // We must be able to convert both to nsIDocShell.
3025 return false;
3026 }
3027
3028 if (targetDS->GetIsInIsolatedMozBrowserElement() !=
3029 accessingDS->GetIsInIsolatedMozBrowserElement()) {
3030 return false;
3031 }
3032
3033 nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
3034 aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
3035 nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot);
3036
3037 nsCOMPtr<nsIDocShellTreeItem> targetRoot;
3038 aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
3039 nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot);
3040
3041 OriginAttributes targetOA =
3042 static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes();
3043 OriginAttributes accessingOA =
3044 static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes();
3045
3046 // When the first party isolation is on, the top-level docShell may not have
3047 // the firstPartyDomain in its originAttributes, but its document will have
3048 // it. So we get the firstPartyDomain from the nodePrincipal of the document
3049 // before we compare the originAttributes.
3050 if (OriginAttributes::IsFirstPartyEnabled()) {
3051 if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3052 (accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) {
3053 nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
3054
3055 if (accessingDoc) {
3056 nsCOMPtr<nsIPrincipal> accessingPrincipal =
3057 accessingDoc->NodePrincipal();
3058
3059 accessingOA.mFirstPartyDomain =
3060 accessingPrincipal->OriginAttributesRef().mFirstPartyDomain;
3061 }
3062 }
3063
3064 if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3065 (targetDS == targetRootDS || targetDS->GetIsMozBrowser())) {
3066 nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
3067
3068 if (targetDoc) {
3069 nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
3070
3071 targetOA.mFirstPartyDomain =
3072 targetPrincipal->OriginAttributesRef().mFirstPartyDomain;
3073 }
3074 }
3075 }
3076
3077 if (targetOA != accessingOA) {
3078 return false;
3079 }
3080
3081 // A private document can't access a non-private one, and vice versa.
3082 if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
3083 static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
3084 return false;
3085 }
3086
3087 if (aTargetItem == accessingRoot) {
3088 // A frame can navigate its root.
3089 return true;
3090 }
3091
3092 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
3093 nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
3094 do {
3095 if (ValidateOrigin(aAccessingItem, target)) {
3096 return true;
3097 }
3098
3099 nsCOMPtr<nsIDocShellTreeItem> parent;
3100 target->GetSameTypeParent(getter_AddRefs(parent));
3101 parent.swap(target);
3102 } while (target);
3103
3104 if (aTargetItem != targetRoot) {
3105 // target is a subframe, not in accessor's frame hierarchy, and all its
3106 // ancestors have origins different from that of the accessor. Don't
3107 // allow access.
3108 return false;
3109 }
3110
3111 if (!aConsiderOpener) {
3112 // All done here
3113 return false;
3114 }
3115
3116 nsCOMPtr<nsPIDOMWindowOuter> targetWindow = aTargetItem->GetWindow();
3117 if (!targetWindow) {
3118 NS_ERROR("This should not happen, really");
3119 return false;
3120 }
3121
3122 nsCOMPtr<mozIDOMWindowProxy> targetOpener = targetWindow->GetOpener();
3123 nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
3124 nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
3125
3126 if (!openerItem) {
3127 return false;
3128 }
3129
3130 return CanAccessItem(openerItem, aAccessingItem, false);
3131 }
3132
ItemIsActive(nsIDocShellTreeItem * aItem)3133 static bool ItemIsActive(nsIDocShellTreeItem* aItem) {
3134 if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) {
3135 auto* win = nsGlobalWindowOuter::Cast(window);
3136 if (!win->GetClosedOuter()) {
3137 return true;
3138 }
3139 }
3140
3141 return false;
3142 }
3143
3144 NS_IMETHODIMP
FindItemWithName(const nsAString & aName,nsIDocShellTreeItem * aRequestor,nsIDocShellTreeItem * aOriginalRequestor,bool aSkipTabGroup,nsIDocShellTreeItem ** aResult)3145 nsDocShell::FindItemWithName(const nsAString& aName,
3146 nsIDocShellTreeItem* aRequestor,
3147 nsIDocShellTreeItem* aOriginalRequestor,
3148 bool aSkipTabGroup,
3149 nsIDocShellTreeItem** aResult) {
3150 NS_ENSURE_ARG_POINTER(aResult);
3151
3152 // If we don't find one, we return NS_OK and a null result
3153 *aResult = nullptr;
3154
3155 if (aName.IsEmpty()) {
3156 return NS_OK;
3157 }
3158
3159 if (aRequestor) {
3160 // If aRequestor is not null we don't need to check special names, so
3161 // just hand straight off to the search by actual name function.
3162 return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
3163 aSkipTabGroup, aResult);
3164 } else {
3165 // This is the entry point into the target-finding algorithm. Check
3166 // for special names. This should only be done once, hence the check
3167 // for a null aRequestor.
3168
3169 nsCOMPtr<nsIDocShellTreeItem> foundItem;
3170 if (aName.LowerCaseEqualsLiteral("_self")) {
3171 foundItem = this;
3172 } else if (aName.LowerCaseEqualsLiteral("_blank")) {
3173 // Just return null. Caller must handle creating a new window with
3174 // a blank name himself.
3175 return NS_OK;
3176 } else if (aName.LowerCaseEqualsLiteral("_parent")) {
3177 GetSameTypeParent(getter_AddRefs(foundItem));
3178 if (!foundItem) {
3179 foundItem = this;
3180 }
3181 } else if (aName.LowerCaseEqualsLiteral("_top")) {
3182 GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
3183 NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
3184 } else {
3185 // Do the search for item by an actual name.
3186 DoFindItemWithName(aName, aRequestor, aOriginalRequestor, aSkipTabGroup,
3187 getter_AddRefs(foundItem));
3188 }
3189
3190 if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
3191 foundItem = nullptr;
3192 }
3193
3194 // DoFindItemWithName only returns active items and we don't check if
3195 // the item is active for the special cases.
3196 if (foundItem) {
3197 foundItem.swap(*aResult);
3198 }
3199 return NS_OK;
3200 }
3201 }
3202
AssertOriginAttributesMatchPrivateBrowsing()3203 void nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
3204 // Chrome docshells must not have a private browsing OriginAttribute
3205 // Content docshells must maintain the equality:
3206 // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
3207 if (mItemType == typeChrome) {
3208 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
3209 } else {
3210 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId ==
3211 mPrivateBrowsingId);
3212 }
3213 }
3214
DoFindItemWithName(const nsAString & aName,nsIDocShellTreeItem * aRequestor,nsIDocShellTreeItem * aOriginalRequestor,bool aSkipTabGroup,nsIDocShellTreeItem ** aResult)3215 nsresult nsDocShell::DoFindItemWithName(const nsAString& aName,
3216 nsIDocShellTreeItem* aRequestor,
3217 nsIDocShellTreeItem* aOriginalRequestor,
3218 bool aSkipTabGroup,
3219 nsIDocShellTreeItem** aResult) {
3220 // First we check our name.
3221 if (mName.Equals(aName) && ItemIsActive(this) &&
3222 CanAccessItem(this, aOriginalRequestor)) {
3223 NS_ADDREF(*aResult = this);
3224 return NS_OK;
3225 }
3226
3227 // Second we check our children making sure not to ask a child if
3228 // it is the aRequestor.
3229 #ifdef DEBUG
3230 nsresult rv =
3231 #endif
3232 FindChildWithName(aName, true, true, aRequestor, aOriginalRequestor,
3233 aResult);
3234 NS_ASSERTION(NS_SUCCEEDED(rv),
3235 "FindChildWithName should not be failing here.");
3236 if (*aResult) {
3237 return NS_OK;
3238 }
3239
3240 // Third if we have a parent and it isn't the requestor then we
3241 // should ask it to do the search. If it is the requestor we
3242 // should just stop here and let the parent do the rest. If we
3243 // don't have a parent, then we should ask the
3244 // docShellTreeOwner to do the search.
3245 nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
3246 do_QueryInterface(GetAsSupports(mParent));
3247 if (parentAsTreeItem) {
3248 if (parentAsTreeItem == aRequestor) {
3249 return NS_OK;
3250 }
3251
3252 // If we have a same-type parent, respecting browser and app boundaries.
3253 // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344
3254 // are fixed.
3255 if (!GetIsMozBrowser() && parentAsTreeItem->ItemType() == mItemType) {
3256 return parentAsTreeItem->FindItemWithName(
3257 aName, static_cast<nsIDocShellTreeItem*>(this), aOriginalRequestor,
3258 /* aSkipTabGroup = */ false, aResult);
3259 }
3260 }
3261
3262 // If we have a null parent or the parent is not of the same type, we need to
3263 // give up on finding it in our tree, and start looking in our TabGroup.
3264 nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
3265 if (window && !aSkipTabGroup) {
3266 RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup();
3267 tabGroup->FindItemWithName(aName, aRequestor, aOriginalRequestor, aResult);
3268 }
3269
3270 return NS_OK;
3271 }
3272
IsSandboxedFrom(nsIDocShell * aTargetDocShell)3273 bool nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell) {
3274 // If no target then not sandboxed.
3275 if (!aTargetDocShell) {
3276 return false;
3277 }
3278
3279 // We cannot be sandboxed from ourselves.
3280 if (aTargetDocShell == this) {
3281 return false;
3282 }
3283
3284 // Default the sandbox flags to our flags, so that if we can't retrieve the
3285 // active document, we will still enforce our own.
3286 uint32_t sandboxFlags = mSandboxFlags;
3287 if (mContentViewer) {
3288 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
3289 if (doc) {
3290 sandboxFlags = doc->GetSandboxFlags();
3291 }
3292 }
3293
3294 // If no flags, we are not sandboxed at all.
3295 if (!sandboxFlags) {
3296 return false;
3297 }
3298
3299 // If aTargetDocShell has an ancestor, it is not top level.
3300 nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
3301 aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
3302 if (ancestorOfTarget) {
3303 do {
3304 // We are not sandboxed if we are an ancestor of target.
3305 if (ancestorOfTarget == this) {
3306 return false;
3307 }
3308 nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
3309 ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
3310 tempTreeItem.swap(ancestorOfTarget);
3311 } while (ancestorOfTarget);
3312
3313 // Otherwise, we are sandboxed from aTargetDocShell.
3314 return true;
3315 }
3316
3317 // aTargetDocShell is top level, are we the "one permitted sandboxed
3318 // navigator", i.e. did we open aTargetDocShell?
3319 nsCOMPtr<nsIDocShell> permittedNavigator;
3320 aTargetDocShell->GetOnePermittedSandboxedNavigator(
3321 getter_AddRefs(permittedNavigator));
3322 if (permittedNavigator == this) {
3323 return false;
3324 }
3325
3326 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
3327 // from our top.
3328 if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
3329 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
3330 GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
3331 if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
3332 return false;
3333 }
3334 }
3335
3336 // Otherwise, we are sandboxed from aTargetDocShell.
3337 return true;
3338 }
3339
3340 NS_IMETHODIMP
GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)3341 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) {
3342 NS_ENSURE_ARG_POINTER(aTreeOwner);
3343
3344 *aTreeOwner = mTreeOwner;
3345 NS_IF_ADDREF(*aTreeOwner);
3346 return NS_OK;
3347 }
3348
3349 #ifdef DEBUG_DOCSHELL_FOCUS
PrintDocTree(nsIDocShellTreeItem * aParentNode,int aLevel)3350 static void PrintDocTree(nsIDocShellTreeItem* aParentNode, int aLevel) {
3351 for (int32_t i = 0; i < aLevel; i++) {
3352 printf(" ");
3353 }
3354
3355 int32_t childWebshellCount;
3356 aParentNode->GetChildCount(&childWebshellCount);
3357 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
3358 int32_t type = aParentNode->ItemType();
3359 nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
3360 RefPtr<nsPresContext> presContext;
3361 parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
3362 nsIDocument* doc = presShell->GetDocument();
3363
3364 nsCOMPtr<nsPIDOMWindowOuter> domwin(doc->GetWindow());
3365
3366 nsCOMPtr<nsIWidget> widget;
3367 nsViewManager* vm = presShell->GetViewManager();
3368 if (vm) {
3369 vm->GetWidget(getter_AddRefs(widget));
3370 }
3371 dom::Element* rootElement = doc->GetRootElement();
3372
3373 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
3374 (void*)parentAsDocShell.get(),
3375 type == nsIDocShellTreeItem::typeChrome ? "Chr" : "Con", (void*)doc,
3376 (void*)domwin.get(), (void*)presContext->EventStateManager(),
3377 (void*)rootElement);
3378
3379 if (childWebshellCount > 0) {
3380 for (int32_t i = 0; i < childWebshellCount; i++) {
3381 nsCOMPtr<nsIDocShellTreeItem> child;
3382 aParentNode->GetChildAt(i, getter_AddRefs(child));
3383 PrintDocTree(child, aLevel + 1);
3384 }
3385 }
3386 }
3387
PrintDocTree(nsIDocShellTreeItem * aParentNode)3388 static void PrintDocTree(nsIDocShellTreeItem* aParentNode) {
3389 NS_ASSERTION(aParentNode, "Pointer is null!");
3390
3391 nsCOMPtr<nsIDocShellTreeItem> parentItem;
3392 aParentNode->GetParent(getter_AddRefs(parentItem));
3393 while (parentItem) {
3394 nsCOMPtr<nsIDocShellTreeItem> tmp;
3395 parentItem->GetParent(getter_AddRefs(tmp));
3396 if (!tmp) {
3397 break;
3398 }
3399 parentItem = tmp;
3400 }
3401
3402 if (!parentItem) {
3403 parentItem = aParentNode;
3404 }
3405
3406 PrintDocTree(parentItem, 0);
3407 }
3408 #endif
3409
3410 NS_IMETHODIMP
SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)3411 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) {
3412 if (mIsBeingDestroyed && aTreeOwner) {
3413 return NS_ERROR_FAILURE;
3414 }
3415
3416 #ifdef DEBUG_DOCSHELL_FOCUS
3417 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
3418 if (item) {
3419 PrintDocTree(item);
3420 }
3421 #endif
3422
3423 // Don't automatically set the progress based on the tree owner for frames
3424 if (!IsFrame()) {
3425 nsCOMPtr<nsIWebProgress> webProgress =
3426 do_QueryInterface(GetAsSupports(this));
3427
3428 if (webProgress) {
3429 nsCOMPtr<nsIWebProgressListener> oldListener =
3430 do_QueryInterface(mTreeOwner);
3431 nsCOMPtr<nsIWebProgressListener> newListener =
3432 do_QueryInterface(aTreeOwner);
3433
3434 if (oldListener) {
3435 webProgress->RemoveProgressListener(oldListener);
3436 }
3437
3438 if (newListener) {
3439 webProgress->AddProgressListener(newListener,
3440 nsIWebProgress::NOTIFY_ALL);
3441 }
3442 }
3443 }
3444
3445 mTreeOwner = aTreeOwner; // Weak reference per API
3446
3447 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
3448 while (iter.HasMore()) {
3449 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
3450 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3451
3452 if (child->ItemType() == mItemType) {
3453 child->SetTreeOwner(aTreeOwner);
3454 }
3455 }
3456
3457 // Our tree owner has changed. Recompute scriptability.
3458 //
3459 // Note that this is near-redundant with the recomputation in
3460 // SetDocLoaderParent(), but not so for the root DocShell, where the call to
3461 // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
3462 // and we never set another parent. Given that this is neither expensive nor
3463 // performance-critical, let's be safe and unconditionally recompute this
3464 // state whenever dependent state changes.
3465 RecomputeCanExecuteScripts();
3466
3467 return NS_OK;
3468 }
3469
3470 NS_IMETHODIMP
SetChildOffset(int32_t aChildOffset)3471 nsDocShell::SetChildOffset(int32_t aChildOffset) {
3472 mChildOffset = aChildOffset;
3473 return NS_OK;
3474 }
3475
3476 NS_IMETHODIMP
GetChildOffset(int32_t * aChildOffset)3477 nsDocShell::GetChildOffset(int32_t* aChildOffset) {
3478 *aChildOffset = mChildOffset;
3479 return NS_OK;
3480 }
3481
3482 NS_IMETHODIMP
GetHistoryID(nsID ** aID)3483 nsDocShell::GetHistoryID(nsID** aID) {
3484 *aID = mHistoryID.Clone();
3485 return NS_OK;
3486 }
3487
HistoryID()3488 const nsID nsDocShell::HistoryID() { return mHistoryID; }
3489
3490 NS_IMETHODIMP
GetIsInUnload(bool * aIsInUnload)3491 nsDocShell::GetIsInUnload(bool* aIsInUnload) {
3492 *aIsInUnload = mFiredUnloadEvent;
3493 return NS_OK;
3494 }
3495
3496 NS_IMETHODIMP
GetChildCount(int32_t * aChildCount)3497 nsDocShell::GetChildCount(int32_t* aChildCount) {
3498 NS_ENSURE_ARG_POINTER(aChildCount);
3499 *aChildCount = mChildList.Length();
3500 return NS_OK;
3501 }
3502
3503 NS_IMETHODIMP
AddChild(nsIDocShellTreeItem * aChild)3504 nsDocShell::AddChild(nsIDocShellTreeItem* aChild) {
3505 NS_ENSURE_ARG_POINTER(aChild);
3506
3507 RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3508 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3509
3510 // Make sure we're not creating a loop in the docshell tree
3511 nsDocLoader* ancestor = this;
3512 do {
3513 if (childAsDocLoader == ancestor) {
3514 return NS_ERROR_ILLEGAL_VALUE;
3515 }
3516 ancestor = ancestor->GetParent();
3517 } while (ancestor);
3518
3519 // Make sure to remove the child from its current parent.
3520 nsDocLoader* childsParent = childAsDocLoader->GetParent();
3521 if (childsParent) {
3522 nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader);
3523 NS_ENSURE_SUCCESS(rv, rv);
3524 }
3525
3526 // Make sure to clear the treeowner in case this child is a different type
3527 // from us.
3528 aChild->SetTreeOwner(nullptr);
3529
3530 nsresult res = AddChildLoader(childAsDocLoader);
3531 NS_ENSURE_SUCCESS(res, res);
3532 NS_ASSERTION(!mChildList.IsEmpty(),
3533 "child list must not be empty after a successful add");
3534
3535 nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
3536 bool dynamic = false;
3537 childDocShell->GetCreatedDynamically(&dynamic);
3538 if (!dynamic) {
3539 nsCOMPtr<nsISHEntry> currentSH;
3540 bool oshe = false;
3541 GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
3542 if (currentSH) {
3543 currentSH->HasDynamicallyAddedChild(&dynamic);
3544 }
3545 }
3546 childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
3547
3548 /* Set the child's global history if the parent has one */
3549 if (mUseGlobalHistory) {
3550 childDocShell->SetUseGlobalHistory(true);
3551 }
3552
3553 if (aChild->ItemType() != mItemType) {
3554 return NS_OK;
3555 }
3556
3557 aChild->SetTreeOwner(mTreeOwner);
3558
3559 nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
3560 if (!childAsDocShell) {
3561 return NS_OK;
3562 }
3563
3564 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3565
3566 // Now take this document's charset and set the child's parentCharset field
3567 // to it. We'll later use that field, in the loading process, for the
3568 // charset choosing algorithm.
3569 // If we fail, at any point, we just return NS_OK.
3570 // This code has some performance impact. But this will be reduced when
3571 // the current charset will finally be stored as an Atom, avoiding the
3572 // alias resolution extra look-up.
3573
3574 // we are NOT going to propagate the charset is this Chrome's docshell
3575 if (mItemType == nsIDocShellTreeItem::typeChrome) {
3576 return NS_OK;
3577 }
3578
3579 // get the parent's current charset
3580 if (!mContentViewer) {
3581 return NS_OK;
3582 }
3583 nsIDocument* doc = mContentViewer->GetDocument();
3584 if (!doc) {
3585 return NS_OK;
3586 }
3587
3588 bool isWyciwyg = false;
3589
3590 if (mCurrentURI) {
3591 // Check if the url is wyciwyg
3592 mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
3593 }
3594
3595 if (!isWyciwyg) {
3596 // If this docshell is loaded from a wyciwyg: URI, don't
3597 // advertise our charset since it does not in any way reflect
3598 // the actual source charset, which is what we're trying to
3599 // expose here.
3600
3601 const Encoding* parentCS = doc->GetDocumentCharacterSet();
3602 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
3603 // set the child's parentCharset
3604 childAsDocShell->SetParentCharset(parentCS, charsetSource,
3605 doc->NodePrincipal());
3606 }
3607
3608 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
3609 // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3610
3611 return NS_OK;
3612 }
3613
3614 NS_IMETHODIMP
RemoveChild(nsIDocShellTreeItem * aChild)3615 nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild) {
3616 NS_ENSURE_ARG_POINTER(aChild);
3617
3618 RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3619 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3620
3621 nsresult rv = RemoveChildLoader(childAsDocLoader);
3622 NS_ENSURE_SUCCESS(rv, rv);
3623
3624 aChild->SetTreeOwner(nullptr);
3625
3626 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
3627 }
3628
3629 NS_IMETHODIMP
GetChildAt(int32_t aIndex,nsIDocShellTreeItem ** aChild)3630 nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild) {
3631 NS_ENSURE_ARG_POINTER(aChild);
3632
3633 #ifdef DEBUG
3634 if (aIndex < 0) {
3635 NS_WARNING("Negative index passed to GetChildAt");
3636 } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
3637 NS_WARNING("Too large an index passed to GetChildAt");
3638 }
3639 #endif
3640
3641 nsIDocumentLoader* child = ChildAt(aIndex);
3642 NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
3643
3644 return CallQueryInterface(child, aChild);
3645 }
3646
3647 NS_IMETHODIMP
FindChildWithName(const nsAString & aName,bool aRecurse,bool aSameType,nsIDocShellTreeItem * aRequestor,nsIDocShellTreeItem * aOriginalRequestor,nsIDocShellTreeItem ** aResult)3648 nsDocShell::FindChildWithName(const nsAString& aName, bool aRecurse,
3649 bool aSameType, nsIDocShellTreeItem* aRequestor,
3650 nsIDocShellTreeItem* aOriginalRequestor,
3651 nsIDocShellTreeItem** aResult) {
3652 NS_ENSURE_ARG_POINTER(aResult);
3653
3654 // if we don't find one, we return NS_OK and a null result
3655 *aResult = nullptr;
3656
3657 if (aName.IsEmpty()) {
3658 return NS_OK;
3659 }
3660
3661 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
3662 while (iter.HasMore()) {
3663 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
3664 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3665 int32_t childType = child->ItemType();
3666
3667 if (aSameType && (childType != mItemType)) {
3668 continue;
3669 }
3670
3671 bool childNameEquals = false;
3672 child->NameEquals(aName, &childNameEquals);
3673 if (childNameEquals && ItemIsActive(child) &&
3674 CanAccessItem(child, aOriginalRequestor)) {
3675 child.swap(*aResult);
3676 break;
3677 }
3678
3679 // Only ask it to check children if it is same type
3680 if (childType != mItemType) {
3681 continue;
3682 }
3683
3684 // Only ask the child if it isn't the requestor
3685 if (aRecurse && (aRequestor != child)) {
3686 // See if child contains the shell with the given name
3687 #ifdef DEBUG
3688 nsresult rv =
3689 #endif
3690 child->FindChildWithName(aName, true, aSameType,
3691 static_cast<nsIDocShellTreeItem*>(this),
3692 aOriginalRequestor, aResult);
3693 NS_ASSERTION(NS_SUCCEEDED(rv), "FindChildWithName should not fail here");
3694 if (*aResult) {
3695 // found it
3696 return NS_OK;
3697 }
3698 }
3699 }
3700 return NS_OK;
3701 }
3702
3703 NS_IMETHODIMP
GetChildSHEntry(int32_t aChildOffset,nsISHEntry ** aResult)3704 nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry** aResult) {
3705 nsresult rv = NS_OK;
3706
3707 NS_ENSURE_ARG_POINTER(aResult);
3708 *aResult = nullptr;
3709
3710 // A nsISHEntry for a child is *only* available when the parent is in
3711 // the progress of loading a document too...
3712
3713 if (mLSHE) {
3714 /* Before looking for the subframe's url, check
3715 * the expiration status of the parent. If the parent
3716 * has expired from cache, then subframes will not be
3717 * loaded from history in certain situations.
3718 */
3719 bool parentExpired = false;
3720 mLSHE->GetExpirationStatus(&parentExpired);
3721
3722 /* Get the parent's Load Type so that it can be set on the child too.
3723 * By default give a loadHistory value
3724 */
3725 uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
3726 mLSHE->GetLoadType(&loadType);
3727 // If the user did a shift-reload on this frameset page,
3728 // we don't want to load the subframes from history.
3729 if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
3730 loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
3731 loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
3732 loadType == nsIDocShellLoadInfo::loadRefresh) {
3733 return rv;
3734 }
3735
3736 /* If the user pressed reload and the parent frame has expired
3737 * from cache, we do not want to load the child frame from history.
3738 */
3739 if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
3740 // The parent has expired. Return null.
3741 *aResult = nullptr;
3742 return rv;
3743 }
3744
3745 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
3746 if (container) {
3747 // Get the child subframe from session history.
3748 rv = container->GetChildAt(aChildOffset, aResult);
3749 if (*aResult) {
3750 (*aResult)->SetLoadType(loadType);
3751 }
3752 }
3753 }
3754 return rv;
3755 }
3756
3757 NS_IMETHODIMP
AddChildSHEntry(nsISHEntry * aCloneRef,nsISHEntry * aNewEntry,int32_t aChildOffset,uint32_t aLoadType,bool aCloneChildren)3758 nsDocShell::AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
3759 int32_t aChildOffset, uint32_t aLoadType,
3760 bool aCloneChildren) {
3761 nsresult rv = NS_OK;
3762
3763 if (mLSHE && aLoadType != LOAD_PUSHSTATE) {
3764 /* You get here if you are currently building a
3765 * hierarchy ie.,you just visited a frameset page
3766 */
3767 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
3768 if (container) {
3769 if (NS_FAILED(container->ReplaceChild(aNewEntry))) {
3770 rv = container->AddChild(aNewEntry, aChildOffset);
3771 }
3772 }
3773 } else if (!aCloneRef) {
3774 /* This is an initial load in some subframe. Just append it if we can */
3775 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
3776 if (container) {
3777 rv = container->AddChild(aNewEntry, aChildOffset);
3778 }
3779 } else {
3780 rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset, aLoadType,
3781 aCloneChildren);
3782 }
3783 return rv;
3784 }
3785
AddChildSHEntryInternal(nsISHEntry * aCloneRef,nsISHEntry * aNewEntry,int32_t aChildOffset,uint32_t aLoadType,bool aCloneChildren)3786 nsresult nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
3787 nsISHEntry* aNewEntry,
3788 int32_t aChildOffset,
3789 uint32_t aLoadType,
3790 bool aCloneChildren) {
3791 nsresult rv = NS_OK;
3792 if (mSessionHistory) {
3793 /* You are currently in the rootDocShell.
3794 * You will get here when a subframe has a new url
3795 * to load and you have walked up the tree all the
3796 * way to the top to clone the current SHEntry hierarchy
3797 * and replace the subframe where a new url was loaded with
3798 * a new entry.
3799 */
3800 int32_t index = -1;
3801 nsCOMPtr<nsISHEntry> currentHE;
3802 mSessionHistory->GetIndex(&index);
3803 if (index < 0) {
3804 return NS_ERROR_FAILURE;
3805 }
3806
3807 rv = mSessionHistory->GetEntryAtIndex(index, false,
3808 getter_AddRefs(currentHE));
3809 NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
3810
3811 nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
3812 if (currentEntry) {
3813 uint32_t cloneID = 0;
3814 nsCOMPtr<nsISHEntry> nextEntry;
3815 aCloneRef->GetID(&cloneID);
3816 rv = nsSHistory::CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
3817 aCloneChildren,
3818 getter_AddRefs(nextEntry));
3819
3820 if (NS_SUCCEEDED(rv)) {
3821 nsCOMPtr<nsISHistoryInternal> shPrivate =
3822 do_QueryInterface(mSessionHistory);
3823 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
3824 rv = shPrivate->AddEntry(nextEntry, true);
3825 }
3826 }
3827 } else {
3828 /* Just pass this along */
3829 nsCOMPtr<nsIDocShell> parent =
3830 do_QueryInterface(GetAsSupports(mParent), &rv);
3831 if (parent) {
3832 rv = static_cast<nsDocShell*>(parent.get())
3833 ->AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
3834 aLoadType, aCloneChildren);
3835 }
3836 }
3837 return rv;
3838 }
3839
AddChildSHEntryToParent(nsISHEntry * aNewEntry,int32_t aChildOffset,bool aCloneChildren)3840 nsresult nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry,
3841 int32_t aChildOffset,
3842 bool aCloneChildren) {
3843 /* You will get here when you are in a subframe and
3844 * a new url has been loaded on you.
3845 * The mOSHE in this subframe will be the previous url's
3846 * mOSHE. This mOSHE will be used as the identification
3847 * for this subframe in the CloneAndReplace function.
3848 */
3849
3850 // In this case, we will end up calling AddEntry, which increases the
3851 // current index by 1
3852 nsCOMPtr<nsISHistory> rootSH;
3853 GetRootSessionHistory(getter_AddRefs(rootSH));
3854 if (rootSH) {
3855 rootSH->GetIndex(&mPreviousTransIndex);
3856 }
3857
3858 nsresult rv;
3859 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(GetAsSupports(mParent), &rv);
3860 if (parent) {
3861 rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
3862 aCloneChildren);
3863 }
3864
3865 if (rootSH) {
3866 rootSH->GetIndex(&mLoadedTransIndex);
3867 #ifdef DEBUG_PAGE_CACHE
3868 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
3869 mLoadedTransIndex);
3870 #endif
3871 }
3872
3873 return rv;
3874 }
3875
3876 NS_IMETHODIMP
SetUseGlobalHistory(bool aUseGlobalHistory)3877 nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory) {
3878 nsresult rv;
3879
3880 mUseGlobalHistory = aUseGlobalHistory;
3881
3882 if (!aUseGlobalHistory) {
3883 mGlobalHistory = nullptr;
3884 return NS_OK;
3885 }
3886
3887 // No need to initialize mGlobalHistory if IHistory is available.
3888 nsCOMPtr<IHistory> history = services::GetHistoryService();
3889 if (history) {
3890 return NS_OK;
3891 }
3892
3893 if (mGlobalHistory) {
3894 return NS_OK;
3895 }
3896
3897 mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
3898 return rv;
3899 }
3900
3901 NS_IMETHODIMP
GetUseGlobalHistory(bool * aUseGlobalHistory)3902 nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory) {
3903 *aUseGlobalHistory = mUseGlobalHistory;
3904 return NS_OK;
3905 }
3906
3907 NS_IMETHODIMP
RemoveFromSessionHistory()3908 nsDocShell::RemoveFromSessionHistory() {
3909 nsCOMPtr<nsISHistoryInternal> internalHistory;
3910 nsCOMPtr<nsISHistory> sessionHistory;
3911 nsCOMPtr<nsIDocShellTreeItem> root;
3912 GetSameTypeRootTreeItem(getter_AddRefs(root));
3913 if (root) {
3914 nsCOMPtr<nsIWebNavigation> rootAsWebnav = do_QueryInterface(root);
3915 if (rootAsWebnav) {
3916 rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
3917 internalHistory = do_QueryInterface(sessionHistory);
3918 }
3919 }
3920 if (!internalHistory) {
3921 return NS_OK;
3922 }
3923
3924 int32_t index = 0;
3925 sessionHistory->GetIndex(&index);
3926 AutoTArray<nsID, 16> ids({mHistoryID});
3927 internalHistory->RemoveEntries(ids, index);
3928 return NS_OK;
3929 }
3930
3931 NS_IMETHODIMP
SetCreatedDynamically(bool aDynamic)3932 nsDocShell::SetCreatedDynamically(bool aDynamic) {
3933 mDynamicallyCreated = aDynamic;
3934 return NS_OK;
3935 }
3936
3937 NS_IMETHODIMP
GetCreatedDynamically(bool * aDynamic)3938 nsDocShell::GetCreatedDynamically(bool* aDynamic) {
3939 *aDynamic = mDynamicallyCreated;
3940 return NS_OK;
3941 }
3942
3943 NS_IMETHODIMP
GetCurrentSHEntry(nsISHEntry ** aEntry,bool * aOSHE)3944 nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE) {
3945 *aOSHE = false;
3946 *aEntry = nullptr;
3947 if (mLSHE) {
3948 NS_ADDREF(*aEntry = mLSHE);
3949 } else if (mOSHE) {
3950 NS_ADDREF(*aEntry = mOSHE);
3951 *aOSHE = true;
3952 }
3953 return NS_OK;
3954 }
3955
GetScriptGlobalObject()3956 nsIScriptGlobalObject* nsDocShell::GetScriptGlobalObject() {
3957 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
3958 return mScriptGlobal;
3959 }
3960
GetDocument()3961 nsIDocument* nsDocShell::GetDocument() {
3962 NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
3963 return mContentViewer->GetDocument();
3964 }
3965
GetWindow()3966 nsPIDOMWindowOuter* nsDocShell::GetWindow() {
3967 if (NS_FAILED(EnsureScriptEnvironment())) {
3968 return nullptr;
3969 }
3970 return mScriptGlobal->AsOuter();
3971 }
3972
3973 NS_IMETHODIMP
SetDeviceSizeIsPageSize(bool aValue)3974 nsDocShell::SetDeviceSizeIsPageSize(bool aValue) {
3975 if (mDeviceSizeIsPageSize != aValue) {
3976 mDeviceSizeIsPageSize = aValue;
3977 RefPtr<nsPresContext> presContext;
3978 GetPresContext(getter_AddRefs(presContext));
3979 if (presContext) {
3980 presContext->MediaFeatureValuesChanged(
3981 {MediaFeatureChangeReason::DeviceSizeIsPageSizeChange});
3982 }
3983 }
3984 return NS_OK;
3985 }
3986
3987 NS_IMETHODIMP
GetDeviceSizeIsPageSize(bool * aValue)3988 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue) {
3989 *aValue = mDeviceSizeIsPageSize;
3990 return NS_OK;
3991 }
3992
ClearFrameHistory(nsISHEntry * aEntry)3993 void nsDocShell::ClearFrameHistory(nsISHEntry* aEntry) {
3994 nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
3995 nsCOMPtr<nsISHistory> rootSH;
3996 GetRootSessionHistory(getter_AddRefs(rootSH));
3997 nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
3998 if (!history || !shcontainer) {
3999 return;
4000 }
4001
4002 int32_t count = 0;
4003 shcontainer->GetChildCount(&count);
4004 AutoTArray<nsID, 16> ids;
4005 for (int32_t i = 0; i < count; ++i) {
4006 nsCOMPtr<nsISHEntry> child;
4007 shcontainer->GetChildAt(i, getter_AddRefs(child));
4008 if (child) {
4009 ids.AppendElement(child->DocshellID());
4010 }
4011 }
4012 int32_t index = 0;
4013 rootSH->GetIndex(&index);
4014 history->RemoveEntries(ids, index);
4015 }
4016
4017 //-------------------------------------
4018 //-- Helper Method for Print discovery
4019 //-------------------------------------
IsPrintingOrPP(bool aDisplayErrorDialog)4020 bool nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog) {
4021 if (mIsPrintingOrPP && aDisplayErrorDialog) {
4022 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
4023 }
4024
4025 return mIsPrintingOrPP;
4026 }
4027
IsNavigationAllowed(bool aDisplayPrintErrorDialog,bool aCheckIfUnloadFired)4028 bool nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
4029 bool aCheckIfUnloadFired) {
4030 bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) &&
4031 (!aCheckIfUnloadFired || !mFiredUnloadEvent);
4032 if (!isAllowed) {
4033 return false;
4034 }
4035 if (!mContentViewer) {
4036 return true;
4037 }
4038 bool firingBeforeUnload;
4039 mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
4040 return !firingBeforeUnload;
4041 }
4042
4043 //*****************************************************************************
4044 // nsDocShell::nsIWebNavigation
4045 //*****************************************************************************
4046
4047 NS_IMETHODIMP
GetCanGoBack(bool * aCanGoBack)4048 nsDocShell::GetCanGoBack(bool* aCanGoBack) {
4049 if (!IsNavigationAllowed(false)) {
4050 *aCanGoBack = false;
4051 return NS_OK; // JS may not handle returning of an error code
4052 }
4053 nsresult rv;
4054 nsCOMPtr<nsISHistory> rootSH;
4055 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4056 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4057 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4058 rv = webnav->GetCanGoBack(aCanGoBack);
4059 return rv;
4060 }
4061
4062 NS_IMETHODIMP
GetCanGoForward(bool * aCanGoForward)4063 nsDocShell::GetCanGoForward(bool* aCanGoForward) {
4064 if (!IsNavigationAllowed(false)) {
4065 *aCanGoForward = false;
4066 return NS_OK; // JS may not handle returning of an error code
4067 }
4068 nsresult rv;
4069 nsCOMPtr<nsISHistory> rootSH;
4070 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4071 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4072 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4073 rv = webnav->GetCanGoForward(aCanGoForward);
4074 return rv;
4075 }
4076
4077 NS_IMETHODIMP
GoBack()4078 nsDocShell::GoBack() {
4079 if (!IsNavigationAllowed()) {
4080 return NS_OK; // JS may not handle returning of an error code
4081 }
4082 nsresult rv;
4083 nsCOMPtr<nsISHistory> rootSH;
4084 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4085 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4086 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4087 rv = webnav->GoBack();
4088 return rv;
4089 }
4090
4091 NS_IMETHODIMP
GoForward()4092 nsDocShell::GoForward() {
4093 if (!IsNavigationAllowed()) {
4094 return NS_OK; // JS may not handle returning of an error code
4095 }
4096 nsresult rv;
4097 nsCOMPtr<nsISHistory> rootSH;
4098 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4099 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4100 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4101 rv = webnav->GoForward();
4102 return rv;
4103 }
4104
4105 NS_IMETHODIMP
GotoIndex(int32_t aIndex)4106 nsDocShell::GotoIndex(int32_t aIndex) {
4107 if (!IsNavigationAllowed()) {
4108 return NS_OK; // JS may not handle returning of an error code
4109 }
4110 nsresult rv;
4111 nsCOMPtr<nsISHistory> rootSH;
4112 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4113 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4114 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4115 rv = webnav->GotoIndex(aIndex);
4116 return rv;
4117 }
4118
4119 NS_IMETHODIMP
LoadURI(const char16_t * aURI,uint32_t aLoadFlags,nsIURI * aReferringURI,nsIInputStream * aPostStream,nsIInputStream * aHeaderStream,nsIPrincipal * aTriggeringPrincipal)4120 nsDocShell::LoadURI(const char16_t* aURI, uint32_t aLoadFlags,
4121 nsIURI* aReferringURI, nsIInputStream* aPostStream,
4122 nsIInputStream* aHeaderStream,
4123 nsIPrincipal* aTriggeringPrincipal) {
4124 return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
4125 mozilla::net::RP_Unset, aPostStream, aHeaderStream,
4126 nullptr, aTriggeringPrincipal);
4127 }
4128
4129 NS_IMETHODIMP
LoadURIWithOptions(const char16_t * aURI,uint32_t aLoadFlags,nsIURI * aReferringURI,uint32_t aReferrerPolicy,nsIInputStream * aPostStream,nsIInputStream * aHeaderStream,nsIURI * aBaseURI,nsIPrincipal * aTriggeringPrincipal)4130 nsDocShell::LoadURIWithOptions(const char16_t* aURI, uint32_t aLoadFlags,
4131 nsIURI* aReferringURI, uint32_t aReferrerPolicy,
4132 nsIInputStream* aPostStream,
4133 nsIInputStream* aHeaderStream, nsIURI* aBaseURI,
4134 nsIPrincipal* aTriggeringPrincipal) {
4135 NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
4136
4137 if (!IsNavigationAllowed()) {
4138 return NS_OK; // JS may not handle returning of an error code
4139 }
4140 nsCOMPtr<nsIURI> uri;
4141 nsCOMPtr<nsIInputStream> postStream(aPostStream);
4142 nsresult rv = NS_OK;
4143
4144 // Create a URI from our string; if that succeeds, we want to
4145 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
4146 // flag.
4147
4148 NS_ConvertUTF16toUTF8 uriString(aURI);
4149 // Cleanup the empty spaces that might be on each end.
4150 uriString.Trim(" ");
4151 // Eliminate embedded newlines, which single-line text fields now allow:
4152 uriString.StripCRLF();
4153 NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
4154
4155 rv = NS_NewURI(getter_AddRefs(uri), uriString);
4156 if (uri) {
4157 aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
4158 }
4159
4160 nsCOMPtr<nsIURIFixupInfo> fixupInfo;
4161 if (sURIFixup) {
4162 // Call the fixup object. This will clobber the rv from NS_NewURI
4163 // above, but that's fine with us. Note that we need to do this even
4164 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
4165 // (things like view-source:mozilla.org for example).
4166 uint32_t fixupFlags = 0;
4167 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4168 fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
4169 }
4170 if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
4171 fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
4172 }
4173 nsCOMPtr<nsIInputStream> fixupStream;
4174 rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
4175 getter_AddRefs(fixupStream),
4176 getter_AddRefs(fixupInfo));
4177
4178 if (NS_SUCCEEDED(rv)) {
4179 fixupInfo->GetPreferredURI(getter_AddRefs(uri));
4180 fixupInfo->SetConsumer(GetAsSupports(this));
4181 }
4182
4183 if (fixupStream) {
4184 // GetFixupURIInfo only returns a post data stream if it succeeded
4185 // and changed the URI, in which case we should override the
4186 // passed-in post data.
4187 postStream = fixupStream;
4188 }
4189
4190 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4191 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4192 if (serv) {
4193 serv->NotifyObservers(fixupInfo, "keyword-uri-fixup", aURI);
4194 }
4195 }
4196 }
4197 // else no fixup service so just use the URI we created and see
4198 // what happens
4199
4200 if (NS_ERROR_MALFORMED_URI == rv) {
4201 if (DisplayLoadError(rv, uri, aURI, nullptr) &&
4202 (aLoadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
4203 return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
4204 }
4205 }
4206
4207 if (NS_FAILED(rv) || !uri) {
4208 return NS_ERROR_FAILURE;
4209 }
4210
4211 PopupControlState popupState;
4212 if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
4213 popupState = openAllowed;
4214 aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
4215 } else {
4216 popupState = openOverridden;
4217 }
4218 nsAutoPopupStatePusher statePusher(popupState);
4219
4220 bool forceAllowDataURI = aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
4221
4222 // Don't pass certain flags that aren't needed and end up confusing
4223 // ConvertLoadTypeToDocShellInfoLoadType. We do need to ensure that they are
4224 // passed to LoadURI though, since it uses them.
4225 uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
4226 aLoadFlags &= ~EXTRA_LOAD_FLAGS;
4227
4228 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
4229 rv = CreateLoadInfo(getter_AddRefs(loadInfo));
4230 if (NS_FAILED(rv)) {
4231 return rv;
4232 }
4233
4234 /*
4235 * If the user "Disables Protection on This Page", we have to make sure to
4236 * remember the users decision when opening links in child tabs [Bug 906190]
4237 */
4238 uint32_t loadType;
4239 if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
4240 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
4241 } else {
4242 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
4243 }
4244
4245 loadInfo->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(loadType));
4246 loadInfo->SetPostDataStream(postStream);
4247 loadInfo->SetReferrer(aReferringURI);
4248 loadInfo->SetReferrerPolicy(aReferrerPolicy);
4249 loadInfo->SetHeadersStream(aHeaderStream);
4250 loadInfo->SetBaseURI(aBaseURI);
4251 loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
4252 loadInfo->SetForceAllowDataURI(forceAllowDataURI);
4253
4254 if (fixupInfo) {
4255 nsAutoString searchProvider, keyword;
4256 fixupInfo->GetKeywordProviderName(searchProvider);
4257 fixupInfo->GetKeywordAsSent(keyword);
4258 MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
4259 }
4260
4261 rv = LoadURI(uri, loadInfo, extraFlags, true);
4262
4263 // Save URI string in case it's needed later when
4264 // sending to search engine service in EndPageLoad()
4265 mOriginalUriString = uriString;
4266
4267 return rv;
4268 }
4269
4270 NS_IMETHODIMP
DisplayLoadError(nsresult aError,nsIURI * aURI,const char16_t * aURL,nsIChannel * aFailedChannel,bool * aDisplayedErrorPage)4271 nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
4272 const char16_t* aURL, nsIChannel* aFailedChannel,
4273 bool* aDisplayedErrorPage) {
4274 *aDisplayedErrorPage = false;
4275 // Get prompt and string bundle servcies
4276 nsCOMPtr<nsIPrompt> prompter;
4277 nsCOMPtr<nsIStringBundle> stringBundle;
4278 GetPromptAndStringBundle(getter_AddRefs(prompter),
4279 getter_AddRefs(stringBundle));
4280
4281 NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
4282 NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
4283
4284 const char* error = nullptr;
4285 // The key used to select the appropriate error message from the properties
4286 // file.
4287 const char* errorDescriptionID = nullptr;
4288 const uint32_t kMaxFormatStrArgs = 3;
4289 nsAutoString formatStrs[kMaxFormatStrArgs];
4290 uint32_t formatStrCount = 0;
4291 bool addHostPort = false;
4292 nsresult rv = NS_OK;
4293 nsAutoString messageStr;
4294 nsAutoCString cssClass;
4295 nsAutoCString errorPage;
4296
4297 errorPage.AssignLiteral("neterror");
4298
4299 // Turn the error code into a human readable error message.
4300 if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
4301 NS_ENSURE_ARG_POINTER(aURI);
4302
4303 // Extract the schemes into a comma delimited list.
4304 nsAutoCString scheme;
4305 aURI->GetScheme(scheme);
4306 CopyASCIItoUTF16(scheme, formatStrs[0]);
4307 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
4308 while (nestedURI) {
4309 nsCOMPtr<nsIURI> tempURI;
4310 nsresult rv2;
4311 rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
4312 if (NS_SUCCEEDED(rv2) && tempURI) {
4313 tempURI->GetScheme(scheme);
4314 formatStrs[0].AppendLiteral(", ");
4315 AppendASCIItoUTF16(scheme, formatStrs[0]);
4316 }
4317 nestedURI = do_QueryInterface(tempURI);
4318 }
4319 formatStrCount = 1;
4320 error = "unknownProtocolFound";
4321 } else if (NS_ERROR_FILE_NOT_FOUND == aError) {
4322 NS_ENSURE_ARG_POINTER(aURI);
4323 error = "fileNotFound";
4324 } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) {
4325 NS_ENSURE_ARG_POINTER(aURI);
4326 error = "fileAccessDenied";
4327 } else if (NS_ERROR_UNKNOWN_HOST == aError) {
4328 NS_ENSURE_ARG_POINTER(aURI);
4329 // Get the host
4330 nsAutoCString host;
4331 nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
4332 innermostURI->GetHost(host);
4333 CopyUTF8toUTF16(host, formatStrs[0]);
4334 formatStrCount = 1;
4335 errorDescriptionID = "dnsNotFound2";
4336 error = "dnsNotFound";
4337 } else if (NS_ERROR_CONNECTION_REFUSED == aError) {
4338 NS_ENSURE_ARG_POINTER(aURI);
4339 addHostPort = true;
4340 error = "connectionFailure";
4341 } else if (NS_ERROR_NET_INTERRUPT == aError) {
4342 NS_ENSURE_ARG_POINTER(aURI);
4343 addHostPort = true;
4344 error = "netInterrupt";
4345 } else if (NS_ERROR_NET_TIMEOUT == aError) {
4346 NS_ENSURE_ARG_POINTER(aURI);
4347 // Get the host
4348 nsAutoCString host;
4349 aURI->GetHost(host);
4350 CopyUTF8toUTF16(host, formatStrs[0]);
4351 formatStrCount = 1;
4352 error = "netTimeout";
4353 } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError ||
4354 NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) {
4355 // CSP error
4356 cssClass.AssignLiteral("neterror");
4357 error = "cspBlocked";
4358 } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
4359 nsCOMPtr<nsINSSErrorsService> nsserr =
4360 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
4361
4362 uint32_t errorClass;
4363 if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
4364 errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
4365 }
4366
4367 nsCOMPtr<nsISupports> securityInfo;
4368 nsCOMPtr<nsITransportSecurityInfo> tsi;
4369 if (aFailedChannel) {
4370 aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
4371 }
4372 tsi = do_QueryInterface(securityInfo);
4373 if (tsi) {
4374 uint32_t securityState;
4375 tsi->GetSecurityState(&securityState);
4376 if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
4377 error = "sslv3Used";
4378 addHostPort = true;
4379 } else if (securityState &
4380 nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
4381 error = "weakCryptoUsed";
4382 addHostPort = true;
4383 } else {
4384 // Usually we should have aFailedChannel and get a detailed message
4385 tsi->GetErrorMessage(getter_Copies(messageStr));
4386 }
4387 } else {
4388 // No channel, let's obtain the generic error message
4389 if (nsserr) {
4390 nsserr->GetErrorMessage(aError, messageStr);
4391 }
4392 }
4393 if (!messageStr.IsEmpty()) {
4394 if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
4395 error = "nssBadCert";
4396
4397 // If this is an HTTP Strict Transport Security host or a pinned host
4398 // and the certificate is bad, don't allow overrides (RFC 6797 section
4399 // 12.1, HPKP draft spec section 2.6).
4400 uint32_t flags =
4401 UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
4402 bool isStsHost = false;
4403 bool isPinnedHost = false;
4404 if (XRE_IsParentProcess()) {
4405 nsCOMPtr<nsISiteSecurityService> sss =
4406 do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
4407 NS_ENSURE_SUCCESS(rv, rv);
4408 rv =
4409 sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
4410 mOriginAttributes, nullptr, nullptr, &isStsHost);
4411 NS_ENSURE_SUCCESS(rv, rv);
4412 rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
4413 flags, mOriginAttributes, nullptr, nullptr,
4414 &isPinnedHost);
4415 NS_ENSURE_SUCCESS(rv, rv);
4416 } else {
4417 mozilla::dom::ContentChild* cc =
4418 mozilla::dom::ContentChild::GetSingleton();
4419 mozilla::ipc::URIParams uri;
4420 SerializeURI(aURI, uri);
4421 cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
4422 mOriginAttributes, &isStsHost);
4423 cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
4424 mOriginAttributes, &isPinnedHost);
4425 }
4426
4427 if (Preferences::GetBool("browser.xul.error_pages.expert_bad_cert",
4428 false)) {
4429 cssClass.AssignLiteral("expertBadCert");
4430 }
4431
4432 // HSTS/pinning takes precedence over the expert bad cert pref. We
4433 // never want to show the "Add Exception" button for these sites.
4434 // In the future we should differentiate between an HSTS host and a
4435 // pinned host and display a more informative message to the user.
4436 if (isStsHost || isPinnedHost) {
4437 cssClass.AssignLiteral("badStsCert");
4438 }
4439
4440 uint32_t bucketId;
4441 if (isStsHost) {
4442 // measuring STS separately allows us to measure click through
4443 // rates easily
4444 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
4445 } else {
4446 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
4447 }
4448
4449 // See if an alternate cert error page is registered
4450 nsAutoCString alternateErrorPage;
4451 nsresult rv = Preferences::GetCString(
4452 "security.alternate_certificate_error_page", alternateErrorPage);
4453 if (NS_SUCCEEDED(rv)) {
4454 errorPage.Assign(alternateErrorPage);
4455 }
4456
4457 if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) {
4458 Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
4459 }
4460
4461 } else {
4462 error = "nssFailure2";
4463 }
4464 }
4465 } else if (NS_ERROR_PHISHING_URI == aError ||
4466 NS_ERROR_MALWARE_URI == aError ||
4467 NS_ERROR_UNWANTED_URI == aError ||
4468 NS_ERROR_HARMFUL_URI == aError) {
4469 nsAutoCString host;
4470 aURI->GetHost(host);
4471 CopyUTF8toUTF16(host, formatStrs[0]);
4472 formatStrCount = 1;
4473
4474 // Malware and phishing detectors may want to use an alternate error
4475 // page, but if the pref's not set, we'll fall back on the standard page
4476 nsAutoCString alternateErrorPage;
4477 nsresult rv = Preferences::GetCString("urlclassifier.alternate_error_page",
4478 alternateErrorPage);
4479 if (NS_SUCCEEDED(rv)) {
4480 errorPage.Assign(alternateErrorPage);
4481 }
4482
4483 uint32_t bucketId;
4484 bool sendTelemetry = false;
4485 if (NS_ERROR_PHISHING_URI == aError) {
4486 sendTelemetry = true;
4487 error = "deceptiveBlocked";
4488 bucketId = IsFrame()
4489 ? IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_FRAME
4490 : IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_TOP;
4491 } else if (NS_ERROR_MALWARE_URI == aError) {
4492 sendTelemetry = true;
4493 error = "malwareBlocked";
4494 bucketId = IsFrame()
4495 ? IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_FRAME
4496 : IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_TOP;
4497 } else if (NS_ERROR_UNWANTED_URI == aError) {
4498 sendTelemetry = true;
4499 error = "unwantedBlocked";
4500 bucketId = IsFrame()
4501 ? IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_FRAME
4502 : IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_TOP;
4503 } else if (NS_ERROR_HARMFUL_URI == aError) {
4504 sendTelemetry = true;
4505 error = "harmfulBlocked";
4506 bucketId = IsFrame()
4507 ? IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_FRAME
4508 : IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_TOP;
4509 }
4510
4511 if (sendTelemetry && errorPage.EqualsIgnoreCase("blocked")) {
4512 Telemetry::Accumulate(Telemetry::URLCLASSIFIER_UI_EVENTS, bucketId);
4513 }
4514
4515 cssClass.AssignLiteral("blacklist");
4516 } else if (NS_ERROR_CONTENT_CRASHED == aError) {
4517 errorPage.AssignLiteral("tabcrashed");
4518 error = "tabcrashed";
4519
4520 nsCOMPtr<EventTarget> handler = mChromeEventHandler;
4521 if (handler) {
4522 nsCOMPtr<Element> element = do_QueryInterface(handler);
4523 element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
4524 }
4525
4526 // DisplayLoadError requires a non-empty messageStr to proceed and call
4527 // LoadErrorPage. If the page doesn't have a title, we will use a blank
4528 // space which will be trimmed and thus treated as empty by the front-end.
4529 if (messageStr.IsEmpty()) {
4530 messageStr.AssignLiteral(u" ");
4531 }
4532 } else {
4533 // Errors requiring simple formatting
4534 switch (aError) {
4535 case NS_ERROR_MALFORMED_URI:
4536 // URI is malformed
4537 error = "malformedURI";
4538 errorDescriptionID = "malformedURI2";
4539 break;
4540 case NS_ERROR_REDIRECT_LOOP:
4541 // Doc failed to load because the server generated too many redirects
4542 error = "redirectLoop";
4543 break;
4544 case NS_ERROR_UNKNOWN_SOCKET_TYPE:
4545 // Doc failed to load because PSM is not installed
4546 error = "unknownSocketType";
4547 break;
4548 case NS_ERROR_NET_RESET:
4549 // Doc failed to load because the server kept reseting the connection
4550 // before we could read any data from it
4551 error = "netReset";
4552 break;
4553 case NS_ERROR_DOCUMENT_NOT_CACHED:
4554 // Doc failed to load because the cache does not contain a copy of
4555 // the document.
4556 error = "notCached";
4557 break;
4558 case NS_ERROR_OFFLINE:
4559 // Doc failed to load because we are offline.
4560 error = "netOffline";
4561 break;
4562 case NS_ERROR_DOCUMENT_IS_PRINTMODE:
4563 // Doc navigation attempted while Printing or Print Preview
4564 error = "isprinting";
4565 break;
4566 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
4567 // Port blocked for security reasons
4568 addHostPort = true;
4569 error = "deniedPortAccess";
4570 break;
4571 case NS_ERROR_UNKNOWN_PROXY_HOST:
4572 // Proxy hostname could not be resolved.
4573 error = "proxyResolveFailure";
4574 break;
4575 case NS_ERROR_PROXY_CONNECTION_REFUSED:
4576 // Proxy connection was refused.
4577 error = "proxyConnectFailure";
4578 break;
4579 case NS_ERROR_INVALID_CONTENT_ENCODING:
4580 // Bad Content Encoding.
4581 error = "contentEncodingError";
4582 break;
4583 case NS_ERROR_REMOTE_XUL:
4584 error = "remoteXUL";
4585 break;
4586 case NS_ERROR_UNSAFE_CONTENT_TYPE:
4587 // Channel refused to load from an unrecognized content type.
4588 error = "unsafeContentType";
4589 break;
4590 case NS_ERROR_CORRUPTED_CONTENT:
4591 // Broken Content Detected. e.g. Content-MD5 check failure.
4592 error = "corruptedContentErrorv2";
4593 break;
4594 case NS_ERROR_INTERCEPTION_FAILED:
4595 // ServiceWorker intercepted request, but something went wrong.
4596 error = "corruptedContentErrorv2";
4597 break;
4598 case NS_ERROR_NET_INADEQUATE_SECURITY:
4599 // Server negotiated bad TLS for HTTP/2.
4600 error = "inadequateSecurityError";
4601 addHostPort = true;
4602 break;
4603 case NS_ERROR_BLOCKED_BY_POLICY:
4604 // Page blocked by policy
4605 error = "blockedByPolicy";
4606 break;
4607 default:
4608 break;
4609 }
4610 }
4611
4612 // Test if the error should be displayed
4613 if (!error) {
4614 return NS_OK;
4615 }
4616
4617 if (!errorDescriptionID) {
4618 errorDescriptionID = error;
4619 }
4620
4621 // Test if the error needs to be formatted
4622 if (!messageStr.IsEmpty()) {
4623 // already obtained message
4624 } else {
4625 if (addHostPort) {
4626 // Build up the host:port string.
4627 nsAutoCString hostport;
4628 if (aURI) {
4629 aURI->GetHostPort(hostport);
4630 } else {
4631 hostport.Assign('?');
4632 }
4633 CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
4634 }
4635
4636 nsAutoCString spec;
4637 rv = NS_ERROR_NOT_AVAILABLE;
4638 if (aURI) {
4639 // displaying "file://" is aesthetically unpleasing and could even be
4640 // confusing to the user
4641 bool isFileURI = false;
4642 rv = aURI->SchemeIs("file", &isFileURI);
4643 if (NS_SUCCEEDED(rv) && isFileURI) {
4644 aURI->GetPathQueryRef(spec);
4645 } else {
4646 aURI->GetSpec(spec);
4647 }
4648
4649 nsCOMPtr<nsITextToSubURI> textToSubURI(
4650 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
4651 if (NS_SUCCEEDED(rv)) {
4652 rv = textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), spec,
4653 formatStrs[formatStrCount]);
4654 }
4655 } else {
4656 spec.Assign('?');
4657 }
4658 if (NS_FAILED(rv)) {
4659 CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
4660 }
4661 rv = NS_OK;
4662 ++formatStrCount;
4663
4664 const char16_t* strs[kMaxFormatStrArgs];
4665 for (uint32_t i = 0; i < formatStrCount; i++) {
4666 strs[i] = formatStrs[i].get();
4667 }
4668 nsAutoString str;
4669 rv = stringBundle->FormatStringFromName(errorDescriptionID, strs,
4670 formatStrCount, str);
4671 NS_ENSURE_SUCCESS(rv, rv);
4672 messageStr.Assign(str.get());
4673 }
4674
4675 // Display the error as a page or an alert prompt
4676 NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
4677
4678 if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) {
4679 bool isSecureURI = false;
4680 rv = aURI->SchemeIs("https", &isSecureURI);
4681 if (NS_SUCCEEDED(rv) && isSecureURI) {
4682 // Maybe TLS intolerant. Treat this as an SSL error.
4683 error = "nssFailure2";
4684 }
4685 }
4686
4687 if (UseErrorPages()) {
4688 // Display an error page
4689 nsresult loadedPage =
4690 LoadErrorPage(aURI, aURL, errorPage.get(), error, messageStr.get(),
4691 cssClass.get(), aFailedChannel);
4692 *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage);
4693 } else {
4694 // The prompter reqires that our private window has a document (or it
4695 // asserts). Satisfy that assertion now since GetDoc will force
4696 // creation of one if it hasn't already been created.
4697 if (mScriptGlobal) {
4698 Unused << mScriptGlobal->GetDoc();
4699 }
4700
4701 // Display a message box
4702 prompter->Alert(nullptr, messageStr.get());
4703 }
4704
4705 return NS_OK;
4706 }
4707
4708 #define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride"
4709
LoadErrorPage(nsIURI * aURI,const char16_t * aURL,const char * aErrorPage,const char * aErrorType,const char16_t * aDescription,const char * aCSSClass,nsIChannel * aFailedChannel)4710 nsresult nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
4711 const char* aErrorPage,
4712 const char* aErrorType,
4713 const char16_t* aDescription,
4714 const char* aCSSClass,
4715 nsIChannel* aFailedChannel) {
4716 MOZ_ASSERT(!mIsBeingDestroyed);
4717
4718 #if defined(DEBUG)
4719 if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
4720 nsAutoCString chanName;
4721 if (aFailedChannel) {
4722 aFailedChannel->GetName(chanName);
4723 } else {
4724 chanName.AssignLiteral("<no channel>");
4725 }
4726
4727 MOZ_LOG(gDocShellLog, LogLevel::Debug,
4728 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n",
4729 this, aURI ? aURI->GetSpecOrDefault().get() : "",
4730 NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
4731 }
4732 #endif
4733 mFailedChannel = aFailedChannel;
4734 mFailedURI = aURI;
4735 mFailedLoadType = mLoadType;
4736
4737 if (mLSHE) {
4738 // Abandon mLSHE's BFCache entry and create a new one. This way, if
4739 // we go back or forward to another SHEntry with the same doc
4740 // identifier, the error page won't persist.
4741 mLSHE->AbandonBFCacheEntry();
4742 }
4743
4744 nsAutoCString url;
4745 if (aURI) {
4746 nsresult rv = aURI->GetSpec(url);
4747 NS_ENSURE_SUCCESS(rv, rv);
4748 } else if (aURL) {
4749 CopyUTF16toUTF8(aURL, url);
4750 } else {
4751 return NS_ERROR_INVALID_POINTER;
4752 }
4753
4754 // Create a URL to pass all the error information through to the page.
4755
4756 #undef SAFE_ESCAPE
4757 #define SAFE_ESCAPE(output, input, params) \
4758 if (NS_WARN_IF(!NS_Escape(input, output, params))) { \
4759 return NS_ERROR_OUT_OF_MEMORY; \
4760 }
4761
4762 nsCString escapedUrl, escapedError, escapedDescription, escapedCSSClass;
4763 SAFE_ESCAPE(escapedUrl, url, url_Path);
4764 SAFE_ESCAPE(escapedError, nsDependentCString(aErrorType), url_Path);
4765 SAFE_ESCAPE(escapedDescription, NS_ConvertUTF16toUTF8(aDescription),
4766 url_Path);
4767 if (aCSSClass) {
4768 nsCString cssClass(aCSSClass);
4769 SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path);
4770 }
4771 nsCString errorPageUrl("about:");
4772 errorPageUrl.AppendASCII(aErrorPage);
4773 errorPageUrl.AppendLiteral("?e=");
4774
4775 errorPageUrl.AppendASCII(escapedError.get());
4776 errorPageUrl.AppendLiteral("&u=");
4777 errorPageUrl.AppendASCII(escapedUrl.get());
4778 if ((strcmp(aErrorPage, "blocked") == 0) &&
4779 Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE, true)) {
4780 errorPageUrl.AppendLiteral("&o=1");
4781 }
4782 if (!escapedCSSClass.IsEmpty()) {
4783 errorPageUrl.AppendLiteral("&s=");
4784 errorPageUrl.AppendASCII(escapedCSSClass.get());
4785 }
4786 errorPageUrl.AppendLiteral("&c=UTF-8");
4787
4788 nsAutoCString frameType(FrameTypeToString(mFrameType));
4789 errorPageUrl.AppendLiteral("&f=");
4790 errorPageUrl.AppendASCII(frameType.get());
4791
4792 nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
4793 int32_t cpsState;
4794 if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) &&
4795 cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
4796 errorPageUrl.AppendLiteral("&captive=true");
4797 }
4798
4799 // netError.xhtml's getDescription only handles the "d" parameter at the
4800 // end of the URL, so append it last.
4801 errorPageUrl.AppendLiteral("&d=");
4802 errorPageUrl.AppendASCII(escapedDescription.get());
4803
4804 nsCOMPtr<nsIURI> errorPageURI;
4805 nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
4806 NS_ENSURE_SUCCESS(rv, rv);
4807
4808 return InternalLoad(
4809 errorPageURI, nullptr, Nothing(), false, false, false, nullptr,
4810 mozilla::net::RP_Unset, nsContentUtils::GetSystemPrincipal(), nullptr,
4811 INTERNAL_LOAD_FLAGS_NONE, EmptyString(), nullptr, VoidString(), nullptr,
4812 -1, nullptr, LOAD_ERROR_PAGE, nullptr, true, VoidString(), this, nullptr,
4813 nullptr, nullptr);
4814 }
4815
4816 NS_IMETHODIMP
Reload(uint32_t aReloadFlags)4817 nsDocShell::Reload(uint32_t aReloadFlags) {
4818 if (!IsNavigationAllowed()) {
4819 return NS_OK; // JS may not handle returning of an error code
4820 }
4821 nsresult rv;
4822 NS_ASSERTION(((aReloadFlags & 0xf) == 0),
4823 "Reload command not updated to use load flags!");
4824 NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
4825 "Don't pass these flags to Reload");
4826
4827 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
4828 NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
4829
4830 // Send notifications to the HistoryListener if any, about the impending
4831 // reload
4832 nsCOMPtr<nsISHistory> rootSH;
4833 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4834 nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
4835 bool canReload = true;
4836 if (rootSH) {
4837 shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
4838 }
4839
4840 if (!canReload) {
4841 return NS_OK;
4842 }
4843
4844 /* If you change this part of code, make sure bug 45297 does not re-occur */
4845 if (mOSHE) {
4846 rv = LoadHistoryEntry(mOSHE, loadType);
4847 } else if (mLSHE) { // In case a reload happened before the current load is
4848 // done
4849 rv = LoadHistoryEntry(mLSHE, loadType);
4850 } else {
4851 nsCOMPtr<nsIDocument> doc(GetDocument());
4852
4853 if (!doc) {
4854 return NS_OK;
4855 }
4856
4857 // Do not inherit owner from document
4858 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
4859 nsAutoString srcdoc;
4860 nsCOMPtr<nsIURI> baseURI;
4861 nsCOMPtr<nsIURI> originalURI;
4862 nsCOMPtr<nsIURI> resultPrincipalURI;
4863 bool loadReplace = false;
4864
4865 nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
4866 nsAutoString contentTypeHint;
4867 doc->GetContentType(contentTypeHint);
4868
4869 if (doc->IsSrcdocDocument()) {
4870 doc->GetSrcdocData(srcdoc);
4871 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
4872 baseURI = doc->GetBaseURI();
4873 }
4874 nsCOMPtr<nsIChannel> chan = doc->GetChannel();
4875 if (chan) {
4876 uint32_t loadFlags;
4877 chan->GetLoadFlags(&loadFlags);
4878 loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
4879 nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
4880 if (httpChan) {
4881 httpChan->GetOriginalURI(getter_AddRefs(originalURI));
4882 }
4883
4884 nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
4885 if (loadInfo) {
4886 loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
4887 }
4888 }
4889
4890 MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
4891
4892 // Stack variables to ensure changes to the member variables don't affect to
4893 // the call.
4894 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
4895 nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
4896 uint32_t referrerPolicy = mReferrerPolicy;
4897
4898 // Reload always rewrites result principal URI.
4899 Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
4900 emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
4901 rv = InternalLoad(currentURI, originalURI, emplacedResultPrincipalURI,
4902 false, loadReplace,
4903 false, // IsFromProcessingFrameAttributes
4904 referrerURI, referrerPolicy, triggeringPrincipal,
4905 triggeringPrincipal, flags,
4906 EmptyString(), // No window target
4907 NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
4908 VoidString(), // No forced download
4909 nullptr, // No post data
4910 -1, // No post data length
4911 nullptr, // No headers data
4912 loadType, // Load type
4913 nullptr, // No SHEntry
4914 true,
4915 srcdoc, // srcdoc argument for iframe
4916 this, // For reloads we are the source
4917 baseURI,
4918 nullptr, // No nsIDocShell
4919 nullptr); // No nsIRequest
4920 }
4921
4922 return rv;
4923 }
4924
4925 NS_IMETHODIMP
Stop(uint32_t aStopFlags)4926 nsDocShell::Stop(uint32_t aStopFlags) {
4927 // Revoke any pending event related to content viewer restoration
4928 mRestorePresentationEvent.Revoke();
4929
4930 if (mLoadType == LOAD_ERROR_PAGE) {
4931 if (mLSHE) {
4932 // Since error page loads never unset mLSHE, do so now
4933 SetHistoryEntry(&mOSHE, mLSHE);
4934 SetHistoryEntry(&mLSHE, nullptr);
4935 }
4936
4937 mFailedChannel = nullptr;
4938 mFailedURI = nullptr;
4939 }
4940
4941 if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
4942 // Stop the document loading
4943 if (mContentViewer) {
4944 nsCOMPtr<nsIContentViewer> cv = mContentViewer;
4945 cv->Stop();
4946 }
4947 }
4948
4949 if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
4950 // Suspend any timers that were set for this loader. We'll clear
4951 // them out for good in CreateContentViewer.
4952 if (mRefreshURIList) {
4953 SuspendRefreshURIs();
4954 mSavedRefreshURIList.swap(mRefreshURIList);
4955 mRefreshURIList = nullptr;
4956 }
4957
4958 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4959 // just call Stop() on us as an nsIDocumentLoader... We need fewer
4960 // redundant apis!
4961 Stop();
4962 }
4963
4964 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
4965 while (iter.HasMore()) {
4966 nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
4967 if (shellAsNav) {
4968 shellAsNav->Stop(aStopFlags);
4969 }
4970 }
4971
4972 return NS_OK;
4973 }
4974
4975 NS_IMETHODIMP
GetDocument(nsIDOMDocument ** aDocument)4976 nsDocShell::GetDocument(nsIDOMDocument** aDocument) {
4977 NS_ENSURE_ARG_POINTER(aDocument);
4978 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
4979
4980 nsIDocument* doc = mContentViewer->GetDocument();
4981 if (!doc) {
4982 return NS_ERROR_NOT_AVAILABLE;
4983 }
4984
4985 return CallQueryInterface(doc, aDocument);
4986 }
4987
4988 NS_IMETHODIMP
GetCurrentURI(nsIURI ** aURI)4989 nsDocShell::GetCurrentURI(nsIURI** aURI) {
4990 NS_ENSURE_ARG_POINTER(aURI);
4991
4992 if (mCurrentURI) {
4993 return NS_EnsureSafeToReturn(mCurrentURI, aURI);
4994 }
4995
4996 *aURI = nullptr;
4997 return NS_OK;
4998 }
4999
5000 NS_IMETHODIMP
GetReferringURI(nsIURI ** aURI)5001 nsDocShell::GetReferringURI(nsIURI** aURI) {
5002 NS_ENSURE_ARG_POINTER(aURI);
5003
5004 *aURI = mReferrerURI;
5005 NS_IF_ADDREF(*aURI);
5006
5007 return NS_OK;
5008 }
5009
5010 NS_IMETHODIMP
SetSessionHistory(nsISHistory * aSessionHistory)5011 nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory) {
5012 NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
5013 // make sure that we are the root docshell and
5014 // set a handle to root docshell in SH.
5015
5016 MOZ_ASSERT(!mIsBeingDestroyed);
5017
5018 nsCOMPtr<nsIDocShellTreeItem> root;
5019 /* Get the root docshell. If *this* is the root docshell
5020 * then save a handle to *this* in SH. SH needs it to do
5021 * traversions thro' its entries
5022 */
5023 GetSameTypeRootTreeItem(getter_AddRefs(root));
5024 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
5025 if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
5026 mSessionHistory = aSessionHistory;
5027 nsCOMPtr<nsISHistoryInternal> shPrivate =
5028 do_QueryInterface(mSessionHistory);
5029 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
5030 shPrivate->SetRootDocShell(this);
5031 return NS_OK;
5032 }
5033 return NS_ERROR_FAILURE;
5034 }
5035
5036 NS_IMETHODIMP
GetSessionHistory(nsISHistory ** aSessionHistory)5037 nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory) {
5038 NS_ENSURE_ARG_POINTER(aSessionHistory);
5039 *aSessionHistory = mSessionHistory;
5040 NS_IF_ADDREF(*aSessionHistory);
5041 return NS_OK;
5042 }
5043
5044 //*****************************************************************************
5045 // nsDocShell::nsIWebPageDescriptor
5046 //*****************************************************************************
5047
5048 NS_IMETHODIMP
LoadPage(nsISupports * aPageDescriptor,uint32_t aDisplayType)5049 nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType) {
5050 nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
5051
5052 // Currently, the opaque 'page descriptor' is an nsISHEntry...
5053 if (!shEntryIn) {
5054 return NS_ERROR_INVALID_POINTER;
5055 }
5056
5057 // Now clone shEntryIn, since we might end up modifying it later on, and we
5058 // want a page descriptor to be reusable.
5059 nsCOMPtr<nsISHEntry> shEntry;
5060 nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
5061 NS_ENSURE_SUCCESS(rv, rv);
5062
5063 // Give our cloned shEntry a new bfcache entry so this load is independent
5064 // of all other loads. (This is important, in particular, for bugs 582795
5065 // and 585298.)
5066 rv = shEntry->AbandonBFCacheEntry();
5067 NS_ENSURE_SUCCESS(rv, rv);
5068
5069 //
5070 // load the page as view-source
5071 //
5072 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
5073 nsCOMPtr<nsIURI> oldUri, newUri;
5074 nsCString spec, newSpec;
5075
5076 // Create a new view-source URI and replace the original.
5077 rv = shEntry->GetURI(getter_AddRefs(oldUri));
5078 if (NS_FAILED(rv)) {
5079 return rv;
5080 }
5081
5082 oldUri->GetSpec(spec);
5083 newSpec.AppendLiteral("view-source:");
5084 newSpec.Append(spec);
5085
5086 rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
5087 if (NS_FAILED(rv)) {
5088 return rv;
5089 }
5090 shEntry->SetURI(newUri);
5091 shEntry->SetOriginalURI(nullptr);
5092 shEntry->SetResultPrincipalURI(nullptr);
5093 // shEntry's current triggering principal is whoever loaded that page
5094 // initially. But now we're doing another load of the page, via an API that
5095 // is only exposed to system code. The triggering principal for this load
5096 // should be the system principal.
5097 shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
5098 }
5099
5100 rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
5101 return rv;
5102 }
5103
5104 NS_IMETHODIMP
GetCurrentDescriptor(nsISupports ** aPageDescriptor)5105 nsDocShell::GetCurrentDescriptor(nsISupports** aPageDescriptor) {
5106 NS_PRECONDITION(aPageDescriptor, "Null out param?");
5107
5108 *aPageDescriptor = nullptr;
5109
5110 nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
5111 if (src) {
5112 nsCOMPtr<nsISHEntry> dest;
5113
5114 nsresult rv = src->Clone(getter_AddRefs(dest));
5115 if (NS_FAILED(rv)) {
5116 return rv;
5117 }
5118
5119 // null out inappropriate cloned attributes...
5120 dest->SetParent(nullptr);
5121 dest->SetIsSubFrame(false);
5122
5123 return CallQueryInterface(dest, aPageDescriptor);
5124 }
5125
5126 return NS_ERROR_NOT_AVAILABLE;
5127 }
5128
5129 //*****************************************************************************
5130 // nsDocShell::nsIBaseWindow
5131 //*****************************************************************************
5132
5133 NS_IMETHODIMP
InitWindow(nativeWindow aParentNativeWindow,nsIWidget * aParentWidget,int32_t aX,int32_t aY,int32_t aWidth,int32_t aHeight)5134 nsDocShell::InitWindow(nativeWindow aParentNativeWindow,
5135 nsIWidget* aParentWidget, int32_t aX, int32_t aY,
5136 int32_t aWidth, int32_t aHeight) {
5137 SetParentWidget(aParentWidget);
5138 SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
5139
5140 return NS_OK;
5141 }
5142
5143 NS_IMETHODIMP
Create()5144 nsDocShell::Create() {
5145 if (mCreated) {
5146 // We've already been created
5147 return NS_OK;
5148 }
5149
5150 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5151 "Unexpected item type in docshell");
5152
5153 NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
5154 mCreated = true;
5155
5156 if (gValidateOrigin == 0xffffffff) {
5157 // Check pref to see if we should prevent frameset spoofing
5158 gValidateOrigin =
5159 Preferences::GetBool("browser.frame.validate_origin", true);
5160 }
5161
5162 // Should we use XUL error pages instead of alerts if possible?
5163 mUseErrorPages =
5164 Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
5165
5166 if (!gAddedPreferencesVarCache) {
5167 Preferences::AddBoolVarCache(
5168 &sUseErrorPages, "browser.xul.error_pages.enabled", mUseErrorPages);
5169 gAddedPreferencesVarCache = true;
5170 }
5171
5172 mDisableMetaRefreshWhenInactive =
5173 Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
5174 mDisableMetaRefreshWhenInactive);
5175
5176 mDeviceSizeIsPageSize = Preferences::GetBool(
5177 "docshell.device_size_is_page_size", mDeviceSizeIsPageSize);
5178
5179 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5180 if (serv) {
5181 const char* msg = mItemType == typeContent ? NS_WEBNAVIGATION_CREATE
5182 : NS_CHROME_WEBNAVIGATION_CREATE;
5183 serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5184 }
5185
5186 return NS_OK;
5187 }
5188
5189 NS_IMETHODIMP
Destroy()5190 nsDocShell::Destroy() {
5191 // XXX: We allow this function to be called just once. If you are going to
5192 // reset new variables in this function, please make sure the variables will
5193 // never be re-initialized. Adding assertions to check |mIsBeingDestroyed|
5194 // in the setter functions for the variables would be enough.
5195 if (mIsBeingDestroyed) {
5196 return NS_ERROR_DOCSHELL_DYING;
5197 }
5198
5199 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5200 "Unexpected item type in docshell");
5201
5202 AssertOriginAttributesMatchPrivateBrowsing();
5203
5204 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5205 if (serv) {
5206 const char* msg = mItemType == typeContent
5207 ? NS_WEBNAVIGATION_DESTROY
5208 : NS_CHROME_WEBNAVIGATION_DESTROY;
5209 serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5210 }
5211
5212 mIsBeingDestroyed = true;
5213
5214 // Brak the cycle with the initial client, if present.
5215 mInitialClientSource.reset();
5216
5217 // Make sure we don't record profile timeline markers anymore
5218 SetRecordProfileTimelineMarkers(false);
5219
5220 // Remove our pref observers
5221 if (mObserveErrorPages) {
5222 mObserveErrorPages = false;
5223 }
5224
5225 // Make sure to blow away our mLoadingURI just in case. No loads
5226 // from inside this pagehide.
5227 mLoadingURI = nullptr;
5228
5229 // Fire unload event before we blow anything away.
5230 (void)FirePageHideNotification(true);
5231
5232 // Clear pointers to any detached nsEditorData that's lying
5233 // around in shistory entries. Breaks cycle. See bug 430921.
5234 if (mOSHE) {
5235 mOSHE->SetEditorData(nullptr);
5236 }
5237 if (mLSHE) {
5238 mLSHE->SetEditorData(nullptr);
5239 }
5240
5241 // Note: mContentListener can be null if Init() failed and we're being
5242 // called from the destructor.
5243 if (mContentListener) {
5244 mContentListener->DropDocShellReference();
5245 mContentListener->SetParentContentListener(nullptr);
5246 // Note that we do NOT set mContentListener to null here; that
5247 // way if someone tries to do a load in us after this point
5248 // the nsDSURIContentListener will block it. All of which
5249 // means that we should do this before calling Stop(), of
5250 // course.
5251 }
5252
5253 // Stop any URLs that are currently being loaded...
5254 Stop(nsIWebNavigation::STOP_ALL);
5255
5256 mEditorData = nullptr;
5257
5258 mTransferableHookData = nullptr;
5259
5260 // Save the state of the current document, before destroying the window.
5261 // This is needed to capture the state of a frameset when the new document
5262 // causes the frameset to be destroyed...
5263 PersistLayoutHistoryState();
5264
5265 // Remove this docshell from its parent's child list
5266 nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
5267 do_QueryInterface(GetAsSupports(mParent));
5268 if (docShellParentAsItem) {
5269 docShellParentAsItem->RemoveChild(this);
5270 }
5271
5272 if (mContentViewer) {
5273 mContentViewer->Close(nullptr);
5274 mContentViewer->Destroy();
5275 mContentViewer = nullptr;
5276 }
5277
5278 nsDocLoader::Destroy();
5279
5280 mParentWidget = nullptr;
5281 mCurrentURI = nullptr;
5282
5283 if (mScriptGlobal) {
5284 mScriptGlobal->DetachFromDocShell();
5285 mScriptGlobal = nullptr;
5286 }
5287
5288 if (mSessionHistory) {
5289 // We want to destroy these content viewers now rather than
5290 // letting their destruction wait for the session history
5291 // entries to get garbage collected. (Bug 488394)
5292 nsCOMPtr<nsISHistoryInternal> shPrivate =
5293 do_QueryInterface(mSessionHistory);
5294 if (shPrivate) {
5295 shPrivate->EvictAllContentViewers();
5296 }
5297 mSessionHistory = nullptr;
5298 }
5299
5300 SetTreeOwner(nullptr);
5301
5302 mChromeEventHandler = nullptr;
5303
5304 mOnePermittedSandboxedNavigator = nullptr;
5305
5306 // required to break ref cycle
5307 mSecurityUI = nullptr;
5308
5309 // Cancel any timers that were set for this docshell; this is needed
5310 // to break the cycle between us and the timers.
5311 CancelRefreshURITimers();
5312
5313 if (UsePrivateBrowsing()) {
5314 mPrivateBrowsingId = 0;
5315 mOriginAttributes.SyncAttributesWithPrivateBrowsing(false);
5316 if (mAffectPrivateSessionLifetime) {
5317 DecreasePrivateDocShellCount();
5318 }
5319 }
5320
5321 return NS_OK;
5322 }
5323
5324 NS_IMETHODIMP
GetUnscaledDevicePixelsPerCSSPixel(double * aScale)5325 nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale) {
5326 if (mParentWidget) {
5327 *aScale = mParentWidget->GetDefaultScale().scale;
5328 return NS_OK;
5329 }
5330
5331 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5332 if (ownerWindow) {
5333 return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
5334 }
5335
5336 *aScale = 1.0;
5337 return NS_OK;
5338 }
5339
5340 NS_IMETHODIMP
GetDevicePixelsPerDesktopPixel(double * aScale)5341 nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale) {
5342 if (mParentWidget) {
5343 *aScale = mParentWidget->GetDesktopToDeviceScale().scale;
5344 return NS_OK;
5345 }
5346
5347 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5348 if (ownerWindow) {
5349 return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale);
5350 }
5351
5352 *aScale = 1.0;
5353 return NS_OK;
5354 }
5355
5356 NS_IMETHODIMP
SetPosition(int32_t aX,int32_t aY)5357 nsDocShell::SetPosition(int32_t aX, int32_t aY) {
5358 mBounds.MoveTo(aX, aY);
5359
5360 if (mContentViewer) {
5361 NS_ENSURE_SUCCESS(mContentViewer->Move(aX, aY), NS_ERROR_FAILURE);
5362 }
5363
5364 return NS_OK;
5365 }
5366
5367 NS_IMETHODIMP
SetPositionDesktopPix(int32_t aX,int32_t aY)5368 nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY) {
5369 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5370 if (ownerWindow) {
5371 return ownerWindow->SetPositionDesktopPix(aX, aY);
5372 }
5373
5374 double scale = 1.0;
5375 GetDevicePixelsPerDesktopPixel(&scale);
5376 return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
5377 }
5378
5379 NS_IMETHODIMP
GetPosition(int32_t * aX,int32_t * aY)5380 nsDocShell::GetPosition(int32_t* aX, int32_t* aY) {
5381 return GetPositionAndSize(aX, aY, nullptr, nullptr);
5382 }
5383
5384 NS_IMETHODIMP
SetSize(int32_t aWidth,int32_t aHeight,bool aRepaint)5385 nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint) {
5386 int32_t x = 0, y = 0;
5387 GetPosition(&x, &y);
5388 return SetPositionAndSize(x, y, aWidth, aHeight,
5389 aRepaint ? nsIBaseWindow::eRepaint : 0);
5390 }
5391
5392 NS_IMETHODIMP
GetSize(int32_t * aWidth,int32_t * aHeight)5393 nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight) {
5394 return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
5395 }
5396
5397 NS_IMETHODIMP
SetPositionAndSize(int32_t aX,int32_t aY,int32_t aWidth,int32_t aHeight,uint32_t aFlags)5398 nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
5399 int32_t aHeight, uint32_t aFlags) {
5400 mBounds.SetRect(aX, aY, aWidth, aHeight);
5401
5402 // Hold strong ref, since SetBounds can make us null out mContentViewer
5403 nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
5404 if (viewer) {
5405 uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize)
5406 ? nsIContentViewer::eDelayResize
5407 : 0;
5408 // XXX Border figured in here or is that handled elsewhere?
5409 nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
5410 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5411 }
5412
5413 return NS_OK;
5414 }
5415
5416 NS_IMETHODIMP
GetPositionAndSize(int32_t * aX,int32_t * aY,int32_t * aWidth,int32_t * aHeight)5417 nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
5418 int32_t* aHeight) {
5419 if (mParentWidget) {
5420 // ensure size is up-to-date if window has changed resolution
5421 LayoutDeviceIntRect r = mParentWidget->GetClientBounds();
5422 SetPositionAndSize(mBounds.X(), mBounds.Y(), r.Width(), r.Height(), 0);
5423 }
5424
5425 // We should really consider just getting this information from
5426 // our window instead of duplicating the storage and code...
5427 if (aWidth || aHeight) {
5428 // Caller wants to know our size; make sure to give them up to
5429 // date information.
5430 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
5431 if (doc) {
5432 doc->FlushPendingNotifications(FlushType::Layout);
5433 }
5434 }
5435
5436 DoGetPositionAndSize(aX, aY, aWidth, aHeight);
5437 return NS_OK;
5438 }
5439
DoGetPositionAndSize(int32_t * aX,int32_t * aY,int32_t * aWidth,int32_t * aHeight)5440 void nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
5441 int32_t* aHeight) {
5442 if (aX) {
5443 *aX = mBounds.X();
5444 }
5445 if (aY) {
5446 *aY = mBounds.Y();
5447 }
5448 if (aWidth) {
5449 *aWidth = mBounds.Width();
5450 }
5451 if (aHeight) {
5452 *aHeight = mBounds.Height();
5453 }
5454 }
5455
5456 NS_IMETHODIMP
Repaint(bool aForce)5457 nsDocShell::Repaint(bool aForce) {
5458 nsCOMPtr<nsIPresShell> presShell = GetPresShell();
5459 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
5460
5461 nsViewManager* viewManager = presShell->GetViewManager();
5462 NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
5463
5464 viewManager->InvalidateAllViews();
5465 return NS_OK;
5466 }
5467
5468 NS_IMETHODIMP
GetParentWidget(nsIWidget ** aParentWidget)5469 nsDocShell::GetParentWidget(nsIWidget** aParentWidget) {
5470 NS_ENSURE_ARG_POINTER(aParentWidget);
5471
5472 *aParentWidget = mParentWidget;
5473 NS_IF_ADDREF(*aParentWidget);
5474
5475 return NS_OK;
5476 }
5477
5478 NS_IMETHODIMP
SetParentWidget(nsIWidget * aParentWidget)5479 nsDocShell::SetParentWidget(nsIWidget* aParentWidget) {
5480 MOZ_ASSERT(!mIsBeingDestroyed);
5481 mParentWidget = aParentWidget;
5482
5483 return NS_OK;
5484 }
5485
5486 NS_IMETHODIMP
GetParentNativeWindow(nativeWindow * aParentNativeWindow)5487 nsDocShell::GetParentNativeWindow(nativeWindow* aParentNativeWindow) {
5488 NS_ENSURE_ARG_POINTER(aParentNativeWindow);
5489
5490 if (mParentWidget) {
5491 *aParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
5492 } else {
5493 *aParentNativeWindow = nullptr;
5494 }
5495
5496 return NS_OK;
5497 }
5498
5499 NS_IMETHODIMP
SetParentNativeWindow(nativeWindow aParentNativeWindow)5500 nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow) {
5501 return NS_ERROR_NOT_IMPLEMENTED;
5502 }
5503
5504 NS_IMETHODIMP
GetNativeHandle(nsAString & aNativeHandle)5505 nsDocShell::GetNativeHandle(nsAString& aNativeHandle) {
5506 // the nativeHandle should be accessed from nsIXULWindow
5507 return NS_ERROR_NOT_IMPLEMENTED;
5508 }
5509
5510 NS_IMETHODIMP
GetVisibility(bool * aVisibility)5511 nsDocShell::GetVisibility(bool* aVisibility) {
5512 NS_ENSURE_ARG_POINTER(aVisibility);
5513
5514 *aVisibility = false;
5515
5516 if (!mContentViewer) {
5517 return NS_OK;
5518 }
5519
5520 nsCOMPtr<nsIPresShell> presShell = GetPresShell();
5521 if (!presShell) {
5522 return NS_OK;
5523 }
5524
5525 // get the view manager
5526 nsViewManager* vm = presShell->GetViewManager();
5527 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
5528
5529 // get the root view
5530 nsView* view = vm->GetRootView(); // views are not ref counted
5531 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
5532
5533 // if our root view is hidden, we are not visible
5534 if (view->GetVisibility() == nsViewVisibility_kHide) {
5535 return NS_OK;
5536 }
5537
5538 // otherwise, we must walk up the document and view trees checking
5539 // for a hidden view, unless we're an off screen browser, which
5540 // would make this test meaningless.
5541
5542 RefPtr<nsDocShell> docShell = this;
5543 RefPtr<nsDocShell> parentItem = docShell->GetParentDocshell();
5544 while (parentItem) {
5545 presShell = docShell->GetPresShell();
5546
5547 nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell();
5548
5549 // Null-check for crash in bug 267804
5550 if (!pPresShell) {
5551 NS_NOTREACHED("parent docshell has null pres shell");
5552 return NS_OK;
5553 }
5554
5555 vm = presShell->GetViewManager();
5556 if (vm) {
5557 view = vm->GetRootView();
5558 }
5559
5560 if (view) {
5561 view = view->GetParent(); // anonymous inner view
5562 if (view) {
5563 view = view->GetParent(); // subdocumentframe's view
5564 }
5565 }
5566
5567 nsIFrame* frame = view ? view->GetFrame() : nullptr;
5568 bool isDocShellOffScreen = false;
5569 docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
5570 if (frame &&
5571 !frame->IsVisibleConsideringAncestors(
5572 nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
5573 !isDocShellOffScreen) {
5574 return NS_OK;
5575 }
5576
5577 docShell = parentItem;
5578 parentItem = docShell->GetParentDocshell();
5579 }
5580
5581 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
5582 if (!treeOwnerAsWin) {
5583 *aVisibility = true;
5584 return NS_OK;
5585 }
5586
5587 // Check with the tree owner as well to give embedders a chance to
5588 // expose visibility as well.
5589 return treeOwnerAsWin->GetVisibility(aVisibility);
5590 }
5591
5592 NS_IMETHODIMP
SetIsOffScreenBrowser(bool aIsOffScreen)5593 nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen) {
5594 mIsOffScreenBrowser = aIsOffScreen;
5595 return NS_OK;
5596 }
5597
5598 NS_IMETHODIMP
GetIsOffScreenBrowser(bool * aIsOffScreen)5599 nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen) {
5600 *aIsOffScreen = mIsOffScreenBrowser;
5601 return NS_OK;
5602 }
5603
5604 NS_IMETHODIMP
SetIsActive(bool aIsActive)5605 nsDocShell::SetIsActive(bool aIsActive) {
5606 // We disallow setting active on chrome docshells.
5607 if (mItemType == nsIDocShellTreeItem::typeChrome) {
5608 return NS_ERROR_INVALID_ARG;
5609 }
5610
5611 // Keep track ourselves.
5612 mIsActive = aIsActive;
5613
5614 // Tell the PresShell about it.
5615 nsCOMPtr<nsIPresShell> pshell = GetPresShell();
5616 if (pshell) {
5617 pshell->SetIsActive(aIsActive);
5618 }
5619
5620 // Tell the window about it
5621 if (mScriptGlobal) {
5622 mScriptGlobal->SetIsBackground(!aIsActive);
5623 if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
5624 // Update orientation when the top-level browsing context becomes active.
5625 if (aIsActive) {
5626 nsCOMPtr<nsIDocShellTreeItem> parent;
5627 GetSameTypeParent(getter_AddRefs(parent));
5628 if (!parent) {
5629 // We only care about the top-level browsing context.
5630 uint16_t orientation = OrientationLock();
5631 ScreenOrientation::UpdateActiveOrientationLock(orientation);
5632 }
5633 }
5634
5635 doc->PostVisibilityUpdateEvent();
5636 }
5637 }
5638
5639 // Tell the nsDOMNavigationTiming about it
5640 RefPtr<nsDOMNavigationTiming> timing = mTiming;
5641 if (!timing && mContentViewer) {
5642 nsIDocument* doc = mContentViewer->GetDocument();
5643 if (doc) {
5644 timing = doc->GetNavigationTiming();
5645 }
5646 }
5647 if (timing) {
5648 timing->NotifyDocShellStateChanged(
5649 aIsActive ? nsDOMNavigationTiming::DocShellState::eActive
5650 : nsDOMNavigationTiming::DocShellState::eInactive);
5651 }
5652
5653 // Recursively tell all of our children, but don't tell <iframe mozbrowser>
5654 // children; they handle their state separately.
5655 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5656 while (iter.HasMore()) {
5657 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
5658 if (!docshell) {
5659 continue;
5660 }
5661
5662 if (!docshell->GetIsMozBrowser()) {
5663 docshell->SetIsActive(aIsActive);
5664 }
5665 }
5666
5667 // Restart or stop meta refresh timers if necessary
5668 if (mDisableMetaRefreshWhenInactive) {
5669 if (mIsActive) {
5670 ResumeRefreshURIs();
5671 } else {
5672 SuspendRefreshURIs();
5673 }
5674 }
5675
5676 return NS_OK;
5677 }
5678
5679 NS_IMETHODIMP
GetIsActive(bool * aIsActive)5680 nsDocShell::GetIsActive(bool* aIsActive) {
5681 *aIsActive = mIsActive;
5682 return NS_OK;
5683 }
5684
5685 NS_IMETHODIMP
SetIsAppTab(bool aIsAppTab)5686 nsDocShell::SetIsAppTab(bool aIsAppTab) {
5687 mIsAppTab = aIsAppTab;
5688 return NS_OK;
5689 }
5690
5691 NS_IMETHODIMP
GetIsAppTab(bool * aIsAppTab)5692 nsDocShell::GetIsAppTab(bool* aIsAppTab) {
5693 *aIsAppTab = mIsAppTab;
5694 return NS_OK;
5695 }
5696
5697 NS_IMETHODIMP
SetSandboxFlags(uint32_t aSandboxFlags)5698 nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags) {
5699 mSandboxFlags = aSandboxFlags;
5700 return NS_OK;
5701 }
5702
5703 NS_IMETHODIMP
GetSandboxFlags(uint32_t * aSandboxFlags)5704 nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags) {
5705 *aSandboxFlags = mSandboxFlags;
5706 return NS_OK;
5707 }
5708
5709 NS_IMETHODIMP
SetOnePermittedSandboxedNavigator(nsIDocShell * aSandboxedNavigator)5710 nsDocShell::SetOnePermittedSandboxedNavigator(
5711 nsIDocShell* aSandboxedNavigator) {
5712 if (mOnePermittedSandboxedNavigator) {
5713 NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
5714 return NS_OK;
5715 }
5716
5717 MOZ_ASSERT(!mIsBeingDestroyed);
5718
5719 mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
5720 NS_ASSERTION(
5721 mOnePermittedSandboxedNavigator,
5722 "One Permitted Sandboxed Navigator must support weak references.");
5723
5724 return NS_OK;
5725 }
5726
5727 NS_IMETHODIMP
GetOnePermittedSandboxedNavigator(nsIDocShell ** aSandboxedNavigator)5728 nsDocShell::GetOnePermittedSandboxedNavigator(
5729 nsIDocShell** aSandboxedNavigator) {
5730 NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
5731 nsCOMPtr<nsIDocShell> permittedNavigator =
5732 do_QueryReferent(mOnePermittedSandboxedNavigator);
5733 permittedNavigator.forget(aSandboxedNavigator);
5734 return NS_OK;
5735 }
5736
5737 NS_IMETHODIMP
SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)5738 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags) {
5739 mDefaultLoadFlags = aDefaultLoadFlags;
5740
5741 // Tell the load group to set these flags all requests in the group
5742 if (mLoadGroup) {
5743 mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
5744 } else {
5745 NS_WARNING(
5746 "nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the "
5747 "flags to");
5748 }
5749
5750 // Recursively tell all of our children. We *do not* skip
5751 // <iframe mozbrowser> children - if someone sticks custom flags in this
5752 // docShell then they too get the same flags.
5753 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5754 while (iter.HasMore()) {
5755 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
5756 if (!docshell) {
5757 continue;
5758 }
5759 docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
5760 }
5761 return NS_OK;
5762 }
5763
5764 NS_IMETHODIMP
GetDefaultLoadFlags(uint32_t * aDefaultLoadFlags)5765 nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags) {
5766 *aDefaultLoadFlags = mDefaultLoadFlags;
5767 return NS_OK;
5768 }
5769
5770 NS_IMETHODIMP
SetMixedContentChannel(nsIChannel * aMixedContentChannel)5771 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel) {
5772 #ifdef DEBUG
5773 // if the channel is non-null
5774 if (aMixedContentChannel) {
5775 // Get the root docshell.
5776 nsCOMPtr<nsIDocShellTreeItem> root;
5777 GetSameTypeRootTreeItem(getter_AddRefs(root));
5778 NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this),
5779 "Setting mMixedContentChannel on a docshell that is "
5780 "not the root docshell");
5781 }
5782 #endif
5783 mMixedContentChannel = aMixedContentChannel;
5784 return NS_OK;
5785 }
5786
5787 NS_IMETHODIMP
GetFailedChannel(nsIChannel ** aFailedChannel)5788 nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel) {
5789 NS_ENSURE_ARG_POINTER(aFailedChannel);
5790 nsIDocument* doc = GetDocument();
5791 if (!doc) {
5792 *aFailedChannel = nullptr;
5793 return NS_OK;
5794 }
5795 NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel());
5796 return NS_OK;
5797 }
5798
5799 NS_IMETHODIMP
GetMixedContentChannel(nsIChannel ** aMixedContentChannel)5800 nsDocShell::GetMixedContentChannel(nsIChannel** aMixedContentChannel) {
5801 NS_ENSURE_ARG_POINTER(aMixedContentChannel);
5802 NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
5803 return NS_OK;
5804 }
5805
5806 NS_IMETHODIMP
GetAllowMixedContentAndConnectionData(bool * aRootHasSecureConnection,bool * aAllowMixedContent,bool * aIsRootDocShell)5807 nsDocShell::GetAllowMixedContentAndConnectionData(
5808 bool* aRootHasSecureConnection, bool* aAllowMixedContent,
5809 bool* aIsRootDocShell) {
5810 *aRootHasSecureConnection = true;
5811 *aAllowMixedContent = false;
5812 *aIsRootDocShell = false;
5813
5814 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
5815 GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
5816 NS_ASSERTION(
5817 sameTypeRoot,
5818 "No document shell root tree item from document shell tree item!");
5819 *aIsRootDocShell =
5820 sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this);
5821
5822 // now get the document from sameTypeRoot
5823 nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument();
5824 if (rootDoc) {
5825 nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
5826
5827 // For things with system principal (e.g. scratchpad) there is no uri
5828 // aRootHasSecureConnection should be false.
5829 nsCOMPtr<nsIURI> rootUri;
5830 if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
5831 NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
5832 NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
5833 *aRootHasSecureConnection = false;
5834 }
5835
5836 // Check the root doc's channel against the root docShell's
5837 // mMixedContentChannel to see if they are the same. If they are the same,
5838 // the user has overriden the block.
5839 nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
5840 nsCOMPtr<nsIChannel> mixedChannel;
5841 rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
5842 *aAllowMixedContent =
5843 mixedChannel && (mixedChannel == rootDoc->GetChannel());
5844 }
5845
5846 return NS_OK;
5847 }
5848
5849 NS_IMETHODIMP
SetVisibility(bool aVisibility)5850 nsDocShell::SetVisibility(bool aVisibility) {
5851 // Show()/Hide() may change mContentViewer.
5852 nsCOMPtr<nsIContentViewer> cv = mContentViewer;
5853 if (!cv) {
5854 return NS_OK;
5855 }
5856 if (aVisibility) {
5857 cv->Show();
5858 } else {
5859 cv->Hide();
5860 }
5861
5862 return NS_OK;
5863 }
5864
5865 NS_IMETHODIMP
GetEnabled(bool * aEnabled)5866 nsDocShell::GetEnabled(bool* aEnabled) {
5867 NS_ENSURE_ARG_POINTER(aEnabled);
5868 *aEnabled = true;
5869 return NS_ERROR_NOT_IMPLEMENTED;
5870 }
5871
5872 NS_IMETHODIMP
SetEnabled(bool aEnabled)5873 nsDocShell::SetEnabled(bool aEnabled) { return NS_ERROR_NOT_IMPLEMENTED; }
5874
5875 NS_IMETHODIMP
SetFocus()5876 nsDocShell::SetFocus() { return NS_OK; }
5877
5878 NS_IMETHODIMP
GetMainWidget(nsIWidget ** aMainWidget)5879 nsDocShell::GetMainWidget(nsIWidget** aMainWidget) {
5880 // We don't create our own widget, so simply return the parent one.
5881 return GetParentWidget(aMainWidget);
5882 }
5883
5884 NS_IMETHODIMP
GetTitle(nsAString & aTitle)5885 nsDocShell::GetTitle(nsAString& aTitle) {
5886 aTitle = mTitle;
5887 return NS_OK;
5888 }
5889
5890 NS_IMETHODIMP
SetTitle(const nsAString & aTitle)5891 nsDocShell::SetTitle(const nsAString& aTitle) {
5892 // Store local title
5893 mTitle = aTitle;
5894
5895 nsCOMPtr<nsIDocShellTreeItem> parent;
5896 GetSameTypeParent(getter_AddRefs(parent));
5897
5898 // When title is set on the top object it should then be passed to the
5899 // tree owner.
5900 if (!parent) {
5901 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
5902 if (treeOwnerAsWin) {
5903 treeOwnerAsWin->SetTitle(aTitle);
5904 }
5905 }
5906
5907 AssertOriginAttributesMatchPrivateBrowsing();
5908 if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
5909 UpdateGlobalHistoryTitle(mCurrentURI);
5910 }
5911
5912 // Update SessionHistory with the document's title.
5913 if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
5914 mLoadType != LOAD_ERROR_PAGE) {
5915 mOSHE->SetTitle(mTitle);
5916 }
5917
5918 return NS_OK;
5919 }
5920
GetCurScrollPos(int32_t aScrollOrientation,int32_t * aCurPos)5921 nsresult nsDocShell::GetCurScrollPos(int32_t aScrollOrientation,
5922 int32_t* aCurPos) {
5923 NS_ENSURE_ARG_POINTER(aCurPos);
5924
5925 nsIScrollableFrame* sf = GetRootScrollFrame();
5926 if (!sf) {
5927 return NS_ERROR_FAILURE;
5928 }
5929
5930 nsPoint pt = sf->GetScrollPosition();
5931
5932 switch (aScrollOrientation) {
5933 case ScrollOrientation_X:
5934 *aCurPos = pt.x;
5935 return NS_OK;
5936
5937 case ScrollOrientation_Y:
5938 *aCurPos = pt.y;
5939 return NS_OK;
5940
5941 default:
5942 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5943 }
5944 }
5945
SetCurScrollPosEx(int32_t aCurHorizontalPos,int32_t aCurVerticalPos)5946 nsresult nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos,
5947 int32_t aCurVerticalPos) {
5948 nsIScrollableFrame* sf = GetRootScrollFrame();
5949 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5950
5951 sf->ScrollTo(nsPoint(aCurHorizontalPos, aCurVerticalPos),
5952 nsIScrollableFrame::INSTANT);
5953 return NS_OK;
5954 }
5955
5956 //*****************************************************************************
5957 // nsDocShell::nsIScrollable
5958 //*****************************************************************************
5959
5960 NS_IMETHODIMP
GetDefaultScrollbarPreferences(int32_t aScrollOrientation,int32_t * aScrollbarPref)5961 nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation,
5962 int32_t* aScrollbarPref) {
5963 NS_ENSURE_ARG_POINTER(aScrollbarPref);
5964 switch (aScrollOrientation) {
5965 case ScrollOrientation_X:
5966 *aScrollbarPref = mDefaultScrollbarPref.x;
5967 return NS_OK;
5968
5969 case ScrollOrientation_Y:
5970 *aScrollbarPref = mDefaultScrollbarPref.y;
5971 return NS_OK;
5972
5973 default:
5974 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5975 }
5976 return NS_ERROR_FAILURE;
5977 }
5978
5979 NS_IMETHODIMP
SetDefaultScrollbarPreferences(int32_t aScrollOrientation,int32_t aScrollbarPref)5980 nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation,
5981 int32_t aScrollbarPref) {
5982 switch (aScrollOrientation) {
5983 case ScrollOrientation_X:
5984 mDefaultScrollbarPref.x = aScrollbarPref;
5985 return NS_OK;
5986
5987 case ScrollOrientation_Y:
5988 mDefaultScrollbarPref.y = aScrollbarPref;
5989 return NS_OK;
5990
5991 default:
5992 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5993 }
5994 return NS_ERROR_FAILURE;
5995 }
5996
5997 NS_IMETHODIMP
GetScrollbarVisibility(bool * aVerticalVisible,bool * aHorizontalVisible)5998 nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible,
5999 bool* aHorizontalVisible) {
6000 nsIScrollableFrame* sf = GetRootScrollFrame();
6001 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6002
6003 uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
6004 if (aVerticalVisible) {
6005 *aVerticalVisible =
6006 (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
6007 }
6008 if (aHorizontalVisible) {
6009 *aHorizontalVisible =
6010 (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
6011 }
6012
6013 return NS_OK;
6014 }
6015
6016 //*****************************************************************************
6017 // nsDocShell::nsITextScroll
6018 //*****************************************************************************
6019
6020 NS_IMETHODIMP
ScrollByLines(int32_t aNumLines)6021 nsDocShell::ScrollByLines(int32_t aNumLines) {
6022 nsIScrollableFrame* sf = GetRootScrollFrame();
6023 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6024
6025 sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES,
6026 nsIScrollableFrame::SMOOTH);
6027 return NS_OK;
6028 }
6029
6030 NS_IMETHODIMP
ScrollByPages(int32_t aNumPages)6031 nsDocShell::ScrollByPages(int32_t aNumPages) {
6032 nsIScrollableFrame* sf = GetRootScrollFrame();
6033 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6034
6035 sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES,
6036 nsIScrollableFrame::SMOOTH);
6037 return NS_OK;
6038 }
6039
6040 //*****************************************************************************
6041 // nsDocShell::nsIRefreshURI
6042 //*****************************************************************************
6043
6044 NS_IMETHODIMP
RefreshURI(nsIURI * aURI,nsIPrincipal * aPrincipal,int32_t aDelay,bool aRepeat,bool aMetaRefresh)6045 nsDocShell::RefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDelay,
6046 bool aRepeat, bool aMetaRefresh) {
6047 MOZ_ASSERT(!mIsBeingDestroyed);
6048
6049 NS_ENSURE_ARG(aURI);
6050
6051 /* Check if Meta refresh/redirects are permitted. Some
6052 * embedded applications may not want to do this.
6053 * Must do this before sending out NOTIFY_REFRESH events
6054 * because listeners may have side effects (e.g. displaying a
6055 * button to manually trigger the refresh later).
6056 */
6057 bool allowRedirects = true;
6058 GetAllowMetaRedirects(&allowRedirects);
6059 if (!allowRedirects) {
6060 return NS_OK;
6061 }
6062
6063 // If any web progress listeners are listening for NOTIFY_REFRESH events,
6064 // give them a chance to block this refresh.
6065 bool sameURI;
6066 nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
6067 if (NS_FAILED(rv)) {
6068 sameURI = false;
6069 }
6070 if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
6071 return NS_OK;
6072 }
6073
6074 nsCOMPtr<nsITimerCallback> refreshTimer =
6075 new nsRefreshTimer(this, aURI, aPrincipal, aDelay, aRepeat, aMetaRefresh);
6076
6077 uint32_t busyFlags = 0;
6078 GetBusyFlags(&busyFlags);
6079
6080 if (!mRefreshURIList) {
6081 mRefreshURIList = nsArray::Create();
6082 }
6083
6084 if (busyFlags & BUSY_FLAGS_BUSY ||
6085 (!mIsActive && mDisableMetaRefreshWhenInactive)) {
6086 // We don't want to create the timer right now. Instead queue up the
6087 // request and trigger the timer in EndPageLoad() or whenever we become
6088 // active.
6089 mRefreshURIList->AppendElement(refreshTimer);
6090 } else {
6091 // There is no page loading going on right now. Create the
6092 // timer and fire it right away.
6093 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
6094 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
6095
6096 nsCOMPtr<nsITimer> timer;
6097 MOZ_TRY_VAR(timer,
6098 NS_NewTimerWithCallback(
6099 refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT,
6100 win->TabGroup()->EventTargetFor(TaskCategory::Network)));
6101
6102 mRefreshURIList->AppendElement(timer); // owning timer ref
6103 }
6104 return NS_OK;
6105 }
6106
ForceRefreshURIFromTimer(nsIURI * aURI,nsIPrincipal * aPrincipal,int32_t aDelay,bool aMetaRefresh,nsITimer * aTimer)6107 nsresult nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI,
6108 nsIPrincipal* aPrincipal,
6109 int32_t aDelay, bool aMetaRefresh,
6110 nsITimer* aTimer) {
6111 NS_PRECONDITION(aTimer, "Must have a timer here");
6112
6113 // Remove aTimer from mRefreshURIList if needed
6114 if (mRefreshURIList) {
6115 uint32_t n = 0;
6116 mRefreshURIList->GetLength(&n);
6117
6118 for (uint32_t i = 0; i < n; ++i) {
6119 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
6120 if (timer == aTimer) {
6121 mRefreshURIList->RemoveElementAt(i);
6122 break;
6123 }
6124 }
6125 }
6126
6127 return ForceRefreshURI(aURI, aPrincipal, aDelay, aMetaRefresh);
6128 }
6129
6130 NS_IMETHODIMP
ForceRefreshURI(nsIURI * aURI,nsIPrincipal * aPrincipal,int32_t aDelay,bool aMetaRefresh)6131 nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
6132 int32_t aDelay, bool aMetaRefresh) {
6133 NS_ENSURE_ARG(aURI);
6134
6135 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
6136 CreateLoadInfo(getter_AddRefs(loadInfo));
6137 NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
6138
6139 /* We do need to pass in a referrer, but we don't want it to
6140 * be sent to the server.
6141 */
6142 loadInfo->SetSendReferrer(false);
6143
6144 /* for most refreshes the current URI is an appropriate
6145 * internal referrer
6146 */
6147 loadInfo->SetReferrer(mCurrentURI);
6148
6149 loadInfo->SetOriginalURI(mCurrentURI);
6150 loadInfo->SetResultPrincipalURI(aURI);
6151 loadInfo->SetResultPrincipalURIIsSome(true);
6152 loadInfo->SetKeepResultPrincipalURIIfSet(true);
6153
6154 // Set the triggering pricipal to aPrincipal if available, or current
6155 // document's principal otherwise.
6156 nsCOMPtr<nsIPrincipal> principal = aPrincipal;
6157 if (!principal) {
6158 nsCOMPtr<nsIDocument> doc = GetDocument();
6159 if (!doc) {
6160 return NS_ERROR_FAILURE;
6161 }
6162 principal = doc->NodePrincipal();
6163 }
6164 loadInfo->SetTriggeringPrincipal(principal);
6165 loadInfo->SetPrincipalIsExplicit(true);
6166
6167 /* Check if this META refresh causes a redirection
6168 * to another site.
6169 */
6170 bool equalUri = false;
6171 nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
6172 if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
6173 aDelay <= REFRESH_REDIRECT_TIMER) {
6174 /* It is a META refresh based redirection within the threshold time
6175 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
6176 * Pass a REPLACE flag to LoadURI().
6177 */
6178 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
6179
6180 /* for redirects we mimic HTTP, which passes the
6181 * original referrer
6182 */
6183 nsCOMPtr<nsIURI> internalReferrer;
6184 GetReferringURI(getter_AddRefs(internalReferrer));
6185 if (internalReferrer) {
6186 loadInfo->SetReferrer(internalReferrer);
6187 }
6188 } else {
6189 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
6190 }
6191
6192 /*
6193 * LoadURI(...) will cancel all refresh timers... This causes the
6194 * Timer and its refreshData instance to be released...
6195 */
6196 LoadURI(aURI, loadInfo,
6197 nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true);
6198
6199 return NS_OK;
6200 }
6201
SetupRefreshURIFromHeader(nsIURI * aBaseURI,nsIPrincipal * aPrincipal,const nsACString & aHeader)6202 nsresult nsDocShell::SetupRefreshURIFromHeader(nsIURI* aBaseURI,
6203 nsIPrincipal* aPrincipal,
6204 const nsACString& aHeader) {
6205 // Refresh headers are parsed with the following format in mind
6206 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
6207 // By the time we are here, the following is true:
6208 // header = "REFRESH"
6209 // content = "5; URL=http://uri" // note the URL attribute is
6210 // optional, if it is absent, the currently loaded url is used.
6211 // Also note that the seconds and URL separator can be either
6212 // a ';' or a ','. The ',' separator should be illegal but CNN
6213 // is using it.
6214 //
6215 // We need to handle the following strings, where
6216 // - X is a set of digits
6217 // - URI is either a relative or absolute URI
6218 //
6219 // Note that URI should start with "url=" but we allow omission
6220 //
6221 // "" || ";" || ","
6222 // empty string. use the currently loaded URI
6223 // and refresh immediately.
6224 // "X" || "X;" || "X,"
6225 // Refresh the currently loaded URI in X seconds.
6226 // "X; URI" || "X, URI"
6227 // Refresh using URI as the destination in X seconds.
6228 // "URI" || "; URI" || ", URI"
6229 // Refresh immediately using URI as the destination.
6230 //
6231 // Currently, anything immediately following the URI, if
6232 // separated by any char in the set "'\"\t\r\n " will be
6233 // ignored. So "10; url=go.html ; foo=bar" will work,
6234 // and so will "10; url='go.html'; foo=bar". However,
6235 // "10; url=go.html; foo=bar" will result in the uri
6236 // "go.html;" since ';' and ',' are valid uri characters.
6237 //
6238 // Note that we need to remove any tokens wrapping the URI.
6239 // These tokens currently include spaces, double and single
6240 // quotes.
6241
6242 // when done, seconds is 0 or the given number of seconds
6243 // uriAttrib is empty or the URI specified
6244 MOZ_ASSERT(aPrincipal);
6245
6246 nsAutoCString uriAttrib;
6247 int32_t seconds = 0;
6248 bool specifiesSeconds = false;
6249
6250 nsACString::const_iterator iter, tokenStart, doneIterating;
6251
6252 aHeader.BeginReading(iter);
6253 aHeader.EndReading(doneIterating);
6254
6255 // skip leading whitespace
6256 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6257 ++iter;
6258 }
6259
6260 tokenStart = iter;
6261
6262 // skip leading + and -
6263 if (iter != doneIterating && (*iter == '-' || *iter == '+')) {
6264 ++iter;
6265 }
6266
6267 // parse number
6268 while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
6269 seconds = seconds * 10 + (*iter - '0');
6270 specifiesSeconds = true;
6271 ++iter;
6272 }
6273
6274 if (iter != doneIterating) {
6275 // if we started with a '-', number is negative
6276 if (*tokenStart == '-') {
6277 seconds = -seconds;
6278 }
6279
6280 // skip to next ';' or ','
6281 nsACString::const_iterator iterAfterDigit = iter;
6282 while (iter != doneIterating && !(*iter == ';' || *iter == ',')) {
6283 if (specifiesSeconds) {
6284 // Non-whitespace characters here mean that the string is
6285 // malformed but tolerate sites that specify a decimal point,
6286 // even though meta refresh only works on whole seconds.
6287 if (iter == iterAfterDigit && !nsCRT::IsAsciiSpace(*iter) &&
6288 *iter != '.') {
6289 // The characters between the seconds and the next
6290 // section are just garbage!
6291 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
6292 // Just ignore this redirect.
6293 return NS_ERROR_FAILURE;
6294 } else if (nsCRT::IsAsciiSpace(*iter)) {
6295 // We've had at least one whitespace so tolerate the mistake
6296 // and drop through.
6297 // e.g. content="10 foo"
6298 ++iter;
6299 break;
6300 }
6301 }
6302 ++iter;
6303 }
6304
6305 // skip any remaining whitespace
6306 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6307 ++iter;
6308 }
6309
6310 // skip ';' or ','
6311 if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
6312 ++iter;
6313 }
6314
6315 // skip whitespace
6316 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6317 ++iter;
6318 }
6319 }
6320
6321 // possible start of URI
6322 tokenStart = iter;
6323
6324 // skip "url = " to real start of URI
6325 if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
6326 ++iter;
6327 if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
6328 ++iter;
6329 if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
6330 ++iter;
6331
6332 // skip whitespace
6333 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6334 ++iter;
6335 }
6336
6337 if (iter != doneIterating && *iter == '=') {
6338 ++iter;
6339
6340 // skip whitespace
6341 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6342 ++iter;
6343 }
6344
6345 // found real start of URI
6346 tokenStart = iter;
6347 }
6348 }
6349 }
6350 }
6351
6352 // skip a leading '"' or '\''.
6353
6354 bool isQuotedURI = false;
6355 if (tokenStart != doneIterating &&
6356 (*tokenStart == '"' || *tokenStart == '\'')) {
6357 isQuotedURI = true;
6358 ++tokenStart;
6359 }
6360
6361 // set iter to start of URI
6362 iter = tokenStart;
6363
6364 // tokenStart here points to the beginning of URI
6365
6366 // grab the rest of the URI
6367 while (iter != doneIterating) {
6368 if (isQuotedURI && (*iter == '"' || *iter == '\'')) {
6369 break;
6370 }
6371 ++iter;
6372 }
6373
6374 // move iter one back if the last character is a '"' or '\''
6375 if (iter != tokenStart && isQuotedURI) {
6376 --iter;
6377 if (!(*iter == '"' || *iter == '\'')) {
6378 ++iter;
6379 }
6380 }
6381
6382 // URI is whatever's contained from tokenStart to iter.
6383 // note: if tokenStart == doneIterating, so is iter.
6384
6385 nsresult rv = NS_OK;
6386
6387 nsCOMPtr<nsIURI> uri;
6388 bool specifiesURI = false;
6389 if (tokenStart == iter) {
6390 uri = aBaseURI;
6391 } else {
6392 uriAttrib = Substring(tokenStart, iter);
6393 // NS_NewURI takes care of any whitespace surrounding the URL
6394 rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
6395 specifiesURI = true;
6396 }
6397
6398 // No URI or seconds were specified
6399 if (!specifiesSeconds && !specifiesURI) {
6400 // Do nothing because the alternative is to spin around in a refresh
6401 // loop forever!
6402 return NS_ERROR_FAILURE;
6403 }
6404
6405 if (NS_SUCCEEDED(rv)) {
6406 nsCOMPtr<nsIScriptSecurityManager> securityManager(
6407 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
6408 if (NS_SUCCEEDED(rv)) {
6409 rv = securityManager->CheckLoadURIWithPrincipal(
6410 aPrincipal, uri,
6411 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
6412
6413 if (NS_SUCCEEDED(rv)) {
6414 bool isjs = true;
6415 rv = NS_URIChainHasFlags(
6416 uri, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
6417 NS_ENSURE_SUCCESS(rv, rv);
6418
6419 if (isjs) {
6420 return NS_ERROR_FAILURE;
6421 }
6422 }
6423
6424 if (NS_SUCCEEDED(rv)) {
6425 // Since we can't travel back in time yet, just pretend
6426 // negative numbers do nothing at all.
6427 if (seconds < 0) {
6428 return NS_ERROR_FAILURE;
6429 }
6430
6431 rv = RefreshURI(uri, aPrincipal, seconds * 1000, false, true);
6432 }
6433 }
6434 }
6435 return rv;
6436 }
6437
6438 NS_IMETHODIMP
SetupRefreshURI(nsIChannel * aChannel)6439 nsDocShell::SetupRefreshURI(nsIChannel* aChannel) {
6440 nsresult rv;
6441 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
6442 if (NS_SUCCEEDED(rv)) {
6443 nsAutoCString refreshHeader;
6444 rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
6445 refreshHeader);
6446
6447 if (!refreshHeader.IsEmpty()) {
6448 nsCOMPtr<nsIScriptSecurityManager> secMan =
6449 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
6450 NS_ENSURE_SUCCESS(rv, rv);
6451
6452 nsCOMPtr<nsIPrincipal> principal;
6453 rv = secMan->GetChannelResultPrincipal(aChannel,
6454 getter_AddRefs(principal));
6455 NS_ENSURE_SUCCESS(rv, rv);
6456
6457 SetupReferrerFromChannel(aChannel);
6458 rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
6459 if (NS_SUCCEEDED(rv)) {
6460 return NS_REFRESHURI_HEADER_FOUND;
6461 }
6462 }
6463 }
6464 return rv;
6465 }
6466
DoCancelRefreshURITimers(nsIMutableArray * aTimerList)6467 static void DoCancelRefreshURITimers(nsIMutableArray* aTimerList) {
6468 if (!aTimerList) {
6469 return;
6470 }
6471
6472 uint32_t n = 0;
6473 aTimerList->GetLength(&n);
6474
6475 while (n) {
6476 nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
6477
6478 aTimerList->RemoveElementAt(n); // bye bye owning timer ref
6479
6480 if (timer) {
6481 timer->Cancel();
6482 }
6483 }
6484 }
6485
6486 NS_IMETHODIMP
CancelRefreshURITimers()6487 nsDocShell::CancelRefreshURITimers() {
6488 DoCancelRefreshURITimers(mRefreshURIList);
6489 DoCancelRefreshURITimers(mSavedRefreshURIList);
6490 mRefreshURIList = nullptr;
6491 mSavedRefreshURIList = nullptr;
6492
6493 return NS_OK;
6494 }
6495
6496 NS_IMETHODIMP
GetRefreshPending(bool * aResult)6497 nsDocShell::GetRefreshPending(bool* aResult) {
6498 if (!mRefreshURIList) {
6499 *aResult = false;
6500 return NS_OK;
6501 }
6502
6503 uint32_t count;
6504 nsresult rv = mRefreshURIList->GetLength(&count);
6505 if (NS_SUCCEEDED(rv)) {
6506 *aResult = (count != 0);
6507 }
6508 return rv;
6509 }
6510
6511 NS_IMETHODIMP
SuspendRefreshURIs()6512 nsDocShell::SuspendRefreshURIs() {
6513 if (mRefreshURIList) {
6514 uint32_t n = 0;
6515 mRefreshURIList->GetLength(&n);
6516
6517 for (uint32_t i = 0; i < n; ++i) {
6518 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
6519 if (!timer) {
6520 continue; // this must be a nsRefreshURI already
6521 }
6522
6523 // Replace this timer object with a nsRefreshTimer object.
6524 nsCOMPtr<nsITimerCallback> callback;
6525 timer->GetCallback(getter_AddRefs(callback));
6526
6527 timer->Cancel();
6528
6529 nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
6530 NS_ASSERTION(
6531 rt,
6532 "RefreshURIList timer callbacks should only be RefreshTimer objects");
6533
6534 mRefreshURIList->ReplaceElementAt(rt, i);
6535 }
6536 }
6537
6538 // Suspend refresh URIs for our child shells as well.
6539 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6540 while (iter.HasMore()) {
6541 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
6542 if (shell) {
6543 shell->SuspendRefreshURIs();
6544 }
6545 }
6546
6547 return NS_OK;
6548 }
6549
6550 NS_IMETHODIMP
ResumeRefreshURIs()6551 nsDocShell::ResumeRefreshURIs() {
6552 RefreshURIFromQueue();
6553
6554 // Resume refresh URIs for our child shells as well.
6555 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6556 while (iter.HasMore()) {
6557 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
6558 if (shell) {
6559 shell->ResumeRefreshURIs();
6560 }
6561 }
6562
6563 return NS_OK;
6564 }
6565
RefreshURIFromQueue()6566 nsresult nsDocShell::RefreshURIFromQueue() {
6567 if (!mRefreshURIList) {
6568 return NS_OK;
6569 }
6570 uint32_t n = 0;
6571 mRefreshURIList->GetLength(&n);
6572
6573 while (n) {
6574 nsCOMPtr<nsITimerCallback> refreshInfo =
6575 do_QueryElementAt(mRefreshURIList, --n);
6576
6577 if (refreshInfo) {
6578 // This is the nsRefreshTimer object, waiting to be
6579 // setup in a timer object and fired.
6580 // Create the timer and trigger it.
6581 uint32_t delay = static_cast<nsRefreshTimer*>(
6582 static_cast<nsITimerCallback*>(refreshInfo))
6583 ->GetDelay();
6584 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
6585 if (win) {
6586 nsCOMPtr<nsITimer> timer;
6587 NS_NewTimerWithCallback(
6588 getter_AddRefs(timer), refreshInfo, delay, nsITimer::TYPE_ONE_SHOT,
6589 win->TabGroup()->EventTargetFor(TaskCategory::Network));
6590
6591 if (timer) {
6592 // Replace the nsRefreshTimer element in the queue with
6593 // its corresponding timer object, so that in case another
6594 // load comes through before the timer can go off, the timer will
6595 // get cancelled in CancelRefreshURITimer()
6596 mRefreshURIList->ReplaceElementAt(timer, n);
6597 }
6598 }
6599 }
6600 }
6601
6602 return NS_OK;
6603 }
6604
Embed(nsIContentViewer * aContentViewer,const char * aCommand,nsISupports * aExtraInfo)6605 nsresult nsDocShell::Embed(nsIContentViewer* aContentViewer,
6606 const char* aCommand, nsISupports* aExtraInfo) {
6607 // Save the LayoutHistoryState of the previous document, before
6608 // setting up new document
6609 PersistLayoutHistoryState();
6610
6611 nsresult rv = SetupNewViewer(aContentViewer);
6612 NS_ENSURE_SUCCESS(rv, rv);
6613
6614 // If we are loading a wyciwyg url from history, change the base URI for
6615 // the document to the original http url that created the document.write().
6616 // This makes sure that all relative urls in a document.written page loaded
6617 // via history work properly.
6618 if (mCurrentURI &&
6619 (mLoadType & LOAD_CMD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL ||
6620 mLoadType == LOAD_RELOAD_CHARSET_CHANGE ||
6621 mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE ||
6622 mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)) {
6623 bool isWyciwyg = false;
6624 // Check if the url is wyciwyg
6625 rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
6626 if (isWyciwyg && NS_SUCCEEDED(rv)) {
6627 SetBaseUrlForWyciwyg(aContentViewer);
6628 }
6629 }
6630 // XXX What if SetupNewViewer fails?
6631 if (mLSHE) {
6632 // Restore the editing state, if it's stored in session history.
6633 if (mLSHE->HasDetachedEditor()) {
6634 ReattachEditorToWindow(mLSHE);
6635 }
6636 // Set history.state
6637 SetDocCurrentStateObj(mLSHE);
6638
6639 SetHistoryEntry(&mOSHE, mLSHE);
6640 }
6641
6642 bool updateHistory = true;
6643
6644 // Determine if this type of load should update history
6645 switch (mLoadType) {
6646 case LOAD_NORMAL_REPLACE:
6647 case LOAD_STOP_CONTENT_AND_REPLACE:
6648 case LOAD_RELOAD_BYPASS_CACHE:
6649 case LOAD_RELOAD_BYPASS_PROXY:
6650 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
6651 case LOAD_REPLACE_BYPASS_CACHE:
6652 updateHistory = false;
6653 break;
6654 default:
6655 break;
6656 }
6657
6658 if (!updateHistory) {
6659 SetLayoutHistoryState(nullptr);
6660 }
6661
6662 return NS_OK;
6663 }
6664
6665 //*****************************************************************************
6666 // nsDocShell::nsIWebProgressListener
6667 //*****************************************************************************
6668
6669 NS_IMETHODIMP
OnProgressChange(nsIWebProgress * aProgress,nsIRequest * aRequest,int32_t aCurSelfProgress,int32_t aMaxSelfProgress,int32_t aCurTotalProgress,int32_t aMaxTotalProgress)6670 nsDocShell::OnProgressChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
6671 int32_t aCurSelfProgress, int32_t aMaxSelfProgress,
6672 int32_t aCurTotalProgress,
6673 int32_t aMaxTotalProgress) {
6674 return NS_OK;
6675 }
6676
6677 NS_IMETHODIMP
OnStateChange(nsIWebProgress * aProgress,nsIRequest * aRequest,uint32_t aStateFlags,nsresult aStatus)6678 nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
6679 uint32_t aStateFlags, nsresult aStatus) {
6680 if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
6681 // Save timing statistics.
6682 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
6683 nsCOMPtr<nsIURI> uri;
6684 channel->GetURI(getter_AddRefs(uri));
6685 nsAutoCString aURI;
6686 uri->GetAsciiSpec(aURI);
6687
6688 nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
6689 nsCOMPtr<nsIWebProgress> webProgress =
6690 do_QueryInterface(GetAsSupports(this));
6691
6692 // We don't update navigation timing for wyciwyg channels
6693 if (this == aProgress && !wcwgChannel) {
6694 mozilla::Unused << MaybeInitTiming();
6695 mTiming->NotifyFetchStart(uri,
6696 ConvertLoadTypeToNavigationType(mLoadType));
6697 }
6698
6699 // Was the wyciwyg document loaded on this docshell?
6700 if (wcwgChannel && !mLSHE && (mItemType == typeContent) &&
6701 aProgress == webProgress.get()) {
6702 bool equalUri = true;
6703 // Store the wyciwyg url in session history, only if it is
6704 // being loaded fresh for the first time. We don't want
6705 // multiple entries for successive loads
6706 if (mCurrentURI && NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
6707 !equalUri) {
6708 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
6709 GetSameTypeParent(getter_AddRefs(parentAsItem));
6710 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
6711 bool inOnLoadHandler = false;
6712 if (parentDS) {
6713 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
6714 }
6715 if (inOnLoadHandler) {
6716 // We're handling parent's load event listener, which causes
6717 // document.write in a subdocument.
6718 // Need to clear the session history for all child
6719 // docshells so that we can handle them like they would
6720 // all be added dynamically.
6721 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
6722 if (parent) {
6723 bool oshe = false;
6724 nsCOMPtr<nsISHEntry> entry;
6725 parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
6726 static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry);
6727 }
6728 }
6729
6730 // This is a document.write(). Get the made-up url
6731 // from the channel and store it in session history.
6732 // Pass false for aCloneChildren, since we're creating
6733 // a new DOM here.
6734 AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false,
6735 getter_AddRefs(mLSHE));
6736 SetCurrentURI(uri, aRequest, true, 0);
6737 // Save history state of the previous page
6738 PersistLayoutHistoryState();
6739 // We'll never get an Embed() for this load, so just go ahead
6740 // and SetHistoryEntry now.
6741 SetHistoryEntry(&mOSHE, mLSHE);
6742 }
6743 }
6744 // Page has begun to load
6745 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
6746
6747 if ((aStateFlags & STATE_RESTORING) == 0) {
6748 // Show the progress cursor if the pref is set
6749 if (nsContentUtils::UseActivityCursor()) {
6750 nsCOMPtr<nsIWidget> mainWidget;
6751 GetMainWidget(getter_AddRefs(mainWidget));
6752 if (mainWidget) {
6753 mainWidget->SetCursor(eCursor_spinning);
6754 }
6755 }
6756 }
6757 } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
6758 // Page is loading
6759 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
6760 } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
6761 // Page has finished loading
6762 mBusyFlags = BUSY_FLAGS_NONE;
6763
6764 // Hide the progress cursor if the pref is set
6765 if (nsContentUtils::UseActivityCursor()) {
6766 nsCOMPtr<nsIWidget> mainWidget;
6767 GetMainWidget(getter_AddRefs(mainWidget));
6768 if (mainWidget) {
6769 mainWidget->SetCursor(eCursor_standard);
6770 }
6771 }
6772 }
6773 if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
6774 nsCOMPtr<nsIWebProgress> webProgress =
6775 do_QueryInterface(GetAsSupports(this));
6776 // Is the document stop notification for this document?
6777 if (aProgress == webProgress.get()) {
6778 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
6779 EndPageLoad(aProgress, channel, aStatus);
6780 }
6781 }
6782 // note that redirect state changes will go through here as well, but it
6783 // is better to handle those in OnRedirectStateChange where more
6784 // information is available.
6785 return NS_OK;
6786 }
6787
6788 NS_IMETHODIMP
OnLocationChange(nsIWebProgress * aProgress,nsIRequest * aRequest,nsIURI * aURI,uint32_t aFlags)6789 nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
6790 nsIURI* aURI, uint32_t aFlags) {
6791 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6792 return NS_OK;
6793 }
6794
OnRedirectStateChange(nsIChannel * aOldChannel,nsIChannel * aNewChannel,uint32_t aRedirectFlags,uint32_t aStateFlags)6795 void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
6796 nsIChannel* aNewChannel,
6797 uint32_t aRedirectFlags,
6798 uint32_t aStateFlags) {
6799 NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
6800 "Calling OnRedirectStateChange when there is no redirect");
6801
6802 // If mixed content is allowed for the old channel, we forward
6803 // the permission to the new channel if it has the same origin
6804 // as the old one.
6805 if (mMixedContentChannel && mMixedContentChannel == aOldChannel) {
6806 nsresult rv =
6807 nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel);
6808 if (NS_SUCCEEDED(rv)) {
6809 SetMixedContentChannel(aNewChannel); // Same origin: forward permission.
6810 } else {
6811 SetMixedContentChannel(
6812 nullptr); // Different origin: clear mMixedContentChannel.
6813 }
6814 }
6815
6816 if (!(aStateFlags & STATE_IS_DOCUMENT)) {
6817 return; // not a toplevel document
6818 }
6819
6820 nsCOMPtr<nsIURI> oldURI, newURI;
6821 aOldChannel->GetURI(getter_AddRefs(oldURI));
6822 aNewChannel->GetURI(getter_AddRefs(newURI));
6823 if (!oldURI || !newURI) {
6824 return;
6825 }
6826
6827 // Below a URI visit is saved (see AddURIVisit method doc).
6828 // The visit chain looks something like:
6829 // ...
6830 // Site N - 1
6831 // => Site N
6832 // (redirect to =>) Site N + 1 (we are here!)
6833
6834 // Get N - 1 and transition type
6835 nsCOMPtr<nsIURI> previousURI;
6836 uint32_t previousFlags = 0;
6837 ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
6838
6839 if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
6840 ChannelIsPost(aOldChannel)) {
6841 // 1. Internal redirects are ignored because they are specific to the
6842 // channel implementation.
6843 // 2. POSTs are not saved by global history.
6844 //
6845 // Regardless, we need to propagate the previous visit to the new
6846 // channel.
6847 SaveLastVisit(aNewChannel, previousURI, previousFlags);
6848 } else {
6849 nsCOMPtr<nsIURI> referrer;
6850 // Treat referrer as null if there is an error getting it.
6851 (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer));
6852
6853 // Get the HTTP response code, if available.
6854 uint32_t responseStatus = 0;
6855 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
6856 if (httpChannel) {
6857 Unused << httpChannel->GetResponseStatus(&responseStatus);
6858 }
6859
6860 // Add visit N -1 => N
6861 AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus);
6862
6863 // Since N + 1 could be the final destination, we will not save N => N + 1
6864 // here. OnNewURI will do that, so we will cache it.
6865 SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
6866 }
6867
6868 // check if the new load should go through the application cache.
6869 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
6870 do_QueryInterface(aNewChannel);
6871 if (appCacheChannel) {
6872 if (GeckoProcessType_Default != XRE_GetProcessType()) {
6873 // Permission will be checked in the parent process.
6874 appCacheChannel->SetChooseApplicationCache(true);
6875 } else {
6876 nsCOMPtr<nsIScriptSecurityManager> secMan =
6877 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
6878
6879 if (secMan) {
6880 nsCOMPtr<nsIPrincipal> principal;
6881 secMan->GetDocShellCodebasePrincipal(newURI, this,
6882 getter_AddRefs(principal));
6883 appCacheChannel->SetChooseApplicationCache(
6884 NS_ShouldCheckAppCache(principal));
6885 }
6886 }
6887 }
6888
6889 if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
6890 mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
6891 mLoadType = LOAD_NORMAL_REPLACE;
6892 SetHistoryEntry(&mLSHE, nullptr);
6893 }
6894 }
6895
6896 NS_IMETHODIMP
OnStatusChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,nsresult aStatus,const char16_t * aMessage)6897 nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
6898 nsresult aStatus, const char16_t* aMessage) {
6899 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6900 return NS_OK;
6901 }
6902
6903 NS_IMETHODIMP
OnSecurityChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,uint32_t aState)6904 nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
6905 uint32_t aState) {
6906 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6907 return NS_OK;
6908 }
6909
EndPageLoad(nsIWebProgress * aProgress,nsIChannel * aChannel,nsresult aStatus)6910 nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
6911 nsIChannel* aChannel, nsresult aStatus) {
6912 if (!aChannel) {
6913 return NS_ERROR_NULL_POINTER;
6914 }
6915
6916 // Make sure to discard the initial client if we never created the initial
6917 // about:blank document. Do this before possibly returning from the method
6918 // due to an error.
6919 mInitialClientSource.reset();
6920
6921 nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
6922 if (reporter) {
6923 nsCOMPtr<nsILoadGroup> loadGroup;
6924 aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
6925 if (loadGroup) {
6926 reporter->FlushConsoleReports(loadGroup);
6927 } else {
6928 reporter->FlushConsoleReports(GetDocument());
6929 }
6930 }
6931
6932 nsCOMPtr<nsIURI> url;
6933 nsresult rv = aChannel->GetURI(getter_AddRefs(url));
6934 if (NS_FAILED(rv)) {
6935 return rv;
6936 }
6937
6938 nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel);
6939 if (timingChannel) {
6940 TimeStamp channelCreationTime;
6941 rv = timingChannel->GetChannelCreation(&channelCreationTime);
6942 if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
6943 Telemetry::AccumulateTimeDelta(Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
6944 channelCreationTime);
6945 nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
6946 do_QueryInterface(mLoadGroup);
6947 if (internalLoadGroup) {
6948 internalLoadGroup->OnEndPageLoad(aChannel);
6949 }
6950 }
6951 }
6952
6953 // Timing is picked up by the window, we don't need it anymore
6954 mTiming = nullptr;
6955
6956 // clean up reload state for meta charset
6957 if (eCharsetReloadRequested == mCharsetReloadState) {
6958 mCharsetReloadState = eCharsetReloadStopOrigional;
6959 } else {
6960 mCharsetReloadState = eCharsetReloadInit;
6961 }
6962
6963 // Save a pointer to the currently-loading history entry.
6964 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
6965 // entry further down in this method.
6966 nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
6967 mozilla::Unused << loadingSHE; // XXX: Not sure if we need this anymore
6968
6969 //
6970 // one of many safeguards that prevent death and destruction if
6971 // someone is so very very rude as to bring this window down
6972 // during this load handler.
6973 //
6974 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
6975
6976 // Notify the ContentViewer that the Document has finished loading. This
6977 // will cause any OnLoad(...) and PopState(...) handlers to fire.
6978 if (!mEODForCurrentDocument && mContentViewer) {
6979 mIsExecutingOnLoadHandler = true;
6980 mContentViewer->LoadComplete(aStatus);
6981 mIsExecutingOnLoadHandler = false;
6982
6983 mEODForCurrentDocument = true;
6984
6985 // If all documents have completed their loading
6986 // favor native event dispatch priorities
6987 // over performance
6988 if (--gNumberOfDocumentsLoading == 0) {
6989 // Hint to use normal native event dispatch priorities
6990 FavorPerformanceHint(false);
6991 }
6992 }
6993 /* Check if the httpChannel has any cache-control related response headers,
6994 * like no-store, no-cache. If so, update SHEntry so that
6995 * when a user goes back/forward to this page, we appropriately do
6996 * form value restoration or load from server.
6997 */
6998 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
6999 if (!httpChannel) {
7000 // HttpChannel could be hiding underneath a Multipart channel.
7001 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
7002 }
7003
7004 if (httpChannel) {
7005 // figure out if SH should be saving layout state.
7006 bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
7007 if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
7008 (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
7009 mLSHE->SetSaveLayoutStateFlag(false);
7010 }
7011 }
7012
7013 // Clear mLSHE after calling the onLoadHandlers. This way, if the
7014 // onLoadHandler tries to load something different in
7015 // itself or one of its children, we can deal with it appropriately.
7016 if (mLSHE) {
7017 mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
7018
7019 // Clear the mLSHE reference to indicate document loading is done one
7020 // way or another.
7021 SetHistoryEntry(&mLSHE, nullptr);
7022 }
7023 // if there's a refresh header in the channel, this method
7024 // will set it up for us.
7025 if (mIsActive || !mDisableMetaRefreshWhenInactive) RefreshURIFromQueue();
7026
7027 // Test whether this is the top frame or a subframe
7028 bool isTopFrame = true;
7029 nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
7030 rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
7031 if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
7032 isTopFrame = false;
7033 }
7034
7035 //
7036 // If the page load failed, then deal with the error condition...
7037 // Errors are handled as follows:
7038 // 1. Check to see if it's a file not found error or bad content
7039 // encoding error.
7040 // 2. Send the URI to a keyword server (if enabled)
7041 // 3. If the error was DNS failure, then add www and .com to the URI
7042 // (if appropriate).
7043 // 4. Throw an error dialog box...
7044 //
7045 if (url && NS_FAILED(aStatus)) {
7046 if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
7047 aStatus == NS_ERROR_FILE_ACCESS_DENIED ||
7048 aStatus == NS_ERROR_CORRUPTED_CONTENT ||
7049 aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
7050 DisplayLoadError(aStatus, url, nullptr, aChannel);
7051 return NS_OK;
7052 }
7053
7054 // Handle iframe document not loading error because source was
7055 // a tracking URL. We make a note of this iframe node by including
7056 // it in a dedicated array of blocked tracking nodes under its parent
7057 // document. (document of parent window of blocked document)
7058 if (isTopFrame == false && aStatus == NS_ERROR_TRACKING_URI) {
7059 // frameElement is our nsIContent to be annotated
7060 nsCOMPtr<nsIDOMElement> frameElement;
7061 nsPIDOMWindowOuter* thisWindow = GetWindow();
7062 if (!thisWindow) {
7063 return NS_OK;
7064 }
7065
7066 frameElement = thisWindow->GetFrameElement();
7067 if (!frameElement) {
7068 return NS_OK;
7069 }
7070
7071 // Parent window
7072 nsCOMPtr<nsIDocShellTreeItem> parentItem;
7073 GetSameTypeParent(getter_AddRefs(parentItem));
7074 if (!parentItem) {
7075 return NS_OK;
7076 }
7077
7078 nsCOMPtr<nsIDocument> parentDoc;
7079 parentDoc = parentItem->GetDocument();
7080 if (!parentDoc) {
7081 return NS_OK;
7082 }
7083
7084 nsCOMPtr<nsIContent> cont = do_QueryInterface(frameElement);
7085 parentDoc->AddBlockedTrackingNode(cont);
7086
7087 return NS_OK;
7088 }
7089
7090 if (sURIFixup) {
7091 //
7092 // Try and make an alternative URI from the old one
7093 //
7094 nsCOMPtr<nsIURI> newURI;
7095 nsCOMPtr<nsIInputStream> newPostData;
7096
7097 nsAutoCString oldSpec;
7098 url->GetSpec(oldSpec);
7099
7100 //
7101 // First try keyword fixup
7102 //
7103 nsAutoString keywordProviderName, keywordAsSent;
7104 if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
7105 bool keywordsEnabled = Preferences::GetBool("keyword.enabled", false);
7106
7107 nsAutoCString host;
7108 url->GetHost(host);
7109
7110 nsAutoCString scheme;
7111 url->GetScheme(scheme);
7112
7113 int32_t dotLoc = host.FindChar('.');
7114
7115 // we should only perform a keyword search under the following
7116 // conditions:
7117 // (0) Pref keyword.enabled is true
7118 // (1) the url scheme is http (or https)
7119 // (2) the url does not have a protocol scheme
7120 // If we don't enforce such a policy, then we end up doing
7121 // keyword searchs on urls we don't intend like imap, file,
7122 // mailbox, etc. This could lead to a security problem where we
7123 // send data to the keyword server that we shouldn't be.
7124 // Someone needs to clean up keywords in general so we can
7125 // determine on a per url basis if we want keywords
7126 // enabled...this is just a bandaid...
7127 if (keywordsEnabled && !scheme.IsEmpty() &&
7128 (scheme.Find("http") != 0)) {
7129 keywordsEnabled = false;
7130 }
7131
7132 if (keywordsEnabled && (kNotFound == dotLoc)) {
7133 nsCOMPtr<nsIURIFixupInfo> info;
7134 // only send non-qualified hosts to the keyword server
7135 if (!mOriginalUriString.IsEmpty()) {
7136 sURIFixup->KeywordToURI(mOriginalUriString,
7137 getter_AddRefs(newPostData),
7138 getter_AddRefs(info));
7139 } else {
7140 //
7141 // If this string was passed through nsStandardURL by
7142 // chance, then it may have been converted from UTF-8 to
7143 // ACE, which would result in a completely bogus keyword
7144 // query. Here we try to recover the original Unicode
7145 // value, but this is not 100% correct since the value may
7146 // have been normalized per the IDN normalization rules.
7147 //
7148 // Since we don't have access to the exact original string
7149 // that was entered by the user, this will just have to do.
7150 bool isACE;
7151 nsAutoCString utf8Host;
7152 nsCOMPtr<nsIIDNService> idnSrv =
7153 do_GetService(NS_IDNSERVICE_CONTRACTID);
7154 if (idnSrv && NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
7155 NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
7156 sURIFixup->KeywordToURI(utf8Host, getter_AddRefs(newPostData),
7157 getter_AddRefs(info));
7158 } else {
7159 sURIFixup->KeywordToURI(host, getter_AddRefs(newPostData),
7160 getter_AddRefs(info));
7161 }
7162 }
7163
7164 info->GetPreferredURI(getter_AddRefs(newURI));
7165 if (newURI) {
7166 info->GetKeywordAsSent(keywordAsSent);
7167 info->GetKeywordProviderName(keywordProviderName);
7168 }
7169 } // end keywordsEnabled
7170 }
7171
7172 //
7173 // Now try change the address, e.g. turn http://foo into
7174 // http://www.foo.com
7175 //
7176 if (aStatus == NS_ERROR_UNKNOWN_HOST || aStatus == NS_ERROR_NET_RESET) {
7177 bool doCreateAlternate = true;
7178
7179 // Skip fixup for anything except a normal document load
7180 // operation on the topframe.
7181
7182 if (mLoadType != LOAD_NORMAL || !isTopFrame) {
7183 doCreateAlternate = false;
7184 } else {
7185 // Test if keyword lookup produced a new URI or not
7186 if (newURI) {
7187 bool sameURI = false;
7188 url->Equals(newURI, &sameURI);
7189 if (!sameURI) {
7190 // Keyword lookup made a new URI so no need to try
7191 // an alternate one.
7192 doCreateAlternate = false;
7193 }
7194 }
7195
7196 if (doCreateAlternate) {
7197 // Skip doing this if our channel was redirected, because we
7198 // shouldn't be guessing things about the post-redirect URI.
7199 nsLoadFlags loadFlags = 0;
7200 if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) ||
7201 (loadFlags & nsIChannel::LOAD_REPLACE)) {
7202 doCreateAlternate = false;
7203 }
7204 }
7205 }
7206 if (doCreateAlternate) {
7207 newURI = nullptr;
7208 newPostData = nullptr;
7209 keywordProviderName.Truncate();
7210 keywordAsSent.Truncate();
7211 sURIFixup->CreateFixupURI(
7212 oldSpec, nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
7213 getter_AddRefs(newPostData), getter_AddRefs(newURI));
7214 }
7215 }
7216
7217 // Did we make a new URI that is different to the old one? If so
7218 // load it.
7219 //
7220 if (newURI) {
7221 // Make sure the new URI is different from the old one,
7222 // otherwise there's little point trying to load it again.
7223 bool sameURI = false;
7224 url->Equals(newURI, &sameURI);
7225 if (!sameURI) {
7226 nsAutoCString newSpec;
7227 newURI->GetSpec(newSpec);
7228 NS_ConvertUTF8toUTF16 newSpecW(newSpec);
7229
7230 // This notification is meant for Firefox Health Report so it
7231 // can increment counts from the search engine
7232 MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent);
7233
7234 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
7235 nsCOMPtr<nsIPrincipal> triggeringPrincipal =
7236 loadInfo ? loadInfo->TriggeringPrincipal()
7237 : nsContentUtils::GetSystemPrincipal();
7238 return LoadURI(newSpecW.get(), // URI string
7239 LOAD_FLAGS_NONE, // Load flags
7240 nullptr, // Referring URI
7241 newPostData, // Post data stream
7242 nullptr, // Headers stream
7243 triggeringPrincipal); // TriggeringPrincipal
7244 }
7245 }
7246 }
7247
7248 // Well, fixup didn't work :-(
7249 // It is time to throw an error dialog box, and be done with it...
7250
7251 // Errors to be shown only on top-level frames
7252 if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
7253 aStatus == NS_ERROR_CONNECTION_REFUSED ||
7254 aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
7255 aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
7256 aStatus == NS_ERROR_BLOCKED_BY_POLICY) &&
7257 (isTopFrame || UseErrorPages())) {
7258 DisplayLoadError(aStatus, url, nullptr, aChannel);
7259 } else if (aStatus == NS_ERROR_NET_TIMEOUT ||
7260 aStatus == NS_ERROR_REDIRECT_LOOP ||
7261 aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
7262 aStatus == NS_ERROR_NET_INTERRUPT ||
7263 aStatus == NS_ERROR_NET_RESET || aStatus == NS_ERROR_OFFLINE ||
7264 aStatus == NS_ERROR_MALWARE_URI ||
7265 aStatus == NS_ERROR_PHISHING_URI ||
7266 aStatus == NS_ERROR_UNWANTED_URI ||
7267 aStatus == NS_ERROR_HARMFUL_URI ||
7268 aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
7269 aStatus == NS_ERROR_REMOTE_XUL ||
7270 aStatus == NS_ERROR_INTERCEPTION_FAILED ||
7271 aStatus == NS_ERROR_NET_INADEQUATE_SECURITY ||
7272 NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
7273 // Errors to be shown for any frame
7274 DisplayLoadError(aStatus, url, nullptr, aChannel);
7275 } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
7276 // Non-caching channels will simply return NS_ERROR_OFFLINE.
7277 // Caching channels would have to look at their flags to work
7278 // out which error to return. Or we can fix up the error here.
7279 if (!(mLoadType & LOAD_CMD_HISTORY)) {
7280 aStatus = NS_ERROR_OFFLINE;
7281 }
7282 DisplayLoadError(aStatus, url, nullptr, aChannel);
7283 }
7284 } else if (url && NS_SUCCEEDED(aStatus)) {
7285 // If we have a host
7286 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
7287 if (loadInfo) {
7288 mozilla::net::PredictorLearnRedirect(url, aChannel,
7289 loadInfo->GetOriginAttributes());
7290 }
7291 }
7292
7293 return NS_OK;
7294 }
7295
7296 //*****************************************************************************
7297 // nsDocShell: Content Viewer Management
7298 //*****************************************************************************
7299
EnsureContentViewer()7300 nsresult nsDocShell::EnsureContentViewer() {
7301 if (mContentViewer) {
7302 return NS_OK;
7303 }
7304 if (mIsBeingDestroyed) {
7305 return NS_ERROR_FAILURE;
7306 }
7307
7308 nsCOMPtr<nsIURI> baseURI;
7309 nsIPrincipal* principal = GetInheritedPrincipal(false);
7310 nsCOMPtr<nsIDocShellTreeItem> parentItem;
7311 GetSameTypeParent(getter_AddRefs(parentItem));
7312 if (parentItem) {
7313 if (nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow()) {
7314 nsCOMPtr<Element> parentElement = domWin->GetFrameElementInternal();
7315 if (parentElement) {
7316 baseURI = parentElement->GetBaseURI();
7317 }
7318 }
7319 }
7320
7321 nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
7322
7323 NS_ENSURE_STATE(mContentViewer);
7324
7325 if (NS_SUCCEEDED(rv)) {
7326 nsCOMPtr<nsIDocument> doc(GetDocument());
7327 NS_ASSERTION(doc,
7328 "Should have doc if CreateAboutBlankContentViewer "
7329 "succeeded!");
7330
7331 doc->SetIsInitialDocument(true);
7332
7333 // Documents created using EnsureContentViewer may be transient
7334 // placeholders created by framescripts before content has a chance to
7335 // load. In some cases, window.open(..., "noopener") will create such a
7336 // document (in a new TabGroup) and then synchronously tear it down, firing
7337 // a "pagehide" event. Doing so violates our assertions about
7338 // DocGroups. It's easier to silence the assertion here than to avoid
7339 // creating the extra document.
7340 doc->IgnoreDocGroupMismatches();
7341 }
7342
7343 return rv;
7344 }
7345
CreateAboutBlankContentViewer(nsIPrincipal * aPrincipal,nsIURI * aBaseURI,bool aTryToSaveOldPresentation,bool aCheckPermitUnload)7346 nsresult nsDocShell::CreateAboutBlankContentViewer(
7347 nsIPrincipal* aPrincipal, nsIURI* aBaseURI, bool aTryToSaveOldPresentation,
7348 bool aCheckPermitUnload) {
7349 nsCOMPtr<nsIDocument> blankDoc;
7350 nsCOMPtr<nsIContentViewer> viewer;
7351 nsresult rv = NS_ERROR_FAILURE;
7352
7353 /* mCreatingDocument should never be true at this point. However, it's
7354 a theoretical possibility. We want to know about it and make it stop,
7355 and this sounds like a job for an assertion. */
7356 NS_ASSERTION(!mCreatingDocument,
7357 "infinite(?) loop creating document averted");
7358 if (mCreatingDocument) {
7359 return NS_ERROR_FAILURE;
7360 }
7361
7362 // mContentViewer->PermitUnload may release |this| docshell.
7363 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
7364
7365 AutoRestore<bool> creatingDocument(mCreatingDocument);
7366 mCreatingDocument = true;
7367
7368 if (aPrincipal && !nsContentUtils::IsSystemPrincipal(aPrincipal) &&
7369 mItemType != typeChrome) {
7370 MOZ_ASSERT(aPrincipal->OriginAttributesRef() == mOriginAttributes);
7371 }
7372
7373 // Make sure timing is created. But first record whether we had it
7374 // already, so we don't clobber the timing for an in-progress load.
7375 bool hadTiming = mTiming;
7376 bool toBeReset = MaybeInitTiming();
7377 if (mContentViewer) {
7378 if (aCheckPermitUnload) {
7379 // We've got a content viewer already. Make sure the user
7380 // permits us to discard the current document and replace it
7381 // with about:blank. And also ensure we fire the unload events
7382 // in the current document.
7383
7384 // Unload gets fired first for
7385 // document loaded from the session history.
7386 mTiming->NotifyBeforeUnload();
7387
7388 bool okToUnload;
7389 rv = mContentViewer->PermitUnload(&okToUnload);
7390
7391 if (NS_SUCCEEDED(rv) && !okToUnload) {
7392 // The user chose not to unload the page, interrupt the load.
7393 MaybeResetInitTiming(toBeReset);
7394 return NS_ERROR_FAILURE;
7395 }
7396 if (mTiming) {
7397 mTiming->NotifyUnloadAccepted(mCurrentURI);
7398 }
7399 }
7400
7401 mSavingOldViewer = aTryToSaveOldPresentation &&
7402 CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
7403
7404 // Make sure to blow away our mLoadingURI just in case. No loads
7405 // from inside this pagehide.
7406 mLoadingURI = nullptr;
7407
7408 // Stop any in-progress loading, so that we don't accidentally trigger any
7409 // PageShow notifications from Embed() interrupting our loading below.
7410 Stop();
7411
7412 // Notify the current document that it is about to be unloaded!!
7413 //
7414 // It is important to fire the unload() notification *before* any state
7415 // is changed within the DocShell - otherwise, javascript will get the
7416 // wrong information :-(
7417 //
7418 (void)FirePageHideNotification(!mSavingOldViewer);
7419 // pagehide notification might destroy this docshell.
7420 if (mIsBeingDestroyed) {
7421 return NS_ERROR_DOCSHELL_DYING;
7422 }
7423 }
7424
7425 // Now make sure we don't think we're in the middle of firing unload after
7426 // this point. This will make us fire unload when the about:blank document
7427 // unloads... but that's ok, more or less. Would be nice if it fired load
7428 // too, of course.
7429 mFiredUnloadEvent = false;
7430
7431 nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
7432 nsContentUtils::FindInternalContentViewer(
7433 NS_LITERAL_CSTRING("text/html"));
7434
7435 if (docFactory) {
7436 nsCOMPtr<nsIPrincipal> principal;
7437 if (mSandboxFlags & SANDBOXED_ORIGIN) {
7438 if (aPrincipal) {
7439 principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal);
7440 } else {
7441 principal = NullPrincipal::CreateWithInheritedAttributes(this);
7442 }
7443 } else {
7444 principal = aPrincipal;
7445 }
7446
7447 MaybeCreateInitialClientSource(principal);
7448
7449 // generate (about:blank) document to load
7450 blankDoc = nsContentDLF::CreateBlankDocument(mLoadGroup, principal, this);
7451 if (blankDoc) {
7452 // Hack: set the base URI manually, since this document never
7453 // got Reset() with a channel.
7454 blankDoc->SetBaseURI(aBaseURI);
7455
7456 // Copy our sandbox flags to the document. These are immutable
7457 // after being set here.
7458 blankDoc->SetSandboxFlags(mSandboxFlags);
7459
7460 // create a content viewer for us and the new document
7461 docFactory->CreateInstanceForDocument(
7462 NS_ISUPPORTS_CAST(nsIDocShell*, this), blankDoc, "view",
7463 getter_AddRefs(viewer));
7464
7465 // hook 'em up
7466 if (viewer) {
7467 viewer->SetContainer(this);
7468 rv = Embed(viewer, "", 0);
7469 NS_ENSURE_SUCCESS(rv, rv);
7470
7471 SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
7472 rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
7473 }
7474 }
7475 }
7476
7477 // The transient about:blank viewer doesn't have a session history entry.
7478 SetHistoryEntry(&mOSHE, nullptr);
7479
7480 // Clear out our mTiming like we would in EndPageLoad, if we didn't
7481 // have one before entering this function.
7482 if (!hadTiming) {
7483 mTiming = nullptr;
7484 mBlankTiming = true;
7485 }
7486
7487 return rv;
7488 }
7489
7490 NS_IMETHODIMP
CreateAboutBlankContentViewer(nsIPrincipal * aPrincipal)7491 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal) {
7492 return CreateAboutBlankContentViewer(aPrincipal, nullptr);
7493 }
7494
7495 NS_IMETHODIMP
ForceCreateAboutBlankContentViewer(nsIPrincipal * aPrincipal)7496 nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal* aPrincipal) {
7497 return CreateAboutBlankContentViewer(aPrincipal, nullptr, true, false);
7498 }
7499
CanSavePresentation(uint32_t aLoadType,nsIRequest * aNewRequest,nsIDocument * aNewDocument)7500 bool nsDocShell::CanSavePresentation(uint32_t aLoadType,
7501 nsIRequest* aNewRequest,
7502 nsIDocument* aNewDocument) {
7503 if (!mOSHE) {
7504 return false; // no entry to save into
7505 }
7506
7507 nsCOMPtr<nsIContentViewer> viewer;
7508 mOSHE->GetContentViewer(getter_AddRefs(viewer));
7509 if (viewer) {
7510 NS_WARNING("mOSHE already has a content viewer!");
7511 return false;
7512 }
7513
7514 // Only save presentation for "normal" loads and link loads. Anything else
7515 // probably wants to refetch the page, so caching the old presentation
7516 // would be incorrect.
7517 if (aLoadType != LOAD_NORMAL && aLoadType != LOAD_HISTORY &&
7518 aLoadType != LOAD_LINK && aLoadType != LOAD_STOP_CONTENT &&
7519 aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
7520 aLoadType != LOAD_ERROR_PAGE) {
7521 return false;
7522 }
7523
7524 // If the session history entry has the saveLayoutState flag set to false,
7525 // then we should not cache the presentation.
7526 bool canSaveState;
7527 mOSHE->GetSaveLayoutStateFlag(&canSaveState);
7528 if (!canSaveState) {
7529 return false;
7530 }
7531
7532 // If the document is not done loading, don't cache it.
7533 if (!mScriptGlobal || mScriptGlobal->IsLoading()) {
7534 return false;
7535 }
7536
7537 if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) {
7538 return false;
7539 }
7540
7541 // Avoid doing the work of saving the presentation state in the case where
7542 // the content viewer cache is disabled.
7543 if (nsSHistory::GetMaxTotalViewers() == 0) {
7544 return false;
7545 }
7546
7547 // Don't cache the content viewer if we're in a subframe.
7548 nsCOMPtr<nsIDocShellTreeItem> root;
7549 GetSameTypeParent(getter_AddRefs(root));
7550 if (root && root != this) {
7551 return false; // this is a subframe load
7552 }
7553
7554 // If the document does not want its presentation cached, then don't.
7555 nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
7556 return doc && doc->CanSavePresentation(aNewRequest);
7557 }
7558
ReattachEditorToWindow(nsISHEntry * aSHEntry)7559 void nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry) {
7560 MOZ_ASSERT(!mIsBeingDestroyed);
7561
7562 NS_ASSERTION(!mEditorData,
7563 "Why reattach an editor when we already have one?");
7564 NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
7565 "Reattaching when there's not a detached editor.");
7566
7567 if (mEditorData || !aSHEntry) {
7568 return;
7569 }
7570
7571 mEditorData = aSHEntry->ForgetEditorData();
7572 if (mEditorData) {
7573 #ifdef DEBUG
7574 nsresult rv =
7575 #endif
7576 mEditorData->ReattachToWindow(this);
7577 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
7578 }
7579 }
7580
DetachEditorFromWindow()7581 void nsDocShell::DetachEditorFromWindow() {
7582 if (!mEditorData || mEditorData->WaitingForLoad()) {
7583 // If there's nothing to detach, or if the editor data is actually set
7584 // up for the _new_ page that's coming in, don't detach.
7585 return;
7586 }
7587
7588 NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
7589 "Detaching editor when it's already detached.");
7590
7591 nsresult res = mEditorData->DetachFromWindow();
7592 NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
7593
7594 if (NS_SUCCEEDED(res)) {
7595 // Make mOSHE hold the owning ref to the editor data.
7596 if (mOSHE) {
7597 MOZ_ASSERT(!mIsBeingDestroyed || !mOSHE->HasDetachedEditor(),
7598 "We should not set the editor data again once after we "
7599 "detached the editor data during destroying this docshell");
7600 mOSHE->SetEditorData(mEditorData.forget());
7601 } else {
7602 mEditorData = nullptr;
7603 }
7604 }
7605
7606 #ifdef DEBUG
7607 {
7608 bool isEditable;
7609 GetEditable(&isEditable);
7610 NS_ASSERTION(!isEditable,
7611 "Window is still editable after detaching editor.");
7612 }
7613 #endif // DEBUG
7614 }
7615
CaptureState()7616 nsresult nsDocShell::CaptureState() {
7617 if (!mOSHE || mOSHE == mLSHE) {
7618 // No entry to save into, or we're replacing the existing entry.
7619 return NS_ERROR_FAILURE;
7620 }
7621
7622 if (!mScriptGlobal) {
7623 return NS_ERROR_FAILURE;
7624 }
7625
7626 nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
7627 NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
7628
7629 #ifdef DEBUG_PAGE_CACHE
7630 nsCOMPtr<nsIURI> uri;
7631 mOSHE->GetURI(getter_AddRefs(uri));
7632 nsAutoCString spec;
7633 if (uri) {
7634 uri->GetSpec(spec);
7635 }
7636 printf("Saving presentation into session history\n");
7637 printf(" SH URI: %s\n", spec.get());
7638 #endif
7639
7640 nsresult rv = mOSHE->SetWindowState(windowState);
7641 NS_ENSURE_SUCCESS(rv, rv);
7642
7643 // Suspend refresh URIs and save off the timer queue
7644 rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
7645 NS_ENSURE_SUCCESS(rv, rv);
7646
7647 // Capture the current content viewer bounds.
7648 if (mContentViewer) {
7649 nsIntRect bounds;
7650 mContentViewer->GetBounds(bounds);
7651 rv = mOSHE->SetViewerBounds(bounds);
7652 NS_ENSURE_SUCCESS(rv, rv);
7653 }
7654
7655 // Capture the docshell hierarchy.
7656 mOSHE->ClearChildShells();
7657
7658 uint32_t childCount = mChildList.Length();
7659 for (uint32_t i = 0; i < childCount; ++i) {
7660 nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
7661 NS_ASSERTION(childShell, "null child shell");
7662
7663 mOSHE->AddChildShell(childShell);
7664 }
7665
7666 return NS_OK;
7667 }
7668
7669 NS_IMETHODIMP
Run()7670 nsDocShell::RestorePresentationEvent::Run() {
7671 if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) {
7672 NS_WARNING("RestoreFromHistory failed");
7673 }
7674 return NS_OK;
7675 }
7676
7677 NS_IMETHODIMP
BeginRestore(nsIContentViewer * aContentViewer,bool aTop)7678 nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop) {
7679 nsresult rv;
7680 if (!aContentViewer) {
7681 rv = EnsureContentViewer();
7682 NS_ENSURE_SUCCESS(rv, rv);
7683
7684 aContentViewer = mContentViewer;
7685 }
7686
7687 // Dispatch events for restoring the presentation. We try to simulate
7688 // the progress notifications loading the document would cause, so we add
7689 // the document's channel to the loadgroup to initiate stateChange
7690 // notifications.
7691
7692 nsCOMPtr<nsIDocument> doc = aContentViewer->GetDocument();
7693 if (doc) {
7694 nsIChannel* channel = doc->GetChannel();
7695 if (channel) {
7696 mEODForCurrentDocument = false;
7697 mIsRestoringDocument = true;
7698 mLoadGroup->AddRequest(channel, nullptr);
7699 mIsRestoringDocument = false;
7700 }
7701 }
7702
7703 if (!aTop) {
7704 // This point corresponds to us having gotten OnStartRequest or
7705 // STATE_START, so do the same thing that CreateContentViewer does at
7706 // this point to ensure that unload/pagehide events for this document
7707 // will fire when it's unloaded again.
7708 mFiredUnloadEvent = false;
7709
7710 // For non-top frames, there is no notion of making sure that the
7711 // previous document is in the domwindow when STATE_START notifications
7712 // happen. We can just call BeginRestore for all of the child shells
7713 // now.
7714 rv = BeginRestoreChildren();
7715 NS_ENSURE_SUCCESS(rv, rv);
7716 }
7717
7718 return NS_OK;
7719 }
7720
BeginRestoreChildren()7721 nsresult nsDocShell::BeginRestoreChildren() {
7722 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7723 while (iter.HasMore()) {
7724 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
7725 if (child) {
7726 nsresult rv = child->BeginRestore(nullptr, false);
7727 NS_ENSURE_SUCCESS(rv, rv);
7728 }
7729 }
7730 return NS_OK;
7731 }
7732
7733 NS_IMETHODIMP
FinishRestore()7734 nsDocShell::FinishRestore() {
7735 // First we call finishRestore() on our children. In the simulated load,
7736 // all of the child frames finish loading before the main document.
7737
7738 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7739 while (iter.HasMore()) {
7740 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
7741 if (child) {
7742 child->FinishRestore();
7743 }
7744 }
7745
7746 if (mOSHE && mOSHE->HasDetachedEditor()) {
7747 ReattachEditorToWindow(mOSHE);
7748 }
7749
7750 nsCOMPtr<nsIDocument> doc = GetDocument();
7751 if (doc) {
7752 // Finally, we remove the request from the loadgroup. This will
7753 // cause onStateChange(STATE_STOP) to fire, which will fire the
7754 // pageshow event to the chrome.
7755
7756 nsIChannel* channel = doc->GetChannel();
7757 if (channel) {
7758 mIsRestoringDocument = true;
7759 mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
7760 mIsRestoringDocument = false;
7761 }
7762 }
7763
7764 return NS_OK;
7765 }
7766
7767 NS_IMETHODIMP
GetRestoringDocument(bool * aRestoring)7768 nsDocShell::GetRestoringDocument(bool* aRestoring) {
7769 *aRestoring = mIsRestoringDocument;
7770 return NS_OK;
7771 }
7772
RestorePresentation(nsISHEntry * aSHEntry,bool * aRestoring)7773 nsresult nsDocShell::RestorePresentation(nsISHEntry* aSHEntry,
7774 bool* aRestoring) {
7775 MOZ_ASSERT(!mIsBeingDestroyed);
7776
7777 NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
7778 "RestorePresentation should only be called for history loads");
7779
7780 nsCOMPtr<nsIContentViewer> viewer;
7781 aSHEntry->GetContentViewer(getter_AddRefs(viewer));
7782
7783 #ifdef DEBUG_PAGE_CACHE
7784 nsCOMPtr<nsIURI> uri;
7785 aSHEntry->GetURI(getter_AddRefs(uri));
7786
7787 nsAutoCString spec;
7788 if (uri) {
7789 uri->GetSpec(spec);
7790 }
7791 #endif
7792
7793 *aRestoring = false;
7794
7795 if (!viewer) {
7796 #ifdef DEBUG_PAGE_CACHE
7797 printf("no saved presentation for uri: %s\n", spec.get());
7798 #endif
7799 return NS_OK;
7800 }
7801
7802 // We need to make sure the content viewer's container is this docshell.
7803 // In subframe navigation, it's possible for the docshell that the
7804 // content viewer was originally loaded into to be replaced with a
7805 // different one. We don't currently support restoring the presentation
7806 // in that case.
7807
7808 nsCOMPtr<nsIDocShell> container;
7809 viewer->GetContainer(getter_AddRefs(container));
7810 if (!::SameCOMIdentity(container, GetAsSupports(this))) {
7811 #ifdef DEBUG_PAGE_CACHE
7812 printf("No valid container, clearing presentation\n");
7813 #endif
7814 aSHEntry->SetContentViewer(nullptr);
7815 return NS_ERROR_FAILURE;
7816 }
7817
7818 NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
7819
7820 #ifdef DEBUG_PAGE_CACHE
7821 printf("restoring presentation from session history: %s\n", spec.get());
7822 #endif
7823
7824 SetHistoryEntry(&mLSHE, aSHEntry);
7825
7826 // Post an event that will remove the request after we've returned
7827 // to the event loop. This mimics the way it is called by nsIChannel
7828 // implementations.
7829
7830 // Revoke any pending restore (just in case)
7831 NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
7832 "should only have one RestorePresentationEvent");
7833 mRestorePresentationEvent.Revoke();
7834
7835 RefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
7836 nsresult rv = DispatchToTabGroup(
7837 TaskCategory::Other, RefPtr<RestorePresentationEvent>(evt).forget());
7838 if (NS_SUCCEEDED(rv)) {
7839 mRestorePresentationEvent = evt.get();
7840 // The rest of the restore processing will happen on our event
7841 // callback.
7842 *aRestoring = true;
7843 }
7844
7845 return rv;
7846 }
7847
7848 namespace {
7849 class MOZ_STACK_CLASS PresentationEventForgetter {
7850 public:
PresentationEventForgetter(nsRevocableEventPtr<nsDocShell::RestorePresentationEvent> & aRestorePresentationEvent)7851 explicit PresentationEventForgetter(
7852 nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
7853 aRestorePresentationEvent)
7854 : mRestorePresentationEvent(aRestorePresentationEvent),
7855 mEvent(aRestorePresentationEvent.get()) {}
7856
~PresentationEventForgetter()7857 ~PresentationEventForgetter() { Forget(); }
7858
Forget()7859 void Forget() {
7860 if (mRestorePresentationEvent.get() == mEvent) {
7861 mRestorePresentationEvent.Forget();
7862 mEvent = nullptr;
7863 }
7864 }
7865
7866 private:
7867 nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
7868 mRestorePresentationEvent;
7869 RefPtr<nsDocShell::RestorePresentationEvent> mEvent;
7870 };
7871
7872 } // namespace
7873
SandboxFlagsImplyCookies(const uint32_t & aSandboxFlags)7874 bool nsDocShell::SandboxFlagsImplyCookies(const uint32_t& aSandboxFlags) {
7875 return (aSandboxFlags & (SANDBOXED_ORIGIN | SANDBOXED_SCRIPTS)) == 0;
7876 }
7877
RestoreFromHistory()7878 nsresult nsDocShell::RestoreFromHistory() {
7879 MOZ_ASSERT(mRestorePresentationEvent.IsPending());
7880 PresentationEventForgetter forgetter(mRestorePresentationEvent);
7881
7882 // This section of code follows the same ordering as CreateContentViewer.
7883 if (!mLSHE) {
7884 return NS_ERROR_FAILURE;
7885 }
7886
7887 nsCOMPtr<nsIContentViewer> viewer;
7888 mLSHE->GetContentViewer(getter_AddRefs(viewer));
7889 if (!viewer) {
7890 return NS_ERROR_FAILURE;
7891 }
7892
7893 if (mSavingOldViewer) {
7894 // We determined that it was safe to cache the document presentation
7895 // at the time we initiated the new load. We need to check whether
7896 // it's still safe to do so, since there may have been DOM mutations
7897 // or new requests initiated.
7898 nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
7899 nsIRequest* request = nullptr;
7900 if (doc) {
7901 request = doc->GetChannel();
7902 }
7903 mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
7904 }
7905
7906 nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
7907 nsCOMPtr<nsIContentViewer> newCv(viewer);
7908 int32_t minFontSize = 0;
7909 float textZoom = 1.0f;
7910 float pageZoom = 1.0f;
7911 float overrideDPPX = 0.0f;
7912
7913 bool styleDisabled = false;
7914 if (oldCv && newCv) {
7915 oldCv->GetMinFontSize(&minFontSize);
7916 oldCv->GetTextZoom(&textZoom);
7917 oldCv->GetFullZoom(&pageZoom);
7918 oldCv->GetOverrideDPPX(&overrideDPPX);
7919 oldCv->GetAuthorStyleDisabled(&styleDisabled);
7920 }
7921
7922 // Protect against mLSHE going away via a load triggered from
7923 // pagehide or unload.
7924 nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
7925
7926 // Make sure to blow away our mLoadingURI just in case. No loads
7927 // from inside this pagehide.
7928 mLoadingURI = nullptr;
7929
7930 // Notify the old content viewer that it's being hidden.
7931 FirePageHideNotification(!mSavingOldViewer);
7932 // pagehide notification might destroy this docshell.
7933 if (mIsBeingDestroyed) {
7934 return NS_ERROR_DOCSHELL_DYING;
7935 }
7936
7937 // If mLSHE was changed as a result of the pagehide event, then
7938 // something else was loaded. Don't finish restoring.
7939 if (mLSHE != origLSHE) {
7940 return NS_OK;
7941 }
7942
7943 // Add the request to our load group. We do this before swapping out
7944 // the content viewers so that consumers of STATE_START can access
7945 // the old document. We only deal with the toplevel load at this time --
7946 // to be consistent with normal document loading, subframes cannot start
7947 // loading until after data arrives, which is after STATE_START completes.
7948
7949 RefPtr<RestorePresentationEvent> currentPresentationRestoration =
7950 mRestorePresentationEvent.get();
7951 Stop();
7952 // Make sure we're still restoring the same presentation.
7953 // If we aren't, docshell is in process doing another load already.
7954 NS_ENSURE_STATE(currentPresentationRestoration ==
7955 mRestorePresentationEvent.get());
7956 BeginRestore(viewer, true);
7957 NS_ENSURE_STATE(currentPresentationRestoration ==
7958 mRestorePresentationEvent.get());
7959 forgetter.Forget();
7960
7961 // Set mFiredUnloadEvent = false so that the unload handler for the
7962 // *new* document will fire.
7963 mFiredUnloadEvent = false;
7964
7965 mURIResultedInDocument = true;
7966 nsCOMPtr<nsISHistory> rootSH;
7967 GetRootSessionHistory(getter_AddRefs(rootSH));
7968 if (rootSH) {
7969 nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
7970 rootSH->GetIndex(&mPreviousTransIndex);
7971 hist->UpdateIndex();
7972 rootSH->GetIndex(&mLoadedTransIndex);
7973 #ifdef DEBUG_PAGE_CACHE
7974 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
7975 mLoadedTransIndex);
7976 #endif
7977 }
7978
7979 // Rather than call Embed(), we will retrieve the viewer from the session
7980 // history entry and swap it in.
7981 // XXX can we refactor this so that we can just call Embed()?
7982 PersistLayoutHistoryState();
7983 nsresult rv;
7984 if (mContentViewer) {
7985 if (mSavingOldViewer && NS_FAILED(CaptureState())) {
7986 if (mOSHE) {
7987 mOSHE->SyncPresentationState();
7988 }
7989 mSavingOldViewer = false;
7990 }
7991 }
7992
7993 mSavedRefreshURIList = nullptr;
7994
7995 // In cases where we use a transient about:blank viewer between loads,
7996 // we never show the transient viewer, so _its_ previous viewer is never
7997 // unhooked from the view hierarchy. Destroy any such previous viewer now,
7998 // before we grab the root view sibling, so that we don't grab a view
7999 // that's about to go away.
8000
8001 if (mContentViewer) {
8002 nsCOMPtr<nsIContentViewer> previousViewer;
8003 mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
8004 if (previousViewer) {
8005 mContentViewer->SetPreviousViewer(nullptr);
8006 previousViewer->Destroy();
8007 }
8008 }
8009
8010 // Save off the root view's parent and sibling so that we can insert the
8011 // new content viewer's root view at the same position. Also save the
8012 // bounds of the root view's widget.
8013
8014 nsView* rootViewSibling = nullptr;
8015 nsView* rootViewParent = nullptr;
8016 nsIntRect newBounds(0, 0, 0, 0);
8017
8018 nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
8019 if (oldPresShell) {
8020 nsViewManager* vm = oldPresShell->GetViewManager();
8021 if (vm) {
8022 nsView* oldRootView = vm->GetRootView();
8023
8024 if (oldRootView) {
8025 rootViewSibling = oldRootView->GetNextSibling();
8026 rootViewParent = oldRootView->GetParent();
8027
8028 mContentViewer->GetBounds(newBounds);
8029 }
8030 }
8031 }
8032
8033 nsCOMPtr<nsIContent> container;
8034 nsCOMPtr<nsIDocument> sibling;
8035 if (rootViewParent && rootViewParent->GetParent()) {
8036 nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
8037 container = frame ? frame->GetContent() : nullptr;
8038 }
8039 if (rootViewSibling) {
8040 nsIFrame* frame = rootViewSibling->GetFrame();
8041 sibling = frame ? frame->PresShell()->GetDocument() : nullptr;
8042 }
8043
8044 // Transfer ownership to mContentViewer. By ensuring that either the
8045 // docshell or the session history, but not both, have references to the
8046 // content viewer, we prevent the viewer from being torn down after
8047 // Destroy() is called.
8048
8049 if (mContentViewer) {
8050 mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
8051 viewer->SetPreviousViewer(mContentViewer);
8052 }
8053 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
8054 // We don't plan to save a viewer in mOSHE; tell it to drop
8055 // any other state it's holding.
8056 mOSHE->SyncPresentationState();
8057 }
8058
8059 // Order the mContentViewer setup just like Embed does.
8060 mContentViewer = nullptr;
8061
8062 // Now that we're about to switch documents, forget all of our children.
8063 // Note that we cached them as needed up in CaptureState above.
8064 DestroyChildren();
8065
8066 mContentViewer.swap(viewer);
8067
8068 // Grab all of the related presentation from the SHEntry now.
8069 // Clearing the viewer from the SHEntry will clear all of this state.
8070 nsCOMPtr<nsISupports> windowState;
8071 mLSHE->GetWindowState(getter_AddRefs(windowState));
8072 mLSHE->SetWindowState(nullptr);
8073
8074 bool sticky;
8075 mLSHE->GetSticky(&sticky);
8076
8077 nsCOMPtr<nsIDocument> document = mContentViewer->GetDocument();
8078
8079 nsCOMArray<nsIDocShellTreeItem> childShells;
8080 int32_t i = 0;
8081 nsCOMPtr<nsIDocShellTreeItem> child;
8082 while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
8083 child) {
8084 childShells.AppendObject(child);
8085 }
8086
8087 // get the previous content viewer size
8088 nsIntRect oldBounds(0, 0, 0, 0);
8089 mLSHE->GetViewerBounds(oldBounds);
8090
8091 // Restore the refresh URI list. The refresh timers will be restarted
8092 // when EndPageLoad() is called.
8093 nsCOMPtr<nsIMutableArray> refreshURIList;
8094 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
8095
8096 // Reattach to the window object.
8097 mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
8098 rv = mContentViewer->Open(windowState, mLSHE);
8099 mIsRestoringDocument = false;
8100
8101 // Hack to keep nsDocShellEditorData alive across the
8102 // SetContentViewer(nullptr) call below.
8103 nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
8104
8105 // Now remove it from the cached presentation.
8106 mLSHE->SetContentViewer(nullptr);
8107 mEODForCurrentDocument = false;
8108
8109 mLSHE->SetEditorData(data.forget());
8110
8111 #ifdef DEBUG
8112 {
8113 nsCOMPtr<nsIMutableArray> refreshURIs;
8114 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
8115 nsCOMPtr<nsIDocShellTreeItem> childShell;
8116 mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
8117 NS_ASSERTION(!refreshURIs && !childShell,
8118 "SHEntry should have cleared presentation state");
8119 }
8120 #endif
8121
8122 // Restore the sticky state of the viewer. The viewer has set this state
8123 // on the history entry in Destroy() just before marking itself non-sticky,
8124 // to avoid teardown of the presentation.
8125 mContentViewer->SetSticky(sticky);
8126
8127 NS_ENSURE_SUCCESS(rv, rv);
8128
8129 // mLSHE is now our currently-loaded document.
8130 SetHistoryEntry(&mOSHE, mLSHE);
8131
8132 // XXX special wyciwyg handling in Embed()?
8133
8134 // We aren't going to restore any items from the LayoutHistoryState,
8135 // but we don't want them to stay around in case the page is reloaded.
8136 SetLayoutHistoryState(nullptr);
8137
8138 // This is the end of our Embed() replacement
8139
8140 mSavingOldViewer = false;
8141 mEODForCurrentDocument = false;
8142
8143 // Tell the event loop to favor plevents over user events, see comments
8144 // in CreateContentViewer.
8145 if (++gNumberOfDocumentsLoading == 1) {
8146 FavorPerformanceHint(true);
8147 }
8148
8149 if (oldCv && newCv) {
8150 newCv->SetMinFontSize(minFontSize);
8151 newCv->SetTextZoom(textZoom);
8152 newCv->SetFullZoom(pageZoom);
8153 newCv->SetOverrideDPPX(overrideDPPX);
8154 newCv->SetAuthorStyleDisabled(styleDisabled);
8155 }
8156
8157 if (document) {
8158 RefPtr<nsDocShell> parent = GetParentDocshell();
8159 if (parent) {
8160 nsCOMPtr<nsIDocument> d = parent->GetDocument();
8161 if (d) {
8162 if (d->EventHandlingSuppressed()) {
8163 document->SuppressEventHandling(d->EventHandlingSuppressed());
8164 }
8165 }
8166 }
8167
8168 // Use the uri from the mLSHE we had when we entered this function
8169 // (which need not match the document's URI if anchors are involved),
8170 // since that's the history entry we're loading. Note that if we use
8171 // origLSHE we don't have to worry about whether the entry in question
8172 // is still mLSHE or whether it's now mOSHE.
8173 nsCOMPtr<nsIURI> uri;
8174 origLSHE->GetURI(getter_AddRefs(uri));
8175 SetCurrentURI(uri, document->GetChannel(), true, 0);
8176 }
8177
8178 // This is the end of our CreateContentViewer() replacement.
8179 // Now we simulate a load. First, we restore the state of the javascript
8180 // window object.
8181 nsCOMPtr<nsPIDOMWindowOuter> privWin = GetWindow();
8182 NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
8183
8184 // Now, dispatch a title change event which would happen as the
8185 // <head> is parsed.
8186 document->NotifyPossibleTitleChange(false);
8187
8188 // Now we simulate appending child docshells for subframes.
8189 for (i = 0; i < childShells.Count(); ++i) {
8190 nsIDocShellTreeItem* childItem = childShells.ObjectAt(i);
8191 nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
8192
8193 // Make sure to not clobber the state of the child. Since AddChild
8194 // always clobbers it, save it off first.
8195 bool allowPlugins;
8196 childShell->GetAllowPlugins(&allowPlugins);
8197
8198 bool allowJavascript;
8199 childShell->GetAllowJavascript(&allowJavascript);
8200
8201 bool allowRedirects;
8202 childShell->GetAllowMetaRedirects(&allowRedirects);
8203
8204 bool allowSubframes;
8205 childShell->GetAllowSubframes(&allowSubframes);
8206
8207 bool allowImages;
8208 childShell->GetAllowImages(&allowImages);
8209
8210 bool allowMedia = childShell->GetAllowMedia();
8211
8212 bool allowDNSPrefetch;
8213 childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
8214
8215 bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
8216 bool allowContentRetargetingOnChildren =
8217 childShell->GetAllowContentRetargetingOnChildren();
8218
8219 uint32_t defaultLoadFlags;
8220 childShell->GetDefaultLoadFlags(&defaultLoadFlags);
8221
8222 // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
8223 // the child inherits our state. Among other things, this means that the
8224 // child inherits our mIsActive mPrivateBrowsingId, which is what we want.
8225 AddChild(childItem);
8226
8227 childShell->SetAllowPlugins(allowPlugins);
8228 childShell->SetAllowJavascript(allowJavascript);
8229 childShell->SetAllowMetaRedirects(allowRedirects);
8230 childShell->SetAllowSubframes(allowSubframes);
8231 childShell->SetAllowImages(allowImages);
8232 childShell->SetAllowMedia(allowMedia);
8233 childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
8234 childShell->SetAllowContentRetargeting(allowContentRetargeting);
8235 childShell->SetAllowContentRetargetingOnChildren(
8236 allowContentRetargetingOnChildren);
8237 childShell->SetDefaultLoadFlags(defaultLoadFlags);
8238
8239 rv = childShell->BeginRestore(nullptr, false);
8240 NS_ENSURE_SUCCESS(rv, rv);
8241 }
8242
8243 // Make sure to restore the window state after adding the child shells back
8244 // to the tree. This is necessary for Thaw() and Resume() to propagate
8245 // properly.
8246 rv = privWin->RestoreWindowState(windowState);
8247 NS_ENSURE_SUCCESS(rv, rv);
8248
8249 nsCOMPtr<nsIPresShell> shell = GetPresShell();
8250
8251 // We may be displayed on a different monitor (or in a different
8252 // HiDPI mode) than when we got into the history list. So we need
8253 // to check if this has happened. See bug 838239.
8254
8255 // Because the prescontext normally handles resolution changes via
8256 // a runnable (see nsPresContext::UIResolutionChanged), its device
8257 // context won't be -immediately- updated as a result of calling
8258 // shell->BackingScaleFactorChanged().
8259
8260 // But we depend on that device context when adjusting the view size
8261 // via mContentViewer->SetBounds(newBounds) below. So we need to
8262 // explicitly tell it to check for changed resolution here.
8263 if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
8264 shell->BackingScaleFactorChanged();
8265 }
8266
8267 nsViewManager* newVM = shell ? shell->GetViewManager() : nullptr;
8268 nsView* newRootView = newVM ? newVM->GetRootView() : nullptr;
8269
8270 // Insert the new root view at the correct location in the view tree.
8271 if (container) {
8272 nsSubDocumentFrame* subDocFrame =
8273 do_QueryFrame(container->GetPrimaryFrame());
8274 rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
8275 } else {
8276 rootViewParent = nullptr;
8277 }
8278 if (sibling && sibling->GetShell() && sibling->GetShell()->GetViewManager()) {
8279 rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
8280 } else {
8281 rootViewSibling = nullptr;
8282 }
8283 if (rootViewParent && newRootView &&
8284 newRootView->GetParent() != rootViewParent) {
8285 nsViewManager* parentVM = rootViewParent->GetViewManager();
8286 if (parentVM) {
8287 // InsertChild(parent, child, sib, true) inserts the child after
8288 // sib in content order, which is before sib in view order. BUT
8289 // when sib is null it inserts at the end of the the document
8290 // order, i.e., first in view order. But when oldRootSibling is
8291 // null, the old root as at the end of the view list --- last in
8292 // content order --- and we want to call InsertChild(parent, child,
8293 // nullptr, false) in that case.
8294 parentVM->InsertChild(rootViewParent, newRootView, rootViewSibling,
8295 rootViewSibling ? true : false);
8296
8297 NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
8298 "error in InsertChild");
8299 }
8300 }
8301
8302 nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow();
8303
8304 // If parent is suspended, increase suspension count.
8305 // This can't be done as early as event suppression since this
8306 // depends on docshell tree.
8307 privWinInner->SyncStateFromParentWindow();
8308
8309 // Now that all of the child docshells have been put into place, we can
8310 // restart the timers for the window and all of the child frames.
8311 privWinInner->Resume();
8312
8313 // Restore the refresh URI list. The refresh timers will be restarted
8314 // when EndPageLoad() is called.
8315 mRefreshURIList = refreshURIList;
8316
8317 // Meta-refresh timers have been restarted for this shell, but not
8318 // for our children. Walk the child shells and restart their timers.
8319 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
8320 while (iter.HasMore()) {
8321 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
8322 if (child) {
8323 child->ResumeRefreshURIs();
8324 }
8325 }
8326
8327 // Make sure this presentation is the same size as the previous
8328 // presentation. If this is not the same size we showed it at last time,
8329 // then we need to resize the widget.
8330
8331 // XXXbryner This interacts poorly with Firefox's infobar. If the old
8332 // presentation had the infobar visible, then we will resize the new
8333 // presentation to that smaller size. However, firing the locationchanged
8334 // event will hide the infobar, which will immediately resize the window
8335 // back to the larger size. A future optimization might be to restore
8336 // the presentation at the "wrong" size, then fire the locationchanged
8337 // event and check whether the docshell's new size is the same as the
8338 // cached viewer size (skipping the resize if they are equal).
8339
8340 if (newRootView) {
8341 if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
8342 #ifdef DEBUG_PAGE_CACHE
8343 printf("resize widget(%d, %d, %d, %d)\n", newBounds.x, newBounds.y,
8344 newBounds.width, newBounds.height);
8345 #endif
8346 mContentViewer->SetBounds(newBounds);
8347 } else {
8348 nsIScrollableFrame* rootScrollFrame =
8349 shell->GetRootScrollFrameAsScrollable();
8350 if (rootScrollFrame) {
8351 rootScrollFrame->PostScrolledAreaEventForCurrentArea();
8352 }
8353 }
8354 }
8355
8356 // The FinishRestore call below can kill these, null them out so we don't
8357 // have invalid pointer lying around.
8358 newRootView = rootViewSibling = rootViewParent = nullptr;
8359 newVM = nullptr;
8360
8361 // Simulate the completion of the load.
8362 nsDocShell::FinishRestore();
8363
8364 // Restart plugins, and paint the content.
8365 if (shell) {
8366 shell->Thaw();
8367 }
8368
8369 return privWin->FireDelayedDOMEvents();
8370 }
8371
CreateContentViewer(const nsACString & aContentType,nsIRequest * aRequest,nsIStreamListener ** aContentHandler)8372 nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType,
8373 nsIRequest* aRequest,
8374 nsIStreamListener** aContentHandler) {
8375 *aContentHandler = nullptr;
8376
8377 if (!mTreeOwner || mIsBeingDestroyed) {
8378 // If we don't have a tree owner, then we're in the process of being
8379 // destroyed. Rather than continue trying to load something, just give up.
8380 return NS_ERROR_DOCSHELL_DYING;
8381 }
8382
8383 // Can we check the content type of the current content viewer
8384 // and reuse it without destroying it and re-creating it?
8385
8386 NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
8387
8388 // Instantiate the content viewer object
8389 nsCOMPtr<nsIContentViewer> viewer;
8390 nsresult rv = NewContentViewerObj(aContentType, aRequest, mLoadGroup,
8391 aContentHandler, getter_AddRefs(viewer));
8392
8393 if (NS_FAILED(rv)) {
8394 return rv;
8395 }
8396
8397 // Notify the current document that it is about to be unloaded!!
8398 //
8399 // It is important to fire the unload() notification *before* any state
8400 // is changed within the DocShell - otherwise, javascript will get the
8401 // wrong information :-(
8402 //
8403
8404 if (mSavingOldViewer) {
8405 // We determined that it was safe to cache the document presentation
8406 // at the time we initiated the new load. We need to check whether
8407 // it's still safe to do so, since there may have been DOM mutations
8408 // or new requests initiated.
8409 nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
8410 mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc);
8411 }
8412
8413 NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
8414
8415 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
8416 if (aOpenedChannel) {
8417 aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
8418 }
8419 FirePageHideNotification(!mSavingOldViewer);
8420 if (mIsBeingDestroyed) {
8421 // Force to stop the newly created orphaned viewer.
8422 viewer->Stop();
8423 return NS_ERROR_DOCSHELL_DYING;
8424 }
8425 mLoadingURI = nullptr;
8426
8427 // Set mFiredUnloadEvent = false so that the unload handler for the
8428 // *new* document will fire.
8429 mFiredUnloadEvent = false;
8430
8431 // we've created a new document so go ahead and call
8432 // OnLoadingSite(), but don't fire OnLocationChange()
8433 // notifications before we've called Embed(). See bug 284993.
8434 mURIResultedInDocument = true;
8435 bool errorOnLocationChangeNeeded = false;
8436 nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
8437 nsCOMPtr<nsIURI> failedURI;
8438
8439 if (mLoadType == LOAD_ERROR_PAGE) {
8440 // We need to set the SH entry and our current URI here and not
8441 // at the moment we load the page. We want the same behavior
8442 // of Stop() as for a normal page load. See bug 514232 for details.
8443
8444 // Revert mLoadType to load type to state the page load failed,
8445 // following function calls need it.
8446 mLoadType = mFailedLoadType;
8447
8448 nsIDocument* doc = viewer->GetDocument();
8449 if (doc) {
8450 doc->SetFailedChannel(failedChannel);
8451 }
8452
8453 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
8454 if (failedChannel) {
8455 // Make sure we have a URI to set currentURI.
8456 NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
8457 } else {
8458 // if there is no failed channel we have to explicitly provide
8459 // a triggeringPrincipal for the history entry.
8460 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
8461 }
8462
8463 if (!failedURI) {
8464 failedURI = mFailedURI;
8465 }
8466 if (!failedURI) {
8467 // We need a URI object to store a session history entry, so make up a URI
8468 NS_NewURI(getter_AddRefs(failedURI), "about:blank");
8469 }
8470
8471 // When we don't have failedURI, something wrong will happen. See
8472 // bug 291876.
8473 MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
8474
8475 mFailedChannel = nullptr;
8476 mFailedURI = nullptr;
8477
8478 // Create an shistory entry for the old load.
8479 if (failedURI) {
8480 errorOnLocationChangeNeeded =
8481 OnNewURI(failedURI, failedChannel, triggeringPrincipal, nullptr,
8482 mLoadType, false, false, false);
8483 }
8484
8485 // Be sure to have a correct mLSHE, it may have been cleared by
8486 // EndPageLoad. See bug 302115.
8487 if (mSessionHistory && !mLSHE) {
8488 int32_t idx;
8489 mSessionHistory->GetRequestedIndex(&idx);
8490 if (idx == -1) {
8491 mSessionHistory->GetIndex(&idx);
8492 }
8493 mSessionHistory->GetEntryAtIndex(idx, false, getter_AddRefs(mLSHE));
8494 }
8495
8496 mLoadType = LOAD_ERROR_PAGE;
8497 }
8498
8499 bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
8500
8501 // let's try resetting the load group if we need to...
8502 nsCOMPtr<nsILoadGroup> currentLoadGroup;
8503 NS_ENSURE_SUCCESS(
8504 aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),
8505 NS_ERROR_FAILURE);
8506
8507 if (currentLoadGroup != mLoadGroup) {
8508 nsLoadFlags loadFlags = 0;
8509
8510 // Cancel any URIs that are currently loading...
8511 // XXX: Need to do this eventually Stop();
8512 //
8513 // Retarget the document to this loadgroup...
8514 //
8515 /* First attach the channel to the right loadgroup
8516 * and then remove from the old loadgroup. This
8517 * puts the notifications in the right order and
8518 * we don't null-out mLSHE in OnStateChange() for
8519 * all redirected urls
8520 */
8521 aOpenedChannel->SetLoadGroup(mLoadGroup);
8522
8523 // Mark the channel as being a document URI...
8524 aOpenedChannel->GetLoadFlags(&loadFlags);
8525 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
8526 if (SandboxFlagsImplyCookies(mSandboxFlags)) {
8527 loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
8528 }
8529
8530 aOpenedChannel->SetLoadFlags(loadFlags);
8531
8532 mLoadGroup->AddRequest(aRequest, nullptr);
8533 if (currentLoadGroup) {
8534 currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED);
8535 }
8536
8537 // Update the notification callbacks, so that progress and
8538 // status information are sent to the right docshell...
8539 aOpenedChannel->SetNotificationCallbacks(this);
8540 }
8541
8542 NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE);
8543
8544 mSavedRefreshURIList = nullptr;
8545 mSavingOldViewer = false;
8546 mEODForCurrentDocument = false;
8547
8548 // if this document is part of a multipart document,
8549 // the ID can be used to distinguish it from the other parts.
8550 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
8551 if (multiPartChannel) {
8552 nsCOMPtr<nsIPresShell> shell = GetPresShell();
8553 if (NS_SUCCEEDED(rv) && shell) {
8554 nsIDocument* doc = shell->GetDocument();
8555 if (doc) {
8556 uint32_t partID;
8557 multiPartChannel->GetPartID(&partID);
8558 doc->SetPartID(partID);
8559 }
8560 }
8561 }
8562
8563 // Give hint to native plevent dispatch mechanism. If a document
8564 // is loading the native plevent dispatch mechanism should favor
8565 // performance over normal native event dispatch priorities.
8566 if (++gNumberOfDocumentsLoading == 1) {
8567 // Hint to favor performance for the plevent notification mechanism.
8568 // We want the pages to load as fast as possible even if its means
8569 // native messages might be starved.
8570 FavorPerformanceHint(true);
8571 }
8572
8573 if (errorOnLocationChangeNeeded) {
8574 FireOnLocationChange(this, failedChannel, failedURI,
8575 LOCATION_CHANGE_ERROR_PAGE);
8576 } else if (onLocationChangeNeeded) {
8577 FireOnLocationChange(this, aRequest, mCurrentURI, 0);
8578 }
8579
8580 return NS_OK;
8581 }
8582
NewContentViewerObj(const nsACString & aContentType,nsIRequest * aRequest,nsILoadGroup * aLoadGroup,nsIStreamListener ** aContentHandler,nsIContentViewer ** aViewer)8583 nsresult nsDocShell::NewContentViewerObj(const nsACString& aContentType,
8584 nsIRequest* aRequest,
8585 nsILoadGroup* aLoadGroup,
8586 nsIStreamListener** aContentHandler,
8587 nsIContentViewer** aViewer) {
8588 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
8589
8590 nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
8591 nsContentUtils::FindInternalContentViewer(aContentType);
8592 if (!docLoaderFactory) {
8593 return NS_ERROR_FAILURE;
8594 }
8595
8596 // Now create an instance of the content viewer nsLayoutDLF makes the
8597 // determination if it should be a "view-source" instead of "view"
8598 nsresult rv = docLoaderFactory->CreateInstance(
8599 "view", aOpenedChannel, aLoadGroup, aContentType, this, nullptr,
8600 aContentHandler, aViewer);
8601 NS_ENSURE_SUCCESS(rv, rv);
8602
8603 (*aViewer)->SetContainer(this);
8604 return NS_OK;
8605 }
8606
SetupNewViewer(nsIContentViewer * aNewViewer)8607 nsresult nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer) {
8608 MOZ_ASSERT(!mIsBeingDestroyed);
8609
8610 //
8611 // Copy content viewer state from previous or parent content viewer.
8612 //
8613 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
8614 //
8615 // Do NOT to maintain a reference to the old content viewer outside
8616 // of this "copying" block, or it will not be destroyed until the end of
8617 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
8618 //
8619 // In this block of code, if we get an error result, we return it
8620 // but if we get a null pointer, that's perfectly legal for parent
8621 // and parentContentViewer.
8622 //
8623
8624 int32_t x = 0;
8625 int32_t y = 0;
8626 int32_t cx = 0;
8627 int32_t cy = 0;
8628
8629 // This will get the size from the current content viewer or from the
8630 // Init settings
8631 DoGetPositionAndSize(&x, &y, &cx, &cy);
8632
8633 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
8634 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
8635 NS_ERROR_FAILURE);
8636 nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
8637
8638 const Encoding* forceCharset = nullptr;
8639 const Encoding* hintCharset = nullptr;
8640 int32_t hintCharsetSource;
8641 int32_t minFontSize;
8642 float textZoom;
8643 float pageZoom;
8644 float overrideDPPX;
8645 bool styleDisabled;
8646 // |newMUDV| also serves as a flag to set the data from the above vars
8647 nsCOMPtr<nsIContentViewer> newCv;
8648
8649 if (mContentViewer || parent) {
8650 nsCOMPtr<nsIContentViewer> oldCv;
8651 if (mContentViewer) {
8652 // Get any interesting state from old content viewer
8653 // XXX: it would be far better to just reuse the document viewer ,
8654 // since we know we're just displaying the same document as before
8655 oldCv = mContentViewer;
8656
8657 // Tell the old content viewer to hibernate in session history when
8658 // it is destroyed.
8659
8660 if (mSavingOldViewer && NS_FAILED(CaptureState())) {
8661 if (mOSHE) {
8662 mOSHE->SyncPresentationState();
8663 }
8664 mSavingOldViewer = false;
8665 }
8666 } else {
8667 // No old content viewer, so get state from parent's content viewer
8668 parent->GetContentViewer(getter_AddRefs(oldCv));
8669 }
8670
8671 if (oldCv) {
8672 newCv = aNewViewer;
8673 if (newCv) {
8674 forceCharset = oldCv->GetForceCharset();
8675 hintCharset = oldCv->GetHintCharset();
8676 NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource),
8677 NS_ERROR_FAILURE);
8678 NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize),
8679 NS_ERROR_FAILURE);
8680 NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom), NS_ERROR_FAILURE);
8681 NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom), NS_ERROR_FAILURE);
8682 NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX),
8683 NS_ERROR_FAILURE);
8684 NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled),
8685 NS_ERROR_FAILURE);
8686 }
8687 }
8688 }
8689
8690 nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
8691 bool isActive = false;
8692 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
8693 nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
8694 if (contentViewer) {
8695 // Stop any activity that may be happening in the old document before
8696 // releasing it...
8697 contentViewer->Stop();
8698
8699 // Try to extract the canvas background color from the old
8700 // presentation shell, so we can use it for the next document.
8701 nsCOMPtr<nsIPresShell> shell;
8702 contentViewer->GetPresShell(getter_AddRefs(shell));
8703
8704 if (shell) {
8705 bgcolor = shell->GetCanvasBackground();
8706 isActive = shell->IsActive();
8707 }
8708
8709 contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
8710 aNewViewer->SetPreviousViewer(contentViewer);
8711 }
8712 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
8713 // We don't plan to save a viewer in mOSHE; tell it to drop
8714 // any other state it's holding.
8715 mOSHE->SyncPresentationState();
8716 }
8717
8718 mContentViewer = nullptr;
8719
8720 // Now that we're about to switch documents, forget all of our children.
8721 // Note that we cached them as needed up in CaptureState above.
8722 DestroyChildren();
8723
8724 mContentViewer = aNewViewer;
8725
8726 nsCOMPtr<nsIWidget> widget;
8727 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
8728
8729 nsIntRect bounds(x, y, cx, cy);
8730
8731 mContentViewer->SetNavigationTiming(mTiming);
8732
8733 if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
8734 mContentViewer = nullptr;
8735 NS_WARNING("ContentViewer Initialization failed");
8736 return NS_ERROR_FAILURE;
8737 }
8738
8739 // If we have old state to copy, set the old state onto the new content
8740 // viewer
8741 if (newCv) {
8742 newCv->SetForceCharset(forceCharset);
8743 newCv->SetHintCharset(hintCharset);
8744 NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource),
8745 NS_ERROR_FAILURE);
8746 NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize), NS_ERROR_FAILURE);
8747 NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom), NS_ERROR_FAILURE);
8748 NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom), NS_ERROR_FAILURE);
8749 NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX), NS_ERROR_FAILURE);
8750 NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
8751 NS_ERROR_FAILURE);
8752 }
8753
8754 // Stuff the bgcolor from the old pres shell into the new
8755 // pres shell. This improves page load continuity.
8756 nsCOMPtr<nsIPresShell> shell;
8757 mContentViewer->GetPresShell(getter_AddRefs(shell));
8758
8759 if (shell) {
8760 shell->SetCanvasBackground(bgcolor);
8761 if (isActive) {
8762 shell->SetIsActive(isActive);
8763 }
8764 }
8765
8766 // XXX: It looks like the LayoutState gets restored again in Embed()
8767 // right after the call to SetupNewViewer(...)
8768
8769 // We don't show the mContentViewer yet, since we want to draw the old page
8770 // until we have enough of the new page to show. Just return with the new
8771 // viewer still set to hidden.
8772
8773 return NS_OK;
8774 }
8775
SetDocCurrentStateObj(nsISHEntry * aShEntry)8776 nsresult nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry) {
8777 NS_ENSURE_STATE(mContentViewer);
8778 nsCOMPtr<nsIDocument> document = GetDocument();
8779 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
8780
8781 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
8782 if (aShEntry) {
8783 nsresult rv = aShEntry->GetStateData(getter_AddRefs(scContainer));
8784 NS_ENSURE_SUCCESS(rv, rv);
8785
8786 // If aShEntry is null, just set the document's state object to null.
8787 }
8788
8789 // It's OK for scContainer too be null here; that just means there's no
8790 // state data associated with this history entry.
8791 document->SetStateObject(scContainer);
8792
8793 return NS_OK;
8794 }
8795
CheckLoadingPermissions()8796 nsresult nsDocShell::CheckLoadingPermissions() {
8797 // This method checks whether the caller may load content into
8798 // this docshell. Even though we've done our best to hide windows
8799 // from code that doesn't have the right to access them, it's
8800 // still possible for an evil site to open a window and access
8801 // frames in the new window through window.frames[] (which is
8802 // allAccess for historic reasons), so we still need to do this
8803 // check on load.
8804 nsresult rv = NS_OK;
8805
8806 if (!gValidateOrigin || !IsFrame()) {
8807 // Origin validation was turned off, or we're not a frame.
8808 // Permit all loads.
8809
8810 return rv;
8811 }
8812
8813 // Note - The check for a current JSContext here isn't necessarily sensical.
8814 // It's just designed to preserve the old semantics during a mass-conversion
8815 // patch.
8816 if (!nsContentUtils::GetCurrentJSContext()) {
8817 return NS_OK;
8818 }
8819
8820 // Check if the caller is from the same origin as this docshell,
8821 // or any of its ancestors.
8822 nsCOMPtr<nsIDocShellTreeItem> item(this);
8823 do {
8824 nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(item);
8825 nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
8826
8827 nsIPrincipal* p;
8828 if (!sop || !(p = sop->GetPrincipal())) {
8829 return NS_ERROR_UNEXPECTED;
8830 }
8831
8832 if (nsContentUtils::SubjectPrincipal()->Subsumes(p)) {
8833 // Same origin, permit load
8834 return NS_OK;
8835 }
8836
8837 nsCOMPtr<nsIDocShellTreeItem> tmp;
8838 item->GetSameTypeParent(getter_AddRefs(tmp));
8839 item.swap(tmp);
8840 } while (item);
8841
8842 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
8843 }
8844
8845 //*****************************************************************************
8846 // nsDocShell: Site Loading
8847 //*****************************************************************************
8848
CopyFavicon(nsIURI * aOldURI,nsIURI * aNewURI,nsIPrincipal * aLoadingPrincipal,bool aInPrivateBrowsing)8849 void nsDocShell::CopyFavicon(nsIURI* aOldURI, nsIURI* aNewURI,
8850 nsIPrincipal* aLoadingPrincipal,
8851 bool aInPrivateBrowsing) {
8852 if (XRE_IsContentProcess()) {
8853 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
8854 if (contentChild) {
8855 mozilla::ipc::URIParams oldURI, newURI;
8856 SerializeURI(aOldURI, oldURI);
8857 SerializeURI(aNewURI, newURI);
8858 contentChild->SendCopyFavicon(oldURI, newURI,
8859 IPC::Principal(aLoadingPrincipal),
8860 aInPrivateBrowsing);
8861 }
8862 return;
8863 }
8864
8865 #ifdef MOZ_PLACES
8866 nsCOMPtr<mozIAsyncFavicons> favSvc =
8867 do_GetService("@mozilla.org/browser/favicon-service;1");
8868 if (favSvc) {
8869 favSvc->CopyFavicons(aOldURI, aNewURI,
8870 aInPrivateBrowsing
8871 ? nsIFaviconService::FAVICON_LOAD_PRIVATE
8872 : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
8873 nullptr);
8874 }
8875 #endif
8876 }
8877
8878 class InternalLoadEvent : public Runnable {
8879 public:
InternalLoadEvent(nsDocShell * aDocShell,nsIURI * aURI,nsIURI * aOriginalURI,Maybe<nsCOMPtr<nsIURI>> const & aResultPrincipalURI,bool aKeepResultPrincipalURIIfSet,bool aLoadReplace,bool aIsFromProcessingFrameAttributes,nsIURI * aReferrer,uint32_t aReferrerPolicy,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aPrincipalToInherit,uint32_t aFlags,const char * aTypeHint,nsIInputStream * aPostData,int64_t aPostDataLength,nsIInputStream * aHeadersData,uint32_t aLoadType,nsISHEntry * aSHEntry,bool aFirstParty,const nsAString & aSrcdoc,nsIDocShell * aSourceDocShell,nsIURI * aBaseURI)8880 InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, nsIURI* aOriginalURI,
8881 Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
8882 bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
8883 bool aIsFromProcessingFrameAttributes, nsIURI* aReferrer,
8884 uint32_t aReferrerPolicy,
8885 nsIPrincipal* aTriggeringPrincipal,
8886 nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
8887 const char* aTypeHint, nsIInputStream* aPostData,
8888 int64_t aPostDataLength, nsIInputStream* aHeadersData,
8889 uint32_t aLoadType, nsISHEntry* aSHEntry, bool aFirstParty,
8890 const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
8891 nsIURI* aBaseURI)
8892 : mozilla::Runnable("InternalLoadEvent"),
8893 mSrcdoc(aSrcdoc),
8894 mDocShell(aDocShell),
8895 mURI(aURI),
8896 mOriginalURI(aOriginalURI),
8897 mResultPrincipalURI(aResultPrincipalURI),
8898 mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet),
8899 mLoadReplace(aLoadReplace),
8900 mIsFromProcessingFrameAttributes(aIsFromProcessingFrameAttributes),
8901 mReferrer(aReferrer),
8902 mReferrerPolicy(aReferrerPolicy),
8903 mTriggeringPrincipal(aTriggeringPrincipal),
8904 mPrincipalToInherit(aPrincipalToInherit),
8905 mPostData(aPostData),
8906 mPostDataLength(aPostDataLength),
8907 mHeadersData(aHeadersData),
8908 mSHEntry(aSHEntry),
8909 mFlags(aFlags),
8910 mLoadType(aLoadType),
8911 mFirstParty(aFirstParty),
8912 mSourceDocShell(aSourceDocShell),
8913 mBaseURI(aBaseURI) {
8914 // Make sure to keep null things null as needed
8915 if (aTypeHint) {
8916 mTypeHint = aTypeHint;
8917 } else {
8918 mTypeHint.SetIsVoid(true);
8919 }
8920 }
8921
8922 NS_IMETHOD
Run()8923 Run() override {
8924 return mDocShell->InternalLoad(
8925 mURI, mOriginalURI, mResultPrincipalURI, mKeepResultPrincipalURIIfSet,
8926 mLoadReplace, mIsFromProcessingFrameAttributes, mReferrer,
8927 mReferrerPolicy, mTriggeringPrincipal, mPrincipalToInherit, mFlags,
8928 EmptyString(), mTypeHint.IsVoid() ? nullptr : mTypeHint.get(),
8929 VoidString(), mPostData, mPostDataLength, mHeadersData, mLoadType,
8930 mSHEntry, mFirstParty, mSrcdoc, mSourceDocShell, mBaseURI, nullptr,
8931 nullptr);
8932 }
8933
8934 private:
8935 nsCString mTypeHint;
8936 nsString mSrcdoc;
8937
8938 RefPtr<nsDocShell> mDocShell;
8939 nsCOMPtr<nsIURI> mURI;
8940 nsCOMPtr<nsIURI> mOriginalURI;
8941 Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
8942 bool mKeepResultPrincipalURIIfSet;
8943 bool mLoadReplace;
8944 bool mIsFromProcessingFrameAttributes;
8945 nsCOMPtr<nsIURI> mReferrer;
8946 uint32_t mReferrerPolicy;
8947 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
8948 nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
8949 nsCOMPtr<nsIInputStream> mPostData;
8950 int64_t mPostDataLength;
8951 nsCOMPtr<nsIInputStream> mHeadersData;
8952 nsCOMPtr<nsISHEntry> mSHEntry;
8953 uint32_t mFlags;
8954 uint32_t mLoadType;
8955 bool mFirstParty;
8956 nsCOMPtr<nsIDocShell> mSourceDocShell;
8957 nsCOMPtr<nsIURI> mBaseURI;
8958 };
8959
8960 /**
8961 * Returns true if we started an asynchronous load (i.e., from the network), but
8962 * the document we're loading there hasn't yet become this docshell's active
8963 * document.
8964 *
8965 * When JustStartedNetworkLoad is true, you should be careful about modifying
8966 * mLoadType and mLSHE. These are both set when the asynchronous load first
8967 * starts, and the load expects that, when it eventually runs InternalLoad,
8968 * mLoadType and mLSHE will have their original values.
8969 */
JustStartedNetworkLoad()8970 bool nsDocShell::JustStartedNetworkLoad() {
8971 return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
8972 }
8973
CreatePrincipalFromReferrer(nsIURI * aReferrer,nsIPrincipal ** aResult)8974 nsresult nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
8975 nsIPrincipal** aResult) {
8976 nsCOMPtr<nsIPrincipal> prin =
8977 BasePrincipal::CreateCodebasePrincipal(aReferrer, mOriginAttributes);
8978 prin.forget(aResult);
8979
8980 return *aResult ? NS_OK : NS_ERROR_FAILURE;
8981 }
8982
8983 NS_IMETHODIMP
InternalLoad(nsIURI * aURI,nsIURI * aOriginalURI,Maybe<nsCOMPtr<nsIURI>> const & aResultPrincipalURI,bool aKeepResultPrincipalURIIfSet,bool aLoadReplace,bool aIsFromProcessingFrameAttributes,nsIURI * aReferrer,uint32_t aReferrerPolicy,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aPrincipalToInherit,uint32_t aFlags,const nsAString & aWindowTarget,const char * aTypeHint,const nsAString & aFileName,nsIInputStream * aPostData,int64_t aPostDataLength,nsIInputStream * aHeadersData,uint32_t aLoadType,nsISHEntry * aSHEntry,bool aFirstParty,const nsAString & aSrcdoc,nsIDocShell * aSourceDocShell,nsIURI * aBaseURI,nsIDocShell ** aDocShell,nsIRequest ** aRequest)8984 nsDocShell::InternalLoad(nsIURI* aURI, nsIURI* aOriginalURI,
8985 Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
8986 bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
8987 bool aIsFromProcessingFrameAttributes,
8988 nsIURI* aReferrer, uint32_t aReferrerPolicy,
8989 nsIPrincipal* aTriggeringPrincipal,
8990 nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
8991 const nsAString& aWindowTarget, const char* aTypeHint,
8992 const nsAString& aFileName, nsIInputStream* aPostData,
8993 int64_t aPostDataLength, nsIInputStream* aHeadersData,
8994 uint32_t aLoadType, nsISHEntry* aSHEntry,
8995 bool aFirstParty, const nsAString& aSrcdoc,
8996 nsIDocShell* aSourceDocShell, nsIURI* aBaseURI,
8997 nsIDocShell** aDocShell, nsIRequest** aRequest) {
8998 MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
8999
9000 nsresult rv = NS_OK;
9001 mOriginalUriString.Truncate();
9002
9003 MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
9004 ("DOCSHELL %p InternalLoad %s\n", this,
9005 aURI ? aURI->GetSpecOrDefault().get() : ""));
9006 // Initialize aDocShell/aRequest
9007 if (aDocShell) {
9008 *aDocShell = nullptr;
9009 }
9010 if (aRequest) {
9011 *aRequest = nullptr;
9012 }
9013
9014 if (!aURI) {
9015 return NS_ERROR_NULL_POINTER;
9016 }
9017
9018 NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
9019
9020 NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
9021
9022 rv = EnsureScriptEnvironment();
9023 if (NS_FAILED(rv)) {
9024 return rv;
9025 }
9026
9027 // wyciwyg urls can only be loaded through history. Any normal load of
9028 // wyciwyg through docshell is illegal. Disallow such loads.
9029 if (aLoadType & LOAD_CMD_NORMAL) {
9030 bool isWyciwyg = false;
9031 rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
9032 if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) {
9033 return NS_ERROR_FAILURE;
9034 }
9035 }
9036
9037 bool isJavaScript = false;
9038 if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) {
9039 isJavaScript = false;
9040 }
9041
9042 bool isTargetTopLevelDocShell = false;
9043 nsCOMPtr<nsIDocShell> targetDocShell;
9044 if (!aWindowTarget.IsEmpty()) {
9045 // Locate the target DocShell.
9046 nsCOMPtr<nsIDocShellTreeItem> targetItem;
9047 // Only _self, _parent, and _top are supported in noopener case. But we
9048 // have to be careful to not apply that to the noreferrer case. See bug
9049 // 1358469.
9050 bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
9051 (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
9052 if (allowNamedTarget || aWindowTarget.LowerCaseEqualsLiteral("_self") ||
9053 aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
9054 aWindowTarget.LowerCaseEqualsLiteral("_top")) {
9055 rv = FindItemWithName(aWindowTarget, nullptr, this, false,
9056 getter_AddRefs(targetItem));
9057 NS_ENSURE_SUCCESS(rv, rv);
9058 }
9059
9060 targetDocShell = do_QueryInterface(targetItem);
9061 if (targetDocShell) {
9062 // If the targetDocShell and the rootDocShell are the same, then the
9063 // targetDocShell is the top level document and hence we should
9064 // consider this TYPE_DOCUMENT
9065 //
9066 // For example:
9067 // 1. target="_top"
9068 // 2. target="_parent", where this docshell is in the 2nd level of
9069 // docshell tree.
9070 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
9071 targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
9072 NS_ASSERTION(sameTypeRoot,
9073 "No document shell root tree item from targetDocShell!");
9074 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
9075 NS_ASSERTION(rootShell,
9076 "No root docshell from document shell root tree item.");
9077 isTargetTopLevelDocShell = targetDocShell == rootShell;
9078 } else {
9079 // If the targetDocShell doesn't exist, then this is a new docShell
9080 // and we should consider this a TYPE_DOCUMENT load
9081 //
9082 // For example, when target="_blank"
9083 isTargetTopLevelDocShell = true;
9084 }
9085 }
9086
9087 // The contentType will be INTERNAL_(I)FRAME if:
9088 // 1. This docshell is for iframe.
9089 // 2. AND aWindowTarget is not a new window, nor a top-level window.
9090 //
9091 // This variable will be used when we call NS_CheckContentLoadPolicy, and
9092 // later when we call DoURILoad.
9093 uint32_t contentType;
9094 if (IsFrame() && !isTargetTopLevelDocShell) {
9095 nsCOMPtr<Element> requestingElement =
9096 mScriptGlobal->AsOuter()->GetFrameElementInternal();
9097 if (requestingElement) {
9098 contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe)
9099 ? nsIContentPolicy::TYPE_INTERNAL_IFRAME
9100 : nsIContentPolicy::TYPE_INTERNAL_FRAME;
9101 } else {
9102 // If we have lost our frame element by now, just assume we're
9103 // an iframe since that's more common.
9104 contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
9105 }
9106 } else {
9107 contentType = nsIContentPolicy::TYPE_DOCUMENT;
9108 isTargetTopLevelDocShell = true;
9109 }
9110
9111 // If there's no targetDocShell, that means we are about to create a new
9112 // window (or aWindowTarget is empty). Perform a content policy check before
9113 // creating the window. Please note for all other docshell loads
9114 // content policy checks are performed within the contentSecurityManager
9115 // when the channel is about to be openend.
9116 if (!targetDocShell && !aWindowTarget.IsEmpty()) {
9117 MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
9118 "opening a new window requires type to be TYPE_DOCUMENT");
9119
9120 nsISupports* requestingContext = nullptr;
9121 if (XRE_IsContentProcess()) {
9122 // In e10s the child process doesn't have access to the element that
9123 // contains the browsing context (because that element is in the chrome
9124 // process). So we just pass mScriptGlobal.
9125 requestingContext = ToSupports(mScriptGlobal);
9126 } else {
9127 // This is for loading non-e10s tabs and toplevel windows of various
9128 // sorts.
9129 // For the toplevel window cases, requestingElement will be null.
9130 nsCOMPtr<Element> requestingElement =
9131 mScriptGlobal->AsOuter()->GetFrameElementInternal();
9132 requestingContext = requestingElement;
9133 }
9134
9135 // Since Content Policy checks are performed within docShell as well as
9136 // the ContentSecurityManager we need a reliable way to let certain
9137 // nsIContentPolicy consumers ignore duplicate calls. Let's use the 'extra'
9138 // argument to pass a specific identifier.
9139 nsCOMPtr<nsISupportsString> extraStr =
9140 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
9141 NS_ENSURE_SUCCESS(rv, rv);
9142 NS_NAMED_LITERAL_STRING(msg, "conPolCheckFromDocShell");
9143 rv = extraStr->SetData(msg);
9144 NS_ENSURE_SUCCESS(rv, rv);
9145
9146 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
9147 rv = NS_CheckContentLoadPolicy(contentType, aURI,
9148 // This is a top-level load, so the loading
9149 // principal is null.
9150 nullptr, aTriggeringPrincipal,
9151 requestingContext,
9152 EmptyCString(), // mime guess
9153 extraStr, // extra
9154 &shouldLoad);
9155
9156 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
9157 if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
9158 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
9159 }
9160
9161 return NS_ERROR_CONTENT_BLOCKED;
9162 }
9163 }
9164
9165 nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
9166 //
9167 // Get a principal from the current document if necessary. Note that we only
9168 // do this for URIs that inherit a security context and local file URIs;
9169 // in particular we do NOT do this for about:blank. This way, random
9170 // about:blank loads that have no principal (which basically means they were
9171 // done by someone from chrome manually messing with our nsIWebNavigation
9172 // or by C++ setting document.location) don't get a funky principal. If
9173 // callers want something interesting to happen with the about:blank
9174 // principal in this case, they should pass aPrincipalToInherit in.
9175 //
9176 {
9177 bool inherits;
9178 // One more twist: Don't inherit the principal for external loads.
9179 if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
9180 (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
9181 NS_SUCCEEDED(
9182 nsContentUtils::URIInheritsSecurityContext(aURI, &inherits)) &&
9183 inherits) {
9184 principalToInherit = GetInheritedPrincipal(true);
9185 }
9186 }
9187
9188 // Don't allow loads that would inherit our security context
9189 // if this document came from an unsafe channel.
9190 {
9191 bool willInherit;
9192 // This condition needs to match the one in
9193 // nsContentUtils::ChannelShouldInheritPrincipal.
9194 // Except we reverse the rv check to be safe in case
9195 // nsContentUtils::URIInheritsSecurityContext fails here and
9196 // succeeds there.
9197 rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
9198 if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
9199 nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
9200 do {
9201 nsCOMPtr<nsIDocShell> itemDocShell = do_QueryInterface(treeItem);
9202 bool isUnsafe;
9203 if (itemDocShell &&
9204 NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
9205 isUnsafe) {
9206 return NS_ERROR_DOM_SECURITY_ERR;
9207 }
9208
9209 nsCOMPtr<nsIDocShellTreeItem> parent;
9210 treeItem->GetSameTypeParent(getter_AddRefs(parent));
9211 parent.swap(treeItem);
9212 } while (treeItem);
9213 }
9214 }
9215
9216 nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
9217
9218 const bool isDocumentAuxSandboxed =
9219 doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
9220
9221 if (aURI && mLoadURIDelegate &&
9222 (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
9223 // Dispatch only load requests for the current or a new window to the
9224 // delegate, e.g., to allow for GeckoView apps to handle the load event
9225 // outside of Gecko.
9226 const int where = (aWindowTarget.IsEmpty() || targetDocShell)
9227 ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
9228 : nsIBrowserDOMWindow::OPEN_NEWWINDOW;
9229
9230 if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW &&
9231 isDocumentAuxSandboxed) {
9232 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9233 }
9234
9235 bool loadURIHandled = false;
9236 rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
9237 &loadURIHandled);
9238 if (NS_SUCCEEDED(rv) && loadURIHandled) {
9239 // The request has been handled, nothing to do here.
9240 return NS_OK;
9241 }
9242 }
9243
9244 //
9245 // Resolve the window target before going any further...
9246 // If the load has been targeted to another DocShell, then transfer the
9247 // load to it...
9248 //
9249 if (!aWindowTarget.IsEmpty()) {
9250 // We've already done our owner-inheriting. Mask out that bit, so we
9251 // don't try inheriting an owner from the target window if we came up
9252 // with a null owner above.
9253 aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
9254
9255 bool isNewWindow = false;
9256 if (!targetDocShell) {
9257 // If the docshell's document is sandboxed, only open a new window
9258 // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
9259 // (i.e. if allow-popups is specified)
9260 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
9261 if (isDocumentAuxSandboxed) {
9262 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9263 }
9264
9265 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
9266 NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
9267
9268 nsCOMPtr<nsPIDOMWindowOuter> newWin;
9269 nsAutoCString spec;
9270 if (aURI) {
9271 aURI->GetSpec(spec);
9272 }
9273 // If we are a noopener load, we just hand the whole thing over to our
9274 // window.
9275 if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
9276 // Various asserts that we know to hold because NO_OPENER loads can only
9277 // happen for links.
9278 MOZ_ASSERT(!aLoadReplace);
9279 MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
9280 MOZ_ASSERT(aFlags == INTERNAL_LOAD_FLAGS_NO_OPENER ||
9281 aFlags == (INTERNAL_LOAD_FLAGS_NO_OPENER |
9282 INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
9283 MOZ_ASSERT(!aPostData);
9284 MOZ_ASSERT(!aHeadersData);
9285 // If OnLinkClickSync was invoked inside the onload handler, the load
9286 // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
9287 // LOAD_LINK.
9288 MOZ_ASSERT(aLoadType == LOAD_LINK || aLoadType == LOAD_NORMAL_REPLACE);
9289 MOZ_ASSERT(!aSHEntry);
9290 MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
9291
9292 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
9293 rv = CreateLoadInfo(getter_AddRefs(loadInfo));
9294 if (NS_FAILED(rv)) {
9295 return rv;
9296 }
9297
9298 // Set up our loadinfo so it will do the load as much like we would have
9299 // as possible.
9300 loadInfo->SetReferrer(aReferrer);
9301 loadInfo->SetReferrerPolicy(aReferrerPolicy);
9302 loadInfo->SetSendReferrer(
9303 !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
9304 loadInfo->SetOriginalURI(aOriginalURI);
9305 SetMaybeResultPrincipalURI(loadInfo, aResultPrincipalURI);
9306 loadInfo->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet);
9307 loadInfo->SetLoadReplace(aLoadReplace);
9308 loadInfo->SetIsFromProcessingFrameAttributes(
9309 aIsFromProcessingFrameAttributes);
9310 loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
9311 loadInfo->SetInheritPrincipal(aFlags &
9312 INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
9313 // Explicit principal because we do not want any guesses as to what the
9314 // principal to inherit is: it should be aTriggeringPrincipal.
9315 loadInfo->SetPrincipalIsExplicit(true);
9316 loadInfo->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(LOAD_LINK));
9317 loadInfo->SetForceAllowDataURI(
9318 aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
9319
9320 rv = win->Open(NS_ConvertUTF8toUTF16(spec),
9321 aWindowTarget, // window name
9322 EmptyString(), // Features
9323 loadInfo,
9324 true, // aForceNoOpener
9325 getter_AddRefs(newWin));
9326 MOZ_ASSERT(!newWin);
9327 return rv;
9328 }
9329
9330 rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
9331 aWindowTarget, // window name
9332 EmptyString(), // Features
9333 getter_AddRefs(newWin));
9334
9335 // In some cases the Open call doesn't actually result in a new
9336 // window being opened. We can detect these cases by examining the
9337 // document in |newWin|, if any.
9338 nsCOMPtr<nsPIDOMWindowOuter> piNewWin = do_QueryInterface(newWin);
9339 if (piNewWin) {
9340 nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
9341 if (!newDoc || newDoc->IsInitialDocument()) {
9342 isNewWindow = true;
9343 aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
9344 }
9345 }
9346
9347 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
9348 targetDocShell = do_QueryInterface(webNav);
9349 }
9350
9351 //
9352 // Transfer the load to the target DocShell... Pass nullptr as the
9353 // window target name from to prevent recursive retargeting!
9354 //
9355 if (NS_SUCCEEDED(rv) && targetDocShell) {
9356 rv = targetDocShell->InternalLoad(
9357 aURI, aOriginalURI, aResultPrincipalURI, aKeepResultPrincipalURIIfSet,
9358 aLoadReplace, aIsFromProcessingFrameAttributes, aReferrer,
9359 aReferrerPolicy, aTriggeringPrincipal, principalToInherit, aFlags,
9360 EmptyString(), // No window target
9361 aTypeHint,
9362 VoidString(), // No forced download
9363 aPostData, aPostDataLength, aHeadersData, aLoadType, aSHEntry,
9364 aFirstParty, aSrcdoc, aSourceDocShell, aBaseURI, aDocShell, aRequest);
9365 if (rv == NS_ERROR_NO_CONTENT) {
9366 // XXXbz except we never reach this code!
9367 if (isNewWindow) {
9368 //
9369 // At this point, a new window has been created, but the
9370 // URI did not have any data associated with it...
9371 //
9372 // So, the best we can do, is to tear down the new window
9373 // that was just created!
9374 //
9375 if (nsCOMPtr<nsPIDOMWindowOuter> domWin =
9376 targetDocShell->GetWindow()) {
9377 domWin->Close();
9378 }
9379 }
9380 //
9381 // NS_ERROR_NO_CONTENT should not be returned to the
9382 // caller... This is an internal error code indicating that
9383 // the URI had no data associated with it - probably a
9384 // helper-app style protocol (ie. mailto://)
9385 //
9386 rv = NS_OK;
9387 } else if (isNewWindow) {
9388 // XXX: Once new windows are created hidden, the new
9389 // window will need to be made visible... For now,
9390 // do nothing.
9391 }
9392
9393 if (NS_SUCCEEDED(rv)) {
9394 // Switch to target tab if we're currently focused window.
9395 // Take loadDivertedInBackground into account so the behavior would be
9396 // the same as how the tab first opened.
9397 bool isTargetActive = false;
9398 targetDocShell->GetIsActive(&isTargetActive);
9399 nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
9400 if (mIsActive && !isTargetActive && domWin &&
9401 !Preferences::GetBool("browser.tabs.loadDivertedInBackground",
9402 false)) {
9403 if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) {
9404 return NS_ERROR_FAILURE;
9405 }
9406 }
9407 }
9408 }
9409
9410 // Else we ran out of memory, or were a popup and got blocked,
9411 // or something.
9412
9413 return rv;
9414 }
9415
9416 //
9417 // Load is being targetted at this docshell so return an error if the
9418 // docshell is in the process of being destroyed.
9419 //
9420 if (mIsBeingDestroyed) {
9421 return NS_ERROR_FAILURE;
9422 }
9423
9424 NS_ENSURE_STATE(!HasUnloadedParent());
9425
9426 rv = CheckLoadingPermissions();
9427 if (NS_FAILED(rv)) {
9428 return rv;
9429 }
9430
9431 if (mFiredUnloadEvent) {
9432 if (IsOKToLoadURI(aURI)) {
9433 NS_PRECONDITION(aWindowTarget.IsEmpty(),
9434 "Shouldn't have a window target here!");
9435
9436 // If this is a replace load, make whatever load triggered
9437 // the unload event also a replace load, so we don't
9438 // create extra history entries.
9439 if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
9440 mLoadType = LOAD_NORMAL_REPLACE;
9441 }
9442
9443 // Do this asynchronously
9444 nsCOMPtr<nsIRunnable> ev = new InternalLoadEvent(
9445 this, aURI, aOriginalURI, aResultPrincipalURI,
9446 aKeepResultPrincipalURIIfSet, aLoadReplace,
9447 aIsFromProcessingFrameAttributes, aReferrer, aReferrerPolicy,
9448 aTriggeringPrincipal, principalToInherit, aFlags, aTypeHint,
9449 aPostData, aPostDataLength, aHeadersData, aLoadType, aSHEntry,
9450 aFirstParty, aSrcdoc, aSourceDocShell, aBaseURI);
9451 return DispatchToTabGroup(TaskCategory::Other, ev.forget());
9452 }
9453
9454 // Just ignore this load attempt
9455 return NS_OK;
9456 }
9457
9458 // If a source docshell has been passed, check to see if we are sandboxed
9459 // from it as the result of an iframe or CSP sandbox.
9460 if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
9461 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9462 }
9463
9464 // If this docshell is owned by a frameloader, make sure to cancel
9465 // possible frameloader initialization before loading a new page.
9466 nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
9467 if (parent) {
9468 nsCOMPtr<nsIDocument> doc = parent->GetDocument();
9469 if (doc) {
9470 doc->TryCancelFrameLoaderInitialization(this);
9471 }
9472 }
9473
9474 bool loadFromExternal = false;
9475
9476 // Before going any further vet loads initiated by external programs.
9477 if (aLoadType == LOAD_NORMAL_EXTERNAL) {
9478 loadFromExternal = true;
9479 // Disallow external chrome: loads targetted at content windows
9480 bool isChrome = false;
9481 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
9482 NS_WARNING("blocked external chrome: url -- use '--chrome' option");
9483 return NS_ERROR_FAILURE;
9484 }
9485
9486 // clear the decks to prevent context bleed-through (bug 298255)
9487 rv = CreateAboutBlankContentViewer(nullptr, nullptr);
9488 if (NS_FAILED(rv)) {
9489 return NS_ERROR_FAILURE;
9490 }
9491
9492 // reset loadType so we don't have to add lots of tests for
9493 // LOAD_NORMAL_EXTERNAL after this point
9494 aLoadType = LOAD_NORMAL;
9495 }
9496
9497 mAllowKeywordFixup =
9498 (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
9499 mURIResultedInDocument = false; // reset the clock...
9500
9501 if (aLoadType == LOAD_NORMAL || aLoadType == LOAD_STOP_CONTENT ||
9502 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
9503 aLoadType == LOAD_HISTORY || aLoadType == LOAD_LINK) {
9504 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
9505
9506 nsAutoCString curHash, newHash;
9507 bool curURIHasRef = false, newURIHasRef = false;
9508
9509 nsresult rvURINew = aURI->GetRef(newHash);
9510 if (NS_SUCCEEDED(rvURINew)) {
9511 rvURINew = aURI->GetHasRef(&newURIHasRef);
9512 }
9513
9514 bool sameExceptHashes = false;
9515 if (currentURI && NS_SUCCEEDED(rvURINew)) {
9516 nsresult rvURIOld = currentURI->GetRef(curHash);
9517 if (NS_SUCCEEDED(rvURIOld)) {
9518 rvURIOld = currentURI->GetHasRef(&curURIHasRef);
9519 }
9520 if (NS_SUCCEEDED(rvURIOld)) {
9521 if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
9522 sameExceptHashes = false;
9523 }
9524 }
9525 }
9526
9527 if (!sameExceptHashes && sURIFixup && currentURI &&
9528 NS_SUCCEEDED(rvURINew)) {
9529 // Maybe aURI came from the exposable form of currentURI?
9530 nsCOMPtr<nsIURI> currentExposableURI;
9531 rv = sURIFixup->CreateExposableURI(currentURI,
9532 getter_AddRefs(currentExposableURI));
9533 NS_ENSURE_SUCCESS(rv, rv);
9534 nsresult rvURIOld = currentExposableURI->GetRef(curHash);
9535 if (NS_SUCCEEDED(rvURIOld)) {
9536 rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef);
9537 }
9538 if (NS_SUCCEEDED(rvURIOld)) {
9539 if (NS_FAILED(currentExposableURI->EqualsExceptRef(
9540 aURI, &sameExceptHashes))) {
9541 sameExceptHashes = false;
9542 }
9543 }
9544 }
9545
9546 bool historyNavBetweenSameDoc = false;
9547 if (mOSHE && aSHEntry) {
9548 // We're doing a history load.
9549
9550 mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
9551
9552 #ifdef DEBUG
9553 if (historyNavBetweenSameDoc) {
9554 nsCOMPtr<nsIInputStream> currentPostData;
9555 mOSHE->GetPostData(getter_AddRefs(currentPostData));
9556 NS_ASSERTION(currentPostData == aPostData,
9557 "Different POST data for entries for the same page?");
9558 }
9559 #endif
9560 }
9561
9562 // A short-circuited load happens when we navigate between two SHEntries
9563 // for the same document. We do a short-circuited load under two
9564 // circumstances. Either
9565 //
9566 // a) we're navigating between two different SHEntries which share a
9567 // document, or
9568 //
9569 // b) we're navigating to a new shentry whose URI differs from the
9570 // current URI only in its hash, the new hash is non-empty, and
9571 // we're not doing a POST.
9572 //
9573 // The restriction tha the SHEntries in (a) must be different ensures
9574 // that history.go(0) and the like trigger full refreshes, rather than
9575 // short-circuited loads.
9576 bool doShortCircuitedLoad =
9577 (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
9578 (!aSHEntry && !aPostData && sameExceptHashes && newURIHasRef);
9579
9580 if (doShortCircuitedLoad) {
9581 // Save the position of the scrollers.
9582 nscoord cx = 0, cy = 0;
9583 GetCurScrollPos(ScrollOrientation_X, &cx);
9584 GetCurScrollPos(ScrollOrientation_Y, &cy);
9585
9586 // Reset mLoadType to its original value once we exit this block,
9587 // because this short-circuited load might have started after a
9588 // normal, network load, and we don't want to clobber its load type.
9589 // See bug 737307.
9590 AutoRestore<uint32_t> loadTypeResetter(mLoadType);
9591
9592 // If a non-short-circuit load (i.e., a network load) is pending,
9593 // make this a replacement load, so that we don't add a SHEntry here
9594 // and the network load goes into the SHEntry it expects to.
9595 if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
9596 mLoadType = LOAD_NORMAL_REPLACE;
9597 } else {
9598 mLoadType = aLoadType;
9599 }
9600
9601 mURIResultedInDocument = true;
9602
9603 nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
9604
9605 /* we need to assign mLSHE to aSHEntry right here, so that on History
9606 * loads, SetCurrentURI() called from OnNewURI() will send proper
9607 * onLocationChange() notifications to the browser to update
9608 * back/forward buttons.
9609 */
9610 SetHistoryEntry(&mLSHE, aSHEntry);
9611
9612 // Set the doc's URI according to the new history entry's URI.
9613 nsCOMPtr<nsIDocument> doc = GetDocument();
9614 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
9615 doc->SetDocumentURI(aURI);
9616
9617 /* This is a anchor traversal with in the same page.
9618 * call OnNewURI() so that, this traversal will be
9619 * recorded in session and global history.
9620 */
9621 nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal,
9622 newURIPrincipalToInherit;
9623 if (mOSHE) {
9624 mOSHE->GetTriggeringPrincipal(
9625 getter_AddRefs(newURITriggeringPrincipal));
9626 mOSHE->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit));
9627 } else {
9628 newURITriggeringPrincipal = aTriggeringPrincipal;
9629 newURIPrincipalToInherit = doc->NodePrincipal();
9630 }
9631 // Pass true for aCloneSHChildren, since we're not
9632 // changing documents here, so all of our subframes are
9633 // still relevant to the new session history entry.
9634 //
9635 // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
9636 // flag on firing onLocationChange(...).
9637 // Anyway, aCloneSHChildren param is simply reflecting
9638 // doShortCircuitedLoad in this scope.
9639 OnNewURI(aURI, nullptr, newURITriggeringPrincipal,
9640 newURIPrincipalToInherit, mLoadType, true, true, true);
9641
9642 nsCOMPtr<nsIInputStream> postData;
9643 nsCOMPtr<nsISupports> cacheKey;
9644
9645 bool scrollRestorationIsManual = false;
9646 if (mOSHE) {
9647 /* save current position of scroller(s) (bug 59774) */
9648 mOSHE->SetScrollPosition(cx, cy);
9649 mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
9650 // Get the postdata and page ident from the current page, if
9651 // the new load is being done via normal means. Note that
9652 // "normal means" can be checked for just by checking for
9653 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
9654 // above -- it filters out some LOAD_CMD_NORMAL cases that we
9655 // wouldn't want here.
9656 if (aLoadType & LOAD_CMD_NORMAL) {
9657 mOSHE->GetPostData(getter_AddRefs(postData));
9658 mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
9659
9660 // Link our new SHEntry to the old SHEntry's back/forward
9661 // cache data, since the two SHEntries correspond to the
9662 // same document.
9663 if (mLSHE) {
9664 if (!aSHEntry) {
9665 // If we're not doing a history load, scroll restoration
9666 // should be inherited from the previous session history entry.
9667 mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
9668 }
9669 mLSHE->AdoptBFCacheEntry(mOSHE);
9670 }
9671 }
9672 }
9673
9674 // If we're doing a history load, use its scroll restoration state.
9675 if (aSHEntry) {
9676 aSHEntry->GetScrollRestorationIsManual(&scrollRestorationIsManual);
9677 }
9678
9679 /* Assign mOSHE to mLSHE. This will either be a new entry created
9680 * by OnNewURI() for normal loads or aSHEntry for history loads.
9681 */
9682 if (mLSHE) {
9683 SetHistoryEntry(&mOSHE, mLSHE);
9684 // Save the postData obtained from the previous page
9685 // in to the session history entry created for the
9686 // anchor page, so that any history load of the anchor
9687 // page will restore the appropriate postData.
9688 if (postData) {
9689 mOSHE->SetPostData(postData);
9690 }
9691
9692 // Make sure we won't just repost without hitting the
9693 // cache first
9694 if (cacheKey) {
9695 mOSHE->SetCacheKey(cacheKey);
9696 }
9697 }
9698
9699 /* Restore the original LSHE if we were loading something
9700 * while short-circuited load was initiated.
9701 */
9702 SetHistoryEntry(&mLSHE, oldLSHE);
9703 /* Set the title for the SH entry for this target url. so that
9704 * SH menus in go/back/forward buttons won't be empty for this.
9705 */
9706 if (mSessionHistory) {
9707 int32_t index = -1;
9708 mSessionHistory->GetIndex(&index);
9709 nsCOMPtr<nsISHEntry> shEntry;
9710 mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(shEntry));
9711 NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
9712 shEntry->SetTitle(mTitle);
9713 }
9714
9715 /* Set the title for the Global History entry for this anchor url.
9716 */
9717 UpdateGlobalHistoryTitle(aURI);
9718
9719 SetDocCurrentStateObj(mOSHE);
9720
9721 // Inform the favicon service that the favicon for oldURI also
9722 // applies to aURI.
9723 CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
9724
9725 RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal;
9726 RefPtr<nsGlobalWindowInner> win =
9727 scriptGlobal ? scriptGlobal->GetCurrentInnerWindowInternal()
9728 : nullptr;
9729
9730 // ScrollToAnchor doesn't necessarily cause us to scroll the window;
9731 // the function decides whether a scroll is appropriate based on the
9732 // arguments it receives. But even if we don't end up scrolling,
9733 // ScrollToAnchor performs other important tasks, such as informing
9734 // the presShell that we have a new hash. See bug 680257.
9735 rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
9736 NS_ENSURE_SUCCESS(rv, rv);
9737
9738 /* restore previous position of scroller(s), if we're moving
9739 * back in history (bug 59774)
9740 */
9741 nscoord bx = 0;
9742 nscoord by = 0;
9743 bool needsScrollPosUpdate = false;
9744 if (mOSHE &&
9745 (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) &&
9746 !scrollRestorationIsManual) {
9747 needsScrollPosUpdate = true;
9748 mOSHE->GetScrollPosition(&bx, &by);
9749 }
9750
9751 // Dispatch the popstate and hashchange events, as appropriate.
9752 //
9753 // The event dispatch below can cause us to re-enter script and
9754 // destroy the docshell, nulling out mScriptGlobal. Hold a stack
9755 // reference to avoid null derefs. See bug 914521.
9756 if (win) {
9757 // Fire a hashchange event URIs differ, and only in their hashes.
9758 bool doHashchange = sameExceptHashes && (curURIHasRef != newURIHasRef ||
9759 !curHash.Equals(newHash));
9760
9761 if (historyNavBetweenSameDoc || doHashchange) {
9762 win->DispatchSyncPopState();
9763 }
9764
9765 if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) {
9766 SetCurScrollPosEx(bx, by);
9767 }
9768
9769 if (doHashchange) {
9770 // Note that currentURI hasn't changed because it's on the
9771 // stack, so we can just use it directly as the old URI.
9772 win->DispatchAsyncHashchange(currentURI, aURI);
9773 }
9774 }
9775
9776 return NS_OK;
9777 }
9778 }
9779
9780 // mContentViewer->PermitUnload can destroy |this| docShell, which
9781 // causes the next call of CanSavePresentation to crash.
9782 // Hold onto |this| until we return, to prevent a crash from happening.
9783 // (bug#331040)
9784 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
9785
9786 // Don't init timing for javascript:, since it generally doesn't
9787 // actually start a load or anything. If it does, we'll init
9788 // timing then, from OnStateChange.
9789
9790 // XXXbz mTiming should know what channel it's for, so we don't
9791 // need this hackery.
9792 bool toBeReset = false;
9793 if (!isJavaScript) {
9794 toBeReset = MaybeInitTiming();
9795 }
9796 bool timeBeforeUnload = aFileName.IsVoid();
9797 if (mTiming && timeBeforeUnload) {
9798 mTiming->NotifyBeforeUnload();
9799 }
9800 // Check if the page doesn't want to be unloaded. The javascript:
9801 // protocol handler deals with this for javascript: URLs.
9802 if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
9803 bool okToUnload;
9804 rv = mContentViewer->PermitUnload(&okToUnload);
9805
9806 if (NS_SUCCEEDED(rv) && !okToUnload) {
9807 // The user chose not to unload the page, interrupt the
9808 // load.
9809 MaybeResetInitTiming(toBeReset);
9810 return NS_OK;
9811 }
9812 }
9813
9814 if (mTiming && timeBeforeUnload) {
9815 mTiming->NotifyUnloadAccepted(mCurrentURI);
9816 }
9817
9818 // Check if the webbrowser chrome wants the load to proceed; this can be
9819 // used to cancel attempts to load URIs in the wrong process.
9820 nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
9821 if (browserChrome3) {
9822 bool shouldLoad;
9823 rv = browserChrome3->ShouldLoadURI(this, aURI, aReferrer, !!aPostData,
9824 aTriggeringPrincipal, &shouldLoad);
9825 if (NS_SUCCEEDED(rv) && !shouldLoad) {
9826 return NS_OK;
9827 }
9828 }
9829
9830 // Whenever a top-level browsing context is navigated, the user agent MUST
9831 // lock the orientation of the document to the document's default
9832 // orientation. We don't explicitly check for a top-level browsing context
9833 // here because orientation is only set on top-level browsing contexts.
9834 if (OrientationLock() != eScreenOrientation_None) {
9835 #ifdef DEBUG
9836 nsCOMPtr<nsIDocShellTreeItem> parent;
9837 GetSameTypeParent(getter_AddRefs(parent));
9838 MOZ_ASSERT(!parent);
9839 #endif
9840 SetOrientationLock(eScreenOrientation_None);
9841 if (mIsActive) {
9842 ScreenOrientation::UpdateActiveOrientationLock(eScreenOrientation_None);
9843 }
9844 }
9845
9846 // Check for saving the presentation here, before calling Stop().
9847 // This is necessary so that we can catch any pending requests.
9848 // Since the new request has not been created yet, we pass null for the
9849 // new request parameter.
9850 // Also pass nullptr for the document, since it doesn't affect the return
9851 // value for our purposes here.
9852 bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
9853
9854 // Don't stop current network activity for javascript: URL's since
9855 // they might not result in any data, and thus nothing should be
9856 // stopped in those cases. In the case where they do result in
9857 // data, the javascript: URL channel takes care of stopping
9858 // current network activity.
9859 if (!isJavaScript && aFileName.IsVoid()) {
9860 // Stop any current network activity.
9861 // Also stop content if this is a zombie doc. otherwise
9862 // the onload will be delayed by other loads initiated in the
9863 // background by the first document that
9864 // didn't fully load before the next load was initiated.
9865 // If not a zombie, don't stop content until data
9866 // starts arriving from the new URI...
9867
9868 nsCOMPtr<nsIContentViewer> zombieViewer;
9869 if (mContentViewer) {
9870 mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
9871 }
9872
9873 if (zombieViewer ||
9874 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
9875 rv = Stop(nsIWebNavigation::STOP_ALL);
9876 } else {
9877 rv = Stop(nsIWebNavigation::STOP_NETWORK);
9878 }
9879
9880 if (NS_FAILED(rv)) {
9881 return rv;
9882 }
9883 }
9884
9885 mLoadType = aLoadType;
9886
9887 // mLSHE should be assigned to aSHEntry, only after Stop() has
9888 // been called. But when loading an error page, do not clear the
9889 // mLSHE for the real page.
9890 if (mLoadType != LOAD_ERROR_PAGE) {
9891 SetHistoryEntry(&mLSHE, aSHEntry);
9892 if (aSHEntry) {
9893 // We're making history navigation or a reload. Make sure our history ID
9894 // points to the same ID as SHEntry's docshell ID.
9895 mHistoryID = aSHEntry->DocshellID();
9896 }
9897 }
9898
9899 mSavingOldViewer = savePresentation;
9900
9901 // If we have a saved content viewer in history, restore and show it now.
9902 if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
9903 // It's possible that the previous viewer of mContentViewer is the
9904 // viewer that will end up in aSHEntry when it gets closed. If that's
9905 // the case, we need to go ahead and force it into its shentry so we
9906 // can restore it.
9907 if (mContentViewer) {
9908 nsCOMPtr<nsIContentViewer> prevViewer;
9909 mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
9910 if (prevViewer) {
9911 #ifdef DEBUG
9912 nsCOMPtr<nsIContentViewer> prevPrevViewer;
9913 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
9914 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
9915 #endif
9916 nsCOMPtr<nsISHEntry> viewerEntry;
9917 prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
9918 if (viewerEntry == aSHEntry) {
9919 // Make sure this viewer ends up in the right place
9920 mContentViewer->SetPreviousViewer(nullptr);
9921 prevViewer->Destroy();
9922 }
9923 }
9924 }
9925 nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
9926 bool restoring;
9927 rv = RestorePresentation(aSHEntry, &restoring);
9928 if (restoring) {
9929 return rv;
9930 }
9931
9932 // We failed to restore the presentation, so clean up.
9933 // Both the old and new history entries could potentially be in
9934 // an inconsistent state.
9935 if (NS_FAILED(rv)) {
9936 if (oldEntry) {
9937 oldEntry->SyncPresentationState();
9938 }
9939
9940 aSHEntry->SyncPresentationState();
9941 }
9942 }
9943
9944 nsAutoString srcdoc;
9945 if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) {
9946 srcdoc = aSrcdoc;
9947 } else {
9948 srcdoc = VoidString();
9949 }
9950
9951 bool isTopLevelDoc = mItemType == typeContent &&
9952 (isTargetTopLevelDocShell || GetIsMozBrowser());
9953
9954 OriginAttributes attrs = GetOriginAttributes();
9955 attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
9956
9957 net::PredictorLearn(aURI, nullptr, nsINetworkPredictor::LEARN_LOAD_TOPLEVEL,
9958 attrs);
9959 net::PredictorPredict(aURI, nullptr, nsINetworkPredictor::PREDICT_LOAD, attrs,
9960 nullptr);
9961
9962 nsCOMPtr<nsIRequest> req;
9963 rv = DoURILoad(
9964 aURI, aOriginalURI, aResultPrincipalURI, aKeepResultPrincipalURIIfSet,
9965 aLoadReplace, aIsFromProcessingFrameAttributes, loadFromExternal,
9966 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
9967 (aFlags & INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC), aReferrer,
9968 !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), aReferrerPolicy,
9969 aTriggeringPrincipal, principalToInherit, aTypeHint, aFileName, aPostData,
9970 aPostDataLength, aHeadersData, aFirstParty, aDocShell,
9971 getter_AddRefs(req), (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
9972 (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
9973 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0, srcdoc, aBaseURI,
9974 contentType);
9975 if (req && aRequest) {
9976 NS_ADDREF(*aRequest = req);
9977 }
9978
9979 if (NS_FAILED(rv)) {
9980 nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
9981 if (DisplayLoadError(rv, aURI, nullptr, chan) &&
9982 (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
9983 return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
9984 }
9985 }
9986
9987 return rv;
9988 }
9989
GetInheritedPrincipal(bool aConsiderCurrentDocument)9990 nsIPrincipal* nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument) {
9991 nsCOMPtr<nsIDocument> document;
9992 bool inheritedFromCurrent = false;
9993
9994 if (aConsiderCurrentDocument && mContentViewer) {
9995 document = mContentViewer->GetDocument();
9996 inheritedFromCurrent = true;
9997 }
9998
9999 if (!document) {
10000 nsCOMPtr<nsIDocShellTreeItem> parentItem;
10001 GetSameTypeParent(getter_AddRefs(parentItem));
10002 if (parentItem) {
10003 document = parentItem->GetDocument();
10004 }
10005 }
10006
10007 if (!document) {
10008 if (!aConsiderCurrentDocument) {
10009 return nullptr;
10010 }
10011
10012 // Make sure we end up with _something_ as the principal no matter
10013 // what.If this fails, we'll just get a null docViewer and bail.
10014 EnsureContentViewer();
10015 if (!mContentViewer) {
10016 return nullptr;
10017 }
10018 document = mContentViewer->GetDocument();
10019 }
10020
10021 //-- Get the document's principal
10022 if (document) {
10023 nsIPrincipal* docPrincipal = document->NodePrincipal();
10024
10025 // Don't allow loads in typeContent docShells to inherit the system
10026 // principal from existing documents.
10027 if (inheritedFromCurrent && mItemType == typeContent &&
10028 nsContentUtils::IsSystemPrincipal(docPrincipal)) {
10029 return nullptr;
10030 }
10031
10032 return docPrincipal;
10033 }
10034
10035 return nullptr;
10036 }
10037
10038 // CSPs upgrade-insecure-requests directive applies to same origin top level
10039 // navigations. Using the SOP would return false for the case when an https
10040 // page triggers and http page to load, even though that http page would be
10041 // upgraded to https later. Hence we have to use that custom function instead
10042 // of simply calling aTriggeringPrincipal->Equals(aResultPrincipal).
IsConsideredSameOriginForUIR(nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aResultPrincipal)10043 static bool IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
10044 nsIPrincipal* aResultPrincipal) {
10045 MOZ_ASSERT(aTriggeringPrincipal);
10046 MOZ_ASSERT(aResultPrincipal);
10047
10048 // we only have to make sure that the following truth table holds:
10049 // aTriggeringPrincipal | aResultPrincipal | Result
10050 // ----------------------------------------------------------------
10051 // http://example.com/foo.html | http://example.com/bar.html | true
10052 // https://example.com/foo.html | https://example.com/bar.html | true
10053 // https://example.com/foo.html | http://example.com/bar.html | true
10054 if (aTriggeringPrincipal->Equals(aResultPrincipal)) {
10055 return true;
10056 }
10057
10058 if (!aResultPrincipal->GetIsCodebasePrincipal()) {
10059 return false;
10060 }
10061
10062 nsCOMPtr<nsIURI> resultURI;
10063 nsresult rv = aResultPrincipal->GetURI(getter_AddRefs(resultURI));
10064 NS_ENSURE_SUCCESS(rv, false);
10065
10066 nsAutoCString resultScheme;
10067 rv = resultURI->GetScheme(resultScheme);
10068 NS_ENSURE_SUCCESS(rv, false);
10069 if (!resultScheme.EqualsLiteral("http")) {
10070 return false;
10071 }
10072
10073 nsAutoCString tmpResultSpec;
10074 rv = resultURI->GetSpec(tmpResultSpec);
10075 NS_ENSURE_SUCCESS(rv, false);
10076 // replace http with https
10077 tmpResultSpec.ReplaceLiteral(0, 4, "https");
10078
10079 nsCOMPtr<nsIURI> tmpResultURI;
10080 rv = NS_NewURI(getter_AddRefs(tmpResultURI), tmpResultSpec);
10081 NS_ENSURE_SUCCESS(rv, false);
10082
10083 mozilla::OriginAttributes tmpOA =
10084 BasePrincipal::Cast(aResultPrincipal)->OriginAttributesRef();
10085
10086 nsCOMPtr<nsIPrincipal> tmpResultPrincipal =
10087 BasePrincipal::CreateCodebasePrincipal(tmpResultURI, tmpOA);
10088
10089 return aTriggeringPrincipal->Equals(tmpResultPrincipal);
10090 }
10091
DoURILoad(nsIURI * aURI,nsIURI * aOriginalURI,Maybe<nsCOMPtr<nsIURI>> const & aResultPrincipalURI,bool aKeepResultPrincipalURIIfSet,bool aLoadReplace,bool aIsFromProcessingFrameAttributes,bool aLoadFromExternal,bool aForceAllowDataURI,bool aOriginalFrameSrc,nsIURI * aReferrerURI,bool aSendReferrer,uint32_t aReferrerPolicy,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aPrincipalToInherit,const char * aTypeHint,const nsAString & aFileName,nsIInputStream * aPostData,int64_t aPostDataLength,nsIInputStream * aHeadersData,bool aFirstParty,nsIDocShell ** aDocShell,nsIRequest ** aRequest,bool aIsNewWindowTarget,bool aBypassClassifier,bool aForceAllowCookies,const nsAString & aSrcdoc,nsIURI * aBaseURI,nsContentPolicyType aContentPolicyType)10092 nsresult nsDocShell::DoURILoad(
10093 nsIURI* aURI, nsIURI* aOriginalURI,
10094 Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
10095 bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
10096 bool aIsFromProcessingFrameAttributes, bool aLoadFromExternal,
10097 bool aForceAllowDataURI, bool aOriginalFrameSrc, nsIURI* aReferrerURI,
10098 bool aSendReferrer, uint32_t aReferrerPolicy,
10099 nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
10100 const char* aTypeHint, const nsAString& aFileName,
10101 nsIInputStream* aPostData, int64_t aPostDataLength,
10102 nsIInputStream* aHeadersData, bool aFirstParty, nsIDocShell** aDocShell,
10103 nsIRequest** aRequest, bool aIsNewWindowTarget, bool aBypassClassifier,
10104 bool aForceAllowCookies, const nsAString& aSrcdoc, nsIURI* aBaseURI,
10105 nsContentPolicyType aContentPolicyType) {
10106 // Double-check that we're still around to load this URI.
10107 if (mIsBeingDestroyed) {
10108 // Return NS_OK despite not doing anything to avoid throwing exceptions from
10109 // nsLocation::SetHref if the unload handler of the existing page tears us
10110 // down.
10111 return NS_OK;
10112 }
10113
10114 nsresult rv;
10115 nsCOMPtr<nsIURILoader> uriLoader =
10116 do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
10117 if (NS_FAILED(rv)) {
10118 return rv;
10119 }
10120
10121 if (IsFrame()) {
10122 MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
10123 aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME,
10124 "DoURILoad thinks this is a frame and InternalLoad does not");
10125
10126 // Only allow view-source scheme in top-level docshells. view-source is
10127 // the only scheme to which this applies at the moment due to potential
10128 // timing attacks to read data from cross-origin iframes. If this widens
10129 // we should add a protocol flag for whether the scheme is allowed in
10130 // frames and use something like nsNetUtil::NS_URIChainHasFlags.
10131 nsCOMPtr<nsIURI> tempURI = aURI;
10132 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
10133 while (nestedURI) {
10134 // view-source should always be an nsINestedURI, loop and check the
10135 // scheme on this and all inner URIs that are also nested URIs.
10136 bool isViewSource = false;
10137 rv = tempURI->SchemeIs("view-source", &isViewSource);
10138 if (NS_FAILED(rv) || isViewSource) {
10139 return NS_ERROR_UNKNOWN_PROTOCOL;
10140 }
10141 nestedURI->GetInnerURI(getter_AddRefs(tempURI));
10142 nestedURI = do_QueryInterface(tempURI);
10143 }
10144 } else {
10145 MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
10146 "DoURILoad thinks this is a document and InternalLoad does not");
10147 }
10148
10149 // open a channel for the url
10150 nsCOMPtr<nsIChannel> channel;
10151
10152 bool isSrcdoc = !aSrcdoc.IsVoid();
10153
10154 // There are two cases we care about:
10155 // * Top-level load: In this case, loadingNode is null, but loadingWindow
10156 // is our mScriptGlobal. We pass null for loadingPrincipal in this case.
10157 // * Subframe load: loadingWindow is null, but loadingNode is the frame
10158 // element for the load. loadingPrincipal is the NodePrincipal of the frame
10159 // element.
10160 nsCOMPtr<nsINode> loadingNode;
10161 nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
10162 nsCOMPtr<nsIPrincipal> loadingPrincipal;
10163 nsCOMPtr<nsISupports> topLevelLoadingContext;
10164
10165 if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
10166 loadingNode = nullptr;
10167 loadingPrincipal = nullptr;
10168 loadingWindow = mScriptGlobal->AsOuter();
10169 if (XRE_IsContentProcess()) {
10170 // In e10s the child process doesn't have access to the element that
10171 // contains the browsing context (because that element is in the chrome
10172 // process).
10173 nsCOMPtr<nsITabChild> tabChild = GetTabChild();
10174 topLevelLoadingContext = ToSupports(tabChild);
10175 } else {
10176 // This is for loading non-e10s tabs and toplevel windows of various
10177 // sorts.
10178 // For the toplevel window cases, requestingElement will be null.
10179 nsCOMPtr<Element> requestingElement =
10180 loadingWindow->GetFrameElementInternal();
10181 topLevelLoadingContext = requestingElement;
10182 }
10183 } else {
10184 loadingWindow = nullptr;
10185 loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
10186 if (loadingNode) {
10187 // If we have a loading node, then use that as our loadingPrincipal.
10188 loadingPrincipal = loadingNode->NodePrincipal();
10189 #ifdef DEBUG
10190 // Get the docshell type for requestingElement.
10191 nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc();
10192 nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
10193 // requestingElement docshell type = current docshell type.
10194 MOZ_ASSERT(
10195 mItemType == elementDocShell->ItemType(),
10196 "subframes should have the same docshell type as their parent");
10197 #endif
10198 } else {
10199 // If this isn't a top-level load and mScriptGlobal's frame element is
10200 // null, then the element got removed from the DOM while we were trying
10201 // to load this resource. This docshell is scheduled for destruction
10202 // already, so bail out here.
10203 return NS_OK;
10204 }
10205 }
10206
10207 // Getting the right triggeringPrincipal needs to be updated and is only
10208 // ready for use once bug 1182569 landed. Until then, we cannot rely on
10209 // the triggeringPrincipal for TYPE_DOCUMENT loads.
10210 MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
10211
10212 bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
10213
10214 // We want to inherit aPrincipalToInherit when:
10215 // 1. ChannelShouldInheritPrincipal returns true.
10216 // 2. aURI is not data: URI, or data: URI is not configured as unique opaque
10217 // origin.
10218 bool inheritAttrs = false, inheritPrincipal = false;
10219
10220 if (aPrincipalToInherit) {
10221 inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
10222 aPrincipalToInherit, aURI,
10223 true, // aInheritForAboutBlank
10224 isSrcdoc);
10225
10226 bool isData;
10227 bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
10228 NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) &&
10229 isData;
10230 inheritPrincipal = inheritAttrs && !isURIUniqueOrigin;
10231 }
10232
10233 nsLoadFlags loadFlags = mDefaultLoadFlags;
10234 nsSecurityFlags securityFlags =
10235 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
10236
10237 if (aFirstParty) {
10238 // tag first party URL loads
10239 loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
10240 }
10241
10242 if (mLoadType == LOAD_ERROR_PAGE) {
10243 // Error pages are LOAD_BACKGROUND
10244 loadFlags |= nsIChannel::LOAD_BACKGROUND;
10245 securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
10246 }
10247
10248 if (inheritPrincipal) {
10249 securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
10250 }
10251 if (isSandBoxed) {
10252 securityFlags |= nsILoadInfo::SEC_SANDBOXED;
10253 }
10254
10255 RefPtr<LoadInfo> loadInfo =
10256 (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT)
10257 ? new LoadInfo(loadingWindow, aTriggeringPrincipal,
10258 topLevelLoadingContext, securityFlags)
10259 : new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
10260 securityFlags, aContentPolicyType);
10261
10262 if (aPrincipalToInherit) {
10263 loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
10264 }
10265 loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal);
10266 loadInfo->SetForceAllowDataURI(aForceAllowDataURI);
10267 loadInfo->SetOriginalFrameSrcLoad(aOriginalFrameSrc);
10268
10269 // We have to do this in case our OriginAttributes are different from the
10270 // OriginAttributes of the parent document. Or in case there isn't a
10271 // parent document.
10272 bool isTopLevelDoc = mItemType == typeContent &&
10273 (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
10274 GetIsMozBrowser());
10275
10276 OriginAttributes attrs;
10277
10278 // Inherit origin attributes from aPrincipalToInherit if inheritAttrs is true.
10279 // Otherwise we just use the origin attributes from docshell.
10280 if (inheritAttrs) {
10281 MOZ_ASSERT(aPrincipalToInherit, "We should have aPrincipalToInherit here.");
10282 attrs = aPrincipalToInherit->OriginAttributesRef();
10283 // If firstPartyIsolation is not enabled, then PrincipalToInherit should
10284 // have the same origin attributes with docshell.
10285 MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(),
10286 attrs == GetOriginAttributes());
10287 } else {
10288 attrs = GetOriginAttributes();
10289 attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
10290 }
10291
10292 rv = loadInfo->SetOriginAttributes(attrs);
10293 if (NS_WARN_IF(NS_FAILED(rv))) {
10294 return rv;
10295 }
10296
10297 // Document loads should set the reload flag on the channel so that it
10298 // can be exposed on the service worker FetchEvent.
10299 rv = loadInfo->SetIsDocshellReload(mLoadType & LOAD_CMD_RELOAD);
10300 NS_ENSURE_SUCCESS(rv, rv);
10301
10302 if (aIsFromProcessingFrameAttributes) {
10303 loadInfo->SetIsFromProcessingFrameAttributes();
10304 }
10305
10306 if (!isSrcdoc) {
10307 rv = NS_NewChannelInternal(getter_AddRefs(channel), aURI, loadInfo,
10308 nullptr, // PerformanceStorage
10309 nullptr, // loadGroup
10310 static_cast<nsIInterfaceRequestor*>(this),
10311 loadFlags);
10312
10313 if (NS_FAILED(rv)) {
10314 if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
10315 // This is a uri with a protocol scheme we don't know how
10316 // to handle. Embedders might still be interested in
10317 // handling the load, though, so we fire a notification
10318 // before throwing the load away.
10319 bool abort = false;
10320 nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
10321 if (NS_SUCCEEDED(rv2) && abort) {
10322 // Hey, they're handling the load for us! How convenient!
10323 return NS_OK;
10324 }
10325 }
10326 return rv;
10327 }
10328
10329 if (aBaseURI) {
10330 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
10331 if (vsc) {
10332 rv = vsc->SetBaseURI(aBaseURI);
10333 MOZ_ASSERT(NS_SUCCEEDED(rv));
10334 }
10335 }
10336 } else {
10337 nsAutoCString scheme;
10338 rv = aURI->GetScheme(scheme);
10339 NS_ENSURE_SUCCESS(rv, rv);
10340 bool isViewSource;
10341 aURI->SchemeIs("view-source", &isViewSource);
10342
10343 if (isViewSource) {
10344 nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
10345 NS_ENSURE_TRUE(vsh, NS_ERROR_FAILURE);
10346
10347 rv = vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, loadInfo,
10348 getter_AddRefs(channel));
10349 } else {
10350 rv = NS_NewInputStreamChannelInternal(
10351 getter_AddRefs(channel), aURI, aSrcdoc,
10352 NS_LITERAL_CSTRING("text/html"), loadInfo, true);
10353 NS_ENSURE_SUCCESS(rv, rv);
10354 nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
10355 MOZ_ASSERT(isc);
10356 isc->SetBaseURI(aBaseURI);
10357 }
10358 }
10359
10360 // Navigational requests that are same origin need to be upgraded in case
10361 // upgrade-insecure-requests is present. Please note that in that case
10362 // the triggeringPrincipal is holding the CSP that potentially
10363 // holds upgrade-insecure-requests.
10364 nsCOMPtr<nsIContentSecurityPolicy> csp;
10365 aTriggeringPrincipal->GetCsp(getter_AddRefs(csp));
10366 if (csp) {
10367 bool upgradeInsecureRequests = false;
10368 csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
10369 if (upgradeInsecureRequests) {
10370 // only upgrade if the navigation is same origin
10371 nsCOMPtr<nsIPrincipal> resultPrincipal;
10372 rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
10373 channel, getter_AddRefs(resultPrincipal));
10374 NS_ENSURE_SUCCESS(rv, rv);
10375 if (IsConsideredSameOriginForUIR(aTriggeringPrincipal, resultPrincipal)) {
10376 static_cast<mozilla::LoadInfo*>(loadInfo.get())
10377 ->SetUpgradeInsecureRequests();
10378 }
10379 }
10380 }
10381
10382 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
10383 do_QueryInterface(channel);
10384 if (appCacheChannel) {
10385 // Any document load should not inherit application cache.
10386 appCacheChannel->SetInheritApplicationCache(false);
10387
10388 // Loads with the correct permissions should check for a matching
10389 // application cache.
10390 if (GeckoProcessType_Default != XRE_GetProcessType()) {
10391 // Permission will be checked in the parent process
10392 appCacheChannel->SetChooseApplicationCache(true);
10393 } else {
10394 nsCOMPtr<nsIScriptSecurityManager> secMan =
10395 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
10396
10397 if (secMan) {
10398 nsCOMPtr<nsIPrincipal> principal;
10399 secMan->GetDocShellCodebasePrincipal(aURI, this,
10400 getter_AddRefs(principal));
10401 appCacheChannel->SetChooseApplicationCache(
10402 NS_ShouldCheckAppCache(principal));
10403 }
10404 }
10405 }
10406
10407 // Make sure to give the caller a channel if we managed to create one
10408 // This is important for correct error page/session history interaction
10409 if (aRequest) {
10410 NS_ADDREF(*aRequest = channel);
10411 }
10412
10413 if (aOriginalURI) {
10414 channel->SetOriginalURI(aOriginalURI);
10415 // The LOAD_REPLACE flag and its handling here will be removed as part
10416 // of bug 1319110. For now preserve its restoration here to not break
10417 // any code expecting it being set specially on redirected channels.
10418 // If the flag has originally been set to change result of
10419 // NS_GetFinalChannelURI it won't have any effect and also won't cause
10420 // any harm.
10421 if (aLoadReplace) {
10422 uint32_t loadFlags;
10423 channel->GetLoadFlags(&loadFlags);
10424 NS_ENSURE_SUCCESS(rv, rv);
10425 channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
10426 }
10427 } else {
10428 channel->SetOriginalURI(aURI);
10429 }
10430
10431 nsCOMPtr<nsIURI> rpURI;
10432 loadInfo->GetResultPrincipalURI(getter_AddRefs(rpURI));
10433 if (aResultPrincipalURI && (!aKeepResultPrincipalURIIfSet || !rpURI)) {
10434 // Unconditionally override, we want the replay to be equal to what has
10435 // been captured.
10436 loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref());
10437 }
10438
10439 if (aTypeHint && *aTypeHint) {
10440 channel->SetContentType(nsDependentCString(aTypeHint));
10441 mContentTypeHint = aTypeHint;
10442 } else {
10443 mContentTypeHint.Truncate();
10444 }
10445
10446 if (!aFileName.IsVoid()) {
10447 rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
10448 NS_ENSURE_SUCCESS(rv, rv);
10449 if (!aFileName.IsEmpty()) {
10450 rv = channel->SetContentDispositionFilename(aFileName);
10451 NS_ENSURE_SUCCESS(rv, rv);
10452 }
10453 }
10454
10455 if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
10456 mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
10457 rv = SetMixedContentChannel(channel);
10458 NS_ENSURE_SUCCESS(rv, rv);
10459 } else if (mMixedContentChannel) {
10460 /*
10461 * If the user "Disables Protection on This Page", we call
10462 * SetMixedContentChannel for the first time, otherwise
10463 * mMixedContentChannel is still null.
10464 * Later, if the new channel passes a same orign check, we remember the
10465 * users decision by calling SetMixedContentChannel using the new channel.
10466 * This way, the user does not have to click the disable protection button
10467 * over and over for browsing the same site.
10468 */
10469 rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
10470 if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
10471 SetMixedContentChannel(nullptr);
10472 }
10473 }
10474
10475 // hack
10476 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
10477 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
10478 do_QueryInterface(channel));
10479 if (httpChannelInternal) {
10480 if (aForceAllowCookies) {
10481 rv = httpChannelInternal->SetThirdPartyFlags(
10482 nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
10483 MOZ_ASSERT(NS_SUCCEEDED(rv));
10484 }
10485 if (aFirstParty) {
10486 rv = httpChannelInternal->SetDocumentURI(aURI);
10487 MOZ_ASSERT(NS_SUCCEEDED(rv));
10488 } else {
10489 rv = httpChannelInternal->SetDocumentURI(aReferrerURI);
10490 MOZ_ASSERT(NS_SUCCEEDED(rv));
10491 }
10492 rv = httpChannelInternal->SetRedirectMode(
10493 nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
10494 MOZ_ASSERT(NS_SUCCEEDED(rv));
10495 }
10496
10497 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
10498 if (props) {
10499 // save true referrer for those who need it (e.g. xpinstall whitelisting)
10500 // Currently only http and ftp channels support this.
10501 props->SetPropertyAsInterface(
10502 NS_LITERAL_STRING("docshell.internalReferrer"), aReferrerURI);
10503 }
10504
10505 nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
10506 /* Get the cache Key from SH */
10507 nsCOMPtr<nsISupports> cacheKey;
10508 if (cacheChannel) {
10509 if (mLSHE) {
10510 mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
10511 } else if (mOSHE) { // for reload cases
10512 mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
10513 }
10514 }
10515
10516 // figure out if we need to set the post data stream on the channel...
10517 if (aPostData) {
10518 nsCOMPtr<nsIFormPOSTActionChannel> postChannel(do_QueryInterface(channel));
10519 if (postChannel) {
10520 // XXX it's a bit of a hack to rewind the postdata stream here but
10521 // it has to be done in case the post data is being reused multiple
10522 // times.
10523 nsCOMPtr<nsISeekableStream> postDataSeekable =
10524 do_QueryInterface(aPostData);
10525 if (postDataSeekable) {
10526 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
10527 NS_ENSURE_SUCCESS(rv, rv);
10528 }
10529
10530 // we really need to have a content type associated with this stream!!
10531 postChannel->SetUploadStream(aPostData, EmptyCString(), aPostDataLength);
10532 }
10533
10534 /* If there is a valid postdata *and* it is a History Load,
10535 * set up the cache key on the channel, to retrieve the
10536 * data *only* from the cache. If it is a normal reload, the
10537 * cache is free to go to the server for updated postdata.
10538 */
10539 if (cacheChannel && cacheKey) {
10540 if (mLoadType == LOAD_HISTORY ||
10541 mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
10542 cacheChannel->SetCacheKey(cacheKey);
10543 uint32_t loadFlags;
10544 if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
10545 channel->SetLoadFlags(loadFlags |
10546 nsICachingChannel::LOAD_ONLY_FROM_CACHE);
10547 }
10548 } else if (mLoadType == LOAD_RELOAD_NORMAL) {
10549 cacheChannel->SetCacheKey(cacheKey);
10550 }
10551 }
10552 } else {
10553 /* If there is no postdata, set the cache key on the channel, and
10554 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
10555 * will be free to get it from net if it is not found in cache.
10556 * New cache may use it creatively on CGI pages with GET
10557 * method and even on those that say "no-cache"
10558 */
10559 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL ||
10560 mLoadType == LOAD_RELOAD_CHARSET_CHANGE ||
10561 mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE ||
10562 mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE) {
10563 if (cacheChannel && cacheKey) {
10564 cacheChannel->SetCacheKey(cacheKey);
10565 }
10566 }
10567 }
10568
10569 if (httpChannel) {
10570 if (aHeadersData) {
10571 rv = AddHeadersToChannel(aHeadersData, httpChannel);
10572 }
10573 // Set the referrer explicitly
10574 if (aReferrerURI && aSendReferrer) {
10575 // Referrer is currenly only set for link clicks here.
10576 rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
10577 MOZ_ASSERT(NS_SUCCEEDED(rv));
10578 }
10579 }
10580
10581 nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
10582 if (scriptChannel) {
10583 // Allow execution against our context if the principals match
10584 scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
10585 }
10586
10587 if (aIsNewWindowTarget) {
10588 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
10589 if (props) {
10590 props->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
10591 true);
10592 }
10593 }
10594
10595 nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
10596 if (timedChannel) {
10597 timedChannel->SetTimingEnabled(true);
10598
10599 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10600 if (IsFrame() && win) {
10601 nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
10602 if (frameElement) {
10603 timedChannel->SetInitiatorType(frameElement->LocalName());
10604 }
10605 }
10606 }
10607
10608 // Mark the http channel as UrgentStart for top level document loading
10609 // in active tab.
10610 if (mIsActive || (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY))) {
10611 if (httpChannel && isTopLevelDoc) {
10612 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
10613 if (cos) {
10614 cos->AddClassFlags(nsIClassOfService::UrgentStart);
10615 }
10616 }
10617 }
10618
10619 rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
10620
10621 //
10622 // If the channel load failed, we failed and nsIWebProgress just ain't
10623 // gonna happen.
10624 //
10625 if (NS_SUCCEEDED(rv)) {
10626 if (aDocShell) {
10627 *aDocShell = this;
10628 NS_ADDREF(*aDocShell);
10629 }
10630 }
10631
10632 return rv;
10633 }
10634
AppendSegmentToString(nsIInputStream * aIn,void * aClosure,const char * aFromRawSegment,uint32_t aToOffset,uint32_t aCount,uint32_t * aWriteCount)10635 static nsresult AppendSegmentToString(nsIInputStream* aIn, void* aClosure,
10636 const char* aFromRawSegment,
10637 uint32_t aToOffset, uint32_t aCount,
10638 uint32_t* aWriteCount) {
10639 // aFromSegment now contains aCount bytes of data.
10640
10641 nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure);
10642 buf->Append(aFromRawSegment, aCount);
10643
10644 // Indicate that we have consumed all of aFromSegment
10645 *aWriteCount = aCount;
10646 return NS_OK;
10647 }
10648
AddHeadersToChannel(nsIInputStream * aHeadersData,nsIChannel * aGenericChannel)10649 nsresult nsDocShell::AddHeadersToChannel(nsIInputStream* aHeadersData,
10650 nsIChannel* aGenericChannel) {
10651 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
10652 NS_ENSURE_STATE(httpChannel);
10653
10654 uint32_t numRead;
10655 nsAutoCString headersString;
10656 nsresult rv = aHeadersData->ReadSegments(
10657 AppendSegmentToString, &headersString, UINT32_MAX, &numRead);
10658 NS_ENSURE_SUCCESS(rv, rv);
10659
10660 // used during the manipulation of the String from the InputStream
10661 nsAutoCString headerName;
10662 nsAutoCString headerValue;
10663 int32_t crlf;
10664 int32_t colon;
10665
10666 //
10667 // Iterate over the headersString: for each "\r\n" delimited chunk,
10668 // add the value as a header to the nsIHttpChannel
10669 //
10670
10671 static const char kWhitespace[] = "\b\t\r\n ";
10672 while (true) {
10673 crlf = headersString.Find("\r\n");
10674 if (crlf == kNotFound) {
10675 return NS_OK;
10676 }
10677
10678 const nsACString& oneHeader = StringHead(headersString, crlf);
10679
10680 colon = oneHeader.FindChar(':');
10681 if (colon == kNotFound) {
10682 return NS_ERROR_UNEXPECTED;
10683 }
10684
10685 headerName = StringHead(oneHeader, colon);
10686 headerValue = Substring(oneHeader, colon + 1);
10687
10688 headerName.Trim(kWhitespace);
10689 headerValue.Trim(kWhitespace);
10690
10691 headersString.Cut(0, crlf + 2);
10692
10693 //
10694 // FINALLY: we can set the header!
10695 //
10696
10697 rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
10698 NS_ENSURE_SUCCESS(rv, rv);
10699 }
10700
10701 NS_NOTREACHED("oops");
10702 return NS_ERROR_UNEXPECTED;
10703 }
10704
DoChannelLoad(nsIChannel * aChannel,nsIURILoader * aURILoader,bool aBypassClassifier)10705 nsresult nsDocShell::DoChannelLoad(nsIChannel* aChannel,
10706 nsIURILoader* aURILoader,
10707 bool aBypassClassifier) {
10708 nsresult rv;
10709 // Mark the channel as being a document URI and allow content sniffing...
10710 nsLoadFlags loadFlags = 0;
10711 (void)aChannel->GetLoadFlags(&loadFlags);
10712 loadFlags |=
10713 nsIChannel::LOAD_DOCUMENT_URI | nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
10714
10715 if (SandboxFlagsImplyCookies(mSandboxFlags)) {
10716 loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
10717 }
10718 // Load attributes depend on load type...
10719 switch (mLoadType) {
10720 case LOAD_HISTORY: {
10721 // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
10722 // push/replaceState (bug 669671).
10723 bool uriModified = false;
10724 if (mLSHE) {
10725 mLSHE->GetURIWasModified(&uriModified);
10726 }
10727
10728 if (!uriModified) {
10729 loadFlags |= nsIRequest::VALIDATE_NEVER;
10730 }
10731 break;
10732 }
10733
10734 case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
10735 case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
10736 loadFlags |=
10737 nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
10738 MOZ_FALLTHROUGH;
10739
10740 case LOAD_RELOAD_CHARSET_CHANGE: {
10741 // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only
10742 // want to force cache load for this channel, not the whole loadGroup.
10743 nsCOMPtr<nsICacheInfoChannel> cachingChannel =
10744 do_QueryInterface(aChannel);
10745 if (cachingChannel) {
10746 cachingChannel->SetAllowStaleCacheContent(true);
10747 }
10748 break;
10749 }
10750
10751 case LOAD_RELOAD_NORMAL:
10752 case LOAD_REFRESH:
10753 loadFlags |= nsIRequest::VALIDATE_ALWAYS;
10754 break;
10755
10756 case LOAD_NORMAL_BYPASS_CACHE:
10757 case LOAD_NORMAL_BYPASS_PROXY:
10758 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
10759 case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
10760 case LOAD_RELOAD_BYPASS_CACHE:
10761 case LOAD_RELOAD_BYPASS_PROXY:
10762 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
10763 case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
10764 case LOAD_REPLACE_BYPASS_CACHE:
10765 loadFlags |=
10766 nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
10767 break;
10768
10769 case LOAD_NORMAL:
10770 case LOAD_LINK:
10771 // Set cache checking flags
10772 switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
10773 case 0:
10774 loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
10775 break;
10776 case 1:
10777 loadFlags |= nsIRequest::VALIDATE_ALWAYS;
10778 break;
10779 case 2:
10780 loadFlags |= nsIRequest::VALIDATE_NEVER;
10781 break;
10782 }
10783 break;
10784 }
10785
10786 if (!aBypassClassifier) {
10787 loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
10788 }
10789
10790 // If the user pressed shift-reload, then do not allow ServiceWorker
10791 // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
10792 if (IsForceReloadType(mLoadType)) {
10793 loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
10794 }
10795
10796 (void)aChannel->SetLoadFlags(loadFlags);
10797
10798 uint32_t openFlags = 0;
10799 if (mLoadType == LOAD_LINK) {
10800 openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
10801 }
10802 if (!mAllowContentRetargeting) {
10803 openFlags |= nsIURILoader::DONT_RETARGET;
10804 }
10805
10806 // If anything fails here, make sure to clear our initial ClientSource.
10807 auto cleanupInitialClient =
10808 MakeScopeExit([&] { mInitialClientSource.reset(); });
10809
10810 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10811 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
10812
10813 MaybeCreateInitialClientSource();
10814
10815 // Since we are loading a document we need to make sure the proper reserved
10816 // and initial client data is stored on the nsILoadInfo. The
10817 // ClientChannelHelper does this and ensures that it is propagated properly
10818 // on redirects. We pass no reserved client here so that the helper will
10819 // create the reserved ClientSource if necessary.
10820 Maybe<ClientInfo> noReservedClient;
10821 rv = AddClientChannelHelper(aChannel, Move(noReservedClient),
10822 GetInitialClientInfo(),
10823 win->EventTargetFor(TaskCategory::Other));
10824 NS_ENSURE_SUCCESS(rv, rv);
10825
10826 rv = aURILoader->OpenURI(aChannel, openFlags, this);
10827 NS_ENSURE_SUCCESS(rv, rv);
10828
10829 // We're about to load a new page and it may take time before necko
10830 // gives back any data, so main thread might have a chance to process a
10831 // collector slice
10832 nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL);
10833
10834 // Success. Keep the initial ClientSource if it exists.
10835 cleanupInitialClient.release();
10836
10837 return NS_OK;
10838 }
10839
ScrollToAnchor(bool aCurHasRef,bool aNewHasRef,nsACString & aNewHash,uint32_t aLoadType)10840 nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
10841 nsACString& aNewHash, uint32_t aLoadType) {
10842 if (!mCurrentURI) {
10843 return NS_OK;
10844 }
10845
10846 nsCOMPtr<nsIPresShell> shell = GetPresShell();
10847 if (!shell) {
10848 // If we failed to get the shell, or if there is no shell,
10849 // nothing left to do here.
10850 return NS_OK;
10851 }
10852
10853 nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
10854 if (rootScroll) {
10855 rootScroll->ClearDidHistoryRestore();
10856 }
10857
10858 // If we have no new anchor, we do not want to scroll, unless there is a
10859 // current anchor and we are doing a history load. So return if we have no
10860 // new anchor, and there is no current anchor or the load is not a history
10861 // load.
10862 if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef) {
10863 return NS_OK;
10864 }
10865
10866 // Both the new and current URIs refer to the same page. We can now
10867 // browse to the hash stored in the new URI.
10868
10869 if (!aNewHash.IsEmpty()) {
10870 // anchor is there, but if it's a load from history,
10871 // we don't have any anchor jumping to do
10872 bool scroll = aLoadType != LOAD_HISTORY && aLoadType != LOAD_RELOAD_NORMAL;
10873
10874 // We assume that the bytes are in UTF-8, as it says in the
10875 // spec:
10876 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
10877
10878 // We try the UTF-8 string first, and then try the document's
10879 // charset (see below). If the string is not UTF-8,
10880 // conversion will fail and give us an empty Unicode string.
10881 // In that case, we should just fall through to using the
10882 // page's charset.
10883 nsresult rv = NS_ERROR_FAILURE;
10884 NS_ConvertUTF8toUTF16 uStr(aNewHash);
10885 if (!uStr.IsEmpty()) {
10886 rv = shell->GoToAnchor(uStr, scroll, nsIPresShell::SCROLL_SMOOTH_AUTO);
10887 }
10888
10889 if (NS_FAILED(rv)) {
10890 char* str = ToNewCString(aNewHash);
10891 if (!str) {
10892 return NS_ERROR_OUT_OF_MEMORY;
10893 }
10894 nsUnescape(str);
10895 NS_ConvertUTF8toUTF16 utf16Str(str);
10896 if (!utf16Str.IsEmpty()) {
10897 rv = shell->GoToAnchor(utf16Str, scroll,
10898 nsIPresShell::SCROLL_SMOOTH_AUTO);
10899 }
10900 free(str);
10901 }
10902
10903 // Above will fail if the anchor name is not UTF-8. Need to
10904 // convert from document charset to unicode.
10905 if (NS_FAILED(rv)) {
10906 // Get a document charset
10907 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
10908 nsIDocument* doc = mContentViewer->GetDocument();
10909 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
10910 nsAutoCString charset;
10911 doc->GetDocumentCharacterSet()->Name(charset);
10912
10913 nsCOMPtr<nsITextToSubURI> textToSubURI =
10914 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
10915 NS_ENSURE_SUCCESS(rv, rv);
10916
10917 // Unescape and convert to unicode
10918 nsAutoString uStr;
10919
10920 rv = textToSubURI->UnEscapeAndConvert(charset, aNewHash, uStr);
10921 NS_ENSURE_SUCCESS(rv, rv);
10922
10923 // Ignore return value of GoToAnchor, since it will return an error
10924 // if there is no such anchor in the document, which is actually a
10925 // success condition for us (we want to update the session history
10926 // with the new URI no matter whether we actually scrolled
10927 // somewhere).
10928 //
10929 // When aNewHash contains "%00", unescaped string may be empty.
10930 // And GoToAnchor asserts if we ask it to scroll to an empty ref.
10931 shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(),
10932 nsIPresShell::SCROLL_SMOOTH_AUTO);
10933 }
10934 } else {
10935 // Tell the shell it's at an anchor, without scrolling.
10936 shell->GoToAnchor(EmptyString(), false);
10937
10938 // An empty anchor was found, but if it's a load from history,
10939 // we don't have to jump to the top of the page. Scrollbar
10940 // position will be restored by the caller, based on positions
10941 // stored in session history.
10942 if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) {
10943 return NS_OK;
10944 }
10945 // An empty anchor. Scroll to the top of the page. Ignore the
10946 // return value; failure to scroll here (e.g. if there is no
10947 // root scrollframe) is not grounds for canceling the load!
10948 SetCurScrollPosEx(0, 0);
10949 }
10950
10951 return NS_OK;
10952 }
10953
SetupReferrerFromChannel(nsIChannel * aChannel)10954 void nsDocShell::SetupReferrerFromChannel(nsIChannel* aChannel) {
10955 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
10956 if (httpChannel) {
10957 nsCOMPtr<nsIURI> referrer;
10958 nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
10959 if (NS_SUCCEEDED(rv)) {
10960 SetReferrerURI(referrer);
10961 }
10962 uint32_t referrerPolicy;
10963 rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
10964 if (NS_SUCCEEDED(rv)) {
10965 SetReferrerPolicy(referrerPolicy);
10966 }
10967 }
10968 }
10969
OnNewURI(nsIURI * aURI,nsIChannel * aChannel,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aPrincipalToInherit,uint32_t aLoadType,bool aFireOnLocationChange,bool aAddToGlobalHistory,bool aCloneSHChildren)10970 bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
10971 nsIPrincipal* aTriggeringPrincipal,
10972 nsIPrincipal* aPrincipalToInherit, uint32_t aLoadType,
10973 bool aFireOnLocationChange, bool aAddToGlobalHistory,
10974 bool aCloneSHChildren) {
10975 NS_PRECONDITION(aURI, "uri is null");
10976 NS_PRECONDITION(!aChannel || !aTriggeringPrincipal,
10977 "Shouldn't have both set");
10978
10979 MOZ_ASSERT(!aPrincipalToInherit ||
10980 (aPrincipalToInherit && aTriggeringPrincipal));
10981
10982 #if defined(DEBUG)
10983 if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
10984 nsAutoCString chanName;
10985 if (aChannel) {
10986 aChannel->GetName(chanName);
10987 } else {
10988 chanName.AssignLiteral("<no channel>");
10989 }
10990
10991 MOZ_LOG(gDocShellLog, LogLevel::Debug,
10992 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this,
10993 aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
10994 }
10995 #endif
10996
10997 bool equalUri = false;
10998
10999 // Get the post data and the HTTP response code from the channel.
11000 uint32_t responseStatus = 0;
11001 nsCOMPtr<nsIInputStream> inputStream;
11002 if (aChannel) {
11003 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11004
11005 // Check if the HTTPChannel is hiding under a multiPartChannel
11006 if (!httpChannel) {
11007 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11008 }
11009
11010 if (httpChannel) {
11011 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11012 if (uploadChannel) {
11013 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11014 }
11015
11016 // If the response status indicates an error, unlink this session
11017 // history entry from any entries sharing its document.
11018 nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
11019 if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
11020 mLSHE->AbandonBFCacheEntry();
11021 }
11022 }
11023 }
11024
11025 // Determine if this type of load should update history.
11026 bool updateGHistory =
11027 !(aLoadType == LOAD_BYPASS_HISTORY || aLoadType == LOAD_ERROR_PAGE ||
11028 aLoadType & LOAD_CMD_HISTORY);
11029
11030 // We don't update session history on reload unless we're loading
11031 // an iframe in shift-reload case.
11032 bool updateSHistory =
11033 updateGHistory && (!(aLoadType & LOAD_CMD_RELOAD) ||
11034 (IsForceReloadType(aLoadType) && IsFrame()));
11035
11036 // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
11037 // current frame or in the root docshell.
11038 nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
11039 if (!rootSH) {
11040 // Get the handle to SH from the root docshell
11041 GetRootSessionHistory(getter_AddRefs(rootSH));
11042 if (!rootSH) {
11043 updateSHistory = false;
11044 updateGHistory = false; // XXX Why global history too?
11045 }
11046 }
11047
11048 // Check if the url to be loaded is the same as the one already loaded.
11049 if (mCurrentURI) {
11050 aURI->Equals(mCurrentURI, &equalUri);
11051 }
11052
11053 #ifdef DEBUG
11054 bool shAvailable = (rootSH != nullptr);
11055
11056 // XXX This log message is almost useless because |updateSHistory|
11057 // and |updateGHistory| are not correct at this point.
11058
11059 MOZ_LOG(gDocShellLog, LogLevel::Debug,
11060 (" shAvailable=%i updateSHistory=%i updateGHistory=%i"
11061 " equalURI=%i\n",
11062 shAvailable, updateSHistory, updateGHistory, equalUri));
11063
11064 if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
11065 // XXX mCurrentURI can be changed from any caller regardless what actual
11066 // loaded document is, so testing mCurrentURI isn't really a reliable way.
11067 // Session restore is one example which changes current URI in order to
11068 // show address before loading. See bug 1301399.
11069 NS_ASSERTION(NS_IsAboutBlank(mCurrentURI),
11070 "no SHEntry for a non-transient viewer?");
11071 }
11072 #endif
11073
11074 /* If the url to be loaded is the same as the one already there,
11075 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
11076 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
11077 * AddToSessionHistory() won't mess with the current SHEntry and
11078 * if this page has any frame children, it also will be handled
11079 * properly. see bug 83684
11080 *
11081 * NB: If mOSHE is null but we have a current URI, then it means
11082 * that we must be at the transient about:blank content viewer
11083 * (asserted above) and we should let the normal load continue,
11084 * since there's nothing to replace.
11085 *
11086 * XXX Hopefully changing the loadType at this time will not hurt
11087 * anywhere. The other way to take care of sequentially repeating
11088 * frameset pages is to add new methods to nsIDocShellTreeItem.
11089 * Hopefully I don't have to do that.
11090 */
11091 if (equalUri && mOSHE &&
11092 (mLoadType == LOAD_NORMAL || mLoadType == LOAD_LINK ||
11093 mLoadType == LOAD_STOP_CONTENT) &&
11094 !inputStream) {
11095 mLoadType = LOAD_NORMAL_REPLACE;
11096 }
11097
11098 // If this is a refresh to the currently loaded url, we don't
11099 // have to update session or global history.
11100 if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
11101 SetHistoryEntry(&mLSHE, mOSHE);
11102 }
11103
11104 /* If the user pressed shift-reload, cache will create a new cache key
11105 * for the page. Save the new cacheKey in Session History.
11106 * see bug 90098
11107 */
11108 if (aChannel && IsForceReloadType(aLoadType)) {
11109 MOZ_ASSERT(!updateSHistory || IsFrame(),
11110 "We shouldn't be updating session history for forced"
11111 " reloads unless we're in a newly created iframe!");
11112
11113 nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel));
11114 nsCOMPtr<nsISupports> cacheKey;
11115 // Get the Cache Key and store it in SH.
11116 if (cacheChannel) {
11117 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
11118 }
11119 // If we already have a loading history entry, store the new cache key
11120 // in it. Otherwise, since we're doing a reload and won't be updating
11121 // our history entry, store the cache key in our current history entry.
11122 if (mLSHE) {
11123 mLSHE->SetCacheKey(cacheKey);
11124 } else if (mOSHE) {
11125 mOSHE->SetCacheKey(cacheKey);
11126 }
11127
11128 // Since we're force-reloading, clear all the sub frame history.
11129 ClearFrameHistory(mLSHE);
11130 ClearFrameHistory(mOSHE);
11131 }
11132
11133 // Clear subframe history on refresh.
11134 // XXX: history.go(0) won't go this path as aLoadType is LOAD_HISTORY in this
11135 // case. One should re-validate after bug 1331865 fixed.
11136 if (aLoadType == LOAD_REFRESH) {
11137 ClearFrameHistory(mLSHE);
11138 ClearFrameHistory(mOSHE);
11139 }
11140
11141 if (updateSHistory) {
11142 // Update session history if necessary...
11143 if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
11144 /* This is a fresh page getting loaded for the first time
11145 *.Create a Entry for it and add it to SH, if this is the
11146 * rootDocShell
11147 */
11148 (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
11149 aPrincipalToInherit, aCloneSHChildren,
11150 getter_AddRefs(mLSHE));
11151 }
11152 } else if (mSessionHistory && mLSHE && mURIResultedInDocument) {
11153 // Even if we don't add anything to SHistory, ensure the current index
11154 // points to the same SHEntry as our mLSHE.
11155 int32_t index = 0;
11156 mSessionHistory->GetRequestedIndex(&index);
11157 if (index == -1) {
11158 mSessionHistory->GetIndex(&index);
11159 }
11160 nsCOMPtr<nsISHEntry> currentSH;
11161 mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(currentSH));
11162 if (currentSH != mLSHE) {
11163 nsCOMPtr<nsISHistoryInternal> shPrivate =
11164 do_QueryInterface(mSessionHistory);
11165 shPrivate->ReplaceEntry(index, mLSHE);
11166 }
11167 }
11168
11169 // If this is a POST request, we do not want to include this in global
11170 // history.
11171 if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
11172 nsCOMPtr<nsIURI> previousURI;
11173 uint32_t previousFlags = 0;
11174
11175 if (aLoadType & LOAD_CMD_RELOAD) {
11176 // On a reload request, we don't set redirecting flags.
11177 previousURI = aURI;
11178 } else {
11179 ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags);
11180 }
11181
11182 // Note: We don't use |referrer| when our global history is
11183 // based on IHistory.
11184 nsCOMPtr<nsIURI> referrer;
11185 // Treat referrer as null if there is an error getting it.
11186 (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
11187
11188 AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
11189 }
11190
11191 // If this was a history load or a refresh, or it was a history load but
11192 // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index
11193 // in session history.
11194 if (rootSH && ((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) ||
11195 mLoadType == LOAD_NORMAL_REPLACE)) {
11196 nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
11197 if (shInternal) {
11198 rootSH->GetIndex(&mPreviousTransIndex);
11199 shInternal->UpdateIndex();
11200 rootSH->GetIndex(&mLoadedTransIndex);
11201 #ifdef DEBUG_PAGE_CACHE
11202 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
11203 mLoadedTransIndex);
11204 #endif
11205 }
11206 }
11207
11208 // aCloneSHChildren exactly means "we are not loading a new document".
11209 uint32_t locationFlags =
11210 aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
11211
11212 bool onLocationChangeNeeded =
11213 SetCurrentURI(aURI, aChannel, aFireOnLocationChange, locationFlags);
11214 // Make sure to store the referrer from the channel, if any
11215 SetupReferrerFromChannel(aChannel);
11216 return onLocationChangeNeeded;
11217 }
11218
OnLoadingSite(nsIChannel * aChannel,bool aFireOnLocationChange,bool aAddToGlobalHistory)11219 bool nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange,
11220 bool aAddToGlobalHistory) {
11221 nsCOMPtr<nsIURI> uri;
11222 // If this a redirect, use the final url (uri)
11223 // else use the original url
11224 //
11225 // Note that this should match what documents do (see nsDocument::Reset).
11226 NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
11227 NS_ENSURE_TRUE(uri, false);
11228
11229 // Pass false for aCloneSHChildren, since we're loading a new page here.
11230 return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType,
11231 aFireOnLocationChange, aAddToGlobalHistory, false);
11232 }
11233
SetReferrerURI(nsIURI * aURI)11234 void nsDocShell::SetReferrerURI(nsIURI* aURI) {
11235 mReferrerURI = aURI; // This assigment addrefs
11236 }
11237
SetReferrerPolicy(uint32_t aReferrerPolicy)11238 void nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy) {
11239 mReferrerPolicy = aReferrerPolicy;
11240 }
11241
11242 //*****************************************************************************
11243 // nsDocShell: Session History
11244 //*****************************************************************************
11245
11246 NS_IMETHODIMP
AddState(JS::Handle<JS::Value> aData,const nsAString & aTitle,const nsAString & aURL,bool aReplace,JSContext * aCx)11247 nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
11248 const nsAString& aURL, bool aReplace, JSContext* aCx) {
11249 // Implements History.pushState and History.replaceState
11250
11251 // Here's what we do, roughly in the order specified by HTML5:
11252 // 1. Serialize aData using structured clone.
11253 // 2. If the third argument is present,
11254 // a. Resolve the url, relative to the first script's base URL
11255 // b. If (a) fails, raise a SECURITY_ERR
11256 // c. Compare the resulting absolute URL to the document's address. If
11257 // any part of the URLs difer other than the <path>, <query>, and
11258 // <fragment> components, raise a SECURITY_ERR and abort.
11259 // 3. If !aReplace:
11260 // Remove from the session history all entries after the current entry,
11261 // as we would after a regular navigation, and save the current
11262 // entry's scroll position (bug 590573).
11263 // 4. As apropriate, either add a state object entry to the session history
11264 // after the current entry with the following properties, or modify the
11265 // current session history entry to set
11266 // a. cloned data as the state object,
11267 // b. if the third argument was present, the absolute URL found in
11268 // step 2
11269 // Also clear the new history entry's POST data (see bug 580069).
11270 // 5. If aReplace is false (i.e. we're doing a pushState instead of a
11271 // replaceState), notify bfcache that we've navigated to a new page.
11272 // 6. If the third argument is present, set the document's current address
11273 // to the absolute URL found in step 2.
11274 //
11275 // It's important that this function not run arbitrary scripts after step 1
11276 // and before completing step 5. For example, if a script called
11277 // history.back() before we completed step 5, bfcache might destroy an
11278 // active content viewer. Since EvictOutOfRangeContentViewers at the end of
11279 // step 5 might run script, we can't just put a script blocker around the
11280 // critical section.
11281 //
11282 // Note that we completely ignore the aTitle parameter.
11283
11284 nsresult rv;
11285
11286 // Don't clobber the load type of an existing network load.
11287 AutoRestore<uint32_t> loadTypeResetter(mLoadType);
11288
11289 // pushState effectively becomes replaceState when we've started a network
11290 // load but haven't adopted its document yet. This mirrors what we do with
11291 // changes to the hash at this stage of the game.
11292 if (JustStartedNetworkLoad()) {
11293 aReplace = true;
11294 }
11295
11296 nsCOMPtr<nsIDocument> document = GetDocument();
11297 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
11298
11299 // Step 1: Serialize aData using structured clone.
11300 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
11301
11302 // scContainer->Init might cause arbitrary JS to run, and this code might
11303 // navigate the page we're on, potentially to a different origin! (bug
11304 // 634834) To protect against this, we abort if our principal changes due
11305 // to the InitFromJSVal() call.
11306 {
11307 nsCOMPtr<nsIDocument> origDocument = GetDocument();
11308 if (!origDocument) {
11309 return NS_ERROR_DOM_SECURITY_ERR;
11310 }
11311 nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
11312
11313 scContainer = new nsStructuredCloneContainer();
11314 rv = scContainer->InitFromJSVal(aData, aCx);
11315 NS_ENSURE_SUCCESS(rv, rv);
11316
11317 nsCOMPtr<nsIDocument> newDocument = GetDocument();
11318 if (!newDocument) {
11319 return NS_ERROR_DOM_SECURITY_ERR;
11320 }
11321 nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
11322
11323 bool principalsEqual = false;
11324 origPrincipal->Equals(newPrincipal, &principalsEqual);
11325 NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
11326 }
11327
11328 // Check that the state object isn't too long.
11329 // Default max length: 640k bytes.
11330 int32_t maxStateObjSize =
11331 Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
11332 if (maxStateObjSize < 0) {
11333 maxStateObjSize = 0;
11334 }
11335
11336 uint64_t scSize;
11337 rv = scContainer->GetSerializedNBytes(&scSize);
11338 NS_ENSURE_SUCCESS(rv, rv);
11339
11340 NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE);
11341
11342 // Step 2: Resolve aURL
11343 bool equalURIs = true;
11344 nsCOMPtr<nsIURI> currentURI;
11345 if (sURIFixup && mCurrentURI) {
11346 rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(currentURI));
11347 NS_ENSURE_SUCCESS(rv, rv);
11348 } else {
11349 currentURI = mCurrentURI;
11350 }
11351 nsCOMPtr<nsIURI> oldURI = currentURI;
11352 nsCOMPtr<nsIURI> newURI;
11353 if (aURL.Length() == 0) {
11354 newURI = currentURI;
11355 } else {
11356 // 2a: Resolve aURL relative to mURI
11357
11358 nsIURI* docBaseURI = document->GetDocBaseURI();
11359 if (!docBaseURI) {
11360 return NS_ERROR_FAILURE;
11361 }
11362
11363 nsAutoCString spec;
11364 docBaseURI->GetSpec(spec);
11365
11366 rv = NS_NewURI(getter_AddRefs(newURI), aURL,
11367 document->GetDocumentCharacterSet(), docBaseURI);
11368
11369 // 2b: If 2a fails, raise a SECURITY_ERR
11370 if (NS_FAILED(rv)) {
11371 return NS_ERROR_DOM_SECURITY_ERR;
11372 }
11373
11374 // 2c: Same-origin check.
11375 if (!nsContentUtils::URIIsLocalFile(newURI)) {
11376 // In addition to checking that the security manager says that
11377 // the new URI has the same origin as our current URI, we also
11378 // check that the two URIs have the same userpass. (The
11379 // security manager says that |http://foo.com| and
11380 // |http://me@foo.com| have the same origin.) currentURI
11381 // won't contain the password part of the userpass, so this
11382 // means that it's never valid to specify a password in a
11383 // pushState or replaceState URI.
11384
11385 nsCOMPtr<nsIScriptSecurityManager> secMan =
11386 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
11387 NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
11388
11389 // It's very important that we check that newURI is of the same
11390 // origin as currentURI, not docBaseURI, because a page can
11391 // set docBaseURI arbitrarily to any domain.
11392 nsAutoCString currentUserPass, newUserPass;
11393 NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
11394 NS_ERROR_FAILURE);
11395 NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE);
11396 if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true)) ||
11397 !currentUserPass.Equals(newUserPass)) {
11398 return NS_ERROR_DOM_SECURITY_ERR;
11399 }
11400 } else {
11401 // It's a file:// URI
11402 nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
11403 do_QueryInterface(document);
11404
11405 if (!docScriptObj) {
11406 return NS_ERROR_DOM_SECURITY_ERR;
11407 }
11408
11409 nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
11410
11411 if (!principal ||
11412 NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
11413 return NS_ERROR_DOM_SECURITY_ERR;
11414 }
11415 }
11416
11417 if (currentURI) {
11418 currentURI->Equals(newURI, &equalURIs);
11419 } else {
11420 equalURIs = false;
11421 }
11422
11423 } // end of same-origin check
11424
11425 // Step 3: Create a new entry in the session history. This will erase
11426 // all SHEntries after the new entry and make this entry the current
11427 // one. This operation may modify mOSHE, which we need later, so we
11428 // keep a reference here.
11429 NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
11430 nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
11431
11432 mLoadType = LOAD_PUSHSTATE;
11433
11434 nsCOMPtr<nsISHEntry> newSHEntry;
11435 if (!aReplace) {
11436 // Save the current scroll position (bug 590573).
11437 nscoord cx = 0, cy = 0;
11438 GetCurScrollPos(ScrollOrientation_X, &cx);
11439 GetCurScrollPos(ScrollOrientation_Y, &cy);
11440 mOSHE->SetScrollPosition(cx, cy);
11441
11442 bool scrollRestorationIsManual = false;
11443 mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
11444
11445 // Since we're not changing which page we have loaded, pass
11446 // true for aCloneChildren.
11447 rv = AddToSessionHistory(newURI, nullptr,
11448 document->NodePrincipal(), // triggeringPrincipal
11449 nullptr, true, getter_AddRefs(newSHEntry));
11450 NS_ENSURE_SUCCESS(rv, rv);
11451
11452 NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
11453
11454 // Session history entries created by pushState inherit scroll restoration
11455 // mode from the current entry.
11456 newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
11457
11458 // Link the new SHEntry to the old SHEntry's BFCache entry, since the
11459 // two entries correspond to the same document.
11460 NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
11461
11462 // Set the new SHEntry's title (bug 655273).
11463 nsString title;
11464 mOSHE->GetTitle(getter_Copies(title));
11465 newSHEntry->SetTitle(title);
11466
11467 // AddToSessionHistory may not modify mOSHE. In case it doesn't,
11468 // we'll just set mOSHE here.
11469 mOSHE = newSHEntry;
11470
11471 } else {
11472 newSHEntry = mOSHE;
11473 newSHEntry->SetURI(newURI);
11474 newSHEntry->SetOriginalURI(newURI);
11475 newSHEntry->SetLoadReplace(false);
11476 }
11477
11478 // Step 4: Modify new/original session history entry and clear its POST
11479 // data, if there is any.
11480 newSHEntry->SetStateData(scContainer);
11481 newSHEntry->SetPostData(nullptr);
11482
11483 // If this push/replaceState changed the document's current URI and the new
11484 // URI differs from the old URI in more than the hash, or if the old
11485 // SHEntry's URI was modified in this way by a push/replaceState call
11486 // set URIWasModified to true for the current SHEntry (bug 669671).
11487 bool sameExceptHashes = true, oldURIWasModified = false;
11488 newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
11489 oldOSHE->GetURIWasModified(&oldURIWasModified);
11490 newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
11491
11492 // Step 5: If aReplace is false, indicating that we're doing a pushState
11493 // rather than a replaceState, notify bfcache that we've added a page to
11494 // the history so it can evict content viewers if appropriate. Otherwise
11495 // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
11496 // was replaced.
11497 nsCOMPtr<nsISHistory> rootSH;
11498 GetRootSessionHistory(getter_AddRefs(rootSH));
11499 NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
11500
11501 nsCOMPtr<nsISHistoryInternal> internalSH = do_QueryInterface(rootSH);
11502 NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
11503
11504 if (!aReplace) {
11505 int32_t curIndex = -1;
11506 rv = rootSH->GetIndex(&curIndex);
11507 if (NS_SUCCEEDED(rv) && curIndex > -1) {
11508 internalSH->EvictOutOfRangeContentViewers(curIndex);
11509 }
11510 } else {
11511 nsCOMPtr<nsISHEntry> rootSHEntry = nsSHistory::GetRootSHEntry(newSHEntry);
11512
11513 int32_t index = -1;
11514 rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
11515 if (NS_SUCCEEDED(rv) && index > -1) {
11516 internalSH->ReplaceEntry(index, rootSHEntry);
11517 }
11518 }
11519
11520 // Step 6: If the document's URI changed, update document's URI and update
11521 // global history.
11522 //
11523 // We need to call FireOnLocationChange so that the browser's address bar
11524 // gets updated and the back button is enabled, but we only need to
11525 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
11526 // since SetCurrentURI will call FireOnLocationChange for us.
11527 //
11528 // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
11529 // nullptr for aRequest param to FireOnLocationChange(...). Such an update
11530 // notification is allowed only when we know docshell is not loading a new
11531 // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
11532 // FireOnLocationChange(...) breaks security UI.
11533 if (!equalURIs) {
11534 document->SetDocumentURI(newURI);
11535 // We can't trust SetCurrentURI to do always fire locationchange events
11536 // when we expect it to, so we hack around that by doing it ourselves...
11537 SetCurrentURI(newURI, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT);
11538 if (mLoadType != LOAD_ERROR_PAGE) {
11539 FireDummyOnLocationChange();
11540 }
11541
11542 AddURIVisit(newURI, oldURI, oldURI, 0);
11543
11544 // AddURIVisit doesn't set the title for the new URI in global history,
11545 // so do that here.
11546 UpdateGlobalHistoryTitle(newURI);
11547
11548 // Inform the favicon service that our old favicon applies to this new
11549 // URI.
11550 CopyFavicon(oldURI, newURI, document->NodePrincipal(),
11551 UsePrivateBrowsing());
11552 } else {
11553 FireDummyOnLocationChange();
11554 }
11555 document->SetStateObject(scContainer);
11556
11557 return NS_OK;
11558 }
11559
11560 NS_IMETHODIMP
GetCurrentScrollRestorationIsManual(bool * aIsManual)11561 nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual) {
11562 *aIsManual = false;
11563 if (mOSHE) {
11564 mOSHE->GetScrollRestorationIsManual(aIsManual);
11565 }
11566
11567 return NS_OK;
11568 }
11569
11570 NS_IMETHODIMP
SetCurrentScrollRestorationIsManual(bool aIsManual)11571 nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual) {
11572 if (mOSHE) {
11573 mOSHE->SetScrollRestorationIsManual(aIsManual);
11574 }
11575
11576 return NS_OK;
11577 }
11578
ShouldAddToSessionHistory(nsIURI * aURI,nsIChannel * aChannel)11579 bool nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel) {
11580 // I believe none of the about: urls should go in the history. But then
11581 // that could just be me... If the intent is only deny about:blank then we
11582 // should just do a spec compare, rather than two gets of the scheme and
11583 // then the path. -Gagan
11584 nsresult rv;
11585 nsAutoCString buf;
11586
11587 rv = aURI->GetScheme(buf);
11588 if (NS_FAILED(rv)) {
11589 return false;
11590 }
11591
11592 if (buf.EqualsLiteral("about")) {
11593 rv = aURI->GetPathQueryRef(buf);
11594 if (NS_FAILED(rv)) {
11595 return false;
11596 }
11597
11598 if (buf.EqualsLiteral("blank")) {
11599 return false;
11600 }
11601 // We only want to add about:newtab if it's not privileged:
11602 if (buf.EqualsLiteral("newtab")) {
11603 NS_ENSURE_TRUE(aChannel, false);
11604 nsCOMPtr<nsIPrincipal> resultPrincipal;
11605 rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
11606 aChannel, getter_AddRefs(resultPrincipal));
11607 NS_ENSURE_SUCCESS(rv, false);
11608 return !nsContentUtils::IsSystemPrincipal(resultPrincipal);
11609 }
11610 }
11611
11612 return true;
11613 }
11614
AddToSessionHistory(nsIURI * aURI,nsIChannel * aChannel,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aPrincipalToInherit,bool aCloneChildren,nsISHEntry ** aNewEntry)11615 nsresult nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
11616 nsIPrincipal* aTriggeringPrincipal,
11617 nsIPrincipal* aPrincipalToInherit,
11618 bool aCloneChildren,
11619 nsISHEntry** aNewEntry) {
11620 NS_PRECONDITION(aURI, "uri is null");
11621 NS_PRECONDITION(!aChannel || !aTriggeringPrincipal,
11622 "Shouldn't have both set");
11623
11624 #if defined(DEBUG)
11625 if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
11626 nsAutoCString chanName;
11627 if (aChannel) {
11628 aChannel->GetName(chanName);
11629 } else {
11630 chanName.AssignLiteral("<no channel>");
11631 }
11632
11633 MOZ_LOG(gDocShellLog, LogLevel::Debug,
11634 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this,
11635 aURI->GetSpecOrDefault().get(), chanName.get()));
11636 }
11637 #endif
11638
11639 nsresult rv = NS_OK;
11640 nsCOMPtr<nsISHEntry> entry;
11641
11642 // Get a handle to the root docshell
11643 nsCOMPtr<nsIDocShellTreeItem> root;
11644 GetSameTypeRootTreeItem(getter_AddRefs(root));
11645 /*
11646 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
11647 * the existing SH entry in the page and replace the url and
11648 * other vitalities.
11649 */
11650 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
11651 root != static_cast<nsIDocShellTreeItem*>(this)) {
11652 // This is a subframe
11653 entry = mOSHE;
11654 nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
11655 if (shContainer) {
11656 int32_t childCount = 0;
11657 shContainer->GetChildCount(&childCount);
11658 // Remove all children of this entry
11659 for (int32_t i = childCount - 1; i >= 0; i--) {
11660 nsCOMPtr<nsISHEntry> child;
11661 shContainer->GetChildAt(i, getter_AddRefs(child));
11662 shContainer->RemoveChild(child);
11663 }
11664 entry->AbandonBFCacheEntry();
11665 }
11666 }
11667
11668 // Create a new entry if necessary.
11669 if (!entry) {
11670 entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
11671
11672 if (!entry) {
11673 return NS_ERROR_OUT_OF_MEMORY;
11674 }
11675 }
11676
11677 // Get the post data & referrer
11678 nsCOMPtr<nsIInputStream> inputStream;
11679 nsCOMPtr<nsIURI> originalURI;
11680 nsCOMPtr<nsIURI> resultPrincipalURI;
11681 bool loadReplace = false;
11682 nsCOMPtr<nsIURI> referrerURI;
11683 uint32_t referrerPolicy = mozilla::net::RP_Unset;
11684 nsCOMPtr<nsISupports> cacheKey;
11685 nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
11686 nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
11687 bool expired = false;
11688 bool discardLayoutState = false;
11689 nsCOMPtr<nsICacheInfoChannel> cacheChannel;
11690 if (aChannel) {
11691 cacheChannel = do_QueryInterface(aChannel);
11692
11693 /* If there is a caching channel, get the Cache Key and store it
11694 * in SH.
11695 */
11696 if (cacheChannel) {
11697 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
11698 }
11699 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11700
11701 // Check if the httpChannel is hiding under a multipartChannel
11702 if (!httpChannel) {
11703 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11704 }
11705 if (httpChannel) {
11706 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11707 if (uploadChannel) {
11708 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11709 }
11710 httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
11711 uint32_t loadFlags;
11712 aChannel->GetLoadFlags(&loadFlags);
11713 loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
11714 rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI));
11715 MOZ_ASSERT(NS_SUCCEEDED(rv));
11716 rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
11717 MOZ_ASSERT(NS_SUCCEEDED(rv));
11718
11719 discardLayoutState = ShouldDiscardLayoutState(httpChannel);
11720 }
11721
11722 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
11723 if (loadInfo) {
11724 if (!triggeringPrincipal) {
11725 triggeringPrincipal = loadInfo->TriggeringPrincipal();
11726 }
11727
11728 loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
11729
11730 // For now keep storing just the principal in the SHEntry.
11731 if (!principalToInherit) {
11732 if (loadInfo->GetLoadingSandboxed()) {
11733 if (loadInfo->LoadingPrincipal()) {
11734 principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
11735 loadInfo->LoadingPrincipal());
11736 } else {
11737 // get the OriginAttributes
11738 OriginAttributes attrs;
11739 loadInfo->GetOriginAttributes(&attrs);
11740 principalToInherit = NullPrincipal::Create(attrs);
11741 }
11742 } else {
11743 principalToInherit = loadInfo->PrincipalToInherit();
11744 }
11745 }
11746 }
11747 }
11748
11749 // Title is set in nsDocShell::SetTitle()
11750 entry->Create(aURI, // uri
11751 EmptyString(), // Title
11752 inputStream, // Post data stream
11753 nullptr, // LayoutHistory state
11754 cacheKey, // CacheKey
11755 mContentTypeHint, // Content-type
11756 triggeringPrincipal, // Channel or provided principal
11757 principalToInherit, mHistoryID, mDynamicallyCreated);
11758
11759 entry->SetOriginalURI(originalURI);
11760 entry->SetResultPrincipalURI(resultPrincipalURI);
11761 entry->SetLoadReplace(loadReplace);
11762 entry->SetReferrerURI(referrerURI);
11763 entry->SetReferrerPolicy(referrerPolicy);
11764 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
11765 if (inStrmChan) {
11766 bool isSrcdocChannel;
11767 inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
11768 if (isSrcdocChannel) {
11769 nsAutoString srcdoc;
11770 inStrmChan->GetSrcdocData(srcdoc);
11771 entry->SetSrcdocData(srcdoc);
11772 nsCOMPtr<nsIURI> baseURI;
11773 inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
11774 entry->SetBaseURI(baseURI);
11775 }
11776 }
11777 /* If cache got a 'no-store', ask SH not to store
11778 * HistoryLayoutState. By default, SH will set this
11779 * flag to true and save HistoryLayoutState.
11780 */
11781 if (discardLayoutState) {
11782 entry->SetSaveLayoutStateFlag(false);
11783 }
11784 if (cacheChannel) {
11785 // Check if the page has expired from cache
11786 uint32_t expTime = 0;
11787 cacheChannel->GetCacheTokenExpirationTime(&expTime);
11788 uint32_t now = PRTimeToSeconds(PR_Now());
11789 if (expTime <= now) {
11790 expired = true;
11791 }
11792 }
11793 if (expired) {
11794 entry->SetExpirationStatus(true);
11795 }
11796
11797 if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) {
11798 // If we need to clone our children onto the new session
11799 // history entry, do so now.
11800 if (aCloneChildren && mOSHE) {
11801 uint32_t cloneID;
11802 mOSHE->GetID(&cloneID);
11803 nsCOMPtr<nsISHEntry> newEntry;
11804 nsSHistory::CloneAndReplace(mOSHE, this, cloneID, entry, true,
11805 getter_AddRefs(newEntry));
11806 NS_ASSERTION(entry == newEntry,
11807 "The new session history should be in the new entry");
11808 }
11809
11810 // This is the root docshell
11811 bool addToSHistory =
11812 !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
11813 if (!addToSHistory) {
11814 // Replace current entry in session history; If the requested index is
11815 // valid, it indicates the loading was triggered by a history load, and
11816 // we should replace the entry at requested index instead.
11817 int32_t index = 0;
11818 mSessionHistory->GetRequestedIndex(&index);
11819 if (index == -1) {
11820 mSessionHistory->GetIndex(&index);
11821 }
11822 nsCOMPtr<nsISHistoryInternal> shPrivate =
11823 do_QueryInterface(mSessionHistory);
11824 // Replace the current entry with the new entry
11825 if (index >= 0) {
11826 if (shPrivate) {
11827 rv = shPrivate->ReplaceEntry(index, entry);
11828 }
11829 } else {
11830 // If we're trying to replace an inexistant shistory entry, append.
11831 addToSHistory = true;
11832 }
11833 }
11834
11835 if (addToSHistory) {
11836 // Add to session history
11837 nsCOMPtr<nsISHistoryInternal> shPrivate =
11838 do_QueryInterface(mSessionHistory);
11839 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
11840 mSessionHistory->GetIndex(&mPreviousTransIndex);
11841
11842 bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel);
11843 rv = shPrivate->AddEntry(entry, shouldPersist);
11844 mSessionHistory->GetIndex(&mLoadedTransIndex);
11845 #ifdef DEBUG_PAGE_CACHE
11846 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
11847 mLoadedTransIndex);
11848 #endif
11849 }
11850 } else {
11851 // This is a subframe.
11852 if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
11853 rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren);
11854 }
11855 }
11856
11857 // Return the new SH entry...
11858 if (aNewEntry) {
11859 *aNewEntry = nullptr;
11860 if (NS_SUCCEEDED(rv)) {
11861 entry.forget(aNewEntry);
11862 }
11863 }
11864
11865 return rv;
11866 }
11867
LoadHistoryEntry(nsISHEntry * aEntry,uint32_t aLoadType)11868 nsresult nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) {
11869 if (!IsNavigationAllowed()) {
11870 return NS_OK;
11871 }
11872
11873 nsCOMPtr<nsIURI> uri;
11874 nsCOMPtr<nsIURI> originalURI;
11875 nsCOMPtr<nsIURI> resultPrincipalURI;
11876 bool loadReplace = false;
11877 nsCOMPtr<nsIInputStream> postData;
11878 nsCOMPtr<nsIURI> referrerURI;
11879 uint32_t referrerPolicy;
11880 nsAutoCString contentType;
11881 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
11882 nsCOMPtr<nsIPrincipal> principalToInherit;
11883
11884 NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
11885
11886 NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
11887 NS_ENSURE_SUCCESS(aEntry->GetOriginalURI(getter_AddRefs(originalURI)),
11888 NS_ERROR_FAILURE);
11889 NS_ENSURE_SUCCESS(
11890 aEntry->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)),
11891 NS_ERROR_FAILURE);
11892 NS_ENSURE_SUCCESS(aEntry->GetLoadReplace(&loadReplace), NS_ERROR_FAILURE);
11893 NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
11894 NS_ERROR_FAILURE);
11895 NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
11896 NS_ERROR_FAILURE);
11897 NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
11898 NS_ERROR_FAILURE);
11899 NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
11900 NS_ENSURE_SUCCESS(
11901 aEntry->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal)),
11902 NS_ERROR_FAILURE);
11903 NS_ENSURE_SUCCESS(
11904 aEntry->GetPrincipalToInherit(getter_AddRefs(principalToInherit)),
11905 NS_ERROR_FAILURE);
11906
11907 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
11908 // that's the only thing holding a ref to aEntry that will cause aEntry to
11909 // die while we're loading it. So hold a strong ref to aEntry here, just
11910 // in case.
11911 nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
11912 bool isJS;
11913 nsresult rv = uri->SchemeIs("javascript", &isJS);
11914 if (NS_FAILED(rv) || isJS) {
11915 // We're loading a URL that will execute script from inside asyncOpen.
11916 // Replace the current document with about:blank now to prevent
11917 // anything from the current document from leaking into any JavaScript
11918 // code in the URL.
11919 // Don't cache the presentation if we're going to just reload the
11920 // current entry. Caching would lead to trying to save the different
11921 // content viewers in the same nsISHEntry object.
11922 rv = CreateAboutBlankContentViewer(principalToInherit, nullptr,
11923 aEntry != mOSHE);
11924
11925 if (NS_FAILED(rv)) {
11926 // The creation of the intermittent about:blank content
11927 // viewer failed for some reason (potentially because the
11928 // user prevented it). Interrupt the history load.
11929 return NS_OK;
11930 }
11931
11932 if (!triggeringPrincipal) {
11933 // Ensure that we have a triggeringPrincipal. Otherwise javascript:
11934 // URIs will pick it up from the about:blank page we just loaded,
11935 // and we don't really want even that in this case.
11936 triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this);
11937 }
11938 }
11939
11940 /* If there is a valid postdata *and* the user pressed
11941 * reload or shift-reload, take user's permission before we
11942 * repost the data to the server.
11943 */
11944 if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
11945 bool repost;
11946 rv = ConfirmRepost(&repost);
11947 if (NS_FAILED(rv)) {
11948 return rv;
11949 }
11950
11951 // If the user pressed cancel in the dialog, return. We're done here.
11952 if (!repost) {
11953 return NS_BINDING_ABORTED;
11954 }
11955 }
11956
11957 // Do not inherit principal from document (security-critical!);
11958 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
11959
11960 nsAutoString srcdoc;
11961 bool isSrcdoc;
11962 nsCOMPtr<nsIURI> baseURI;
11963 aEntry->GetIsSrcdocEntry(&isSrcdoc);
11964 if (isSrcdoc) {
11965 aEntry->GetSrcdocData(srcdoc);
11966 aEntry->GetBaseURI(getter_AddRefs(baseURI));
11967 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
11968 } else {
11969 srcdoc = VoidString();
11970 }
11971
11972 // If there is no valid triggeringPrincipal, we deny the load
11973 MOZ_ASSERT(triggeringPrincipal,
11974 "need a valid triggeringPrincipal to load from history");
11975 if (!triggeringPrincipal) {
11976 return NS_ERROR_FAILURE;
11977 }
11978
11979 // Passing nullptr as aSourceDocShell gives the same behaviour as before
11980 // aSourceDocShell was introduced. According to spec we should be passing
11981 // the source browsing context that was used when the history entry was
11982 // first created. bug 947716 has been created to address this issue.
11983 Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
11984 emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
11985 rv = InternalLoad(uri, originalURI, emplacedResultPrincipalURI, false,
11986 loadReplace,
11987 false, // IsFromProcessingFrameAttributes
11988 referrerURI, referrerPolicy, triggeringPrincipal,
11989 principalToInherit, flags,
11990 EmptyString(), // No window target
11991 contentType.get(), // Type hint
11992 VoidString(), // No forced file download
11993 postData, // Post data stream
11994 -1, // Post data stream length
11995 nullptr, // No headers stream
11996 aLoadType, // Load type
11997 aEntry, // SHEntry
11998 true, srcdoc,
11999 nullptr, // Source docshell, see comment above
12000 baseURI,
12001 nullptr, // No nsIDocShell
12002 nullptr); // No nsIRequest
12003 return rv;
12004 }
12005
12006 NS_IMETHODIMP
GetShouldSaveLayoutState(bool * aShould)12007 nsDocShell::GetShouldSaveLayoutState(bool* aShould) {
12008 *aShould = false;
12009 if (mOSHE) {
12010 // Don't capture historystate and save it in history
12011 // if the page asked not to do so.
12012 mOSHE->GetSaveLayoutStateFlag(aShould);
12013 }
12014
12015 return NS_OK;
12016 }
12017
PersistLayoutHistoryState()12018 nsresult nsDocShell::PersistLayoutHistoryState() {
12019 nsresult rv = NS_OK;
12020
12021 if (mOSHE) {
12022 bool scrollRestorationIsManual = false;
12023 mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
12024
12025 nsCOMPtr<nsIPresShell> shell = GetPresShell();
12026 nsCOMPtr<nsILayoutHistoryState> layoutState;
12027 if (shell) {
12028 rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
12029 } else if (scrollRestorationIsManual) {
12030 // Even if we don't have layout anymore, we may want to reset the current
12031 // scroll state in layout history.
12032 GetLayoutHistoryState(getter_AddRefs(layoutState));
12033 }
12034
12035 if (scrollRestorationIsManual && layoutState) {
12036 layoutState->ResetScrollState();
12037 }
12038 }
12039
12040 return rv;
12041 }
12042
SwapHistoryEntries(nsISHEntry * aOldEntry,nsISHEntry * aNewEntry)12043 void nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry,
12044 nsISHEntry* aNewEntry) {
12045 if (aOldEntry == mOSHE) {
12046 mOSHE = aNewEntry;
12047 }
12048
12049 if (aOldEntry == mLSHE) {
12050 mLSHE = aNewEntry;
12051 }
12052 }
12053
SetHistoryEntry(nsCOMPtr<nsISHEntry> * aPtr,nsISHEntry * aEntry)12054 void nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr,
12055 nsISHEntry* aEntry) {
12056 // We need to sync up the docshell and session history trees for
12057 // subframe navigation. If the load was in a subframe, we forward up to
12058 // the root docshell, which will then recursively sync up all docshells
12059 // to their corresponding entries in the new session history tree.
12060 // If we don't do this, then we can cache a content viewer on the wrong
12061 // cloned entry, and subsequently restore it at the wrong time.
12062
12063 nsISHEntry* newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
12064 if (newRootEntry) {
12065 // newRootEntry is now the new root entry.
12066 // Find the old root entry as well.
12067
12068 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
12069 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
12070 nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr);
12071 if (oldRootEntry) {
12072 nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
12073 GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
12074 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
12075 if (rootShell) { // if we're the root just set it, nothing to swap
12076 nsSHistory::SwapEntriesData data = {this, newRootEntry};
12077 nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell);
12078 nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
12079
12080 #ifdef DEBUG
12081 nsresult rv =
12082 #endif
12083 nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0,
12084 &data);
12085 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
12086 }
12087 }
12088 }
12089
12090 *aPtr = aEntry;
12091 }
12092
GetRootSessionHistory(nsISHistory ** aReturn)12093 nsresult nsDocShell::GetRootSessionHistory(nsISHistory** aReturn) {
12094 nsresult rv;
12095
12096 nsCOMPtr<nsIDocShellTreeItem> root;
12097 // Get the root docshell
12098 rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
12099 // QI to nsIWebNavigation
12100 nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
12101 if (rootAsWebnav) {
12102 // Get the handle to SH from the root docshell
12103 rv = rootAsWebnav->GetSessionHistory(aReturn);
12104 }
12105 return rv;
12106 }
12107
GetHttpChannel(nsIChannel * aChannel,nsIHttpChannel ** aReturn)12108 nsresult nsDocShell::GetHttpChannel(nsIChannel* aChannel,
12109 nsIHttpChannel** aReturn) {
12110 NS_ENSURE_ARG_POINTER(aReturn);
12111 if (!aChannel) {
12112 return NS_ERROR_FAILURE;
12113 }
12114
12115 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
12116 if (multiPartChannel) {
12117 nsCOMPtr<nsIChannel> baseChannel;
12118 multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
12119 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
12120 *aReturn = httpChannel;
12121 NS_IF_ADDREF(*aReturn);
12122 }
12123 return NS_OK;
12124 }
12125
ShouldDiscardLayoutState(nsIHttpChannel * aChannel)12126 bool nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel) {
12127 // By default layout State will be saved.
12128 if (!aChannel) {
12129 return false;
12130 }
12131
12132 // figure out if SH should be saving layout state
12133 bool noStore = false;
12134 Unused << aChannel->IsNoStoreResponse(&noStore);
12135 return noStore;
12136 }
12137
12138 NS_IMETHODIMP
GetEditor(nsIEditor ** aEditor)12139 nsDocShell::GetEditor(nsIEditor** aEditor) {
12140 NS_ENSURE_ARG_POINTER(aEditor);
12141 RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorInternal();
12142 htmlEditor.forget(aEditor);
12143 return NS_OK;
12144 }
12145
12146 NS_IMETHODIMP
SetEditor(nsIEditor * aEditor)12147 nsDocShell::SetEditor(nsIEditor* aEditor) {
12148 HTMLEditor* htmlEditor = aEditor ? aEditor->AsHTMLEditor() : nullptr;
12149 // If TextEditor comes, throw an error.
12150 if (aEditor && !htmlEditor) {
12151 return NS_ERROR_INVALID_ARG;
12152 }
12153 return SetHTMLEditorInternal(htmlEditor);
12154 }
12155
GetHTMLEditorInternal()12156 HTMLEditor* nsDocShell::GetHTMLEditorInternal() {
12157 return mEditorData ? mEditorData->GetHTMLEditor() : nullptr;
12158 }
12159
SetHTMLEditorInternal(HTMLEditor * aHTMLEditor)12160 nsresult nsDocShell::SetHTMLEditorInternal(HTMLEditor* aHTMLEditor) {
12161 if (!aHTMLEditor && !mEditorData) {
12162 return NS_OK;
12163 }
12164
12165 nsresult rv = EnsureEditorData();
12166 if (NS_FAILED(rv)) {
12167 return rv;
12168 }
12169
12170 return mEditorData->SetHTMLEditor(aHTMLEditor);
12171 }
12172
12173 NS_IMETHODIMP
GetEditable(bool * aEditable)12174 nsDocShell::GetEditable(bool* aEditable) {
12175 NS_ENSURE_ARG_POINTER(aEditable);
12176 *aEditable = mEditorData && mEditorData->GetEditable();
12177 return NS_OK;
12178 }
12179
12180 NS_IMETHODIMP
GetHasEditingSession(bool * aHasEditingSession)12181 nsDocShell::GetHasEditingSession(bool* aHasEditingSession) {
12182 NS_ENSURE_ARG_POINTER(aHasEditingSession);
12183
12184 if (mEditorData) {
12185 nsCOMPtr<nsIEditingSession> editingSession;
12186 mEditorData->GetEditingSession(getter_AddRefs(editingSession));
12187 *aHasEditingSession = (editingSession.get() != nullptr);
12188 } else {
12189 *aHasEditingSession = false;
12190 }
12191
12192 return NS_OK;
12193 }
12194
12195 NS_IMETHODIMP
MakeEditable(bool aInWaitForUriLoad)12196 nsDocShell::MakeEditable(bool aInWaitForUriLoad) {
12197 nsresult rv = EnsureEditorData();
12198 if (NS_FAILED(rv)) {
12199 return rv;
12200 }
12201
12202 return mEditorData->MakeEditable(aInWaitForUriLoad);
12203 }
12204
ChannelIsPost(nsIChannel * aChannel)12205 bool nsDocShell::ChannelIsPost(nsIChannel* aChannel) {
12206 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
12207 if (!httpChannel) {
12208 return false;
12209 }
12210
12211 nsAutoCString method;
12212 Unused << httpChannel->GetRequestMethod(method);
12213 return method.EqualsLiteral("POST");
12214 }
12215
ExtractLastVisit(nsIChannel * aChannel,nsIURI ** aURI,uint32_t * aChannelRedirectFlags)12216 void nsDocShell::ExtractLastVisit(nsIChannel* aChannel, nsIURI** aURI,
12217 uint32_t* aChannelRedirectFlags) {
12218 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
12219 if (!props) {
12220 return;
12221 }
12222
12223 nsresult rv = props->GetPropertyAsInterface(
12224 NS_LITERAL_STRING("docshell.previousURI"), NS_GET_IID(nsIURI),
12225 reinterpret_cast<void**>(aURI));
12226
12227 if (NS_FAILED(rv)) {
12228 // There is no last visit for this channel, so this must be the first
12229 // link. Link the visit to the referrer of this request, if any.
12230 // Treat referrer as null if there is an error getting it.
12231 (void)NS_GetReferrerFromChannel(aChannel, aURI);
12232 } else {
12233 rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12234 aChannelRedirectFlags);
12235
12236 NS_WARNING_ASSERTION(
12237 NS_SUCCEEDED(rv),
12238 "Could not fetch previous flags, URI will be treated like referrer");
12239 }
12240 }
12241
SaveLastVisit(nsIChannel * aChannel,nsIURI * aURI,uint32_t aChannelRedirectFlags)12242 void nsDocShell::SaveLastVisit(nsIChannel* aChannel, nsIURI* aURI,
12243 uint32_t aChannelRedirectFlags) {
12244 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
12245 if (!props || !aURI) {
12246 return;
12247 }
12248
12249 props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
12250 aURI);
12251 props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12252 aChannelRedirectFlags);
12253 }
12254
AddURIVisit(nsIURI * aURI,nsIURI * aReferrerURI,nsIURI * aPreviousURI,uint32_t aChannelRedirectFlags,uint32_t aResponseStatus)12255 void nsDocShell::AddURIVisit(nsIURI* aURI, nsIURI* aReferrerURI,
12256 nsIURI* aPreviousURI,
12257 uint32_t aChannelRedirectFlags,
12258 uint32_t aResponseStatus) {
12259 MOZ_ASSERT(aURI, "Visited URI is null!");
12260 MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE && mLoadType != LOAD_BYPASS_HISTORY,
12261 "Do not add error or bypass pages to global history");
12262
12263 // Only content-type docshells save URI visits. Also don't do
12264 // anything here if we're not supposed to use global history.
12265 if (mItemType != typeContent || !mUseGlobalHistory || UsePrivateBrowsing()) {
12266 return;
12267 }
12268
12269 nsCOMPtr<IHistory> history = services::GetHistoryService();
12270
12271 if (history) {
12272 uint32_t visitURIFlags = 0;
12273
12274 if (!IsFrame()) {
12275 visitURIFlags |= IHistory::TOP_LEVEL;
12276 }
12277
12278 if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
12279 visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
12280 } else if (aChannelRedirectFlags &
12281 nsIChannelEventSink::REDIRECT_PERMANENT) {
12282 visitURIFlags |= IHistory::REDIRECT_PERMANENT;
12283 } else {
12284 MOZ_ASSERT(!aChannelRedirectFlags,
12285 "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
12286 "if any flags in aChannelRedirectFlags is set.");
12287 }
12288
12289 if (aResponseStatus >= 300 && aResponseStatus < 400) {
12290 visitURIFlags |= IHistory::REDIRECT_SOURCE;
12291 }
12292 // Errors 400-501 and 505 are considered unrecoverable, in the sense a
12293 // simple retry attempt by the user is unlikely to solve them.
12294 // 408 is special cased, since may actually indicate a temporary
12295 // connection problem.
12296 else if (aResponseStatus != 408 &&
12297 ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
12298 aResponseStatus == 505)) {
12299 visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
12300 }
12301
12302 (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
12303 } else if (mGlobalHistory) {
12304 // Falls back to sync global history interface.
12305 (void)mGlobalHistory->AddURI(aURI, !!aChannelRedirectFlags, !IsFrame(),
12306 aReferrerURI);
12307 }
12308 }
12309
12310 //*****************************************************************************
12311 // nsDocShell: Helper Routines
12312 //*****************************************************************************
12313
12314 NS_IMETHODIMP
SetLoadType(uint32_t aLoadType)12315 nsDocShell::SetLoadType(uint32_t aLoadType) {
12316 mLoadType = aLoadType;
12317 return NS_OK;
12318 }
12319
12320 NS_IMETHODIMP
GetLoadType(uint32_t * aLoadType)12321 nsDocShell::GetLoadType(uint32_t* aLoadType) {
12322 *aLoadType = mLoadType;
12323 return NS_OK;
12324 }
12325
ConfirmRepost(bool * aRepost)12326 nsresult nsDocShell::ConfirmRepost(bool* aRepost) {
12327 nsCOMPtr<nsIPrompt> prompter;
12328 CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
12329 if (!prompter) {
12330 return NS_ERROR_NOT_AVAILABLE;
12331 }
12332
12333 nsCOMPtr<nsIStringBundleService> stringBundleService =
12334 mozilla::services::GetStringBundleService();
12335 if (!stringBundleService) {
12336 return NS_ERROR_FAILURE;
12337 }
12338
12339 nsCOMPtr<nsIStringBundle> appBundle;
12340 nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
12341 getter_AddRefs(appBundle));
12342 NS_ENSURE_SUCCESS(rv, rv);
12343
12344 nsCOMPtr<nsIStringBundle> brandBundle;
12345 rv = stringBundleService->CreateBundle(kBrandBundleURL,
12346 getter_AddRefs(brandBundle));
12347 NS_ENSURE_SUCCESS(rv, rv);
12348
12349 NS_ASSERTION(prompter && brandBundle && appBundle,
12350 "Unable to set up repost prompter.");
12351
12352 nsAutoString brandName;
12353 rv = brandBundle->GetStringFromName("brandShortName", brandName);
12354
12355 nsAutoString msgString, button0Title;
12356 if (NS_FAILED(rv)) { // No brand, use the generic version.
12357 rv = appBundle->GetStringFromName("confirmRepostPrompt", msgString);
12358 } else {
12359 // Brand available - if the app has an override file with formatting, the
12360 // app name will be included. Without an override, the prompt will look
12361 // like the generic version.
12362 const char16_t* formatStrings[] = {brandName.get()};
12363 rv = appBundle->FormatStringFromName("confirmRepostPrompt", formatStrings,
12364 ArrayLength(formatStrings), msgString);
12365 }
12366 if (NS_FAILED(rv)) {
12367 return rv;
12368 }
12369
12370 rv = appBundle->GetStringFromName("resendButton.label", button0Title);
12371 if (NS_FAILED(rv)) {
12372 return rv;
12373 }
12374
12375 // Make the repost prompt tab modal to prevent malicious pages from locking
12376 // up the browser, see bug 1412559 for an example.
12377 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag =
12378 do_QueryInterface(prompter)) {
12379 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
12380 }
12381
12382 int32_t buttonPressed;
12383 // The actual value here is irrelevant, but we can't pass an invalid
12384 // bool through XPConnect.
12385 bool checkState = false;
12386 rv = prompter->ConfirmEx(
12387 nullptr, msgString.get(),
12388 (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
12389 (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
12390 button0Title.get(), nullptr, nullptr, nullptr, &checkState,
12391 &buttonPressed);
12392 if (NS_FAILED(rv)) {
12393 return rv;
12394 }
12395
12396 *aRepost = (buttonPressed == 0);
12397 return NS_OK;
12398 }
12399
GetPromptAndStringBundle(nsIPrompt ** aPrompt,nsIStringBundle ** aStringBundle)12400 nsresult nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
12401 nsIStringBundle** aStringBundle) {
12402 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt),
12403 NS_ERROR_FAILURE);
12404
12405 nsCOMPtr<nsIStringBundleService> stringBundleService =
12406 mozilla::services::GetStringBundleService();
12407 NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
12408
12409 NS_ENSURE_SUCCESS(
12410 stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle),
12411 NS_ERROR_FAILURE);
12412
12413 return NS_OK;
12414 }
12415
GetRootScrollFrame()12416 nsIScrollableFrame* nsDocShell::GetRootScrollFrame() {
12417 nsCOMPtr<nsIPresShell> shell = GetPresShell();
12418 NS_ENSURE_TRUE(shell, nullptr);
12419
12420 return shell->GetRootScrollFrameAsScrollable();
12421 }
12422
EnsureScriptEnvironment()12423 nsresult nsDocShell::EnsureScriptEnvironment() {
12424 if (mScriptGlobal) {
12425 return NS_OK;
12426 }
12427
12428 if (mIsBeingDestroyed) {
12429 return NS_ERROR_NOT_AVAILABLE;
12430 }
12431
12432 #ifdef DEBUG
12433 NS_ASSERTION(!mInEnsureScriptEnv,
12434 "Infinite loop! Calling EnsureScriptEnvironment() from "
12435 "within EnsureScriptEnvironment()!");
12436
12437 // Yeah, this isn't re-entrant safe, but that's ok since if we
12438 // re-enter this method, we'll infinitely loop...
12439 AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
12440 mInEnsureScriptEnv = true;
12441 #endif
12442
12443 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
12444 NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
12445
12446 uint32_t chromeFlags;
12447 browserChrome->GetChromeFlags(&chromeFlags);
12448
12449 // If our window is modal and we're not opened as chrome, make
12450 // this window a modal content window.
12451 mScriptGlobal = NS_NewScriptGlobalObject(mItemType == typeChrome);
12452 MOZ_ASSERT(mScriptGlobal);
12453
12454 mScriptGlobal->SetDocShell(this);
12455
12456 // Ensure the script object is set up to run script.
12457 return mScriptGlobal->EnsureScriptEnvironment();
12458 }
12459
EnsureEditorData()12460 nsresult nsDocShell::EnsureEditorData() {
12461 MOZ_ASSERT(!mIsBeingDestroyed);
12462
12463 bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
12464 if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
12465 // We shouldn't recreate the editor data if it already exists, or
12466 // we're shutting down, or we already have a detached editor data
12467 // stored in the session history. We should only have one editordata
12468 // per docshell.
12469 mEditorData = new nsDocShellEditorData(this);
12470 }
12471
12472 return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
12473 }
12474
EnsureTransferableHookData()12475 nsresult nsDocShell::EnsureTransferableHookData() {
12476 MOZ_ASSERT(!mIsBeingDestroyed);
12477
12478 if (!mTransferableHookData) {
12479 mTransferableHookData = new nsTransferableHookData();
12480 }
12481
12482 return NS_OK;
12483 }
12484
EnsureFind()12485 nsresult nsDocShell::EnsureFind() {
12486 nsresult rv;
12487 if (!mFind) {
12488 mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
12489 if (NS_FAILED(rv)) {
12490 return rv;
12491 }
12492 }
12493
12494 // we promise that the nsIWebBrowserFind that we return has been set
12495 // up to point to the focused, or content window, so we have to
12496 // set that up each time.
12497
12498 nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
12499 NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
12500
12501 // default to our window
12502 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO);
12503 nsCOMPtr<nsPIDOMWindowOuter> windowToSearch;
12504 nsFocusManager::GetFocusedDescendant(ourWindow,
12505 nsFocusManager::eIncludeAllDescendants,
12506 getter_AddRefs(windowToSearch));
12507
12508 nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
12509 if (!findInFrames) {
12510 return NS_ERROR_NO_INTERFACE;
12511 }
12512
12513 rv = findInFrames->SetRootSearchFrame(ourWindow);
12514 if (NS_FAILED(rv)) {
12515 return rv;
12516 }
12517 rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
12518 if (NS_FAILED(rv)) {
12519 return rv;
12520 }
12521
12522 return NS_OK;
12523 }
12524
IsFrame()12525 bool nsDocShell::IsFrame() {
12526 nsCOMPtr<nsIDocShellTreeItem> parent;
12527 GetSameTypeParent(getter_AddRefs(parent));
12528 return !!parent;
12529 }
12530
12531 NS_IMETHODIMP
IsBeingDestroyed(bool * aDoomed)12532 nsDocShell::IsBeingDestroyed(bool* aDoomed) {
12533 NS_ENSURE_ARG(aDoomed);
12534 *aDoomed = mIsBeingDestroyed;
12535 return NS_OK;
12536 }
12537
12538 NS_IMETHODIMP
GetIsExecutingOnLoadHandler(bool * aResult)12539 nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult) {
12540 NS_ENSURE_ARG(aResult);
12541 *aResult = mIsExecutingOnLoadHandler;
12542 return NS_OK;
12543 }
12544
12545 NS_IMETHODIMP
GetLayoutHistoryState(nsILayoutHistoryState ** aLayoutHistoryState)12546 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState) {
12547 if (mOSHE) {
12548 mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
12549 }
12550 return NS_OK;
12551 }
12552
12553 NS_IMETHODIMP
SetLayoutHistoryState(nsILayoutHistoryState * aLayoutHistoryState)12554 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState) {
12555 if (mOSHE) {
12556 mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
12557 }
12558 return NS_OK;
12559 }
12560
InterfaceRequestorProxy(nsIInterfaceRequestor * aRequestor)12561 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
12562 nsIInterfaceRequestor* aRequestor) {
12563 if (aRequestor) {
12564 mWeakPtr = do_GetWeakReference(aRequestor);
12565 }
12566 }
12567
~InterfaceRequestorProxy()12568 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy() {
12569 mWeakPtr = nullptr;
12570 }
12571
NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy,nsIInterfaceRequestor)12572 NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
12573
12574 NS_IMETHODIMP
12575 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID,
12576 void** aSink) {
12577 NS_ENSURE_ARG_POINTER(aSink);
12578 nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
12579 if (ifReq) {
12580 return ifReq->GetInterface(aIID, aSink);
12581 }
12582 *aSink = nullptr;
12583 return NS_NOINTERFACE;
12584 }
12585
SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer)12586 nsresult nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer) {
12587 if (!aContentViewer) {
12588 return NS_ERROR_FAILURE;
12589 }
12590
12591 nsCOMPtr<nsIURI> baseURI;
12592 nsresult rv = NS_ERROR_NOT_AVAILABLE;
12593
12594 if (sURIFixup) {
12595 rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI));
12596 }
12597
12598 // Get the current document and set the base uri
12599 if (baseURI) {
12600 nsIDocument* document = aContentViewer->GetDocument();
12601 if (document) {
12602 document->SetBaseURI(baseURI);
12603 }
12604 }
12605 return rv;
12606 }
12607
12608 //*****************************************************************************
12609 // nsDocShell::nsIAuthPromptProvider
12610 //*****************************************************************************
12611
12612 NS_IMETHODIMP
GetAuthPrompt(uint32_t aPromptReason,const nsIID & aIID,void ** aResult)12613 nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID,
12614 void** aResult) {
12615 // a priority prompt request will override a false mAllowAuth setting
12616 bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
12617
12618 if (!mAllowAuth && !priorityPrompt) {
12619 return NS_ERROR_NOT_AVAILABLE;
12620 }
12621
12622 // we're either allowing auth, or it's a proxy request
12623 nsresult rv;
12624 nsCOMPtr<nsIPromptFactory> wwatch =
12625 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
12626 NS_ENSURE_SUCCESS(rv, rv);
12627
12628 rv = EnsureScriptEnvironment();
12629 NS_ENSURE_SUCCESS(rv, rv);
12630
12631 // Get the an auth prompter for our window so that the parenting
12632 // of the dialogs works as it should when using tabs.
12633
12634 return wwatch->GetPrompt(mScriptGlobal->AsOuter(), aIID,
12635 reinterpret_cast<void**>(aResult));
12636 }
12637
12638 //*****************************************************************************
12639 // nsDocShell::nsILoadContext
12640 //*****************************************************************************
12641
12642 NS_IMETHODIMP
GetAssociatedWindow(mozIDOMWindowProxy ** aWindow)12643 nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow) {
12644 CallGetInterface(this, aWindow);
12645 return NS_OK;
12646 }
12647
12648 NS_IMETHODIMP
GetTopWindow(mozIDOMWindowProxy ** aWindow)12649 nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow) {
12650 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
12651 if (win) {
12652 win = win->GetTop();
12653 }
12654 win.forget(aWindow);
12655 return NS_OK;
12656 }
12657
12658 NS_IMETHODIMP
GetTopFrameElement(nsIDOMElement ** aElement)12659 nsDocShell::GetTopFrameElement(nsIDOMElement** aElement) {
12660 *aElement = nullptr;
12661 nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
12662 if (!win) {
12663 return NS_OK;
12664 }
12665
12666 nsCOMPtr<nsPIDOMWindowOuter> top = win->GetScriptableTop();
12667 NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
12668
12669 // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
12670 // inside <iframe mozbrowser>, we want to return the iframe, not null.
12671 // And we want to cross the content/chrome boundary.
12672 nsCOMPtr<nsIDOMElement> elt =
12673 do_QueryInterface(top->GetFrameElementInternal());
12674 elt.forget(aElement);
12675 return NS_OK;
12676 }
12677
12678 NS_IMETHODIMP
GetNestedFrameId(uint64_t * aId)12679 nsDocShell::GetNestedFrameId(uint64_t* aId) {
12680 *aId = 0;
12681 return NS_OK;
12682 }
12683
12684 NS_IMETHODIMP
GetUseTrackingProtection(bool * aUseTrackingProtection)12685 nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection) {
12686 *aUseTrackingProtection = false;
12687
12688 static bool sTPEnabled = false;
12689 static bool sTPInPBEnabled = false;
12690 static bool sPrefsInit = false;
12691
12692 if (!sPrefsInit) {
12693 sPrefsInit = true;
12694 Preferences::AddBoolVarCache(&sTPEnabled,
12695 "privacy.trackingprotection.enabled", false);
12696 Preferences::AddBoolVarCache(
12697 &sTPInPBEnabled, "privacy.trackingprotection.pbmode.enabled", false);
12698 }
12699
12700 if (mUseTrackingProtection || sTPEnabled ||
12701 (UsePrivateBrowsing() && sTPInPBEnabled)) {
12702 *aUseTrackingProtection = true;
12703 return NS_OK;
12704 }
12705
12706 RefPtr<nsDocShell> parent = GetParentDocshell();
12707 if (parent) {
12708 return parent->GetUseTrackingProtection(aUseTrackingProtection);
12709 }
12710
12711 return NS_OK;
12712 }
12713
12714 NS_IMETHODIMP
SetUseTrackingProtection(bool aUseTrackingProtection)12715 nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection) {
12716 mUseTrackingProtection = aUseTrackingProtection;
12717 return NS_OK;
12718 }
12719
12720 NS_IMETHODIMP
GetIsContent(bool * aIsContent)12721 nsDocShell::GetIsContent(bool* aIsContent) {
12722 *aIsContent = (mItemType == typeContent);
12723 return NS_OK;
12724 }
12725
IsOKToLoadURI(nsIURI * aURI)12726 bool nsDocShell::IsOKToLoadURI(nsIURI* aURI) {
12727 NS_PRECONDITION(aURI, "Must have a URI!");
12728
12729 if (!mFiredUnloadEvent) {
12730 return true;
12731 }
12732
12733 if (!mLoadingURI) {
12734 return false;
12735 }
12736
12737 nsCOMPtr<nsIScriptSecurityManager> secMan =
12738 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
12739 return secMan &&
12740 NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
12741 }
12742
12743 //
12744 // Routines for selection and clipboard
12745 //
GetControllerForCommand(const char * aCommand,nsIController ** aResult)12746 nsresult nsDocShell::GetControllerForCommand(const char* aCommand,
12747 nsIController** aResult) {
12748 NS_ENSURE_ARG_POINTER(aResult);
12749 *aResult = nullptr;
12750
12751 NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
12752
12753 nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
12754 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
12755
12756 return root->GetControllerForCommand(aCommand, false /* for any window */,
12757 aResult);
12758 }
12759
12760 NS_IMETHODIMP
IsCommandEnabled(const char * aCommand,bool * aResult)12761 nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult) {
12762 NS_ENSURE_ARG_POINTER(aResult);
12763 *aResult = false;
12764
12765 nsresult rv = NS_ERROR_FAILURE;
12766
12767 nsCOMPtr<nsIController> controller;
12768 rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12769 if (controller) {
12770 rv = controller->IsCommandEnabled(aCommand, aResult);
12771 }
12772
12773 return rv;
12774 }
12775
12776 NS_IMETHODIMP
DoCommand(const char * aCommand)12777 nsDocShell::DoCommand(const char* aCommand) {
12778 nsresult rv = NS_ERROR_FAILURE;
12779
12780 nsCOMPtr<nsIController> controller;
12781 rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12782 if (controller) {
12783 rv = controller->DoCommand(aCommand);
12784 }
12785
12786 return rv;
12787 }
12788
12789 NS_IMETHODIMP
DoCommandWithParams(const char * aCommand,nsICommandParams * aParams)12790 nsDocShell::DoCommandWithParams(const char* aCommand,
12791 nsICommandParams* aParams) {
12792 nsCOMPtr<nsIController> controller;
12793 nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
12794 if (NS_WARN_IF(NS_FAILED(rv))) {
12795 return rv;
12796 }
12797
12798 nsCOMPtr<nsICommandController> commandController =
12799 do_QueryInterface(controller, &rv);
12800 if (NS_WARN_IF(NS_FAILED(rv))) {
12801 return rv;
12802 }
12803
12804 return commandController->DoCommandWithParams(aCommand, aParams);
12805 }
12806
EnsureCommandHandler()12807 nsresult nsDocShell::EnsureCommandHandler() {
12808 if (!mCommandManager) {
12809 nsCOMPtr<nsPICommandUpdater> commandUpdater =
12810 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
12811 if (!commandUpdater) {
12812 return NS_ERROR_OUT_OF_MEMORY;
12813 }
12814
12815 nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow();
12816 nsresult rv = commandUpdater->Init(domWindow);
12817 if (NS_SUCCEEDED(rv)) {
12818 mCommandManager = do_QueryInterface(commandUpdater);
12819 }
12820 }
12821
12822 return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
12823 }
12824
12825 NS_IMETHODIMP
CanCutSelection(bool * aResult)12826 nsDocShell::CanCutSelection(bool* aResult) {
12827 return IsCommandEnabled("cmd_cut", aResult);
12828 }
12829
12830 NS_IMETHODIMP
CanCopySelection(bool * aResult)12831 nsDocShell::CanCopySelection(bool* aResult) {
12832 return IsCommandEnabled("cmd_copy", aResult);
12833 }
12834
12835 NS_IMETHODIMP
CanCopyLinkLocation(bool * aResult)12836 nsDocShell::CanCopyLinkLocation(bool* aResult) {
12837 return IsCommandEnabled("cmd_copyLink", aResult);
12838 }
12839
12840 NS_IMETHODIMP
CanCopyImageLocation(bool * aResult)12841 nsDocShell::CanCopyImageLocation(bool* aResult) {
12842 return IsCommandEnabled("cmd_copyImageLocation", aResult);
12843 }
12844
12845 NS_IMETHODIMP
CanCopyImageContents(bool * aResult)12846 nsDocShell::CanCopyImageContents(bool* aResult) {
12847 return IsCommandEnabled("cmd_copyImageContents", aResult);
12848 }
12849
12850 NS_IMETHODIMP
CanPaste(bool * aResult)12851 nsDocShell::CanPaste(bool* aResult) {
12852 return IsCommandEnabled("cmd_paste", aResult);
12853 }
12854
12855 NS_IMETHODIMP
CutSelection(void)12856 nsDocShell::CutSelection(void) { return DoCommand("cmd_cut"); }
12857
12858 NS_IMETHODIMP
CopySelection(void)12859 nsDocShell::CopySelection(void) { return DoCommand("cmd_copy"); }
12860
12861 NS_IMETHODIMP
CopyLinkLocation(void)12862 nsDocShell::CopyLinkLocation(void) { return DoCommand("cmd_copyLink"); }
12863
12864 NS_IMETHODIMP
CopyImageLocation(void)12865 nsDocShell::CopyImageLocation(void) {
12866 return DoCommand("cmd_copyImageLocation");
12867 }
12868
12869 NS_IMETHODIMP
CopyImageContents(void)12870 nsDocShell::CopyImageContents(void) {
12871 return DoCommand("cmd_copyImageContents");
12872 }
12873
12874 NS_IMETHODIMP
Paste(void)12875 nsDocShell::Paste(void) { return DoCommand("cmd_paste"); }
12876
12877 NS_IMETHODIMP
SelectAll(void)12878 nsDocShell::SelectAll(void) { return DoCommand("cmd_selectAll"); }
12879
12880 //
12881 // SelectNone
12882 //
12883 // Collapses the current selection, insertion point ends up at beginning
12884 // of previous selection.
12885 //
12886 NS_IMETHODIMP
SelectNone(void)12887 nsDocShell::SelectNone(void) { return DoCommand("cmd_selectNone"); }
12888
12889 // link handling
12890
12891 class OnLinkClickEvent : public Runnable {
12892 public:
12893 OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI,
12894 const char16_t* aTargetSpec, const nsAString& aFileName,
12895 nsIInputStream* aPostDataStream,
12896 int64_t aPostDataStreamLength,
12897 nsIInputStream* aHeadersDataStream, bool aNoOpenerImplied,
12898 bool aIsTrusted, nsIPrincipal* aTriggeringPrincipal);
12899
Run()12900 NS_IMETHOD Run() override {
12901 nsAutoPopupStatePusher popupStatePusher(mPopupState);
12902
12903 // We need to set up an AutoJSAPI here for the following reason: When we do
12904 // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
12905 // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
12906 // So we need to fake things so that we don't look like native code as far
12907 // as LegacyIsCallerNativeCode() is concerned.
12908 AutoJSAPI jsapi;
12909 if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
12910 mHandler->OnLinkClickSync(mContent, mURI, mTargetSpec.get(), mFileName,
12911 mPostDataStream, mPostDataStreamLength,
12912 mHeadersDataStream, mNoOpenerImplied, nullptr,
12913 nullptr, mTriggeringPrincipal);
12914 }
12915 return NS_OK;
12916 }
12917
12918 private:
12919 RefPtr<nsDocShell> mHandler;
12920 nsCOMPtr<nsIURI> mURI;
12921 nsString mTargetSpec;
12922 nsString mFileName;
12923 nsCOMPtr<nsIInputStream> mPostDataStream;
12924 int64_t mPostDataStreamLength;
12925 nsCOMPtr<nsIInputStream> mHeadersDataStream;
12926 nsCOMPtr<nsIContent> mContent;
12927 PopupControlState mPopupState;
12928 bool mNoOpenerImplied;
12929 bool mIsTrusted;
12930 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
12931 };
12932
OnLinkClickEvent(nsDocShell * aHandler,nsIContent * aContent,nsIURI * aURI,const char16_t * aTargetSpec,const nsAString & aFileName,nsIInputStream * aPostDataStream,int64_t aPostDataStreamLength,nsIInputStream * aHeadersDataStream,bool aNoOpenerImplied,bool aIsTrusted,nsIPrincipal * aTriggeringPrincipal)12933 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
12934 nsIURI* aURI, const char16_t* aTargetSpec,
12935 const nsAString& aFileName,
12936 nsIInputStream* aPostDataStream,
12937 int64_t aPostDataStreamLength,
12938 nsIInputStream* aHeadersDataStream,
12939 bool aNoOpenerImplied, bool aIsTrusted,
12940 nsIPrincipal* aTriggeringPrincipal)
12941 : mozilla::Runnable("OnLinkClickEvent"),
12942 mHandler(aHandler),
12943 mURI(aURI),
12944 mTargetSpec(aTargetSpec),
12945 mFileName(aFileName),
12946 mPostDataStream(aPostDataStream),
12947 mPostDataStreamLength(aPostDataStreamLength),
12948 mHeadersDataStream(aHeadersDataStream),
12949 mContent(aContent),
12950 mPopupState(mHandler->mScriptGlobal->GetPopupControlState()),
12951 mNoOpenerImplied(aNoOpenerImplied),
12952 mIsTrusted(aIsTrusted),
12953 mTriggeringPrincipal(aTriggeringPrincipal) {}
12954
12955 NS_IMETHODIMP
OnLinkClick(nsIContent * aContent,nsIURI * aURI,const char16_t * aTargetSpec,const nsAString & aFileName,nsIInputStream * aPostDataStream,int64_t aPostDataStreamLength,nsIInputStream * aHeadersDataStream,bool aIsTrusted,nsIPrincipal * aTriggeringPrincipal)12956 nsDocShell::OnLinkClick(nsIContent* aContent, nsIURI* aURI,
12957 const char16_t* aTargetSpec, const nsAString& aFileName,
12958 nsIInputStream* aPostDataStream,
12959 int64_t aPostDataStreamLength,
12960 nsIInputStream* aHeadersDataStream, bool aIsTrusted,
12961 nsIPrincipal* aTriggeringPrincipal) {
12962 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
12963
12964 if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
12965 return NS_OK;
12966 }
12967
12968 // On history navigation through Back/Forward buttons, don't execute
12969 // automatic JavaScript redirection such as |anchorElement.click()| or
12970 // |formElement.submit()|.
12971 //
12972 // XXX |formElement.submit()| bypasses this checkpoint because it calls
12973 // nsDocShell::OnLinkClickSync(...) instead.
12974 if (ShouldBlockLoadingForBackButton()) {
12975 return NS_OK;
12976 }
12977
12978 if (aContent->IsEditable()) {
12979 return NS_OK;
12980 }
12981
12982 nsresult rv = NS_ERROR_FAILURE;
12983 nsAutoString target;
12984
12985 nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
12986 bool noOpenerImplied = false;
12987 if (browserChrome3) {
12988 nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
12989 nsAutoString oldTarget(aTargetSpec);
12990 rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI, linkNode,
12991 mIsAppTab, target);
12992 if (!oldTarget.Equals(target)) {
12993 noOpenerImplied = true;
12994 }
12995 }
12996
12997 if (NS_FAILED(rv)) {
12998 target = aTargetSpec;
12999 }
13000
13001 nsCOMPtr<nsIRunnable> ev = new OnLinkClickEvent(
13002 this, aContent, aURI, target.get(), aFileName, aPostDataStream,
13003 aPostDataStreamLength, aHeadersDataStream, noOpenerImplied, aIsTrusted,
13004 aTriggeringPrincipal);
13005 return DispatchToTabGroup(TaskCategory::UI, ev.forget());
13006 }
13007
IsElementAnchorOrArea(nsIContent * aContent)13008 static bool IsElementAnchorOrArea(nsIContent* aContent) {
13009 // Make sure we are dealing with either an <A> or <AREA> element in the HTML
13010 // or XHTML namespace.
13011 return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
13012 }
13013
13014 NS_IMETHODIMP
OnLinkClickSync(nsIContent * aContent,nsIURI * aURI,const char16_t * aTargetSpec,const nsAString & aFileName,nsIInputStream * aPostDataStream,int64_t aPostDataStreamLength,nsIInputStream * aHeadersDataStream,bool aNoOpenerImplied,nsIDocShell ** aDocShell,nsIRequest ** aRequest,nsIPrincipal * aTriggeringPrincipal)13015 nsDocShell::OnLinkClickSync(
13016 nsIContent* aContent, nsIURI* aURI, const char16_t* aTargetSpec,
13017 const nsAString& aFileName, nsIInputStream* aPostDataStream,
13018 int64_t aPostDataStreamLength, nsIInputStream* aHeadersDataStream,
13019 bool aNoOpenerImplied, nsIDocShell** aDocShell, nsIRequest** aRequest,
13020 nsIPrincipal* aTriggeringPrincipal) {
13021 // Initialize the DocShell / Request
13022 if (aDocShell) {
13023 *aDocShell = nullptr;
13024 }
13025 if (aRequest) {
13026 *aRequest = nullptr;
13027 }
13028
13029 if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
13030 return NS_OK;
13031 }
13032
13033 // XXX When the linking node was HTMLFormElement, it is synchronous event.
13034 // That is, the caller of this method is not |OnLinkClickEvent::Run()|
13035 // but |HTMLFormElement::SubmitSubmission(...)|.
13036 if (aContent->IsHTMLElement(nsGkAtoms::form) &&
13037 ShouldBlockLoadingForBackButton()) {
13038 return NS_OK;
13039 }
13040
13041 if (aContent->IsEditable()) {
13042 return NS_OK;
13043 }
13044
13045 {
13046 // defer to an external protocol handler if necessary...
13047 nsCOMPtr<nsIExternalProtocolService> extProtService =
13048 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
13049 if (extProtService) {
13050 nsAutoCString scheme;
13051 aURI->GetScheme(scheme);
13052 if (!scheme.IsEmpty()) {
13053 // if the URL scheme does not correspond to an exposed protocol, then we
13054 // need to hand this link click over to the external protocol handler.
13055 bool isExposed;
13056 nsresult rv =
13057 extProtService->IsExposedProtocol(scheme.get(), &isExposed);
13058 if (NS_SUCCEEDED(rv) && !isExposed) {
13059 return extProtService->LoadURI(aURI, this);
13060 }
13061 }
13062 }
13063 }
13064
13065 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
13066 if (IsElementAnchorOrArea(aContent)) {
13067 MOZ_ASSERT(aContent->IsHTMLElement());
13068 nsAutoString referrer;
13069 aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
13070 nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
13071 referrer);
13072 while (tok.hasMoreTokens()) {
13073 const nsAString& token = tok.nextToken();
13074 if (token.LowerCaseEqualsLiteral("noreferrer")) {
13075 flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
13076 INTERNAL_LOAD_FLAGS_NO_OPENER;
13077 // We now have all the flags we could possibly have, so just stop.
13078 break;
13079 }
13080 if (token.LowerCaseEqualsLiteral("noopener")) {
13081 flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13082 }
13083 }
13084 if (aNoOpenerImplied) {
13085 flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13086 }
13087 }
13088
13089 // Get the owner document of the link that was clicked, this will be
13090 // the document that the link is in, or the last document that the
13091 // link was in. From that document, we'll get the URI to use as the
13092 // referer, since the current URI in this docshell may be a
13093 // new document that we're in the process of loading.
13094 nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
13095 NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
13096
13097 // Now check that the refererDoc's inner window is the current inner
13098 // window for mScriptGlobal. If it's not, then we don't want to
13099 // follow this link.
13100 nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow();
13101 NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
13102 if (!mScriptGlobal ||
13103 mScriptGlobal->AsOuter()->GetCurrentInnerWindow() != refererInner) {
13104 // We're no longer the current inner window
13105 return NS_OK;
13106 }
13107
13108 nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
13109 uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
13110
13111 // get referrer attribute from clicked link and parse it
13112 // if per element referrer is enabled, the element referrer overrules
13113 // the document wide referrer
13114 if (IsElementAnchorOrArea(aContent)) {
13115 net::ReferrerPolicy refPolEnum =
13116 aContent->AsElement()->GetReferrerPolicyAsEnum();
13117 if (refPolEnum != net::RP_Unset) {
13118 refererPolicy = refPolEnum;
13119 }
13120 }
13121
13122 // referer could be null here in some odd cases, but that's ok,
13123 // we'll just load the link w/o sending a referer in those cases.
13124
13125 nsAutoString target(aTargetSpec);
13126
13127 // If this is an anchor element, grab its type property to use as a hint
13128 nsAutoString typeHint;
13129 RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::FromContent(aContent);
13130 if (anchor) {
13131 anchor->GetType(typeHint);
13132 NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
13133 nsAutoCString type, dummy;
13134 NS_ParseRequestContentType(utf8Hint, type, dummy);
13135 CopyUTF8toUTF16(type, typeHint);
13136 }
13137
13138 // Clone the URI now, in case a content policy or something messes
13139 // with it under InternalLoad; we do _not_ want to change the URI
13140 // our caller passed in.
13141 nsCOMPtr<nsIURI> clonedURI;
13142 aURI->Clone(getter_AddRefs(clonedURI));
13143 if (!clonedURI) {
13144 return NS_ERROR_OUT_OF_MEMORY;
13145 }
13146
13147 // if the triggeringPrincipal is not passed explicitly, then we
13148 // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
13149 nsCOMPtr<nsIPrincipal> triggeringPrincipal =
13150 aTriggeringPrincipal ? aTriggeringPrincipal : aContent->NodePrincipal();
13151
13152 // Link click (or form submission) can be triggered inside an onload handler,
13153 // and we don't want to add history entry in this case.
13154 bool inOnLoadHandler = false;
13155 GetIsExecutingOnLoadHandler(&inOnLoadHandler);
13156 uint32_t loadType = inOnLoadHandler ? LOAD_NORMAL_REPLACE : LOAD_LINK;
13157
13158 nsresult rv =
13159 InternalLoad(clonedURI, // New URI
13160 nullptr, // Original URI
13161 Nothing(), // Let the protocol handler assign it
13162 false,
13163 false, // LoadReplace
13164 false, // IsFromProcessingFrameAttributes
13165 referer, // Referer URI
13166 refererPolicy, // Referer policy
13167 triggeringPrincipal, aContent->NodePrincipal(), flags,
13168 target, // Window target
13169 NS_LossyConvertUTF16toASCII(typeHint).get(),
13170 aFileName, // Download as file
13171 aPostDataStream, // Post data stream
13172 aPostDataStreamLength, // Post data stream length
13173 aHeadersDataStream, // Headers stream
13174 loadType, // Load type
13175 nullptr, // No SHEntry
13176 true, // first party site
13177 VoidString(), // No srcdoc
13178 this, // We are the source
13179 nullptr, // baseURI not needed
13180 aDocShell, // DocShell out-param
13181 aRequest); // Request out-param
13182 if (NS_SUCCEEDED(rv)) {
13183 nsPingListener::DispatchPings(this, aContent, aURI, referer, refererPolicy);
13184 }
13185 return rv;
13186 }
13187
13188 NS_IMETHODIMP
OnOverLink(nsIContent * aContent,nsIURI * aURI,const char16_t * aTargetSpec)13189 nsDocShell::OnOverLink(nsIContent* aContent, nsIURI* aURI,
13190 const char16_t* aTargetSpec) {
13191 if (aContent->IsEditable()) {
13192 return NS_OK;
13193 }
13194
13195 nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
13196 nsresult rv = NS_ERROR_FAILURE;
13197
13198 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
13199 if (!browserChrome2) {
13200 browserChrome = do_GetInterface(mTreeOwner);
13201 if (!browserChrome) {
13202 return rv;
13203 }
13204 }
13205
13206 nsAutoCString spec;
13207 rv = aURI->GetDisplaySpec(spec);
13208 NS_ENSURE_SUCCESS(rv, rv);
13209
13210 NS_ConvertUTF8toUTF16 uStr(spec);
13211
13212 mozilla::net::PredictorPredict(
13213 aURI, mCurrentURI, nsINetworkPredictor::PREDICT_LINK,
13214 aContent->NodePrincipal()->OriginAttributesRef(), nullptr);
13215
13216 if (browserChrome2) {
13217 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
13218 rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
13219 uStr, element);
13220 } else {
13221 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
13222 }
13223 return rv;
13224 }
13225
13226 NS_IMETHODIMP
OnLeaveLink()13227 nsDocShell::OnLeaveLink() {
13228 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
13229 nsresult rv = NS_ERROR_FAILURE;
13230
13231 if (browserChrome) {
13232 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
13233 EmptyString().get());
13234 }
13235 return rv;
13236 }
13237
ShouldBlockLoadingForBackButton()13238 bool nsDocShell::ShouldBlockLoadingForBackButton() {
13239 if (!(mLoadType & LOAD_CMD_HISTORY) ||
13240 EventStateManager::IsHandlingUserInput() ||
13241 !Preferences::GetBool("accessibility.blockjsredirection")) {
13242 return false;
13243 }
13244
13245 bool canGoForward = false;
13246 GetCanGoForward(&canGoForward);
13247 return canGoForward;
13248 }
13249
PluginsAllowedInCurrentDoc()13250 bool nsDocShell::PluginsAllowedInCurrentDoc() {
13251 if (!mContentViewer) {
13252 return false;
13253 }
13254
13255 nsIDocument* doc = mContentViewer->GetDocument();
13256 if (!doc) {
13257 return false;
13258 }
13259
13260 return doc->GetAllowPlugins();
13261 }
13262
13263 //----------------------------------------------------------------------
13264 // Web Shell Services API
13265
13266 // This functions is only called when a new charset is detected in loading a
13267 // document. Its name should be changed to "CharsetReloadDocument"
13268 NS_IMETHODIMP
ReloadDocument(const char * aCharset,int32_t aSource)13269 nsDocShell::ReloadDocument(const char* aCharset, int32_t aSource) {
13270 // XXX hack. keep the aCharset and aSource wait to pick it up
13271 nsCOMPtr<nsIContentViewer> cv;
13272 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
13273 if (cv) {
13274 int32_t hint;
13275 cv->GetHintCharacterSetSource(&hint);
13276 if (aSource > hint) {
13277 nsCString charset(aCharset);
13278 cv->SetHintCharacterSet(charset);
13279 cv->SetHintCharacterSetSource(aSource);
13280 if (eCharsetReloadRequested != mCharsetReloadState) {
13281 mCharsetReloadState = eCharsetReloadRequested;
13282 switch (mLoadType) {
13283 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
13284 return Reload(LOAD_FLAGS_CHARSET_CHANGE | LOAD_FLAGS_BYPASS_CACHE |
13285 LOAD_FLAGS_BYPASS_PROXY);
13286 case LOAD_RELOAD_BYPASS_CACHE:
13287 return Reload(LOAD_FLAGS_CHARSET_CHANGE | LOAD_FLAGS_BYPASS_CACHE);
13288 default:
13289 return Reload(LOAD_FLAGS_CHARSET_CHANGE);
13290 }
13291 }
13292 }
13293 }
13294 // return failure if this request is not accepted due to mCharsetReloadState
13295 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
13296 }
13297
13298 NS_IMETHODIMP
StopDocumentLoad(void)13299 nsDocShell::StopDocumentLoad(void) {
13300 if (eCharsetReloadRequested != mCharsetReloadState) {
13301 Stop(nsIWebNavigation::STOP_ALL);
13302 return NS_OK;
13303 }
13304 // return failer if this request is not accepted due to mCharsetReloadState
13305 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
13306 }
13307
13308 NS_IMETHODIMP
SetIsPrinting(bool aIsPrinting)13309 nsDocShell::SetIsPrinting(bool aIsPrinting) {
13310 mIsPrintingOrPP = aIsPrinting;
13311 return NS_OK;
13312 }
13313
13314 NS_IMETHODIMP
GetPrintPreview(nsIWebBrowserPrint ** aPrintPreview)13315 nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview) {
13316 *aPrintPreview = nullptr;
13317 #if NS_PRINT_PREVIEW
13318 nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
13319 if (!print || !print->IsInitializedForPrintPreview()) {
13320 // XXX: Creating a brand new content viewer to host preview every
13321 // time we enter here seems overwork. We could skip ahead to where
13322 // we QI the mContentViewer if the current URI is either about:blank
13323 // or about:printpreview.
13324 Stop(nsIWebNavigation::STOP_ALL);
13325 nsCOMPtr<nsIPrincipal> principal =
13326 NullPrincipal::CreateWithInheritedAttributes(this);
13327 nsCOMPtr<nsIURI> uri;
13328 NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview"));
13329 nsresult rv = CreateAboutBlankContentViewer(principal, uri);
13330 NS_ENSURE_SUCCESS(rv, rv);
13331 // Here we manually set current URI since we have just created a
13332 // brand new content viewer (about:blank) to host preview.
13333 SetCurrentURI(uri, nullptr, true, 0);
13334 print = do_QueryInterface(mContentViewer);
13335 NS_ENSURE_STATE(print);
13336 print->InitializeForPrintPreview();
13337 }
13338 nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
13339 result.forget(aPrintPreview);
13340 return NS_OK;
13341 #else
13342 return NS_ERROR_NOT_IMPLEMENTED;
13343 #endif
13344 }
13345
13346 #ifdef DEBUG
13347 unsigned long nsDocShell::gNumberOfDocShells = 0;
13348 #endif
13349
13350 NS_IMETHODIMP
GetCanExecuteScripts(bool * aResult)13351 nsDocShell::GetCanExecuteScripts(bool* aResult) {
13352 *aResult = mCanExecuteScripts;
13353 return NS_OK;
13354 }
13355
SetFrameType(uint32_t aFrameType)13356 /* [infallible] */ NS_IMETHODIMP nsDocShell::SetFrameType(uint32_t aFrameType) {
13357 mFrameType = aFrameType;
13358 return NS_OK;
13359 }
13360
GetFrameType(uint32_t * aFrameType)13361 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetFrameType(
13362 uint32_t* aFrameType) {
13363 *aFrameType = mFrameType;
13364 return NS_OK;
13365 }
13366
GetIsMozBrowser(bool * aIsMozBrowser)13367 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsMozBrowser(
13368 bool* aIsMozBrowser) {
13369 *aIsMozBrowser = (mFrameType == FRAME_TYPE_BROWSER);
13370 return NS_OK;
13371 }
13372
GetInheritedFrameType()13373 uint32_t nsDocShell::GetInheritedFrameType() {
13374 if (mFrameType != FRAME_TYPE_REGULAR) {
13375 return mFrameType;
13376 }
13377
13378 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
13379 GetSameTypeParent(getter_AddRefs(parentAsItem));
13380
13381 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
13382 if (!parent) {
13383 return FRAME_TYPE_REGULAR;
13384 }
13385
13386 return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
13387 }
13388
GetIsIsolatedMozBrowserElement(bool * aIsIsolatedMozBrowserElement)13389 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsIsolatedMozBrowserElement(
13390 bool* aIsIsolatedMozBrowserElement) {
13391 bool result = mFrameType == FRAME_TYPE_BROWSER &&
13392 mOriginAttributes.mInIsolatedMozBrowser;
13393 *aIsIsolatedMozBrowserElement = result;
13394 return NS_OK;
13395 }
13396
GetIsInIsolatedMozBrowserElement(bool * aIsInIsolatedMozBrowserElement)13397 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsInIsolatedMozBrowserElement(
13398 bool* aIsInIsolatedMozBrowserElement) {
13399 MOZ_ASSERT(!mOriginAttributes.mInIsolatedMozBrowser ||
13400 (GetInheritedFrameType() == FRAME_TYPE_BROWSER),
13401 "Isolated mozbrowser should only be true inside browser frames");
13402 bool result = (GetInheritedFrameType() == FRAME_TYPE_BROWSER) &&
13403 mOriginAttributes.mInIsolatedMozBrowser;
13404 *aIsInIsolatedMozBrowserElement = result;
13405 return NS_OK;
13406 }
13407
GetIsInMozBrowser(bool * aIsInMozBrowser)13408 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsInMozBrowser(
13409 bool* aIsInMozBrowser) {
13410 *aIsInMozBrowser = (GetInheritedFrameType() == FRAME_TYPE_BROWSER);
13411 return NS_OK;
13412 }
13413
GetIsTopLevelContentDocShell(bool * aIsTopLevelContentDocShell)13414 /* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsTopLevelContentDocShell(
13415 bool* aIsTopLevelContentDocShell) {
13416 *aIsTopLevelContentDocShell = false;
13417
13418 if (mItemType == typeContent) {
13419 nsCOMPtr<nsIDocShellTreeItem> root;
13420 GetSameTypeRootTreeItem(getter_AddRefs(root));
13421 *aIsTopLevelContentDocShell =
13422 root.get() == static_cast<nsIDocShellTreeItem*>(this);
13423 }
13424
13425 return NS_OK;
13426 }
13427
13428 // Implements nsILoadContext.originAttributes
13429 NS_IMETHODIMP
GetScriptableOriginAttributes(JS::MutableHandle<JS::Value> aVal)13430 nsDocShell::GetScriptableOriginAttributes(JS::MutableHandle<JS::Value> aVal) {
13431 JSContext* cx = nsContentUtils::GetCurrentJSContext();
13432 MOZ_ASSERT(cx);
13433
13434 return GetOriginAttributes(cx, aVal);
13435 }
13436
13437 // Implements nsIDocShell.GetOriginAttributes()
13438 NS_IMETHODIMP
GetOriginAttributes(JSContext * aCx,JS::MutableHandle<JS::Value> aVal)13439 nsDocShell::GetOriginAttributes(JSContext* aCx,
13440 JS::MutableHandle<JS::Value> aVal) {
13441 bool ok = ToJSValue(aCx, mOriginAttributes, aVal);
13442 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
13443 return NS_OK;
13444 }
13445
CanSetOriginAttributes()13446 bool nsDocShell::CanSetOriginAttributes() {
13447 MOZ_ASSERT(mChildList.IsEmpty());
13448 if (!mChildList.IsEmpty()) {
13449 return false;
13450 }
13451
13452 // TODO: Bug 1273058 - mContentViewer should be null when setting origin
13453 // attributes.
13454 if (mContentViewer) {
13455 nsIDocument* doc = mContentViewer->GetDocument();
13456 if (doc) {
13457 nsIURI* uri = doc->GetDocumentURI();
13458 if (!uri) {
13459 return false;
13460 }
13461 nsCString uriSpec = uri->GetSpecOrDefault();
13462 MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
13463 if (!uriSpec.EqualsLiteral("about:blank")) {
13464 return false;
13465 }
13466 }
13467 }
13468
13469 return true;
13470 }
13471
ServiceWorkerAllowedToControlWindow(nsIPrincipal * aPrincipal,nsIURI * aURI)13472 bool nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal,
13473 nsIURI* aURI) {
13474 MOZ_ASSERT(aPrincipal);
13475 MOZ_ASSERT(aURI);
13476
13477 if (UsePrivateBrowsing() || mSandboxFlags) {
13478 return false;
13479 }
13480
13481 nsCOMPtr<nsIDocShellTreeItem> parent;
13482 GetSameTypeParent(getter_AddRefs(parent));
13483 nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
13484 nsPIDOMWindowInner* parentInner =
13485 parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
13486
13487 nsContentUtils::StorageAccess storage =
13488 nsContentUtils::StorageAllowedForNewWindow(aPrincipal, aURI, parentInner);
13489
13490 return storage == nsContentUtils::StorageAccess::eAllow;
13491 }
13492
SetOriginAttributes(const OriginAttributes & aAttrs)13493 nsresult nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs) {
13494 MOZ_ASSERT(!mIsBeingDestroyed);
13495
13496 if (!CanSetOriginAttributes()) {
13497 return NS_ERROR_FAILURE;
13498 }
13499
13500 AssertOriginAttributesMatchPrivateBrowsing();
13501 mOriginAttributes = aAttrs;
13502
13503 bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
13504 // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
13505 if (mItemType == typeChrome && isPrivate) {
13506 mOriginAttributes.mPrivateBrowsingId = 0;
13507 }
13508
13509 SetPrivateBrowsing(isPrivate);
13510 AssertOriginAttributesMatchPrivateBrowsing();
13511
13512 return NS_OK;
13513 }
13514
13515 NS_IMETHODIMP
SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes)13516 nsDocShell::SetOriginAttributesBeforeLoading(
13517 JS::Handle<JS::Value> aOriginAttributes) {
13518 if (!aOriginAttributes.isObject()) {
13519 return NS_ERROR_INVALID_ARG;
13520 }
13521
13522 AutoJSAPI jsapi;
13523 if (!jsapi.Init(&aOriginAttributes.toObject())) {
13524 return NS_ERROR_UNEXPECTED;
13525 }
13526
13527 JSContext* cx = jsapi.cx();
13528 if (NS_WARN_IF(!cx)) {
13529 return NS_ERROR_FAILURE;
13530 }
13531
13532 OriginAttributes attrs;
13533 if (!aOriginAttributes.isObject() || !attrs.Init(cx, aOriginAttributes)) {
13534 return NS_ERROR_INVALID_ARG;
13535 }
13536
13537 return SetOriginAttributes(attrs);
13538 }
13539
13540 NS_IMETHODIMP
SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,JSContext * aCx)13541 nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
13542 JSContext* aCx) {
13543 OriginAttributes attrs;
13544 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
13545 return NS_ERROR_INVALID_ARG;
13546 }
13547
13548 return SetOriginAttributes(attrs);
13549 }
13550
13551 NS_IMETHODIMP
GetAsyncPanZoomEnabled(bool * aOut)13552 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut) {
13553 if (nsIPresShell* presShell = GetPresShell()) {
13554 *aOut = presShell->AsyncPanZoomEnabled();
13555 return NS_OK;
13556 }
13557
13558 // If we don't have a presShell, fall back to the default platform value of
13559 // whether or not APZ is enabled.
13560 *aOut = gfxPlatform::AsyncPanZoomEnabled();
13561 return NS_OK;
13562 }
13563
HasUnloadedParent()13564 bool nsDocShell::HasUnloadedParent() {
13565 RefPtr<nsDocShell> parent = GetParentDocshell();
13566 while (parent) {
13567 bool inUnload = false;
13568 parent->GetIsInUnload(&inUnload);
13569 if (inUnload) {
13570 return true;
13571 }
13572 parent = parent->GetParentDocshell();
13573 }
13574 return false;
13575 }
13576
UpdateGlobalHistoryTitle(nsIURI * aURI)13577 void nsDocShell::UpdateGlobalHistoryTitle(nsIURI* aURI) {
13578 if (mUseGlobalHistory && !UsePrivateBrowsing()) {
13579 nsCOMPtr<IHistory> history = services::GetHistoryService();
13580 if (history) {
13581 history->SetURITitle(aURI, mTitle);
13582 } else if (mGlobalHistory) {
13583 mGlobalHistory->SetPageTitle(aURI, nsString(mTitle));
13584 }
13585 }
13586 }
13587
IsInvisible()13588 bool nsDocShell::IsInvisible() { return mInvisible; }
13589
SetInvisible(bool aInvisible)13590 void nsDocShell::SetInvisible(bool aInvisible) { mInvisible = aInvisible; }
13591
SetOpener(nsITabParent * aOpener)13592 void nsDocShell::SetOpener(nsITabParent* aOpener) {
13593 mOpener = do_GetWeakReference(aOpener);
13594 }
13595
GetOpener()13596 nsITabParent* nsDocShell::GetOpener() {
13597 nsCOMPtr<nsITabParent> opener(do_QueryReferent(mOpener));
13598 return opener;
13599 }
13600
13601 // The caller owns |aAsyncCause| here.
NotifyJSRunToCompletionStart(const char * aReason,const char16_t * aFunctionName,const char16_t * aFilename,const uint32_t aLineNumber,JS::Handle<JS::Value> aAsyncStack,const char * aAsyncCause)13602 void nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
13603 const char16_t* aFunctionName,
13604 const char16_t* aFilename,
13605 const uint32_t aLineNumber,
13606 JS::Handle<JS::Value> aAsyncStack,
13607 const char* aAsyncCause) {
13608 // If first start, mark interval start.
13609 if (mJSRunToCompletionDepth == 0) {
13610 RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
13611 if (timelines && timelines->HasConsumer(this)) {
13612 timelines->AddMarkerForDocShell(
13613 this, Move(mozilla::MakeUnique<JavascriptTimelineMarker>(
13614 aReason, aFunctionName, aFilename, aLineNumber,
13615 MarkerTracingType::START, aAsyncStack, aAsyncCause)));
13616 }
13617 }
13618
13619 mJSRunToCompletionDepth++;
13620 }
13621
NotifyJSRunToCompletionStop()13622 void nsDocShell::NotifyJSRunToCompletionStop() {
13623 mJSRunToCompletionDepth--;
13624
13625 // If last stop, mark interval end.
13626 if (mJSRunToCompletionDepth == 0) {
13627 RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
13628 if (timelines && timelines->HasConsumer(this)) {
13629 timelines->AddMarkerForDocShell(this, "Javascript",
13630 MarkerTracingType::END);
13631 }
13632 }
13633 }
13634
MaybeNotifyKeywordSearchLoading(const nsString & aProvider,const nsString & aKeyword)13635 void nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
13636 const nsString& aKeyword) {
13637 if (aProvider.IsEmpty()) {
13638 return;
13639 }
13640
13641 if (XRE_IsContentProcess()) {
13642 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
13643 if (contentChild) {
13644 contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword);
13645 }
13646 return;
13647 }
13648
13649 #ifdef MOZ_TOOLKIT_SEARCH
13650 nsCOMPtr<nsIBrowserSearchService> searchSvc =
13651 do_GetService("@mozilla.org/browser/search-service;1");
13652 if (searchSvc) {
13653 nsCOMPtr<nsISearchEngine> searchEngine;
13654 searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
13655 if (searchEngine) {
13656 nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
13657 if (obsSvc) {
13658 // Note that "keyword-search" refers to a search via the url
13659 // bar, not a bookmarks keyword search.
13660 obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
13661 }
13662 }
13663 }
13664 #endif
13665 }
13666
13667 NS_IMETHODIMP
ShouldPrepareForIntercept(nsIURI * aURI,nsIChannel * aChannel,bool * aShouldIntercept)13668 nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, nsIChannel* aChannel,
13669 bool* aShouldIntercept) {
13670 return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel,
13671 aShouldIntercept);
13672 }
13673
13674 NS_IMETHODIMP
ChannelIntercepted(nsIInterceptedChannel * aChannel)13675 nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel) {
13676 return mInterceptController->ChannelIntercepted(aChannel);
13677 }
13678
InFrameSwap()13679 bool nsDocShell::InFrameSwap() {
13680 RefPtr<nsDocShell> shell = this;
13681 do {
13682 if (shell->mInFrameSwap) {
13683 return true;
13684 }
13685 shell = shell->GetParentDocshell();
13686 } while (shell);
13687 return false;
13688 }
13689
TakeInitialClientSource()13690 UniquePtr<ClientSource> nsDocShell::TakeInitialClientSource() {
13691 return Move(mInitialClientSource);
13692 }
13693
13694 NS_IMETHODIMP
IssueWarning(uint32_t aWarning,bool aAsError)13695 nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError) {
13696 if (mContentViewer) {
13697 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
13698 if (doc) {
13699 doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
13700 }
13701 }
13702 return NS_OK;
13703 }
13704
13705 NS_IMETHODIMP
GetEditingSession(nsIEditingSession ** aEditSession)13706 nsDocShell::GetEditingSession(nsIEditingSession** aEditSession) {
13707 if (!NS_SUCCEEDED(EnsureEditorData())) {
13708 return NS_ERROR_FAILURE;
13709 }
13710
13711 mEditorData->GetEditingSession(aEditSession);
13712 return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
13713 }
13714
13715 NS_IMETHODIMP
GetScriptableTabChild(nsITabChild ** aTabChild)13716 nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild) {
13717 *aTabChild = GetTabChild().take();
13718 return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
13719 }
13720
GetTabChild()13721 already_AddRefed<nsITabChild> nsDocShell::GetTabChild() {
13722 nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
13723 nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
13724 return tc.forget();
13725 }
13726
GetCommandManager()13727 nsICommandManager* nsDocShell::GetCommandManager() {
13728 NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
13729 return mCommandManager;
13730 }
13731
13732 NS_IMETHODIMP
GetIsOnlyToplevelInTabGroup(bool * aResult)13733 nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult) {
13734 MOZ_ASSERT(aResult);
13735
13736 nsPIDOMWindowOuter* outer = GetWindow();
13737 MOZ_ASSERT(outer);
13738
13739 // If we are not toplevel then we are not the only toplevel window in the tab
13740 // group.
13741 if (outer->GetScriptableParentOrNull()) {
13742 *aResult = false;
13743 return NS_OK;
13744 }
13745
13746 // If we have any other toplevel windows in our tab group, then we are not the
13747 // only toplevel window in the tab group.
13748 nsTArray<nsPIDOMWindowOuter*> toplevelWindows =
13749 outer->TabGroup()->GetTopLevelWindows();
13750 if (toplevelWindows.Length() > 1) {
13751 *aResult = false;
13752 return NS_OK;
13753 }
13754 MOZ_ASSERT(toplevelWindows.Length() == 1);
13755 MOZ_ASSERT(toplevelWindows[0] == outer);
13756
13757 *aResult = true;
13758 return NS_OK;
13759 }
13760
13761 NS_IMETHODIMP
GetAwaitingLargeAlloc(bool * aResult)13762 nsDocShell::GetAwaitingLargeAlloc(bool* aResult) {
13763 MOZ_ASSERT(aResult);
13764 nsCOMPtr<nsITabChild> tabChild = GetTabChild();
13765 if (!tabChild) {
13766 *aResult = false;
13767 return NS_OK;
13768 }
13769 *aResult = static_cast<TabChild*>(tabChild.get())->IsAwaitingLargeAlloc();
13770 return NS_OK;
13771 }
13772
NS_IMETHODIMP_(void)13773 NS_IMETHODIMP_(void)
13774 nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) {
13775 aAttrs = mOriginAttributes;
13776 }
13777
GetHTMLEditor()13778 HTMLEditor* nsIDocShell::GetHTMLEditor() {
13779 nsDocShell* docShell = static_cast<nsDocShell*>(this);
13780 return docShell->GetHTMLEditorInternal();
13781 }
13782
SetHTMLEditor(HTMLEditor * aHTMLEditor)13783 nsresult nsIDocShell::SetHTMLEditor(HTMLEditor* aHTMLEditor) {
13784 nsDocShell* docShell = static_cast<nsDocShell*>(this);
13785 return docShell->SetHTMLEditorInternal(aHTMLEditor);
13786 }
13787
13788 NS_IMETHODIMP
GetDisplayMode(uint32_t * aDisplayMode)13789 nsDocShell::GetDisplayMode(uint32_t* aDisplayMode) {
13790 NS_ENSURE_ARG_POINTER(aDisplayMode);
13791 *aDisplayMode = mDisplayMode;
13792 return NS_OK;
13793 }
13794
13795 NS_IMETHODIMP
SetDisplayMode(uint32_t aDisplayMode)13796 nsDocShell::SetDisplayMode(uint32_t aDisplayMode) {
13797 if (!(aDisplayMode == nsIDocShell::DISPLAY_MODE_BROWSER ||
13798 aDisplayMode == nsIDocShell::DISPLAY_MODE_STANDALONE ||
13799 aDisplayMode == nsIDocShell::DISPLAY_MODE_FULLSCREEN ||
13800 aDisplayMode == nsIDocShell::DISPLAY_MODE_MINIMAL_UI)) {
13801 return NS_ERROR_INVALID_ARG;
13802 }
13803
13804 if (aDisplayMode != mDisplayMode) {
13805 mDisplayMode = aDisplayMode;
13806
13807 RefPtr<nsPresContext> presContext;
13808 if (NS_SUCCEEDED(GetPresContext(getter_AddRefs(presContext)))) {
13809 presContext->MediaFeatureValuesChangedAllDocuments(
13810 {MediaFeatureChangeReason::DisplayModeChange});
13811 }
13812 }
13813
13814 return NS_OK;
13815 }
13816
13817 NS_IMETHODIMP
SetColorMatrix(float * aMatrix,uint32_t aMatrixLen)13818 nsDocShell::SetColorMatrix(float* aMatrix, uint32_t aMatrixLen) {
13819 if (aMatrixLen == 20) {
13820 mColorMatrix.reset(new gfx::Matrix5x4());
13821 MOZ_ASSERT(aMatrixLen * sizeof(*aMatrix) ==
13822 sizeof(mColorMatrix->components));
13823 memcpy(mColorMatrix->components, aMatrix, sizeof(mColorMatrix->components));
13824 } else if (aMatrixLen == 0) {
13825 mColorMatrix.reset();
13826 } else {
13827 return NS_ERROR_INVALID_ARG;
13828 }
13829
13830 nsIPresShell* presShell = GetPresShell();
13831 if (!presShell) {
13832 return NS_ERROR_FAILURE;
13833 }
13834
13835 nsIFrame* frame = presShell->GetRootFrame();
13836 if (!frame) {
13837 return NS_ERROR_FAILURE;
13838 }
13839
13840 frame->SchedulePaint();
13841
13842 return NS_OK;
13843 }
13844
13845 NS_IMETHODIMP
GetColorMatrix(uint32_t * aMatrixLen,float ** aMatrix)13846 nsDocShell::GetColorMatrix(uint32_t* aMatrixLen, float** aMatrix) {
13847 NS_ENSURE_ARG_POINTER(aMatrixLen);
13848 *aMatrixLen = 0;
13849
13850 NS_ENSURE_ARG_POINTER(aMatrix);
13851 *aMatrix = nullptr;
13852
13853 if (mColorMatrix) {
13854 *aMatrix = (float*)moz_xmalloc(20 * sizeof(float));
13855 if (!*aMatrix) {
13856 return NS_ERROR_OUT_OF_MEMORY;
13857 }
13858
13859 MOZ_ASSERT(20 * sizeof(float) == sizeof(mColorMatrix->components));
13860 *aMatrixLen = 20;
13861 memcpy(*aMatrix, mColorMatrix->components, 20 * sizeof(float));
13862 }
13863
13864 return NS_OK;
13865 }
13866