Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/docshell/base/nsDocShell.cpp
Line
Count
Source (jump to first uncovered line)
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/StaticPrefs.h"
33
#include "mozilla/StartupTimeline.h"
34
#include "mozilla/Telemetry.h"
35
#include "mozilla/Unused.h"
36
37
#include "mozilla/dom/ClientChannelHelper.h"
38
#include "mozilla/dom/ClientHandle.h"
39
#include "mozilla/dom/ClientInfo.h"
40
#include "mozilla/dom/ClientManager.h"
41
#include "mozilla/dom/ClientSource.h"
42
#include "mozilla/dom/ContentChild.h"
43
#include "mozilla/dom/ContentFrameMessageManager.h"
44
#include "mozilla/dom/DocGroup.h"
45
#include "mozilla/dom/Element.h"
46
#include "mozilla/dom/HTMLAnchorElement.h"
47
#include "mozilla/dom/PerformanceNavigation.h"
48
#include "mozilla/dom/PermissionMessageUtils.h"
49
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
50
#include "mozilla/dom/ScreenOrientation.h"
51
#include "mozilla/dom/ScriptSettings.h"
52
#include "mozilla/dom/ServiceWorkerInterceptController.h"
53
#include "mozilla/dom/ServiceWorkerUtils.h"
54
#include "mozilla/dom/SessionStorageManager.h"
55
#include "mozilla/dom/TabChild.h"
56
#include "mozilla/dom/TabGroup.h"
57
#include "mozilla/dom/ToJSValue.h"
58
#include "mozilla/dom/ChildSHistory.h"
59
60
61
#include "mozilla/net/ReferrerPolicy.h"
62
63
#include "nsIApplicationCacheChannel.h"
64
#include "nsIApplicationCacheContainer.h"
65
#include "nsIAppShell.h"
66
#include "nsIAsyncVerifyRedirectCallback.h"
67
#include "nsIAuthPrompt.h"
68
#include "nsIAuthPrompt2.h"
69
#include "nsICachingChannel.h"
70
#include "nsICaptivePortalService.h"
71
#include "nsIChannel.h"
72
#include "nsIChannelEventSink.h"
73
#include "nsIClassOfService.h"
74
#include "nsICommandManager.h"
75
#include "nsIConsoleReportCollector.h"
76
#include "nsIContent.h"
77
#include "nsIContentInlines.h"
78
#include "nsIContentSecurityPolicy.h"
79
#include "nsIContentViewer.h"
80
#include "nsIController.h"
81
#include "nsICookieService.h"
82
#include "nsIDocShellTreeItem.h"
83
#include "nsIDocShellTreeOwner.h"
84
#include "nsIDocument.h"
85
#include "nsIDocumentLoaderFactory.h"
86
#include "nsIDOMWindow.h"
87
#include "nsIEditingSession.h"
88
#include "nsIExternalProtocolService.h"
89
#include "nsIFormPOSTActionChannel.h"
90
#include "nsIFrame.h"
91
#include "nsIGlobalObject.h"
92
#include "nsIHttpChannel.h"
93
#include "nsIHttpChannelInternal.h"
94
#include "nsIIDNService.h"
95
#include "nsIInputStreamChannel.h"
96
#include "nsIInterfaceRequestorUtils.h"
97
#include "nsIJARChannel.h"
98
#include "nsILayoutHistoryState.h"
99
#include "nsILoadInfo.h"
100
#include "nsIMultiPartChannel.h"
101
#include "nsINestedURI.h"
102
#include "nsINetworkPredictor.h"
103
#include "nsINode.h"
104
#include "nsINSSErrorsService.h"
105
#include "nsIObserverService.h"
106
#include "nsIOService.h"
107
#include "nsIPrincipal.h"
108
#include "nsIPrivacyTransitionObserver.h"
109
#include "nsIPrompt.h"
110
#include "nsIPromptFactory.h"
111
#include "nsIReflowObserver.h"
112
#include "nsIScriptChannel.h"
113
#include "nsIScriptObjectPrincipal.h"
114
#include "nsIScriptSecurityManager.h"
115
#include "nsIScrollableFrame.h"
116
#include "nsIScrollObserver.h"
117
#include "nsISecureBrowserUI.h"
118
#include "nsISecurityUITelemetry.h"
119
#include "nsISeekableStream.h"
120
#include "nsISelectionDisplay.h"
121
#include "nsISHEntry.h"
122
#include "nsISHistory.h"
123
#include "nsISiteSecurityService.h"
124
#include "nsISocketProvider.h"
125
#include "nsIStringBundle.h"
126
#include "nsIStructuredCloneContainer.h"
127
#include "nsISupportsPrimitives.h"
128
#include "nsITabChild.h"
129
#include "nsITextToSubURI.h"
130
#include "nsITimedChannel.h"
131
#include "nsITimer.h"
132
#include "nsITransportSecurityInfo.h"
133
#include "nsIUploadChannel.h"
134
#include "nsIURIFixup.h"
135
#include "nsIURILoader.h"
136
#include "nsIURIMutator.h"
137
#include "nsIURL.h"
138
#include "nsIViewSourceChannel.h"
139
#include "nsIWebBrowserChrome.h"
140
#include "nsIWebBrowserChrome3.h"
141
#include "nsIWebBrowserChromeFocus.h"
142
#include "nsIWebBrowserFind.h"
143
#include "nsIWebProgress.h"
144
#include "nsIWidget.h"
145
#include "nsIWindowWatcher.h"
146
#include "nsIWritablePropertyBag2.h"
147
#include "nsIWyciwygChannel.h"
148
149
#include "nsCommandManager.h"
150
#include "nsPIDOMWindow.h"
151
#include "nsPILoadGroupInternal.h"
152
#include "nsPIWindowRoot.h"
153
154
#include "IHistory.h"
155
#include "IUrlClassifierUITelemetry.h"
156
157
#include "mozIThirdPartyUtil.h"
158
159
#include "nsArray.h"
160
#include "nsArrayUtils.h"
161
#include "nsAutoPtr.h"
162
#include "nsCDefaultURIFixup.h"
163
#include "nsCExternalHandlerService.h"
164
#include "nsContentDLF.h"
165
#include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
166
#include "nsContentSecurityManager.h"
167
#include "nsContentUtils.h"
168
#include "nsCURILoader.h"
169
#include "nsDocShellCID.h"
170
#include "nsDocShellEditorData.h"
171
#include "nsDocShellEnumerator.h"
172
#include "nsDocShellLoadInfo.h"
173
#include "nsDocShellLoadTypes.h"
174
#include "nsDOMCID.h"
175
#include "nsDOMNavigationTiming.h"
176
#include "nsDSURIContentListener.h"
177
#include "nsError.h"
178
#include "nsEscape.h"
179
#include "nsFocusManager.h"
180
#include "nsGlobalWindow.h"
181
#include "nsJSEnvironment.h"
182
#include "nsNetCID.h"
183
#include "nsNetUtil.h"
184
#include "nsObjectLoadingContent.h"
185
#include "nsPingListener.h"
186
#include "nsPoint.h"
187
#include "nsQueryObject.h"
188
#include "nsRect.h"
189
#include "nsRefreshTimer.h"
190
#include "nsSandboxFlags.h"
191
#include "nsSHistory.h"
192
#include "nsStructuredCloneContainer.h"
193
#include "nsSubDocumentFrame.h"
194
#include "nsView.h"
195
#include "nsViewManager.h"
196
#include "nsViewSourceHandler.h"
197
#include "nsWebBrowserFind.h"
198
#include "nsWhitespaceTokenizer.h"
199
#include "nsWidgetsCID.h"
200
#include "nsXULAppAPI.h"
201
202
#include "GeckoProfiler.h"
203
#include "mozilla/NullPrincipal.h"
204
#include "Navigator.h"
205
#include "prenv.h"
206
#include "URIUtils.h"
207
208
#include "timeline/JavascriptTimelineMarker.h"
209
210
#ifdef MOZ_PLACES
211
#include "nsIFaviconService.h"
212
#include "mozIPlacesPendingOperation.h"
213
#endif
214
215
#if NS_PRINT_PREVIEW
216
#include "nsIDocumentViewerPrint.h"
217
#include "nsIWebBrowserPrint.h"
218
#endif
219
220
#ifdef MOZ_TOOLKIT_SEARCH
221
#include "nsIBrowserSearchService.h"
222
#endif
223
224
using namespace mozilla;
225
using namespace mozilla::dom;
226
using namespace mozilla::net;
227
228
// Threshold value in ms for META refresh based redirects
229
0
#define REFRESH_REDIRECT_TIMER 15000
230
231
// Hint for native dispatch of events on how long to delay after
232
// all documents have loaded in milliseconds before favoring normal
233
// native event dispatch priorites over performance
234
// Can be overridden with docshell.event_starvation_delay_hint pref.
235
0
#define NS_EVENT_STARVATION_DELAY_HINT 2000
236
237
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
238
239
// True means sUseErrorPages has been added to
240
// preferences var cache.
241
static bool gAddedPreferencesVarCache = false;
242
243
// Number of documents currently loading
244
static int32_t gNumberOfDocumentsLoading = 0;
245
246
// Global count of existing docshells.
247
static int32_t gDocShellCount = 0;
248
249
// Global count of docshells with the private attribute set
250
static uint32_t gNumberOfPrivateDocShells = 0;
251
252
// True means we validate window targets to prevent frameset
253
// spoofing. Initialize this to a non-bolean value so we know to check
254
// the pref on the creation of the first docshell.
255
static uint32_t gValidateOrigin = 0xffffffff;
256
257
#ifdef DEBUG
258
static mozilla::LazyLogModule gDocShellLog("nsDocShell");
259
#endif
260
static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");;
261
262
const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
263
const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
264
265
bool nsDocShell::sUseErrorPages = false;
266
267
// Global reference to the URI fixup service.
268
nsIURIFixup* nsDocShell::sURIFixup = nullptr;
269
270
static void
271
FavorPerformanceHint(bool aPerfOverStarvation)
272
0
{
273
0
  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
274
0
  if (appShell) {
275
0
    appShell->FavorPerformanceHint(
276
0
      aPerfOverStarvation,
277
0
      Preferences::GetUint("docshell.event_starvation_delay_hint",
278
0
                           NS_EVENT_STARVATION_DELAY_HINT));
279
0
  }
280
0
}
281
282
static void
283
IncreasePrivateDocShellCount()
284
0
{
285
0
  gNumberOfPrivateDocShells++;
286
0
  if (gNumberOfPrivateDocShells > 1 ||
287
0
      !XRE_IsContentProcess()) {
288
0
    return;
289
0
  }
290
0
291
0
  mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
292
0
  cc->SendPrivateDocShellsExist(true);
293
0
}
294
295
static void
296
DecreasePrivateDocShellCount()
297
0
{
298
0
  MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
299
0
  gNumberOfPrivateDocShells--;
300
0
  if (!gNumberOfPrivateDocShells) {
301
0
    if (XRE_IsContentProcess()) {
302
0
      dom::ContentChild* cc = dom::ContentChild::GetSingleton();
303
0
      cc->SendPrivateDocShellsExist(false);
304
0
      return;
305
0
    }
306
0
307
0
    nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
308
0
    if (obsvc) {
309
0
      obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
310
0
    }
311
0
  }
312
0
}
313
314
nsDocShell::nsDocShell()
315
  : nsDocLoader()
316
  , mForcedCharset(nullptr)
317
  , mParentCharset(nullptr)
318
  , mTreeOwner(nullptr)
319
  , mChromeEventHandler(nullptr)
320
  , mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto)
321
  , mCharsetReloadState(eCharsetReloadInit)
322
  , mOrientationLock(hal::eScreenOrientation_None)
323
  , mParentCharsetSource(0)
324
  , mMarginWidth(-1)
325
  , mMarginHeight(-1)
326
  , mItemType(typeContent)
327
  , mPreviousEntryIndex(-1)
328
  , mLoadedEntryIndex(-1)
329
  , mChildOffset(0)
330
  , mSandboxFlags(0)
331
  , mBusyFlags(BUSY_FLAGS_NONE)
332
  , mAppType(nsIDocShell::APP_TYPE_UNKNOWN)
333
  , mLoadType(0)
334
  , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
335
  , mReferrerPolicy(0)
336
  , mFailedLoadType(0)
337
  , mFrameType(FRAME_TYPE_REGULAR)
338
  , mPrivateBrowsingId(0)
339
  , mDisplayMode(nsIDocShell::DISPLAY_MODE_BROWSER)
340
  , mJSRunToCompletionDepth(0)
341
  , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE)
342
  , mFullscreenAllowed(CHECK_ATTRIBUTES)
343
  , mCreatingDocument(false)
344
#ifdef DEBUG
345
  , mInEnsureScriptEnv(false)
346
#endif
347
  , mCreated(false)
348
  , mAllowSubframes(true)
349
  , mAllowPlugins(true)
350
  , mAllowJavascript(true)
351
  , mAllowMetaRedirects(true)
352
  , mAllowImages(true)
353
  , mAllowMedia(true)
354
  , mAllowDNSPrefetch(true)
355
  , mAllowWindowControl(true)
356
  , mAllowContentRetargeting(true)
357
  , mAllowContentRetargetingOnChildren(true)
358
  , mUseErrorPages(false)
359
  , mObserveErrorPages(true)
360
  , mCSSErrorReportingEnabled(false)
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
0
{
388
0
  mHistoryID.m0 = 0;
389
0
  mHistoryID.m1 = 0;
390
0
  mHistoryID.m2 = 0;
391
0
  AssertOriginAttributesMatchPrivateBrowsing();
392
0
393
0
  nsContentUtils::GenerateUUIDInPlace(mHistoryID);
394
0
395
0
  if (gDocShellCount++ == 0) {
396
0
    NS_ASSERTION(sURIFixup == nullptr,
397
0
                 "Huh, sURIFixup not null in first nsDocShell ctor!");
398
0
399
0
    CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
400
0
  }
401
0
402
0
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
403
0
404
#ifdef DEBUG
405
  // We're counting the number of |nsDocShells| to help find leaks
406
  ++gNumberOfDocShells;
407
  if (!PR_GetEnv("MOZ_QUIET")) {
408
    printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
409
                  (void*)this,
410
                  gNumberOfDocShells,
411
                  getpid(),
412
                  nsIDToCString(mHistoryID).get());
413
  }
414
#endif
415
}
416
417
nsDocShell::~nsDocShell()
418
0
{
419
0
  MOZ_ASSERT(!mObserved);
420
0
421
0
  // Avoid notifying observers while we're in the dtor.
422
0
  mIsBeingDestroyed = true;
423
0
424
0
  Destroy();
425
0
426
0
  if (mSessionHistory) {
427
0
    mSessionHistory->LegacySHistory()->SetRootDocShell(nullptr);
428
0
  }
429
0
430
0
  if (--gDocShellCount == 0) {
431
0
    NS_IF_RELEASE(sURIFixup);
432
0
  }
433
0
434
0
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this));
435
0
436
#ifdef DEBUG
437
  // We're counting the number of |nsDocShells| to help find leaks
438
  --gNumberOfDocShells;
439
  if (!PR_GetEnv("MOZ_QUIET")) {
440
    printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
441
                  (void*)this,
442
                  gNumberOfDocShells,
443
                  getpid(),
444
                  nsIDToCString(mHistoryID).get());
445
  }
446
#endif
447
}
448
449
nsresult
450
nsDocShell::Init()
451
0
{
452
0
  MOZ_ASSERT(!mIsBeingDestroyed);
453
0
454
0
  nsresult rv = nsDocLoader::Init();
455
0
  NS_ENSURE_SUCCESS(rv, rv);
456
0
457
0
  NS_ASSERTION(mLoadGroup, "Something went wrong!");
458
0
459
0
  mContentListener = new nsDSURIContentListener(this);
460
0
  rv = mContentListener->Init();
461
0
  NS_ENSURE_SUCCESS(rv, rv);
462
0
463
0
  // If parent intercept is not enabled then we must forward to
464
0
  // the network controller from docshell.  We also enable if we're
465
0
  // in the parent process in order to support non-e10s configurations.
466
0
  if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
467
0
    mInterceptController = new ServiceWorkerInterceptController();
468
0
  }
469
0
470
0
  // We want to hold a strong ref to the loadgroup, so it better hold a weak
471
0
  // ref to us...  use an InterfaceRequestorProxy to do this.
472
0
  nsCOMPtr<nsIInterfaceRequestor> proxy =
473
0
    new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
474
0
  mLoadGroup->SetNotificationCallbacks(proxy);
475
0
476
0
  rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
477
0
  NS_ENSURE_SUCCESS(rv, rv);
478
0
479
0
  mBrowsingContext = BrowsingContext::Create(this);
480
0
481
0
  // Add as |this| a progress listener to itself.  A little weird, but
482
0
  // simpler than reproducing all the listener-notification logic in
483
0
  // overrides of the various methods via which nsDocLoader can be
484
0
  // notified.   Note that this holds an nsWeakPtr to ourselves, so it's ok.
485
0
  return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
486
0
                                     nsIWebProgress::NOTIFY_STATE_NETWORK);
487
0
}
488
489
void
490
nsDocShell::DestroyChildren()
491
0
{
492
0
  nsCOMPtr<nsIDocShellTreeItem> shell;
493
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
494
0
  while (iter.HasMore()) {
495
0
    shell = do_QueryObject(iter.GetNext());
496
0
    NS_ASSERTION(shell, "docshell has null child");
497
0
498
0
    if (shell) {
499
0
      shell->SetTreeOwner(nullptr);
500
0
    }
501
0
  }
502
0
503
0
  nsDocLoader::DestroyChildren();
504
0
}
505
506
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell,
507
                                   nsDocLoader,
508
                                   mSessionStorageManager,
509
                                   mScriptGlobal,
510
                                   mInitialClientSource,
511
                                   mSessionHistory,
512
                                   mBrowsingContext)
513
514
NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
515
NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
516
517
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
518
0
  NS_INTERFACE_MAP_ENTRY(nsIDocShell)
519
0
  NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
520
0
  NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
521
0
  NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
522
0
  NS_INTERFACE_MAP_ENTRY(nsIScrollable)
523
0
  NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
524
0
  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
525
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
526
0
  NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
527
0
  NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
528
0
  NS_INTERFACE_MAP_ENTRY(nsILoadContext)
529
0
  NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
530
0
  NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
531
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,
532
0
                                     mInterceptController)
533
0
  NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
534
0
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
535
536
NS_IMETHODIMP
537
nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
538
0
{
539
0
  MOZ_ASSERT(aSink, "null out param");
540
0
541
0
  *aSink = nullptr;
542
0
543
0
  if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
544
0
    NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
545
0
    *aSink = mCommandManager;
546
0
  } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
547
0
    *aSink = mContentListener;
548
0
  } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
549
0
              aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
550
0
              aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
551
0
              aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
552
0
              aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
553
0
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
554
0
    return mScriptGlobal->QueryInterface(aIID, aSink);
555
0
  } else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
556
0
             NS_SUCCEEDED(EnsureContentViewer())) {
557
0
    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
558
0
    doc.forget(aSink);
559
0
    return *aSink ? NS_OK : NS_NOINTERFACE;
560
0
  } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
561
0
    *aSink = nullptr;
562
0
563
0
    // Return application cache associated with this docshell, if any
564
0
565
0
    nsCOMPtr<nsIContentViewer> contentViewer;
566
0
    GetContentViewer(getter_AddRefs(contentViewer));
567
0
    if (!contentViewer) {
568
0
      return NS_ERROR_NO_INTERFACE;
569
0
    }
570
0
571
0
    nsCOMPtr<nsIDocument> doc = contentViewer->GetDocument();
572
0
    NS_ASSERTION(doc, "Should have a document.");
573
0
    if (!doc) {
574
0
      return NS_ERROR_NO_INTERFACE;
575
0
    }
576
0
577
#if defined(DEBUG)
578
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
579
           ("nsDocShell[%p]: returning app cache container %p",
580
            this, doc.get()));
581
#endif
582
0
    return doc->QueryInterface(aIID, aSink);
583
0
  } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
584
0
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
585
0
    nsresult rv;
586
0
    nsCOMPtr<nsIWindowWatcher> wwatch =
587
0
      do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
588
0
    NS_ENSURE_SUCCESS(rv, rv);
589
0
590
0
    // Get the an auth prompter for our window so that the parenting
591
0
    // of the dialogs works as it should when using tabs.
592
0
    nsIPrompt* prompt;
593
0
    rv = wwatch->GetNewPrompter(mScriptGlobal->AsOuter(), &prompt);
594
0
    NS_ENSURE_SUCCESS(rv, rv);
595
0
596
0
    *aSink = prompt;
597
0
    return NS_OK;
598
0
  } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
599
0
             aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
600
0
    return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
601
0
      NS_OK : NS_NOINTERFACE;
602
0
  } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
603
0
    RefPtr<ChildSHistory> shistory = GetSessionHistory();
604
0
    if (shistory) {
605
0
      // XXX(nika): Stop exposing nsISHistory through GetInterface.
606
0
      nsCOMPtr<nsISHistory> legacy = shistory->LegacySHistory();
607
0
      legacy.forget(aSink);
608
0
      return NS_OK;
609
0
    }
610
0
    return NS_NOINTERFACE;
611
0
  } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
612
0
    nsresult rv = EnsureFind();
613
0
    if (NS_FAILED(rv)) {
614
0
      return rv;
615
0
    }
616
0
617
0
    *aSink = mFind;
618
0
    NS_ADDREF((nsISupports*)*aSink);
619
0
    return NS_OK;
620
0
  } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
621
0
    nsIPresShell* shell = GetPresShell();
622
0
    if (shell) {
623
0
      return shell->QueryInterface(aIID, aSink);
624
0
    }
625
0
  } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
626
0
    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
627
0
    nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
628
0
    if (NS_SUCCEEDED(rv) && treeOwner) {
629
0
      return treeOwner->QueryInterface(aIID, aSink);
630
0
    }
631
0
  } else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
632
0
    *aSink = GetTabChild().take();
633
0
    return *aSink ? NS_OK : NS_ERROR_FAILURE;
634
0
  } else {
635
0
    return nsDocLoader::GetInterface(aIID, aSink);
636
0
  }
637
0
638
0
  NS_IF_ADDREF(((nsISupports*)*aSink));
639
0
  return *aSink ? NS_OK : NS_NOINTERFACE;
640
0
}
641
642
NS_IMETHODIMP
643
nsDocShell::LoadURI(nsIURI* aURI,
644
                    nsDocShellLoadInfo* aLoadInfo,
645
                    uint32_t aLoadFlags,
646
                    bool aFirstParty)
647
0
{
648
0
  MOZ_ASSERT(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
649
0
             "Unexpected flags");
650
0
  MOZ_ASSERT((aLoadFlags & 0xf) == 0, "Should not have these flags set");
651
0
652
0
  // Note: we allow loads to get through here even if mFiredUnloadEvent is
653
0
  // true; that case will get handled in LoadInternal or LoadHistoryEntry,
654
0
  // so we pass false as the second parameter to IsNavigationAllowed.
655
0
  // However, we don't allow the page to change location *in the middle of*
656
0
  // firing beforeunload, so we do need to check if *beforeunload* is currently
657
0
  // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
658
0
  if (!IsNavigationAllowed(true, false)) {
659
0
    return NS_OK; // JS may not handle returning of an error code
660
0
  }
661
0
662
0
  nsCOMPtr<nsIURI> referrer;
663
0
  nsCOMPtr<nsIURI> originalURI;
664
0
  Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
665
0
  bool keepResultPrincipalURIIfSet = false;
666
0
  bool loadReplace = false;
667
0
  nsCOMPtr<nsIInputStream> postStream;
668
0
  nsCOMPtr<nsIInputStream> headersStream;
669
0
  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
670
0
  bool inheritPrincipal = false;
671
0
  bool principalIsExplicit = false;
672
0
  bool sendReferrer = true;
673
0
  uint32_t referrerPolicy = RP_Unset;
674
0
  bool isSrcdoc = false;
675
0
  nsCOMPtr<nsISHEntry> shEntry;
676
0
  nsString target;
677
0
  nsAutoString srcdoc;
678
0
  bool forceAllowDataURI = false;
679
0
  bool originalFrameSrc = false;
680
0
  nsCOMPtr<nsIDocShell> sourceDocShell;
681
0
  nsCOMPtr<nsIURI> baseURI;
682
0
683
0
  uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
684
0
685
0
  NS_ENSURE_ARG(aURI);
686
0
687
0
  if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
688
0
      mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
689
0
    StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
690
0
  }
691
0
692
0
  // Extract the info from the DocShellLoadInfo struct...
693
0
  if (aLoadInfo) {
694
0
    referrer = aLoadInfo->Referrer();
695
0
    originalURI = aLoadInfo->OriginalURI();
696
0
    aLoadInfo->GetMaybeResultPrincipalURI(resultPrincipalURI);
697
0
    keepResultPrincipalURIIfSet = aLoadInfo->KeepResultPrincipalURIIfSet();
698
0
    loadReplace = aLoadInfo->LoadReplace();
699
0
    // Get the appropriate loadType from nsIDocShellLoadInfo type
700
0
    loadType = aLoadInfo->LoadType();
701
0
702
0
    triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
703
0
    inheritPrincipal = aLoadInfo->InheritPrincipal();
704
0
    principalIsExplicit = aLoadInfo->PrincipalIsExplicit();
705
0
    shEntry = aLoadInfo->SHEntry();
706
0
    aLoadInfo->GetTarget(target);
707
0
    postStream = aLoadInfo->PostDataStream();
708
0
    headersStream = aLoadInfo->HeadersStream();
709
0
    sendReferrer = aLoadInfo->SendReferrer();
710
0
    referrerPolicy = aLoadInfo->ReferrerPolicy();
711
0
    isSrcdoc = aLoadInfo->IsSrcdocLoad();
712
0
    aLoadInfo->GetSrcdocData(srcdoc);
713
0
    sourceDocShell = aLoadInfo->SourceDocShell();
714
0
    baseURI = aLoadInfo->BaseURI();
715
0
    forceAllowDataURI = aLoadInfo->ForceAllowDataURI();
716
0
    originalFrameSrc = aLoadInfo->OriginalFrameSrc();
717
0
  }
718
0
719
0
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
720
0
          ("nsDocShell[%p]: loading %s with flags 0x%08x",
721
0
           this, aURI->GetSpecOrDefault().get(), aLoadFlags));
722
0
723
0
  if (!shEntry &&
724
0
      !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
725
0
    // First verify if this is a subframe.
726
0
    nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
727
0
    GetSameTypeParent(getter_AddRefs(parentAsItem));
728
0
    nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
729
0
    uint32_t parentLoadType;
730
0
731
0
    if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) {
732
0
      /* OK. It is a subframe. Checkout the
733
0
       * parent's loadtype. If the parent was loaded thro' a history
734
0
       * mechanism, then get the SH entry for the child from the parent.
735
0
       * This is done to restore frameset navigation while going back/forward.
736
0
       * If the parent was loaded through any other loadType, set the
737
0
       * child's loadType too accordingly, so that session history does not
738
0
       * get confused.
739
0
       */
740
0
741
0
      // Get the parent's load type
742
0
      parentDS->GetLoadType(&parentLoadType);
743
0
744
0
      // Get the ShEntry for the child from the parent
745
0
      nsCOMPtr<nsISHEntry> currentSH;
746
0
      bool oshe = false;
747
0
      parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
748
0
      bool dynamicallyAddedChild = mDynamicallyCreated;
749
0
      if (!dynamicallyAddedChild && !oshe && currentSH) {
750
0
        currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
751
0
      }
752
0
      if (!dynamicallyAddedChild) {
753
0
        // Only use the old SHEntry, if we're sure enough that
754
0
        // it wasn't originally for some other frame.
755
0
        parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
756
0
      }
757
0
758
0
      // Make some decisions on the child frame's loadType based on the
759
0
      // parent's loadType, if the subframe hasn't loaded anything into it.
760
0
      //
761
0
      // In some cases privileged scripts may try to get the DOMWindow
762
0
      // reference of this docshell before the loading starts, causing the
763
0
      // initial about:blank content viewer being created and mCurrentURI being
764
0
      // set. To handle this case we check if mCurrentURI is about:blank and
765
0
      // currentSHEntry is null.
766
0
      nsCOMPtr<nsISHEntry> currentChildEntry;
767
0
      GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);
768
0
      if (!mCurrentURI || (NS_IsAboutBlank(mCurrentURI) && !currentChildEntry)) {
769
0
        // This is a newly created frame. Check for exception cases first.
770
0
        // By default the subframe will inherit the parent's loadType.
771
0
        if (shEntry && (parentLoadType == LOAD_NORMAL ||
772
0
                        parentLoadType == LOAD_LINK   ||
773
0
                        parentLoadType == LOAD_NORMAL_EXTERNAL)) {
774
0
          // The parent was loaded normally. In this case, this *brand new*
775
0
          // child really shouldn't have a SHEntry. If it does, it could be
776
0
          // because the parent is replacing an existing frame with a new frame,
777
0
          // in the onLoadHandler. We don't want this url to get into session
778
0
          // history. Clear off shEntry, and set load type to
779
0
          // LOAD_BYPASS_HISTORY.
780
0
          bool inOnLoadHandler = false;
781
0
          parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
782
0
          if (inOnLoadHandler) {
783
0
            loadType = LOAD_NORMAL_REPLACE;
784
0
            shEntry = nullptr;
785
0
          }
786
0
        } else if (parentLoadType == LOAD_REFRESH) {
787
0
          // Clear shEntry. For refresh loads, we have to load
788
0
          // what comes thro' the pipe, not what's in history.
789
0
          shEntry = nullptr;
790
0
        } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
791
0
                   (shEntry &&
792
0
                    ((parentLoadType & LOAD_CMD_HISTORY) ||
793
0
                     (parentLoadType == LOAD_RELOAD_NORMAL) ||
794
0
                     (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
795
0
                     (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
796
0
                     (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
797
0
          // If the parent url, bypassed history or was loaded from
798
0
          // history, pass on the parent's loadType to the new child
799
0
          // frame too, so that the child frame will also
800
0
          // avoid getting into history.
801
0
          loadType = parentLoadType;
802
0
        } else if (parentLoadType == LOAD_ERROR_PAGE) {
803
0
          // If the parent document is an error page, we don't
804
0
          // want to update global/session history. However,
805
0
          // this child frame is not an error page.
806
0
          loadType = LOAD_BYPASS_HISTORY;
807
0
        } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
808
0
                   (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
809
0
                   (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
810
0
          // the new frame should inherit the parent's load type so that it also
811
0
          // bypasses the cache and/or proxy
812
0
          loadType = parentLoadType;
813
0
        }
814
0
      } else {
815
0
        // This is a pre-existing subframe. If
816
0
        // 1. The load of this frame was not originally initiated by session
817
0
        //    history directly (i.e. (!shEntry) condition succeeded, but it can
818
0
        //    still be a history load on parent which causes this frame being
819
0
        //    loaded), and
820
0
        // 2. mCurrentURI is not null, nor the initial about:blank,
821
0
        // it is possible that a parent's onLoadHandler or even self's
822
0
        // onLoadHandler is loading a new page in this child. Check parent's and
823
0
        // self's busy flag and if it is set, we don't want this onLoadHandler
824
0
        // load to get in to session history.
825
0
        uint32_t parentBusy = BUSY_FLAGS_NONE;
826
0
        uint32_t selfBusy = BUSY_FLAGS_NONE;
827
0
        parentDS->GetBusyFlags(&parentBusy);
828
0
        GetBusyFlags(&selfBusy);
829
0
        if (parentBusy & BUSY_FLAGS_BUSY ||
830
0
            selfBusy & BUSY_FLAGS_BUSY) {
831
0
          loadType = LOAD_NORMAL_REPLACE;
832
0
          shEntry = nullptr;
833
0
        }
834
0
      }
835
0
    } // parentDS
836
0
    else {
837
0
      // This is the root docshell. If we got here while
838
0
      // executing an onLoad Handler,this load will not go
839
0
      // into session history.
840
0
      bool inOnLoadHandler = false;
841
0
      GetIsExecutingOnLoadHandler(&inOnLoadHandler);
842
0
      if (inOnLoadHandler) {
843
0
        loadType = LOAD_NORMAL_REPLACE;
844
0
      }
845
0
    }
846
0
  } // !shEntry
847
0
848
0
  if (shEntry) {
849
#ifdef DEBUG
850
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
851
           ("nsDocShell[%p]: loading from session history", this));
852
#endif
853
854
0
    return LoadHistoryEntry(shEntry, loadType);
855
0
  }
856
0
857
0
  // On history navigation via Back/Forward buttons, don't execute
858
0
  // automatic JavaScript redirection such as |location.href = ...| or
859
0
  // |window.open()|
860
0
  //
861
0
  // LOAD_NORMAL:        window.open(...) etc.
862
0
  // LOAD_STOP_CONTENT:  location.href = ..., location.assign(...)
863
0
  if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
864
0
      ShouldBlockLoadingForBackButton()) {
865
0
    return NS_OK;
866
0
  }
867
0
868
0
  // Perform the load...
869
0
870
0
  // We need a principalToInherit.
871
0
  //
872
0
  // If principalIsExplicit is not set there are 4 possibilities:
873
0
  // (1) If the system principal or an expanded principal was passed
874
0
  //     in and we're a typeContent docshell, inherit the principal
875
0
  //     from the current document instead.
876
0
  // (2) In all other cases when the principal passed in is not null,
877
0
  //     use that principal.
878
0
  // (3) If the caller has allowed inheriting from the current document,
879
0
  //     or if we're being called from system code (eg chrome JS or pure
880
0
  //     C++) then inheritPrincipal should be true and InternalLoad will get
881
0
  //     a principal from the current document. If none of these things are
882
0
  //     true, then
883
0
  // (4) we don't pass a principal into the channel, and a principal will be
884
0
  //     created later from the channel's internal data.
885
0
  //
886
0
  // If principalIsExplicit *is* set, there are 4 possibilities
887
0
  // (1) If the system principal or an expanded principal was passed in
888
0
  //     and we're a typeContent docshell, return an error.
889
0
  // (2) In all other cases when the principal passed in is not null,
890
0
  //     use that principal.
891
0
  // (3) If the caller has allowed inheriting from the current document,
892
0
  //     then inheritPrincipal should be true and InternalLoad will get
893
0
  //     a principal from the current document. If none of these things are
894
0
  //     true, then
895
0
  // (4) we dont' pass a principal into the channel, and a principal will be
896
0
  //     created later from the channel's internal data.
897
0
  nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal;
898
0
  if (principalToInherit && mItemType != typeChrome) {
899
0
    if (nsContentUtils::IsSystemPrincipal(principalToInherit)) {
900
0
      if (principalIsExplicit) {
901
0
        return NS_ERROR_DOM_SECURITY_ERR;
902
0
      }
903
0
      principalToInherit = nullptr;
904
0
      inheritPrincipal = true;
905
0
    } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) {
906
0
      if (principalIsExplicit) {
907
0
        return NS_ERROR_DOM_SECURITY_ERR;
908
0
      }
909
0
      // Don't inherit from the current page.  Just do the safe thing
910
0
      // and pretend that we were loaded by a nullprincipal.
911
0
      //
912
0
      // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
913
0
      // have origin attributes.
914
0
      principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this);
915
0
      inheritPrincipal = false;
916
0
    }
917
0
  }
918
0
  if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) {
919
0
    // See if there's system or chrome JS code running
920
0
    inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
921
0
  }
922
0
923
0
  if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
924
0
    inheritPrincipal = false;
925
0
    // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
926
0
    // enabled, we will set firstPartyDomain on the origin attributes.
927
0
    principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
928
0
  }
929
0
930
0
  // If the triggeringPrincipal is not passed explicitly, we first try to create
931
0
  // a principal from the referrer, since the referrer URI reflects the web origin
932
0
  // that triggered the load. If there is no referrer URI, we fall back to using
933
0
  // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
934
0
  // and no referrer simulate a load that was triggered by the system.
935
0
  // It's important to note that this block of code needs to appear *after* the block
936
0
  // where we munge the principalToInherit, because otherwise we would never enter
937
0
  // code blocks checking if the principalToInherit is null and we will end up with
938
0
  // a wrong inheritPrincipal flag.
939
0
  if (!triggeringPrincipal) {
940
0
    if (referrer) {
941
0
      nsresult rv = CreatePrincipalFromReferrer(referrer,
942
0
                                                getter_AddRefs(triggeringPrincipal));
943
0
      NS_ENSURE_SUCCESS(rv, rv);
944
0
    }
945
0
    else {
946
0
      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
947
0
    }
948
0
  }
949
0
950
0
  uint32_t flags = 0;
951
0
952
0
  if (inheritPrincipal) {
953
0
    MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(principalToInherit), "Should not inherit SystemPrincipal");
954
0
    flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
955
0
  }
956
0
957
0
  if (!sendReferrer) {
958
0
    flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
959
0
  }
960
0
961
0
  if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
962
0
    flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
963
0
  }
964
0
965
0
  if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) {
966
0
    flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
967
0
  }
968
0
969
0
  if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) {
970
0
    flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
971
0
  }
972
0
973
0
  if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
974
0
    flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
975
0
  }
976
0
977
0
  if (isSrcdoc) {
978
0
    flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
979
0
  }
980
0
981
0
  if (forceAllowDataURI) {
982
0
    flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
983
0
  }
984
0
985
0
  if (originalFrameSrc) {
986
0
    flags |= INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
987
0
  }
988
0
989
0
  return InternalLoad(aURI,
990
0
                      originalURI,
991
0
                      resultPrincipalURI,
992
0
                      keepResultPrincipalURIIfSet,
993
0
                      loadReplace,
994
0
                      referrer,
995
0
                      referrerPolicy,
996
0
                      triggeringPrincipal,
997
0
                      principalToInherit,
998
0
                      flags,
999
0
                      target,
1000
0
                      nullptr,      // No type hint
1001
0
                      VoidString(), // No forced download
1002
0
                      postStream,
1003
0
                      headersStream,
1004
0
                      loadType,
1005
0
                      nullptr, // No SHEntry
1006
0
                      aFirstParty,
1007
0
                      srcdoc,
1008
0
                      sourceDocShell,
1009
0
                      baseURI,
1010
0
                      nullptr,  // No nsIDocShell
1011
0
                      nullptr); // No nsIRequest
1012
0
}
1013
1014
/*
1015
 * Reset state to a new content model within the current document and the
1016
 * document viewer. Called by the document before initiating an out of band
1017
 * document.write().
1018
 */
1019
NS_IMETHODIMP
1020
nsDocShell::PrepareForNewContentModel()
1021
0
{
1022
0
  mEODForCurrentDocument = false;
1023
0
  return NS_OK;
1024
0
}
1025
1026
NS_IMETHODIMP
1027
nsDocShell::FirePageHideNotification(bool aIsUnload)
1028
0
{
1029
0
  FirePageHideNotificationInternal(aIsUnload, false);
1030
0
  return NS_OK;
1031
0
}
1032
1033
void
1034
nsDocShell::FirePageHideNotificationInternal(bool aIsUnload,
1035
                                             bool aSkipCheckingDynEntries)
1036
0
{
1037
0
  if (mContentViewer && !mFiredUnloadEvent) {
1038
0
    // Keep an explicit reference since calling PageHide could release
1039
0
    // mContentViewer
1040
0
    nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer);
1041
0
    mFiredUnloadEvent = true;
1042
0
1043
0
    if (mTiming) {
1044
0
      mTiming->NotifyUnloadEventStart();
1045
0
    }
1046
0
1047
0
    contentViewer->PageHide(aIsUnload);
1048
0
1049
0
    if (mTiming) {
1050
0
      mTiming->NotifyUnloadEventEnd();
1051
0
    }
1052
0
1053
0
    AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
1054
0
    uint32_t n = mChildList.Length();
1055
0
    kids.SetCapacity(n);
1056
0
    for (uint32_t i = 0; i < n; i++) {
1057
0
      kids.AppendElement(do_QueryInterface(ChildAt(i)));
1058
0
    }
1059
0
1060
0
    n = kids.Length();
1061
0
    for (uint32_t i = 0; i < n; ++i) {
1062
0
      RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get());
1063
0
      if (child) {
1064
0
        // Skip checking dynamic subframe entries in our children.
1065
0
        child->FirePageHideNotificationInternal(aIsUnload, true);
1066
0
      }
1067
0
    }
1068
0
1069
0
    // If the document is unloading, remove all dynamic subframe entries.
1070
0
    if (aIsUnload && !aSkipCheckingDynEntries) {
1071
0
      RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
1072
0
      if (rootSH && mOSHE) {
1073
0
        int32_t index = rootSH->Index();
1074
0
        rootSH->LegacySHistory()->RemoveDynEntries(index, mOSHE);
1075
0
      }
1076
0
    }
1077
0
1078
0
    // Now make sure our editor, if any, is detached before we go
1079
0
    // any farther.
1080
0
    DetachEditorFromWindow();
1081
0
  }
1082
0
}
1083
1084
nsresult
1085
nsDocShell::DispatchToTabGroup(TaskCategory aCategory,
1086
                               already_AddRefed<nsIRunnable>&& aRunnable)
1087
0
{
1088
0
  // Hold the ref so we won't forget to release it.
1089
0
  nsCOMPtr<nsIRunnable> runnable(aRunnable);
1090
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
1091
0
  if (!win) {
1092
0
    // Window should only be unavailable after destroyed.
1093
0
    MOZ_ASSERT(mIsBeingDestroyed);
1094
0
    return NS_ERROR_FAILURE;
1095
0
  }
1096
0
1097
0
  if (win->GetDocGroup()) {
1098
0
    return win->GetDocGroup()->Dispatch(aCategory, runnable.forget());
1099
0
  }
1100
0
  RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
1101
0
  return tabGroup->Dispatch(aCategory, runnable.forget());
1102
0
}
1103
1104
NS_IMETHODIMP
1105
nsDocShell::DispatchLocationChangeEvent()
1106
0
{
1107
0
  return DispatchToTabGroup(
1108
0
    TaskCategory::Other,
1109
0
    NewRunnableMethod("nsDocShell::FireDummyOnLocationChange",
1110
0
                      this,
1111
0
                      &nsDocShell::FireDummyOnLocationChange));
1112
0
}
1113
1114
bool
1115
nsDocShell::MaybeInitTiming()
1116
0
{
1117
0
  if (mTiming && !mBlankTiming) {
1118
0
    return false;
1119
0
  }
1120
0
1121
0
  bool canBeReset = false;
1122
0
1123
0
  if (mScriptGlobal && mBlankTiming) {
1124
0
    nsPIDOMWindowInner* innerWin =
1125
0
      mScriptGlobal->AsOuter()->GetCurrentInnerWindow();
1126
0
    if (innerWin && innerWin->GetPerformance()) {
1127
0
      mTiming = innerWin->GetPerformance()->GetDOMTiming();
1128
0
      mBlankTiming = false;
1129
0
    }
1130
0
  }
1131
0
1132
0
  if (!mTiming) {
1133
0
    mTiming = new nsDOMNavigationTiming(this);
1134
0
    canBeReset = true;
1135
0
  }
1136
0
1137
0
  mTiming->NotifyNavigationStart(
1138
0
    mIsActive ? nsDOMNavigationTiming::DocShellState::eActive
1139
0
              : nsDOMNavigationTiming::DocShellState::eInactive);
1140
0
1141
0
  return canBeReset;
1142
0
}
1143
1144
void
1145
nsDocShell::MaybeResetInitTiming(bool aReset)
1146
0
{
1147
0
  if (aReset) {
1148
0
    mTiming = nullptr;
1149
0
  }
1150
0
}
1151
1152
nsDOMNavigationTiming*
1153
nsDocShell::GetNavigationTiming() const
1154
0
{
1155
0
  return mTiming;
1156
0
}
1157
1158
//
1159
// Bug 13871: Prevent frameset spoofing
1160
//
1161
// This routine answers: 'Is origin's document from same domain as
1162
// target's document?'
1163
//
1164
// file: uris are considered the same domain for the purpose of
1165
// frame navigation regardless of script accessibility (bug 420425)
1166
//
1167
/* static */ bool
1168
nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
1169
                           nsIDocShellTreeItem* aTargetTreeItem)
1170
0
{
1171
0
  // We want to bypass this check for chrome callers, but only if there's
1172
0
  // JS on the stack. System callers still need to do it.
1173
0
  if (nsContentUtils::GetCurrentJSContext() &&
1174
0
      nsContentUtils::IsCallerChrome()) {
1175
0
    return true;
1176
0
  }
1177
0
1178
0
  MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells");
1179
0
1180
0
  // Get origin document principal
1181
0
  nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument();
1182
0
  NS_ENSURE_TRUE(originDocument, false);
1183
0
1184
0
  // Get target principal
1185
0
  nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument();
1186
0
  NS_ENSURE_TRUE(targetDocument, false);
1187
0
1188
0
  bool equal;
1189
0
  nsresult rv = originDocument->NodePrincipal()->Equals(
1190
0
    targetDocument->NodePrincipal(), &equal);
1191
0
  if (NS_SUCCEEDED(rv) && equal) {
1192
0
    return true;
1193
0
  }
1194
0
1195
0
  // Not strictly equal, special case if both are file: uris
1196
0
  bool originIsFile = false;
1197
0
  bool targetIsFile = false;
1198
0
  nsCOMPtr<nsIURI> originURI;
1199
0
  nsCOMPtr<nsIURI> targetURI;
1200
0
  nsCOMPtr<nsIURI> innerOriginURI;
1201
0
  nsCOMPtr<nsIURI> innerTargetURI;
1202
0
1203
0
  rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
1204
0
  if (NS_SUCCEEDED(rv) && originURI) {
1205
0
    innerOriginURI = NS_GetInnermostURI(originURI);
1206
0
  }
1207
0
1208
0
  rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
1209
0
  if (NS_SUCCEEDED(rv) && targetURI) {
1210
0
    innerTargetURI = NS_GetInnermostURI(targetURI);
1211
0
  }
1212
0
1213
0
  return innerOriginURI && innerTargetURI &&
1214
0
         NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
1215
0
         NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
1216
0
         originIsFile && targetIsFile;
1217
0
}
1218
1219
nsresult
1220
nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
1221
0
{
1222
0
  NS_ENSURE_ARG_POINTER(aPresContext);
1223
0
  *aPresContext = nullptr;
1224
0
1225
0
  nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
1226
0
  while (viewer) {
1227
0
    nsCOMPtr<nsIContentViewer> prevViewer;
1228
0
    viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1229
0
    if (!prevViewer) {
1230
0
      return viewer->GetPresContext(aPresContext);
1231
0
    }
1232
0
    viewer = prevViewer;
1233
0
  }
1234
0
1235
0
  return NS_OK;
1236
0
}
1237
1238
NS_IMETHODIMP
1239
nsDocShell::GetPresContext(nsPresContext** aPresContext)
1240
0
{
1241
0
  NS_ENSURE_ARG_POINTER(aPresContext);
1242
0
  *aPresContext = nullptr;
1243
0
1244
0
  if (!mContentViewer) {
1245
0
    return NS_OK;
1246
0
  }
1247
0
1248
0
  return mContentViewer->GetPresContext(aPresContext);
1249
0
}
1250
1251
NS_IMETHODIMP_(nsIPresShell*)
1252
nsDocShell::GetPresShell()
1253
0
{
1254
0
  RefPtr<nsPresContext> presContext;
1255
0
  (void)GetPresContext(getter_AddRefs(presContext));
1256
0
  return presContext ? presContext->GetPresShell() : nullptr;
1257
0
}
1258
1259
NS_IMETHODIMP
1260
nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
1261
0
{
1262
0
  nsresult rv = NS_OK;
1263
0
1264
0
  NS_ENSURE_ARG_POINTER(aPresShell);
1265
0
  *aPresShell = nullptr;
1266
0
1267
0
  RefPtr<nsPresContext> presContext;
1268
0
  (void)GetEldestPresContext(getter_AddRefs(presContext));
1269
0
1270
0
  if (presContext) {
1271
0
    NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
1272
0
  }
1273
0
1274
0
  return rv;
1275
0
}
1276
1277
NS_IMETHODIMP
1278
nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer)
1279
0
{
1280
0
  NS_ENSURE_ARG_POINTER(aContentViewer);
1281
0
1282
0
  *aContentViewer = mContentViewer;
1283
0
  NS_IF_ADDREF(*aContentViewer);
1284
0
  return NS_OK;
1285
0
}
1286
1287
NS_IMETHODIMP
1288
nsDocShell::SetChromeEventHandler(EventTarget* aChromeEventHandler)
1289
0
{
1290
0
  // Weak reference. Don't addref.
1291
0
  mChromeEventHandler = aChromeEventHandler;
1292
0
1293
0
  if (mScriptGlobal) {
1294
0
    mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
1295
0
  }
1296
0
1297
0
  return NS_OK;
1298
0
}
1299
1300
NS_IMETHODIMP
1301
nsDocShell::GetChromeEventHandler(EventTarget** aChromeEventHandler)
1302
0
{
1303
0
  NS_ENSURE_ARG_POINTER(aChromeEventHandler);
1304
0
  nsCOMPtr<EventTarget> handler = mChromeEventHandler;
1305
0
  handler.forget(aChromeEventHandler);
1306
0
  return NS_OK;
1307
0
}
1308
1309
NS_IMETHODIMP
1310
nsDocShell::SetCurrentURI(nsIURI* aURI)
1311
0
{
1312
0
  // Note that securityUI will set STATE_IS_INSECURE, even if
1313
0
  // the scheme of |aURI| is "https".
1314
0
  SetCurrentURI(aURI, nullptr, true, 0);
1315
0
  return NS_OK;
1316
0
}
1317
1318
bool
1319
nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
1320
                          bool aFireOnLocationChange, uint32_t aLocationFlags)
1321
0
{
1322
0
  MOZ_ASSERT(!mIsBeingDestroyed);
1323
0
1324
0
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
1325
0
          ("DOCSHELL %p SetCurrentURI %s\n",
1326
0
           this, aURI ? aURI->GetSpecOrDefault().get() : ""));
1327
0
1328
0
  // We don't want to send a location change when we're displaying an error
1329
0
  // page, and we don't want to change our idea of "current URI" either
1330
0
  if (mLoadType == LOAD_ERROR_PAGE) {
1331
0
    return false;
1332
0
  }
1333
0
1334
0
  mCurrentURI = aURI;
1335
0
1336
0
  if (!NS_IsAboutBlank(mCurrentURI)) {
1337
0
    mHasLoadedNonBlankURI = true;
1338
0
  }
1339
0
1340
0
  bool isRoot = false;  // Is this the root docshell
1341
0
  bool isSubFrame = false;  // Is this a subframe navigation?
1342
0
1343
0
  nsCOMPtr<nsIDocShellTreeItem> root;
1344
0
1345
0
  GetSameTypeRootTreeItem(getter_AddRefs(root));
1346
0
  if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
1347
0
    // This is the root docshell
1348
0
    isRoot = true;
1349
0
  }
1350
0
  if (mLSHE) {
1351
0
    isSubFrame = mLSHE->GetIsSubFrame();
1352
0
  }
1353
0
1354
0
  if (!isSubFrame && !isRoot) {
1355
0
    /*
1356
0
     * We don't want to send OnLocationChange notifications when
1357
0
     * a subframe is being loaded for the first time, while
1358
0
     * visiting a frameset page
1359
0
     */
1360
0
    return false;
1361
0
  }
1362
0
1363
0
  if (aFireOnLocationChange) {
1364
0
    FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
1365
0
  }
1366
0
  return !aFireOnLocationChange;
1367
0
}
1368
1369
NS_IMETHODIMP
1370
nsDocShell::GetCharset(nsACString& aCharset)
1371
0
{
1372
0
  aCharset.Truncate();
1373
0
1374
0
  nsIPresShell* presShell = GetPresShell();
1375
0
  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
1376
0
  nsIDocument* doc = presShell->GetDocument();
1377
0
  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
1378
0
  doc->GetDocumentCharacterSet()->Name(aCharset);
1379
0
  return NS_OK;
1380
0
}
1381
1382
NS_IMETHODIMP
1383
nsDocShell::GatherCharsetMenuTelemetry()
1384
0
{
1385
0
  nsCOMPtr<nsIContentViewer> viewer;
1386
0
  GetContentViewer(getter_AddRefs(viewer));
1387
0
  if (!viewer) {
1388
0
    return NS_OK;
1389
0
  }
1390
0
1391
0
  nsIDocument* doc = viewer->GetDocument();
1392
0
  if (!doc || doc->WillIgnoreCharsetOverride()) {
1393
0
    return NS_OK;
1394
0
  }
1395
0
1396
0
  Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
1397
0
1398
0
  bool isFileURL = false;
1399
0
  nsIURI* url = doc->GetOriginalURI();
1400
0
  if (url) {
1401
0
    url->SchemeIs("file", &isFileURL);
1402
0
  }
1403
0
1404
0
  int32_t charsetSource = doc->GetDocumentCharacterSetSource();
1405
0
  switch (charsetSource) {
1406
0
    case kCharsetFromTopLevelDomain:
1407
0
      // Unlabeled doc on a domain that we map to a fallback encoding
1408
0
      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7);
1409
0
      break;
1410
0
    case kCharsetFromFallback:
1411
0
    case kCharsetFromDocTypeDefault:
1412
0
    case kCharsetFromCache:
1413
0
    case kCharsetFromParentFrame:
1414
0
    case kCharsetFromHintPrevDoc:
1415
0
      // Changing charset on an unlabeled doc.
1416
0
      if (isFileURL) {
1417
0
        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
1418
0
      } else {
1419
0
        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
1420
0
      }
1421
0
      break;
1422
0
    case kCharsetFromAutoDetection:
1423
0
      // Changing charset on unlabeled doc where chardet fired
1424
0
      if (isFileURL) {
1425
0
        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
1426
0
      } else {
1427
0
        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
1428
0
      }
1429
0
      break;
1430
0
    case kCharsetFromMetaPrescan:
1431
0
    case kCharsetFromMetaTag:
1432
0
    case kCharsetFromChannel:
1433
0
      // Changing charset on a doc that had a charset label.
1434
0
      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
1435
0
      break;
1436
0
    case kCharsetFromParentForced:
1437
0
    case kCharsetFromUserForced:
1438
0
      // Changing charset on a document that already had an override.
1439
0
      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
1440
0
      break;
1441
0
    case kCharsetFromIrreversibleAutoDetection:
1442
0
    case kCharsetFromOtherComponent:
1443
0
    case kCharsetFromByteOrderMark:
1444
0
    case kCharsetUninitialized:
1445
0
    default:
1446
0
      // Bug. This isn't supposed to happen.
1447
0
      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
1448
0
      break;
1449
0
  }
1450
0
  return NS_OK;
1451
0
}
1452
1453
NS_IMETHODIMP
1454
nsDocShell::SetCharset(const nsACString& aCharset)
1455
0
{
1456
0
  // set the charset override
1457
0
  return SetForcedCharset(aCharset);
1458
0
}
1459
1460
NS_IMETHODIMP
1461
nsDocShell::SetForcedCharset(const nsACString& aCharset)
1462
0
{
1463
0
  if (aCharset.IsEmpty()) {
1464
0
    mForcedCharset = nullptr;
1465
0
    return NS_OK;
1466
0
  }
1467
0
  const Encoding* encoding = Encoding::ForLabel(aCharset);
1468
0
  if (!encoding) {
1469
0
    // Reject unknown labels
1470
0
    return NS_ERROR_INVALID_ARG;
1471
0
  }
1472
0
  if (!encoding->IsAsciiCompatible() && encoding != ISO_2022_JP_ENCODING) {
1473
0
    // Reject XSS hazards
1474
0
    return NS_ERROR_INVALID_ARG;
1475
0
  }
1476
0
  mForcedCharset = encoding;
1477
0
  return NS_OK;
1478
0
}
1479
1480
NS_IMETHODIMP
1481
nsDocShell::GetForcedCharset(nsACString& aResult)
1482
0
{
1483
0
  if (mForcedCharset) {
1484
0
    mForcedCharset->Name(aResult);
1485
0
  } else {
1486
0
    aResult.Truncate();
1487
0
  }
1488
0
  return NS_OK;
1489
0
}
1490
1491
void
1492
nsDocShell::SetParentCharset(const Encoding*& aCharset,
1493
                             int32_t aCharsetSource,
1494
                             nsIPrincipal* aPrincipal)
1495
0
{
1496
0
  mParentCharset = aCharset;
1497
0
  mParentCharsetSource = aCharsetSource;
1498
0
  mParentCharsetPrincipal = aPrincipal;
1499
0
}
1500
1501
void
1502
nsDocShell::GetParentCharset(const Encoding*& aCharset,
1503
                             int32_t* aCharsetSource,
1504
                             nsIPrincipal** aPrincipal)
1505
0
{
1506
0
  aCharset = mParentCharset;
1507
0
  *aCharsetSource = mParentCharsetSource;
1508
0
  NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
1509
0
}
1510
1511
NS_IMETHODIMP
1512
nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded)
1513
0
{
1514
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1515
0
  *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
1516
0
  return NS_OK;
1517
0
}
1518
1519
NS_IMETHODIMP
1520
nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked)
1521
0
{
1522
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1523
0
  *aHasMixedActiveContentBlocked =
1524
0
    doc && doc->GetHasMixedActiveContentBlocked();
1525
0
  return NS_OK;
1526
0
}
1527
1528
NS_IMETHODIMP
1529
nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded)
1530
0
{
1531
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1532
0
  *aHasMixedDisplayContentLoaded =
1533
0
    doc && doc->GetHasMixedDisplayContentLoaded();
1534
0
  return NS_OK;
1535
0
}
1536
1537
NS_IMETHODIMP
1538
nsDocShell::GetHasMixedDisplayContentBlocked(
1539
  bool* aHasMixedDisplayContentBlocked)
1540
0
{
1541
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1542
0
  *aHasMixedDisplayContentBlocked =
1543
0
    doc && doc->GetHasMixedDisplayContentBlocked();
1544
0
  return NS_OK;
1545
0
}
1546
1547
NS_IMETHODIMP
1548
nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked)
1549
0
{
1550
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1551
0
  *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked();
1552
0
  return NS_OK;
1553
0
}
1554
1555
NS_IMETHODIMP
1556
nsDocShell::GetHasSlowTrackingContentBlocked(bool* aHasSlowTrackingContentBlocked)
1557
0
{
1558
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1559
0
  *aHasSlowTrackingContentBlocked = doc && doc->GetHasSlowTrackingContentBlocked();
1560
0
  return NS_OK;
1561
0
}
1562
1563
NS_IMETHODIMP
1564
nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded)
1565
0
{
1566
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1567
0
  *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded();
1568
0
  return NS_OK;
1569
0
}
1570
1571
NS_IMETHODIMP
1572
nsDocShell::GetHasCookiesBlockedByPermission(bool* aHasCookiesBlockedByPermission)
1573
0
{
1574
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1575
0
  *aHasCookiesBlockedByPermission = doc && doc->GetHasCookiesBlockedByPermission();
1576
0
  return NS_OK;
1577
0
}
1578
1579
NS_IMETHODIMP
1580
nsDocShell::GetHasCookiesBlockedDueToTrackers(bool* aHasCookiesBlockedDueToTrackers)
1581
0
{
1582
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1583
0
  *aHasCookiesBlockedDueToTrackers = doc && doc->GetHasTrackingCookiesBlocked();
1584
0
  return NS_OK;
1585
0
}
1586
1587
NS_IMETHODIMP
1588
nsDocShell::GetHasAllCookiesBeenBlocked(bool* aHasAllCookiesBeenBlocked)
1589
0
{
1590
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1591
0
  *aHasAllCookiesBeenBlocked = doc && doc->GetHasAllCookiesBlocked();
1592
0
  return NS_OK;
1593
0
}
1594
1595
NS_IMETHODIMP
1596
nsDocShell::GetHasForeignCookiesBeenBlocked(bool* aHasForeignCookiesBeenBlocked)
1597
0
{
1598
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
1599
0
  *aHasForeignCookiesBeenBlocked = doc && doc->GetHasForeignCookiesBlocked();
1600
0
  return NS_OK;
1601
0
}
1602
1603
NS_IMETHODIMP
1604
nsDocShell::GetAllowPlugins(bool* aAllowPlugins)
1605
0
{
1606
0
  NS_ENSURE_ARG_POINTER(aAllowPlugins);
1607
0
1608
0
  *aAllowPlugins = mAllowPlugins;
1609
0
  return NS_OK;
1610
0
}
1611
1612
NS_IMETHODIMP
1613
nsDocShell::SetAllowPlugins(bool aAllowPlugins)
1614
0
{
1615
0
  mAllowPlugins = aAllowPlugins;
1616
0
  // XXX should enable or disable a plugin host
1617
0
  return NS_OK;
1618
0
}
1619
1620
NS_IMETHODIMP
1621
nsDocShell::GetAllowJavascript(bool* aAllowJavascript)
1622
0
{
1623
0
  NS_ENSURE_ARG_POINTER(aAllowJavascript);
1624
0
1625
0
  *aAllowJavascript = mAllowJavascript;
1626
0
  return NS_OK;
1627
0
}
1628
1629
NS_IMETHODIMP
1630
nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled)
1631
0
{
1632
0
  MOZ_ASSERT(aEnabled);
1633
0
  *aEnabled = mCSSErrorReportingEnabled;
1634
0
  return NS_OK;
1635
0
}
1636
1637
NS_IMETHODIMP
1638
nsDocShell::SetCssErrorReportingEnabled(bool aEnabled)
1639
0
{
1640
0
  mCSSErrorReportingEnabled = aEnabled;
1641
0
  return NS_OK;
1642
0
}
1643
1644
NS_IMETHODIMP
1645
nsDocShell::SetAllowJavascript(bool aAllowJavascript)
1646
0
{
1647
0
  mAllowJavascript = aAllowJavascript;
1648
0
  RecomputeCanExecuteScripts();
1649
0
  return NS_OK;
1650
0
}
1651
1652
NS_IMETHODIMP
1653
nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
1654
0
{
1655
0
  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
1656
0
  AssertOriginAttributesMatchPrivateBrowsing();
1657
0
  *aUsePrivateBrowsing = mPrivateBrowsingId > 0;
1658
0
  return NS_OK;
1659
0
}
1660
1661
NS_IMETHODIMP
1662
nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
1663
0
{
1664
0
  if (!CanSetOriginAttributes()) {
1665
0
    bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
1666
0
1667
0
    return changed ? NS_ERROR_FAILURE : NS_OK;
1668
0
  }
1669
0
1670
0
  return SetPrivateBrowsing(aUsePrivateBrowsing);
1671
0
}
1672
1673
NS_IMETHODIMP
1674
nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
1675
0
{
1676
0
  MOZ_ASSERT(!mIsBeingDestroyed);
1677
0
1678
0
  bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
1679
0
  if (changed) {
1680
0
    mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0;
1681
0
1682
0
    if (mItemType != typeChrome) {
1683
0
      mOriginAttributes.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing);
1684
0
    }
1685
0
1686
0
    if (mAffectPrivateSessionLifetime) {
1687
0
      if (aUsePrivateBrowsing) {
1688
0
        IncreasePrivateDocShellCount();
1689
0
      } else {
1690
0
        DecreasePrivateDocShellCount();
1691
0
      }
1692
0
    }
1693
0
  }
1694
0
1695
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
1696
0
  while (iter.HasMore()) {
1697
0
    nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
1698
0
    if (shell) {
1699
0
      shell->SetPrivateBrowsing(aUsePrivateBrowsing);
1700
0
    }
1701
0
  }
1702
0
1703
0
  if (changed) {
1704
0
    nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
1705
0
    while (iter.HasMore()) {
1706
0
      nsWeakPtr ref = iter.GetNext();
1707
0
      nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
1708
0
      if (!obs) {
1709
0
        mPrivacyObservers.RemoveElement(ref);
1710
0
      } else {
1711
0
        obs->PrivateModeChanged(aUsePrivateBrowsing);
1712
0
      }
1713
0
    }
1714
0
  }
1715
0
1716
0
  AssertOriginAttributesMatchPrivateBrowsing();
1717
0
  return NS_OK;
1718
0
}
1719
1720
NS_IMETHODIMP
1721
nsDocShell::GetHasLoadedNonBlankURI(bool* aResult)
1722
0
{
1723
0
  NS_ENSURE_ARG_POINTER(aResult);
1724
0
1725
0
  *aResult = mHasLoadedNonBlankURI;
1726
0
  return NS_OK;
1727
0
}
1728
1729
NS_IMETHODIMP
1730
nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
1731
0
{
1732
0
  NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
1733
0
1734
0
  *aUseRemoteTabs = mUseRemoteTabs;
1735
0
  return NS_OK;
1736
0
}
1737
1738
NS_IMETHODIMP
1739
nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
1740
0
{
1741
0
  if (aUseRemoteTabs) {
1742
0
    CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled,
1743
0
                                       true);
1744
0
  }
1745
0
1746
0
  mUseRemoteTabs = aUseRemoteTabs;
1747
0
  return NS_OK;
1748
0
}
1749
1750
NS_IMETHODIMP
1751
nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
1752
0
{
1753
0
  MOZ_ASSERT(!mIsBeingDestroyed);
1754
0
1755
0
  bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
1756
0
  if (change && UsePrivateBrowsing()) {
1757
0
    AssertOriginAttributesMatchPrivateBrowsing();
1758
0
    if (aAffectLifetime) {
1759
0
      IncreasePrivateDocShellCount();
1760
0
    } else {
1761
0
      DecreasePrivateDocShellCount();
1762
0
    }
1763
0
  }
1764
0
  mAffectPrivateSessionLifetime = aAffectLifetime;
1765
0
1766
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
1767
0
  while (iter.HasMore()) {
1768
0
    nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
1769
0
    if (shell) {
1770
0
      shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
1771
0
    }
1772
0
  }
1773
0
  return NS_OK;
1774
0
}
1775
1776
NS_IMETHODIMP
1777
nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime)
1778
0
{
1779
0
  *aAffectLifetime = mAffectPrivateSessionLifetime;
1780
0
  return NS_OK;
1781
0
}
1782
1783
NS_IMETHODIMP
1784
nsDocShell::AddWeakPrivacyTransitionObserver(
1785
    nsIPrivacyTransitionObserver* aObserver)
1786
0
{
1787
0
  nsWeakPtr weakObs = do_GetWeakReference(aObserver);
1788
0
  if (!weakObs) {
1789
0
    return NS_ERROR_NOT_AVAILABLE;
1790
0
  }
1791
0
  return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
1792
0
}
1793
1794
NS_IMETHODIMP
1795
nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver)
1796
0
{
1797
0
  nsWeakPtr weakObs = do_GetWeakReference(aObserver);
1798
0
  if (!weakObs) {
1799
0
    return NS_ERROR_FAILURE;
1800
0
  }
1801
0
  return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
1802
0
}
1803
1804
NS_IMETHODIMP
1805
nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver)
1806
0
{
1807
0
  nsWeakPtr obs = do_GetWeakReference(aObserver);
1808
0
  return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
1809
0
}
1810
1811
NS_IMETHODIMP
1812
nsDocShell::NotifyReflowObservers(bool aInterruptible,
1813
                                  DOMHighResTimeStamp aStart,
1814
                                  DOMHighResTimeStamp aEnd)
1815
0
{
1816
0
  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
1817
0
  while (iter.HasMore()) {
1818
0
    nsWeakPtr ref = iter.GetNext();
1819
0
    nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
1820
0
    if (!obs) {
1821
0
      mReflowObservers.RemoveElement(ref);
1822
0
    } else if (aInterruptible) {
1823
0
      obs->ReflowInterruptible(aStart, aEnd);
1824
0
    } else {
1825
0
      obs->Reflow(aStart, aEnd);
1826
0
    }
1827
0
  }
1828
0
  return NS_OK;
1829
0
}
1830
1831
NS_IMETHODIMP
1832
nsDocShell::GetAllowMetaRedirects(bool* aReturn)
1833
0
{
1834
0
  NS_ENSURE_ARG_POINTER(aReturn);
1835
0
1836
0
  *aReturn = mAllowMetaRedirects;
1837
0
  return NS_OK;
1838
0
}
1839
1840
NS_IMETHODIMP
1841
nsDocShell::SetAllowMetaRedirects(bool aValue)
1842
0
{
1843
0
  mAllowMetaRedirects = aValue;
1844
0
  return NS_OK;
1845
0
}
1846
1847
NS_IMETHODIMP
1848
nsDocShell::GetAllowSubframes(bool* aAllowSubframes)
1849
0
{
1850
0
  NS_ENSURE_ARG_POINTER(aAllowSubframes);
1851
0
1852
0
  *aAllowSubframes = mAllowSubframes;
1853
0
  return NS_OK;
1854
0
}
1855
1856
NS_IMETHODIMP
1857
nsDocShell::SetAllowSubframes(bool aAllowSubframes)
1858
0
{
1859
0
  mAllowSubframes = aAllowSubframes;
1860
0
  return NS_OK;
1861
0
}
1862
1863
NS_IMETHODIMP
1864
nsDocShell::GetAllowImages(bool* aAllowImages)
1865
0
{
1866
0
  NS_ENSURE_ARG_POINTER(aAllowImages);
1867
0
1868
0
  *aAllowImages = mAllowImages;
1869
0
  return NS_OK;
1870
0
}
1871
1872
NS_IMETHODIMP
1873
nsDocShell::SetAllowImages(bool aAllowImages)
1874
0
{
1875
0
  mAllowImages = aAllowImages;
1876
0
  return NS_OK;
1877
0
}
1878
1879
NS_IMETHODIMP
1880
nsDocShell::GetAllowMedia(bool* aAllowMedia)
1881
0
{
1882
0
  *aAllowMedia = mAllowMedia;
1883
0
  return NS_OK;
1884
0
}
1885
1886
NS_IMETHODIMP
1887
nsDocShell::SetAllowMedia(bool aAllowMedia)
1888
0
{
1889
0
  mAllowMedia = aAllowMedia;
1890
0
1891
0
  // Mute or unmute audio contexts attached to the inner window.
1892
0
  if (mScriptGlobal) {
1893
0
    if (nsPIDOMWindowInner* innerWin =
1894
0
        mScriptGlobal->AsOuter()->GetCurrentInnerWindow()) {
1895
0
      if (aAllowMedia) {
1896
0
        innerWin->UnmuteAudioContexts();
1897
0
      } else {
1898
0
        innerWin->MuteAudioContexts();
1899
0
      }
1900
0
    }
1901
0
  }
1902
0
1903
0
  return NS_OK;
1904
0
}
1905
1906
NS_IMETHODIMP
1907
nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch)
1908
0
{
1909
0
  *aAllowDNSPrefetch = mAllowDNSPrefetch;
1910
0
  return NS_OK;
1911
0
}
1912
1913
NS_IMETHODIMP
1914
nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
1915
0
{
1916
0
  mAllowDNSPrefetch = aAllowDNSPrefetch;
1917
0
  return NS_OK;
1918
0
}
1919
1920
NS_IMETHODIMP
1921
nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl)
1922
0
{
1923
0
  *aAllowWindowControl = mAllowWindowControl;
1924
0
  return NS_OK;
1925
0
}
1926
1927
NS_IMETHODIMP
1928
nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
1929
0
{
1930
0
  mAllowWindowControl = aAllowWindowControl;
1931
0
  return NS_OK;
1932
0
}
1933
1934
NS_IMETHODIMP
1935
nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
1936
0
{
1937
0
  *aAllowContentRetargeting = mAllowContentRetargeting;
1938
0
  return NS_OK;
1939
0
}
1940
1941
NS_IMETHODIMP
1942
nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
1943
0
{
1944
0
  mAllowContentRetargetingOnChildren = aAllowContentRetargeting;
1945
0
  mAllowContentRetargeting = aAllowContentRetargeting;
1946
0
  return NS_OK;
1947
0
}
1948
1949
NS_IMETHODIMP
1950
nsDocShell::GetAllowContentRetargetingOnChildren(
1951
    bool* aAllowContentRetargetingOnChildren)
1952
0
{
1953
0
  *aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren;
1954
0
  return NS_OK;
1955
0
}
1956
1957
NS_IMETHODIMP
1958
nsDocShell::SetAllowContentRetargetingOnChildren(
1959
    bool aAllowContentRetargetingOnChildren)
1960
0
{
1961
0
  mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren;
1962
0
  return NS_OK;
1963
0
}
1964
1965
NS_IMETHODIMP
1966
nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId)
1967
0
{
1968
0
  *aInheritPrivateBrowsingId = mInheritPrivateBrowsingId;
1969
0
  return NS_OK;
1970
0
}
1971
1972
NS_IMETHODIMP
1973
nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId)
1974
0
{
1975
0
  mInheritPrivateBrowsingId = aInheritPrivateBrowsingId;
1976
0
  return NS_OK;
1977
0
}
1978
1979
NS_IMETHODIMP
1980
nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
1981
0
{
1982
0
  NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
1983
0
1984
0
  // Browsers and apps have their mFullscreenAllowed retrieved from their
1985
0
  // corresponding iframe in their parent upon creation.
1986
0
  if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
1987
0
    *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
1988
0
    return NS_OK;
1989
0
  }
1990
0
1991
0
  // Assume false until we determine otherwise...
1992
0
  *aFullscreenAllowed = false;
1993
0
1994
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
1995
0
  if (!win) {
1996
0
    return NS_OK;
1997
0
  }
1998
0
  if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
1999
0
    if (frameElement->IsXULElement()) {
2000
0
      if (frameElement->HasAttr(kNameSpaceID_None,
2001
0
                                nsGkAtoms::disablefullscreen)) {
2002
0
        // Document inside this frame is explicitly disabled.
2003
0
        return NS_OK;
2004
0
      }
2005
0
    } else {
2006
0
      // We do not allow document inside any containing element other
2007
0
      // than iframe to enter fullscreen.
2008
0
      if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
2009
0
        // If any ancestor iframe does not have allowfullscreen attribute
2010
0
        // set, then fullscreen is not allowed.
2011
0
        if (!frameElement->HasAttr(kNameSpaceID_None,
2012
0
                                  nsGkAtoms::allowfullscreen) &&
2013
0
            !frameElement->HasAttr(kNameSpaceID_None,
2014
0
                                  nsGkAtoms::mozallowfullscreen)) {
2015
0
          return NS_OK;
2016
0
        }
2017
0
      } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
2018
0
        // Respect allowfullscreen only if this is a rewritten YouTube embed.
2019
0
        nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
2020
0
          do_QueryInterface(frameElement);
2021
0
        if (!objectLoadingContent) {
2022
0
          return NS_OK;
2023
0
        }
2024
0
        nsObjectLoadingContent* olc =
2025
0
          static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
2026
0
        if (!olc->IsRewrittenYoutubeEmbed()) {
2027
0
          return NS_OK;
2028
0
        }
2029
0
        // We don't have to check prefixed attributes because Flash does not
2030
0
        // support them.
2031
0
        if (!frameElement->HasAttr(kNameSpaceID_None,
2032
0
                                  nsGkAtoms::allowfullscreen)) {
2033
0
          return NS_OK;
2034
0
        }
2035
0
      } else {
2036
0
        // neither iframe nor embed
2037
0
        return NS_OK;
2038
0
      }
2039
0
    }
2040
0
  }
2041
0
2042
0
  // If we have no parent then we're the root docshell; no ancestor of the
2043
0
  // original docshell doesn't have a allowfullscreen attribute, so
2044
0
  // report fullscreen as allowed.
2045
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
2046
0
  if (!parent) {
2047
0
    *aFullscreenAllowed = true;
2048
0
    return NS_OK;
2049
0
  }
2050
0
2051
0
  // Otherwise, we have a parent, continue the checking for
2052
0
  // mozFullscreenAllowed in the parent docshell's ancestors.
2053
0
  return parent->GetFullscreenAllowed(aFullscreenAllowed);
2054
0
}
2055
2056
NS_IMETHODIMP
2057
nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
2058
0
{
2059
0
  if (!nsIDocShell::GetIsMozBrowser()) {
2060
0
    // Only allow setting of fullscreenAllowed on content/process boundaries.
2061
0
    // At non-boundaries the fullscreenAllowed attribute is calculated based on
2062
0
    // whether all enclosing frames have the "mozFullscreenAllowed" attribute
2063
0
    // set to "true". fullscreenAllowed is set at the process boundaries to
2064
0
    // propagate the value of the parent's "mozFullscreenAllowed" attribute
2065
0
    // across process boundaries.
2066
0
    return NS_ERROR_UNEXPECTED;
2067
0
  }
2068
0
  mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
2069
0
  return NS_OK;
2070
0
}
2071
2072
hal::ScreenOrientation
2073
nsDocShell::OrientationLock()
2074
0
{
2075
0
  return mOrientationLock;
2076
0
}
2077
2078
void
2079
nsDocShell::SetOrientationLock(hal::ScreenOrientation aOrientationLock)
2080
0
{
2081
0
  mOrientationLock = aOrientationLock;
2082
0
}
2083
2084
NS_IMETHODIMP
2085
nsDocShell::GetMayEnableCharacterEncodingMenu(
2086
    bool* aMayEnableCharacterEncodingMenu)
2087
0
{
2088
0
  *aMayEnableCharacterEncodingMenu = false;
2089
0
  if (!mContentViewer) {
2090
0
    return NS_OK;
2091
0
  }
2092
0
  nsIDocument* doc = mContentViewer->GetDocument();
2093
0
  if (!doc) {
2094
0
    return NS_OK;
2095
0
  }
2096
0
  if (doc->WillIgnoreCharsetOverride()) {
2097
0
    return NS_OK;
2098
0
  }
2099
0
2100
0
  *aMayEnableCharacterEncodingMenu = true;
2101
0
  return NS_OK;
2102
0
}
2103
2104
NS_IMETHODIMP
2105
nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection,
2106
                                  nsISimpleEnumerator** aResult)
2107
0
{
2108
0
  NS_ENSURE_ARG_POINTER(aResult);
2109
0
  *aResult = nullptr;
2110
0
2111
0
  RefPtr<nsDocShellEnumerator> docShellEnum;
2112
0
  if (aDirection == ENUMERATE_FORWARDS) {
2113
0
    docShellEnum = new nsDocShellForwardsEnumerator;
2114
0
  } else {
2115
0
    docShellEnum = new nsDocShellBackwardsEnumerator;
2116
0
  }
2117
0
2118
0
  nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
2119
0
  if (NS_FAILED(rv)) {
2120
0
    return rv;
2121
0
  }
2122
0
2123
0
  rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
2124
0
  if (NS_FAILED(rv)) {
2125
0
    return rv;
2126
0
  }
2127
0
2128
0
  rv = docShellEnum->First();
2129
0
  if (NS_FAILED(rv)) {
2130
0
    return rv;
2131
0
  }
2132
0
2133
0
  rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
2134
0
                                    (void**)aResult);
2135
0
2136
0
  return rv;
2137
0
}
2138
2139
NS_IMETHODIMP
2140
nsDocShell::GetAppType(uint32_t* aAppType)
2141
0
{
2142
0
  *aAppType = mAppType;
2143
0
  return NS_OK;
2144
0
}
2145
2146
NS_IMETHODIMP
2147
nsDocShell::SetAppType(uint32_t aAppType)
2148
0
{
2149
0
  mAppType = aAppType;
2150
0
  return NS_OK;
2151
0
}
2152
2153
NS_IMETHODIMP
2154
nsDocShell::GetAllowAuth(bool* aAllowAuth)
2155
0
{
2156
0
  *aAllowAuth = mAllowAuth;
2157
0
  return NS_OK;
2158
0
}
2159
2160
NS_IMETHODIMP
2161
nsDocShell::SetAllowAuth(bool aAllowAuth)
2162
0
{
2163
0
  mAllowAuth = aAllowAuth;
2164
0
  return NS_OK;
2165
0
}
2166
2167
NS_IMETHODIMP
2168
nsDocShell::GetZoom(float* aZoom)
2169
0
{
2170
0
  NS_ENSURE_ARG_POINTER(aZoom);
2171
0
  *aZoom = 1.0f;
2172
0
  return NS_OK;
2173
0
}
2174
2175
NS_IMETHODIMP
2176
nsDocShell::SetZoom(float aZoom)
2177
0
{
2178
0
  return NS_ERROR_NOT_IMPLEMENTED;
2179
0
}
2180
2181
NS_IMETHODIMP
2182
nsDocShell::GetMarginWidth(int32_t* aWidth)
2183
0
{
2184
0
  NS_ENSURE_ARG_POINTER(aWidth);
2185
0
2186
0
  *aWidth = mMarginWidth;
2187
0
  return NS_OK;
2188
0
}
2189
2190
NS_IMETHODIMP
2191
nsDocShell::SetMarginWidth(int32_t aWidth)
2192
0
{
2193
0
  mMarginWidth = aWidth;
2194
0
  return NS_OK;
2195
0
}
2196
2197
NS_IMETHODIMP
2198
nsDocShell::GetMarginHeight(int32_t* aHeight)
2199
0
{
2200
0
  NS_ENSURE_ARG_POINTER(aHeight);
2201
0
2202
0
  *aHeight = mMarginHeight;
2203
0
  return NS_OK;
2204
0
}
2205
2206
NS_IMETHODIMP
2207
nsDocShell::SetMarginHeight(int32_t aHeight)
2208
0
{
2209
0
  mMarginHeight = aHeight;
2210
0
  return NS_OK;
2211
0
}
2212
2213
NS_IMETHODIMP
2214
nsDocShell::GetBusyFlags(uint32_t* aBusyFlags)
2215
0
{
2216
0
  NS_ENSURE_ARG_POINTER(aBusyFlags);
2217
0
2218
0
  *aBusyFlags = mBusyFlags;
2219
0
  return NS_OK;
2220
0
}
2221
2222
NS_IMETHODIMP
2223
nsDocShell::TabToTreeOwner(bool aForward, bool aForDocumentNavigation, bool* aTookFocus)
2224
0
{
2225
0
  NS_ENSURE_ARG_POINTER(aTookFocus);
2226
0
2227
0
  nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
2228
0
  if (chromeFocus) {
2229
0
    if (aForward) {
2230
0
      *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement(aForDocumentNavigation));
2231
0
    } else {
2232
0
      *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement(aForDocumentNavigation));
2233
0
    }
2234
0
  } else {
2235
0
    *aTookFocus = false;
2236
0
  }
2237
0
2238
0
  return NS_OK;
2239
0
}
2240
2241
NS_IMETHODIMP
2242
nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI)
2243
0
{
2244
0
  NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
2245
0
  return NS_OK;
2246
0
}
2247
2248
NS_IMETHODIMP
2249
nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
2250
0
{
2251
0
  MOZ_ASSERT(!mIsBeingDestroyed);
2252
0
2253
0
  mSecurityUI = aSecurityUI;
2254
0
  mSecurityUI->SetDocShell(this);
2255
0
  return NS_OK;
2256
0
}
2257
2258
NS_IMETHODIMP
2259
nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate** aLoadURIDelegate)
2260
0
{
2261
0
  NS_IF_ADDREF(*aLoadURIDelegate = mLoadURIDelegate);
2262
0
  return NS_OK;
2263
0
}
2264
2265
NS_IMETHODIMP
2266
nsDocShell::SetLoadURIDelegate(nsILoadURIDelegate* aLoadURIDelegate)
2267
0
{
2268
0
  mLoadURIDelegate = aLoadURIDelegate;
2269
0
  return NS_OK;
2270
0
}
2271
2272
NS_IMETHODIMP
2273
nsDocShell::GetUseErrorPages(bool* aUseErrorPages)
2274
0
{
2275
0
  *aUseErrorPages = UseErrorPages();
2276
0
  return NS_OK;
2277
0
}
2278
2279
NS_IMETHODIMP
2280
nsDocShell::SetUseErrorPages(bool aUseErrorPages)
2281
0
{
2282
0
  // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
2283
0
  if (mObserveErrorPages) {
2284
0
    mObserveErrorPages = false;
2285
0
  }
2286
0
  mUseErrorPages = aUseErrorPages;
2287
0
  return NS_OK;
2288
0
}
2289
2290
NS_IMETHODIMP
2291
nsDocShell::GetPreviousEntryIndex(int32_t* aPreviousEntryIndex)
2292
0
{
2293
0
  *aPreviousEntryIndex = mPreviousEntryIndex;
2294
0
  return NS_OK;
2295
0
}
2296
2297
NS_IMETHODIMP
2298
nsDocShell::GetLoadedEntryIndex(int32_t* aLoadedEntryIndex)
2299
0
{
2300
0
  *aLoadedEntryIndex = mLoadedEntryIndex;
2301
0
  return NS_OK;
2302
0
}
2303
2304
NS_IMETHODIMP
2305
nsDocShell::HistoryPurged(int32_t aNumEntries)
2306
0
{
2307
0
  // These indices are used for fastback cache eviction, to determine
2308
0
  // which session history entries are candidates for content viewer
2309
0
  // eviction.  We need to adjust by the number of entries that we
2310
0
  // just purged from history, so that we look at the right session history
2311
0
  // entries during eviction.
2312
0
  mPreviousEntryIndex = std::max(-1, mPreviousEntryIndex - aNumEntries);
2313
0
  mLoadedEntryIndex = std::max(0, mLoadedEntryIndex - aNumEntries);
2314
0
2315
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2316
0
  while (iter.HasMore()) {
2317
0
    nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2318
0
    if (shell) {
2319
0
      shell->HistoryPurged(aNumEntries);
2320
0
    }
2321
0
  }
2322
0
2323
0
  return NS_OK;
2324
0
}
2325
2326
nsresult
2327
nsDocShell::HistoryEntryRemoved(int32_t aIndex)
2328
0
{
2329
0
  // These indices are used for fastback cache eviction, to determine
2330
0
  // which session history entries are candidates for content viewer
2331
0
  // eviction.  We need to adjust by the number of entries that we
2332
0
  // just purged from history, so that we look at the right session history
2333
0
  // entries during eviction.
2334
0
  if (aIndex == mPreviousEntryIndex) {
2335
0
    mPreviousEntryIndex = -1;
2336
0
  } else if (aIndex < mPreviousEntryIndex) {
2337
0
    --mPreviousEntryIndex;
2338
0
  }
2339
0
  if (mLoadedEntryIndex == aIndex) {
2340
0
    mLoadedEntryIndex = 0;
2341
0
  } else if (aIndex < mLoadedEntryIndex) {
2342
0
    --mLoadedEntryIndex;
2343
0
  }
2344
0
2345
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2346
0
  while (iter.HasMore()) {
2347
0
    nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2348
0
    if (shell) {
2349
0
      static_cast<nsDocShell*>(shell.get())->HistoryEntryRemoved(aIndex);
2350
0
    }
2351
0
  }
2352
0
2353
0
  return NS_OK;
2354
0
}
2355
2356
NS_IMETHODIMP
2357
nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
2358
0
{
2359
0
  bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
2360
0
  if (currentValue == aValue) {
2361
0
    return NS_OK;
2362
0
  }
2363
0
2364
0
  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
2365
0
  if (!timelines) {
2366
0
    return NS_OK;
2367
0
  }
2368
0
2369
0
  if (aValue) {
2370
0
    MOZ_ASSERT(!timelines->HasConsumer(this));
2371
0
    timelines->AddConsumer(this);
2372
0
    MOZ_ASSERT(timelines->HasConsumer(this));
2373
0
    UseEntryScriptProfiling();
2374
0
  } else {
2375
0
    MOZ_ASSERT(timelines->HasConsumer(this));
2376
0
    timelines->RemoveConsumer(this);
2377
0
    MOZ_ASSERT(!timelines->HasConsumer(this));
2378
0
    UnuseEntryScriptProfiling();
2379
0
  }
2380
0
2381
0
  return NS_OK;
2382
0
}
2383
2384
NS_IMETHODIMP
2385
nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
2386
0
{
2387
0
  *aValue = !!mObserved;
2388
0
  return NS_OK;
2389
0
}
2390
2391
nsresult
2392
nsDocShell::PopProfileTimelineMarkers(
2393
    JSContext* aCx,
2394
    JS::MutableHandle<JS::Value> aOut)
2395
0
{
2396
0
  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
2397
0
  if (!timelines) {
2398
0
    return NS_OK;
2399
0
  }
2400
0
2401
0
  nsTArray<dom::ProfileTimelineMarker> store;
2402
0
  SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
2403
0
2404
0
  timelines->PopMarkers(this, aCx, store);
2405
0
2406
0
  if (!ToJSValue(aCx, store, aOut)) {
2407
0
    JS_ClearPendingException(aCx);
2408
0
    return NS_ERROR_UNEXPECTED;
2409
0
  }
2410
0
2411
0
  return NS_OK;
2412
0
}
2413
2414
nsresult
2415
nsDocShell::Now(DOMHighResTimeStamp* aWhen)
2416
0
{
2417
0
  *aWhen = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
2418
0
  return NS_OK;
2419
0
}
2420
2421
NS_IMETHODIMP
2422
nsDocShell::SetWindowDraggingAllowed(bool aValue)
2423
0
{
2424
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
2425
0
  if (!aValue && mItemType == typeChrome && !parent) {
2426
0
    // Window dragging is always allowed for top level
2427
0
    // chrome docshells.
2428
0
    return NS_ERROR_FAILURE;
2429
0
  }
2430
0
  mWindowDraggingAllowed = aValue;
2431
0
  return NS_OK;
2432
0
}
2433
2434
NS_IMETHODIMP
2435
nsDocShell::GetWindowDraggingAllowed(bool* aValue)
2436
0
{
2437
0
  // window dragging regions in CSS (-moz-window-drag:drag)
2438
0
  // can be slow. Default behavior is to only allow it for
2439
0
  // chrome top level windows.
2440
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
2441
0
  if (mItemType == typeChrome && !parent) {
2442
0
    // Top level chrome window
2443
0
    *aValue = true;
2444
0
  } else {
2445
0
    *aValue = mWindowDraggingAllowed;
2446
0
  }
2447
0
  return NS_OK;
2448
0
}
2449
2450
nsIDOMStorageManager*
2451
nsDocShell::TopSessionStorageManager()
2452
0
{
2453
0
  nsresult rv;
2454
0
2455
0
  nsCOMPtr<nsIDocShellTreeItem> topItem;
2456
0
  rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
2457
0
  if (NS_FAILED(rv)) {
2458
0
    return nullptr;
2459
0
  }
2460
0
2461
0
  if (!topItem) {
2462
0
    return nullptr;
2463
0
  }
2464
0
2465
0
  nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
2466
0
  if (topDocShell != this) {
2467
0
    return topDocShell->TopSessionStorageManager();
2468
0
  }
2469
0
2470
0
  if (!mSessionStorageManager) {
2471
0
    mSessionStorageManager = new SessionStorageManager();
2472
0
  }
2473
0
2474
0
  return mSessionStorageManager;
2475
0
}
2476
2477
NS_IMETHODIMP
2478
nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
2479
0
{
2480
0
  NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
2481
0
  return NS_OK;
2482
0
}
2483
2484
nsIChannel*
2485
nsDocShell::GetCurrentDocChannel()
2486
0
{
2487
0
  if (mContentViewer) {
2488
0
    nsIDocument* doc = mContentViewer->GetDocument();
2489
0
    if (doc) {
2490
0
      return doc->GetChannel();
2491
0
    }
2492
0
  }
2493
0
  return nullptr;
2494
0
}
2495
2496
NS_IMETHODIMP
2497
nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
2498
0
{
2499
0
  nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2500
0
  if (!weakObs) {
2501
0
    return NS_ERROR_FAILURE;
2502
0
  }
2503
0
  return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
2504
0
}
2505
2506
NS_IMETHODIMP
2507
nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
2508
0
{
2509
0
  nsWeakPtr obs = do_GetWeakReference(aObserver);
2510
0
  return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
2511
0
}
2512
2513
void
2514
nsDocShell::NotifyAsyncPanZoomStarted()
2515
0
{
2516
0
  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2517
0
  while (iter.HasMore()) {
2518
0
    nsWeakPtr ref = iter.GetNext();
2519
0
    nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2520
0
    if (obs) {
2521
0
      obs->AsyncPanZoomStarted();
2522
0
    } else {
2523
0
      mScrollObservers.RemoveElement(ref);
2524
0
    }
2525
0
  }
2526
0
}
2527
2528
void
2529
nsDocShell::NotifyAsyncPanZoomStopped()
2530
0
{
2531
0
  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2532
0
  while (iter.HasMore()) {
2533
0
    nsWeakPtr ref = iter.GetNext();
2534
0
    nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2535
0
    if (obs) {
2536
0
      obs->AsyncPanZoomStopped();
2537
0
    } else {
2538
0
      mScrollObservers.RemoveElement(ref);
2539
0
    }
2540
0
  }
2541
0
}
2542
2543
NS_IMETHODIMP
2544
nsDocShell::NotifyScrollObservers()
2545
0
{
2546
0
  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
2547
0
  while (iter.HasMore()) {
2548
0
    nsWeakPtr ref = iter.GetNext();
2549
0
    nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
2550
0
    if (obs) {
2551
0
      obs->ScrollPositionChanged();
2552
0
    } else {
2553
0
      mScrollObservers.RemoveElement(ref);
2554
0
    }
2555
0
  }
2556
0
  return NS_OK;
2557
0
}
2558
2559
//*****************************************************************************
2560
// nsDocShell::nsIDocShellTreeItem
2561
//*****************************************************************************
2562
2563
NS_IMETHODIMP
2564
nsDocShell::GetName(nsAString& aName)
2565
0
{
2566
0
  mBrowsingContext->GetName(aName);
2567
0
  return NS_OK;
2568
0
}
2569
2570
NS_IMETHODIMP
2571
nsDocShell::SetName(const nsAString& aName)
2572
0
{
2573
0
  mBrowsingContext->SetName(aName);
2574
0
  return NS_OK;
2575
0
}
2576
2577
NS_IMETHODIMP
2578
nsDocShell::NameEquals(const nsAString& aName, bool* aResult)
2579
0
{
2580
0
  NS_ENSURE_ARG_POINTER(aResult);
2581
0
  *aResult = mBrowsingContext->NameEquals(aName);
2582
0
  return NS_OK;
2583
0
}
2584
2585
NS_IMETHODIMP
2586
nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent)
2587
0
{
2588
0
  aCustomUserAgent = mCustomUserAgent;
2589
0
  return NS_OK;
2590
0
}
2591
2592
NS_IMETHODIMP
2593
nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
2594
0
{
2595
0
  mCustomUserAgent = aCustomUserAgent;
2596
0
  RefPtr<nsGlobalWindowInner> win = mScriptGlobal ?
2597
0
    mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
2598
0
  if (win) {
2599
0
    Navigator* navigator = win->Navigator();
2600
0
    if (navigator) {
2601
0
      navigator->ClearUserAgentCache();
2602
0
    }
2603
0
  }
2604
0
2605
0
  uint32_t childCount = mChildList.Length();
2606
0
  for (uint32_t i = 0; i < childCount; ++i) {
2607
0
    nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
2608
0
    if (childShell) {
2609
0
      childShell->SetCustomUserAgent(aCustomUserAgent);
2610
0
    }
2611
0
  }
2612
0
  return NS_OK;
2613
0
}
2614
2615
NS_IMETHODIMP
2616
nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride)
2617
0
{
2618
0
  NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
2619
0
2620
0
  *aTouchEventsOverride = mTouchEventsOverride;
2621
0
  return NS_OK;
2622
0
}
2623
2624
NS_IMETHODIMP
2625
nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride)
2626
0
{
2627
0
  if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE ||
2628
0
        aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED ||
2629
0
        aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) {
2630
0
    return NS_ERROR_INVALID_ARG;
2631
0
  }
2632
0
2633
0
  mTouchEventsOverride = aTouchEventsOverride;
2634
0
2635
0
  uint32_t childCount = mChildList.Length();
2636
0
  for (uint32_t i = 0; i < childCount; ++i) {
2637
0
    nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
2638
0
    if (childShell) {
2639
0
      childShell->SetTouchEventsOverride(aTouchEventsOverride);
2640
0
    }
2641
0
  }
2642
0
  return NS_OK;
2643
0
}
2644
2645
/* virtual */ int32_t
2646
nsDocShell::ItemType()
2647
0
{
2648
0
  return mItemType;
2649
0
}
2650
2651
NS_IMETHODIMP
2652
nsDocShell::GetItemType(int32_t* aItemType)
2653
0
{
2654
0
  NS_ENSURE_ARG_POINTER(aItemType);
2655
0
2656
0
  *aItemType = ItemType();
2657
0
  return NS_OK;
2658
0
}
2659
2660
NS_IMETHODIMP
2661
nsDocShell::SetItemType(int32_t aItemType)
2662
0
{
2663
0
  NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
2664
0
2665
0
  // Only allow setting the type on root docshells.  Those would be the ones
2666
0
  // that have the docloader service as mParent or have no mParent at all.
2667
0
  nsCOMPtr<nsIDocumentLoader> docLoaderService =
2668
0
    do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
2669
0
  NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
2670
0
2671
0
  NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
2672
0
2673
0
  mItemType = aItemType;
2674
0
2675
0
  // disable auth prompting for anything but content
2676
0
  mAllowAuth = mItemType == typeContent;
2677
0
2678
0
  RefPtr<nsPresContext> presContext = nullptr;
2679
0
  GetPresContext(getter_AddRefs(presContext));
2680
0
  if (presContext) {
2681
0
    presContext->UpdateIsChrome();
2682
0
  }
2683
0
2684
0
  return NS_OK;
2685
0
}
2686
2687
NS_IMETHODIMP
2688
nsDocShell::GetParent(nsIDocShellTreeItem** aParent)
2689
0
{
2690
0
  if (!mParent) {
2691
0
    *aParent = nullptr;
2692
0
  } else {
2693
0
    CallQueryInterface(mParent, aParent);
2694
0
  }
2695
0
  // Note that in the case when the parent is not an nsIDocShellTreeItem we
2696
0
  // don't want to throw; we just want to return null.
2697
0
  return NS_OK;
2698
0
}
2699
2700
already_AddRefed<nsDocShell>
2701
nsDocShell::GetParentDocshell()
2702
0
{
2703
0
  nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
2704
0
  return docshell.forget().downcast<nsDocShell>();
2705
0
}
2706
2707
void
2708
nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal)
2709
0
{
2710
0
  MOZ_ASSERT(!mIsBeingDestroyed);
2711
0
2712
0
  // If there is an existing document then there is no need to create
2713
0
  // a client for a future initial about:blank document.
2714
0
  if (mScriptGlobal && mScriptGlobal->GetCurrentInnerWindowInternal() &&
2715
0
      mScriptGlobal->GetCurrentInnerWindowInternal()->GetExtantDoc()) {
2716
0
    MOZ_DIAGNOSTIC_ASSERT(
2717
0
      mScriptGlobal->GetCurrentInnerWindowInternal()->GetClientInfo().isSome());
2718
0
    MOZ_DIAGNOSTIC_ASSERT(!mInitialClientSource);
2719
0
    return;
2720
0
  }
2721
0
2722
0
  // Don't recreate the initial client source.  We call this multiple times
2723
0
  // when DoChannelLoad() is called before CreateAboutBlankContentViewer.
2724
0
  if (mInitialClientSource) {
2725
0
    return;
2726
0
  }
2727
0
2728
0
  // Don't pre-allocate the client when we are sandboxed.  The inherited
2729
0
  // principal does not take sandboxing into account.
2730
0
  // TODO: Refactor sandboxing principal code out so we can use it here.
2731
0
  if (!aPrincipal && mSandboxFlags) {
2732
0
    return;
2733
0
  }
2734
0
2735
0
  nsIPrincipal* principal = aPrincipal ? aPrincipal
2736
0
                                       : GetInheritedPrincipal(false);
2737
0
2738
0
  // Sometimes there is no principal available when we are called from
2739
0
  // CreateAboutBlankContentViewer.  For example, sometimes the principal
2740
0
  // is only extracted from the load context after the document is created
2741
0
  // in nsDocument::ResetToURI().  Ideally we would do something similar
2742
0
  // here, but for now lets just avoid the issue by not preallocating the
2743
0
  // client.
2744
0
  if (!principal) {
2745
0
    return;
2746
0
  }
2747
0
2748
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
2749
0
  if (!win) {
2750
0
    return;
2751
0
  }
2752
0
2753
0
  mInitialClientSource =
2754
0
    ClientManager::CreateSource(ClientType::Window,
2755
0
                                win->EventTargetFor(TaskCategory::Other),
2756
0
                                principal);
2757
0
  MOZ_DIAGNOSTIC_ASSERT(mInitialClientSource);
2758
0
2759
0
  // Mark the initial client as execution ready, but owned by the docshell.
2760
0
  // If the client is actually used this will cause ClientSource to force
2761
0
  // the creation of the initial about:blank by calling nsDocShell::GetDocument().
2762
0
  mInitialClientSource->DocShellExecutionReady(this);
2763
0
2764
0
  // Next, check to see if the parent is controlled.
2765
0
  nsCOMPtr<nsIDocShell> parent = GetParentDocshell();
2766
0
  nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
2767
0
  nsPIDOMWindowInner* parentInner =
2768
0
    parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
2769
0
  if (!parentInner) {
2770
0
    return;
2771
0
  }
2772
0
2773
0
  nsCOMPtr<nsIURI> uri;
2774
0
  MOZ_ALWAYS_SUCCEEDS(
2775
0
    NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank")));
2776
0
2777
0
  // We're done if there is no parent controller or if this docshell
2778
0
  // is not permitted to control for some reason.
2779
0
  Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
2780
0
  if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(principal, uri)) {
2781
0
    return;
2782
0
  }
2783
0
2784
0
  mInitialClientSource->InheritController(controller.ref());
2785
0
}
2786
2787
Maybe<ClientInfo>
2788
nsDocShell::GetInitialClientInfo() const
2789
0
{
2790
0
  if (mInitialClientSource) {
2791
0
    Maybe<ClientInfo> result;
2792
0
    result.emplace(mInitialClientSource->Info());
2793
0
    return result;
2794
0
  }
2795
0
2796
0
  nsGlobalWindowInner* innerWindow =
2797
0
    mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
2798
0
  nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
2799
0
2800
0
  if (!doc || !doc->IsInitialDocument()) {
2801
0
    return Maybe<ClientInfo>();
2802
0
  }
2803
0
2804
0
  return innerWindow->GetClientInfo();
2805
0
}
2806
2807
void
2808
nsDocShell::RecomputeCanExecuteScripts()
2809
0
{
2810
0
  bool old = mCanExecuteScripts;
2811
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
2812
0
2813
0
  // If we have no tree owner, that means that we've been detached from the
2814
0
  // docshell tree (this is distinct from having no parent dochshell, which
2815
0
  // is the case for root docshells). It would be nice to simply disallow
2816
0
  // script in detached docshells, but bug 986542 demonstrates that this
2817
0
  // behavior breaks at least one website.
2818
0
  //
2819
0
  // So instead, we use our previous value, unless mAllowJavascript has been
2820
0
  // explicitly set to false.
2821
0
  if (!mTreeOwner) {
2822
0
    mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
2823
0
    // If scripting has been explicitly disabled on our docshell, we're done.
2824
0
  } else if (!mAllowJavascript) {
2825
0
    mCanExecuteScripts = false;
2826
0
    // If we have a parent, inherit.
2827
0
  } else if (parent) {
2828
0
    mCanExecuteScripts = parent->mCanExecuteScripts;
2829
0
    // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2830
0
    // script. Allow.
2831
0
  } else {
2832
0
    mCanExecuteScripts = true;
2833
0
  }
2834
0
2835
0
  // Inform our active DOM window.
2836
0
  //
2837
0
  // This will pass the outer, which will be in the scope of the active inner.
2838
0
  if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
2839
0
    xpc::Scriptability& scriptability =
2840
0
      xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
2841
0
    scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
2842
0
  }
2843
0
2844
0
  // If our value has changed, our children might be affected. Recompute their
2845
0
  // value as well.
2846
0
  if (old != mCanExecuteScripts) {
2847
0
    nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2848
0
    while (iter.HasMore()) {
2849
0
      static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
2850
0
    }
2851
0
  }
2852
0
}
2853
2854
nsresult
2855
nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
2856
0
{
2857
0
  bool wasFrame = IsFrame();
2858
#ifdef DEBUG
2859
  bool wasPrivate = UsePrivateBrowsing();
2860
#endif
2861
2862
0
  nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
2863
0
  NS_ENSURE_SUCCESS(rv, rv);
2864
0
2865
0
  nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
2866
0
  if (wasFrame != IsFrame() && priorityGroup) {
2867
0
    priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
2868
0
  }
2869
0
2870
0
  // Curse ambiguous nsISupports inheritance!
2871
0
  nsISupports* parent = GetAsSupports(aParent);
2872
0
2873
0
  // If parent is another docshell, we inherit all their flags for
2874
0
  // allowing plugins, scripting etc.
2875
0
  bool value;
2876
0
  nsString customUserAgent;
2877
0
  nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
2878
0
2879
0
  if (parentAsDocShell) {
2880
0
    if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
2881
0
      SetAllowPlugins(value);
2882
0
    }
2883
0
    if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
2884
0
      SetAllowJavascript(value);
2885
0
    }
2886
0
    if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
2887
0
      SetAllowMetaRedirects(value);
2888
0
    }
2889
0
    if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
2890
0
      SetAllowSubframes(value);
2891
0
    }
2892
0
    if (mAllowImages && NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
2893
0
      SetAllowImages(value);
2894
0
    }
2895
0
    SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
2896
0
    if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
2897
0
      SetAllowWindowControl(value);
2898
0
    }
2899
0
    SetAllowContentRetargeting(mAllowContentRetargeting &&
2900
0
      parentAsDocShell->GetAllowContentRetargetingOnChildren());
2901
0
    if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
2902
0
      SetIsActive(value);
2903
0
    }
2904
0
    if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
2905
0
        !customUserAgent.IsEmpty()) {
2906
0
      SetCustomUserAgent(customUserAgent);
2907
0
    }
2908
0
    if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
2909
0
      value = false;
2910
0
    }
2911
0
    SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
2912
0
    if (mInheritPrivateBrowsingId) {
2913
0
      value = parentAsDocShell->GetAffectPrivateSessionLifetime();
2914
0
      SetAffectPrivateSessionLifetime(value);
2915
0
    }
2916
0
    uint32_t flags;
2917
0
    if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
2918
0
      SetDefaultLoadFlags(flags);
2919
0
    }
2920
0
    uint32_t touchEventsOverride;
2921
0
    if (NS_SUCCEEDED(parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) {
2922
0
      SetTouchEventsOverride(touchEventsOverride);
2923
0
    }
2924
0
  }
2925
0
2926
0
  nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
2927
0
  if (parentAsLoadContext && mInheritPrivateBrowsingId &&
2928
0
      NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
2929
0
    SetPrivateBrowsing(value);
2930
0
  }
2931
0
2932
0
  nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
2933
0
  if (parentURIListener) {
2934
0
    mContentListener->SetParentContentListener(parentURIListener);
2935
0
  }
2936
0
2937
0
  // Our parent has changed. Recompute scriptability.
2938
0
  RecomputeCanExecuteScripts();
2939
0
2940
0
  NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(),
2941
0
               "Private browsing state changed while inheritance was disabled");
2942
0
2943
0
  return NS_OK;
2944
0
}
2945
2946
NS_IMETHODIMP
2947
nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
2948
0
{
2949
0
  NS_ENSURE_ARG_POINTER(aParent);
2950
0
  *aParent = nullptr;
2951
0
2952
0
  if (nsIDocShell::GetIsMozBrowser()) {
2953
0
    return NS_OK;
2954
0
  }
2955
0
2956
0
  nsCOMPtr<nsIDocShellTreeItem> parent =
2957
0
    do_QueryInterface(GetAsSupports(mParent));
2958
0
  if (!parent) {
2959
0
    return NS_OK;
2960
0
  }
2961
0
2962
0
  if (parent->ItemType() == mItemType) {
2963
0
    parent.swap(*aParent);
2964
0
  }
2965
0
  return NS_OK;
2966
0
}
2967
2968
NS_IMETHODIMP
2969
nsDocShell::GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell** aParent)
2970
0
{
2971
0
  NS_ENSURE_ARG_POINTER(aParent);
2972
0
  *aParent = nullptr;
2973
0
2974
0
  nsCOMPtr<nsIDocShellTreeItem> parent =
2975
0
    do_QueryInterface(GetAsSupports(mParent));
2976
0
  if (!parent) {
2977
0
    return NS_OK;
2978
0
  }
2979
0
2980
0
  if (parent->ItemType() == mItemType) {
2981
0
    nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
2982
0
    parentDS.forget(aParent);
2983
0
  }
2984
0
  return NS_OK;
2985
0
}
2986
2987
NS_IMETHODIMP
2988
nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
2989
0
{
2990
0
  NS_ENSURE_ARG_POINTER(aRootTreeItem);
2991
0
2992
0
  RefPtr<nsDocShell> root = this;
2993
0
  RefPtr<nsDocShell> parent = root->GetParentDocshell();
2994
0
  while (parent) {
2995
0
    root = parent;
2996
0
    parent = root->GetParentDocshell();
2997
0
  }
2998
0
2999
0
  root.forget(aRootTreeItem);
3000
0
  return NS_OK;
3001
0
}
3002
3003
NS_IMETHODIMP
3004
nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
3005
0
{
3006
0
  NS_ENSURE_ARG_POINTER(aRootTreeItem);
3007
0
  *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
3008
0
3009
0
  nsCOMPtr<nsIDocShellTreeItem> parent;
3010
0
  NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
3011
0
                    NS_ERROR_FAILURE);
3012
0
  while (parent) {
3013
0
    *aRootTreeItem = parent;
3014
0
    NS_ENSURE_SUCCESS(
3015
0
      (*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)),
3016
0
      NS_ERROR_FAILURE);
3017
0
  }
3018
0
  NS_ADDREF(*aRootTreeItem);
3019
0
  return NS_OK;
3020
0
}
3021
3022
NS_IMETHODIMP
3023
nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserBoundaries(nsIDocShell** aRootTreeItem)
3024
0
{
3025
0
    NS_ENSURE_ARG_POINTER(aRootTreeItem);
3026
0
    *aRootTreeItem = static_cast<nsIDocShell *>(this);
3027
0
3028
0
    nsCOMPtr<nsIDocShell> parent;
3029
0
    NS_ENSURE_SUCCESS(GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
3030
0
                      NS_ERROR_FAILURE);
3031
0
    while (parent) {
3032
0
      *aRootTreeItem = parent;
3033
0
      NS_ENSURE_SUCCESS((*aRootTreeItem)->
3034
0
        GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
3035
0
        NS_ERROR_FAILURE);
3036
0
    }
3037
0
    NS_ADDREF(*aRootTreeItem);
3038
0
    return NS_OK;
3039
0
}
3040
3041
/* static */
3042
bool
3043
nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
3044
                          nsIDocShellTreeItem* aAccessingItem,
3045
                          bool aConsiderOpener)
3046
0
{
3047
0
  MOZ_ASSERT(aTargetItem, "Must have target item!");
3048
0
3049
0
  if (!gValidateOrigin || !aAccessingItem) {
3050
0
    // Good to go
3051
0
    return true;
3052
0
  }
3053
0
3054
0
  // XXXbz should we care if aAccessingItem or the document therein is
3055
0
  // chrome?  Should those get extra privileges?
3056
0
3057
0
  // For historical context, see:
3058
0
  //
3059
0
  // Bug 13871:  Prevent frameset spoofing
3060
0
  // Bug 103638: Targets with same name in different windows open in wrong
3061
0
  //             window with javascript
3062
0
  // Bug 408052: Adopt "ancestor" frame navigation policy
3063
0
3064
0
  // Now do a security check.
3065
0
  //
3066
0
  // Disallow navigation if the two frames are not part of the same app, or if
3067
0
  // they have different is-in-browser-element states.
3068
0
  //
3069
0
  // Allow navigation if
3070
0
  //  1) aAccessingItem can script aTargetItem or one of its ancestors in
3071
0
  //     the frame hierarchy or
3072
0
  //  2) aTargetItem is a top-level frame and aAccessingItem is its descendant
3073
0
  //  3) aTargetItem is a top-level frame and aAccessingItem can target
3074
0
  //     its opener per rule (1) or (2).
3075
0
3076
0
  if (aTargetItem == aAccessingItem) {
3077
0
    // A frame is allowed to navigate itself.
3078
0
    return true;
3079
0
  }
3080
0
3081
0
  nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
3082
0
  nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
3083
0
  if (!targetDS || !accessingDS) {
3084
0
    // We must be able to convert both to nsIDocShell.
3085
0
    return false;
3086
0
  }
3087
0
3088
0
  if (targetDS->GetIsInIsolatedMozBrowserElement() !=
3089
0
        accessingDS->GetIsInIsolatedMozBrowserElement()) {
3090
0
    return false;
3091
0
  }
3092
0
3093
0
  nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
3094
0
  aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
3095
0
  nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot);
3096
0
3097
0
  nsCOMPtr<nsIDocShellTreeItem> targetRoot;
3098
0
  aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
3099
0
  nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot);
3100
0
3101
0
  OriginAttributes targetOA =
3102
0
    static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes();
3103
0
  OriginAttributes accessingOA =
3104
0
    static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes();
3105
0
3106
0
  // When the first party isolation is on, the top-level docShell may not have
3107
0
  // the firstPartyDomain in its originAttributes, but its document will have
3108
0
  // it. So we get the firstPartyDomain from the nodePrincipal of the document
3109
0
  // before we compare the originAttributes.
3110
0
  if (OriginAttributes::IsFirstPartyEnabled()) {
3111
0
    if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3112
0
        (accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) {
3113
0
3114
0
      nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
3115
0
3116
0
      if (accessingDoc) {
3117
0
        nsCOMPtr<nsIPrincipal> accessingPrincipal = accessingDoc->NodePrincipal();
3118
0
3119
0
        accessingOA.mFirstPartyDomain =
3120
0
          accessingPrincipal->OriginAttributesRef().mFirstPartyDomain;
3121
0
      }
3122
0
    }
3123
0
3124
0
    if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3125
0
        (targetDS == targetRootDS || targetDS->GetIsMozBrowser())) {
3126
0
3127
0
      nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
3128
0
3129
0
      if (targetDoc) {
3130
0
        nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
3131
0
3132
0
        targetOA.mFirstPartyDomain =
3133
0
          targetPrincipal->OriginAttributesRef().mFirstPartyDomain;
3134
0
      }
3135
0
    }
3136
0
  }
3137
0
3138
0
  if (targetOA != accessingOA) {
3139
0
    return false;
3140
0
  }
3141
0
3142
0
  // A private document can't access a non-private one, and vice versa.
3143
0
  if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
3144
0
      static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
3145
0
    return false;
3146
0
  }
3147
0
3148
0
  if (aTargetItem == accessingRoot) {
3149
0
    // A frame can navigate its root.
3150
0
    return true;
3151
0
  }
3152
0
3153
0
  // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
3154
0
  nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
3155
0
  do {
3156
0
    if (ValidateOrigin(aAccessingItem, target)) {
3157
0
      return true;
3158
0
    }
3159
0
3160
0
    nsCOMPtr<nsIDocShellTreeItem> parent;
3161
0
    target->GetSameTypeParent(getter_AddRefs(parent));
3162
0
    parent.swap(target);
3163
0
  } while (target);
3164
0
3165
0
  if (aTargetItem != targetRoot) {
3166
0
    // target is a subframe, not in accessor's frame hierarchy, and all its
3167
0
    // ancestors have origins different from that of the accessor. Don't
3168
0
    // allow access.
3169
0
    return false;
3170
0
  }
3171
0
3172
0
  if (!aConsiderOpener) {
3173
0
    // All done here
3174
0
    return false;
3175
0
  }
3176
0
3177
0
  nsCOMPtr<nsPIDOMWindowOuter> targetWindow = aTargetItem->GetWindow();
3178
0
  if (!targetWindow) {
3179
0
    NS_ERROR("This should not happen, really");
3180
0
    return false;
3181
0
  }
3182
0
3183
0
  nsCOMPtr<mozIDOMWindowProxy> targetOpener = targetWindow->GetOpener();
3184
0
  nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
3185
0
  nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
3186
0
3187
0
  if (!openerItem) {
3188
0
    return false;
3189
0
  }
3190
0
3191
0
  return CanAccessItem(openerItem, aAccessingItem, false);
3192
0
}
3193
3194
static bool
3195
ItemIsActive(nsIDocShellTreeItem* aItem)
3196
0
{
3197
0
  if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) {
3198
0
    auto* win = nsGlobalWindowOuter::Cast(window);
3199
0
    if (!win->GetClosedOuter()) {
3200
0
      return true;
3201
0
    }
3202
0
  }
3203
0
3204
0
  return false;
3205
0
}
3206
3207
NS_IMETHODIMP
3208
nsDocShell::FindItemWithName(const nsAString& aName,
3209
                             nsIDocShellTreeItem* aRequestor,
3210
                             nsIDocShellTreeItem* aOriginalRequestor,
3211
                             bool aSkipTabGroup,
3212
                             nsIDocShellTreeItem** aResult)
3213
0
{
3214
0
  NS_ENSURE_ARG_POINTER(aResult);
3215
0
3216
0
  // If we don't find one, we return NS_OK and a null result
3217
0
  *aResult = nullptr;
3218
0
3219
0
  if (aName.IsEmpty()) {
3220
0
    return NS_OK;
3221
0
  }
3222
0
3223
0
  if (aRequestor) {
3224
0
    // If aRequestor is not null we don't need to check special names, so
3225
0
    // just hand straight off to the search by actual name function.
3226
0
    return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
3227
0
                              aSkipTabGroup, aResult);
3228
0
  } else {
3229
0
    // This is the entry point into the target-finding algorithm.  Check
3230
0
    // for special names.  This should only be done once, hence the check
3231
0
    // for a null aRequestor.
3232
0
3233
0
    nsCOMPtr<nsIDocShellTreeItem> foundItem;
3234
0
    if (aName.LowerCaseEqualsLiteral("_self")) {
3235
0
      foundItem = this;
3236
0
    } else if (aName.LowerCaseEqualsLiteral("_blank")) {
3237
0
      // Just return null.  Caller must handle creating a new window with
3238
0
      // a blank name himself.
3239
0
      return NS_OK;
3240
0
    } else if (aName.LowerCaseEqualsLiteral("_parent")) {
3241
0
      GetSameTypeParent(getter_AddRefs(foundItem));
3242
0
      if (!foundItem) {
3243
0
        foundItem = this;
3244
0
      }
3245
0
    } else if (aName.LowerCaseEqualsLiteral("_top")) {
3246
0
      GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
3247
0
      NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
3248
0
    } else {
3249
0
      // Do the search for item by an actual name.
3250
0
      DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
3251
0
                         aSkipTabGroup, getter_AddRefs(foundItem));
3252
0
    }
3253
0
3254
0
    if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
3255
0
      foundItem = nullptr;
3256
0
    }
3257
0
3258
0
    // DoFindItemWithName only returns active items and we don't check if
3259
0
    // the item is active for the special cases.
3260
0
    if (foundItem) {
3261
0
      foundItem.swap(*aResult);
3262
0
    }
3263
0
    return NS_OK;
3264
0
  }
3265
0
}
3266
3267
void
3268
0
nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
3269
0
  // Chrome docshells must not have a private browsing OriginAttribute
3270
0
  // Content docshells must maintain the equality:
3271
0
  // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
3272
0
  if (mItemType == typeChrome) {
3273
0
    MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
3274
0
  } else {
3275
0
    MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId);
3276
0
  }
3277
0
}
3278
3279
nsresult
3280
nsDocShell::DoFindItemWithName(const nsAString& aName,
3281
                               nsIDocShellTreeItem* aRequestor,
3282
                               nsIDocShellTreeItem* aOriginalRequestor,
3283
                               bool aSkipTabGroup,
3284
                               nsIDocShellTreeItem** aResult)
3285
0
{
3286
0
  // First we check our name.
3287
0
  if (mBrowsingContext->NameEquals(aName) && ItemIsActive(this) &&
3288
0
      CanAccessItem(this, aOriginalRequestor)) {
3289
0
    NS_ADDREF(*aResult = this);
3290
0
    return NS_OK;
3291
0
  }
3292
0
3293
0
  // Second we check our children making sure not to ask a child if
3294
0
  // it is the aRequestor.
3295
#ifdef DEBUG
3296
  nsresult rv =
3297
#endif
3298
0
  FindChildWithName(aName, true, true, aRequestor, aOriginalRequestor,
3299
0
                    aResult);
3300
0
  NS_ASSERTION(NS_SUCCEEDED(rv),
3301
0
               "FindChildWithName should not be failing here.");
3302
0
  if (*aResult) {
3303
0
    return NS_OK;
3304
0
  }
3305
0
3306
0
  // Third if we have a parent and it isn't the requestor then we
3307
0
  // should ask it to do the search.  If it is the requestor we
3308
0
  // should just stop here and let the parent do the rest.  If we
3309
0
  // don't have a parent, then we should ask the
3310
0
  // docShellTreeOwner to do the search.
3311
0
  nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
3312
0
    do_QueryInterface(GetAsSupports(mParent));
3313
0
  if (parentAsTreeItem) {
3314
0
    if (parentAsTreeItem == aRequestor) {
3315
0
      return NS_OK;
3316
0
    }
3317
0
3318
0
    // If we have a same-type parent, respecting browser and app boundaries.
3319
0
    // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344 are fixed.
3320
0
    if (!GetIsMozBrowser() && parentAsTreeItem->ItemType() == mItemType) {
3321
0
      return parentAsTreeItem->FindItemWithName(
3322
0
        aName,
3323
0
        static_cast<nsIDocShellTreeItem*>(this),
3324
0
        aOriginalRequestor,
3325
0
        /* aSkipTabGroup = */ false,
3326
0
        aResult);
3327
0
    }
3328
0
  }
3329
0
3330
0
  // If we have a null parent or the parent is not of the same type, we need to
3331
0
  // give up on finding it in our tree, and start looking in our TabGroup.
3332
0
  nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
3333
0
  if (window && !aSkipTabGroup) {
3334
0
    RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup();
3335
0
    tabGroup->FindItemWithName(aName, aRequestor, aOriginalRequestor, aResult);
3336
0
  }
3337
0
3338
0
  return NS_OK;
3339
0
}
3340
3341
bool
3342
nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell)
3343
0
{
3344
0
  // If no target then not sandboxed.
3345
0
  if (!aTargetDocShell) {
3346
0
    return false;
3347
0
  }
3348
0
3349
0
  // We cannot be sandboxed from ourselves.
3350
0
  if (aTargetDocShell == this) {
3351
0
    return false;
3352
0
  }
3353
0
3354
0
  // Default the sandbox flags to our flags, so that if we can't retrieve the
3355
0
  // active document, we will still enforce our own.
3356
0
  uint32_t sandboxFlags = mSandboxFlags;
3357
0
  if (mContentViewer) {
3358
0
    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
3359
0
    if (doc) {
3360
0
      sandboxFlags = doc->GetSandboxFlags();
3361
0
    }
3362
0
  }
3363
0
3364
0
  // If no flags, we are not sandboxed at all.
3365
0
  if (!sandboxFlags) {
3366
0
    return false;
3367
0
  }
3368
0
3369
0
  // If aTargetDocShell has an ancestor, it is not top level.
3370
0
  nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
3371
0
  aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
3372
0
  if (ancestorOfTarget) {
3373
0
    do {
3374
0
      // We are not sandboxed if we are an ancestor of target.
3375
0
      if (ancestorOfTarget == this) {
3376
0
        return false;
3377
0
      }
3378
0
      nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
3379
0
      ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
3380
0
      tempTreeItem.swap(ancestorOfTarget);
3381
0
    } while (ancestorOfTarget);
3382
0
3383
0
    // Otherwise, we are sandboxed from aTargetDocShell.
3384
0
    return true;
3385
0
  }
3386
0
3387
0
  // aTargetDocShell is top level, are we the "one permitted sandboxed
3388
0
  // navigator", i.e. did we open aTargetDocShell?
3389
0
  nsCOMPtr<nsIDocShell> permittedNavigator;
3390
0
  aTargetDocShell->GetOnePermittedSandboxedNavigator(
3391
0
    getter_AddRefs(permittedNavigator));
3392
0
  if (permittedNavigator == this) {
3393
0
    return false;
3394
0
  }
3395
0
3396
0
  // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
3397
0
  // from our top.
3398
0
  if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
3399
0
    nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
3400
0
    GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
3401
0
    if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
3402
0
      return false;
3403
0
    }
3404
0
  }
3405
0
3406
0
  // Otherwise, we are sandboxed from aTargetDocShell.
3407
0
  return true;
3408
0
}
3409
3410
NS_IMETHODIMP
3411
nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
3412
0
{
3413
0
  NS_ENSURE_ARG_POINTER(aTreeOwner);
3414
0
3415
0
  *aTreeOwner = mTreeOwner;
3416
0
  NS_IF_ADDREF(*aTreeOwner);
3417
0
  return NS_OK;
3418
0
}
3419
3420
NS_IMETHODIMP
3421
nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
3422
0
{
3423
0
  if (mIsBeingDestroyed && aTreeOwner) {
3424
0
    return NS_ERROR_FAILURE;
3425
0
  }
3426
0
3427
0
  // Don't automatically set the progress based on the tree owner for frames
3428
0
  if (!IsFrame()) {
3429
0
    nsCOMPtr<nsIWebProgress> webProgress =
3430
0
      do_QueryInterface(GetAsSupports(this));
3431
0
3432
0
    if (webProgress) {
3433
0
      nsCOMPtr<nsIWebProgressListener> oldListener =
3434
0
        do_QueryInterface(mTreeOwner);
3435
0
      nsCOMPtr<nsIWebProgressListener> newListener =
3436
0
        do_QueryInterface(aTreeOwner);
3437
0
3438
0
      if (oldListener) {
3439
0
        webProgress->RemoveProgressListener(oldListener);
3440
0
      }
3441
0
3442
0
      if (newListener) {
3443
0
        webProgress->AddProgressListener(newListener,
3444
0
                                         nsIWebProgress::NOTIFY_ALL);
3445
0
      }
3446
0
    }
3447
0
  }
3448
0
3449
0
  mTreeOwner = aTreeOwner;  // Weak reference per API
3450
0
3451
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
3452
0
  while (iter.HasMore()) {
3453
0
    nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
3454
0
    NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3455
0
3456
0
    if (child->ItemType() == mItemType) {
3457
0
      child->SetTreeOwner(aTreeOwner);
3458
0
    }
3459
0
  }
3460
0
3461
0
  // Our tree owner has changed. Recompute scriptability.
3462
0
  //
3463
0
  // Note that this is near-redundant with the recomputation in
3464
0
  // SetDocLoaderParent(), but not so for the root DocShell, where the call to
3465
0
  // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
3466
0
  // and we never set another parent. Given that this is neither expensive nor
3467
0
  // performance-critical, let's be safe and unconditionally recompute this
3468
0
  // state whenever dependent state changes.
3469
0
  RecomputeCanExecuteScripts();
3470
0
3471
0
  return NS_OK;
3472
0
}
3473
3474
NS_IMETHODIMP
3475
nsDocShell::SetChildOffset(int32_t aChildOffset)
3476
0
{
3477
0
  mChildOffset = aChildOffset;
3478
0
  return NS_OK;
3479
0
}
3480
3481
NS_IMETHODIMP
3482
nsDocShell::GetChildOffset(int32_t* aChildOffset)
3483
0
{
3484
0
  *aChildOffset = mChildOffset;
3485
0
  return NS_OK;
3486
0
}
3487
3488
NS_IMETHODIMP
3489
nsDocShell::GetHistoryID(nsID** aID)
3490
0
{
3491
0
  *aID = mHistoryID.Clone();
3492
0
  return NS_OK;
3493
0
}
3494
3495
const nsID
3496
nsDocShell::HistoryID()
3497
0
{
3498
0
  return mHistoryID;
3499
0
}
3500
3501
NS_IMETHODIMP
3502
nsDocShell::GetIsInUnload(bool* aIsInUnload)
3503
0
{
3504
0
  *aIsInUnload = mFiredUnloadEvent;
3505
0
  return NS_OK;
3506
0
}
3507
3508
NS_IMETHODIMP
3509
nsDocShell::GetChildCount(int32_t* aChildCount)
3510
0
{
3511
0
  NS_ENSURE_ARG_POINTER(aChildCount);
3512
0
  *aChildCount = mChildList.Length();
3513
0
  return NS_OK;
3514
0
}
3515
3516
NS_IMETHODIMP
3517
nsDocShell::AddChild(nsIDocShellTreeItem* aChild)
3518
0
{
3519
0
  NS_ENSURE_ARG_POINTER(aChild);
3520
0
3521
0
  RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3522
0
  NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3523
0
3524
0
  // Make sure we're not creating a loop in the docshell tree
3525
0
  nsDocLoader* ancestor = this;
3526
0
  do {
3527
0
    if (childAsDocLoader == ancestor) {
3528
0
      return NS_ERROR_ILLEGAL_VALUE;
3529
0
    }
3530
0
    ancestor = ancestor->GetParent();
3531
0
  } while (ancestor);
3532
0
3533
0
  // Make sure to remove the child from its current parent.
3534
0
  nsDocLoader* childsParent = childAsDocLoader->GetParent();
3535
0
  if (childsParent) {
3536
0
    nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader);
3537
0
    NS_ENSURE_SUCCESS(rv, rv);
3538
0
  }
3539
0
3540
0
  // Make sure to clear the treeowner in case this child is a different type
3541
0
  // from us.
3542
0
  aChild->SetTreeOwner(nullptr);
3543
0
3544
0
  nsresult res = AddChildLoader(childAsDocLoader);
3545
0
  NS_ENSURE_SUCCESS(res, res);
3546
0
  NS_ASSERTION(!mChildList.IsEmpty(),
3547
0
               "child list must not be empty after a successful add");
3548
0
3549
0
  nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
3550
0
  bool dynamic = false;
3551
0
  childDocShell->GetCreatedDynamically(&dynamic);
3552
0
  if (!dynamic) {
3553
0
    nsCOMPtr<nsISHEntry> currentSH;
3554
0
    bool oshe = false;
3555
0
    GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
3556
0
    if (currentSH) {
3557
0
      currentSH->HasDynamicallyAddedChild(&dynamic);
3558
0
    }
3559
0
  }
3560
0
  childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
3561
0
3562
0
  /* Set the child's global history if the parent has one */
3563
0
  if (mUseGlobalHistory) {
3564
0
    childDocShell->SetUseGlobalHistory(true);
3565
0
  }
3566
0
3567
0
  if (aChild->ItemType() != mItemType) {
3568
0
    return NS_OK;
3569
0
  }
3570
0
3571
0
  aChild->SetTreeOwner(mTreeOwner);
3572
0
3573
0
  nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
3574
0
  if (!childAsDocShell) {
3575
0
    return NS_OK;
3576
0
  }
3577
0
3578
0
  childAsDocShell->AttachBrowsingContext(this);
3579
0
3580
0
  // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3581
0
3582
0
  // Now take this document's charset and set the child's parentCharset field
3583
0
  // to it. We'll later use that field, in the loading process, for the
3584
0
  // charset choosing algorithm.
3585
0
  // If we fail, at any point, we just return NS_OK.
3586
0
  // This code has some performance impact. But this will be reduced when
3587
0
  // the current charset will finally be stored as an Atom, avoiding the
3588
0
  // alias resolution extra look-up.
3589
0
3590
0
  // we are NOT going to propagate the charset is this Chrome's docshell
3591
0
  if (mItemType == nsIDocShellTreeItem::typeChrome) {
3592
0
    return NS_OK;
3593
0
  }
3594
0
3595
0
  // get the parent's current charset
3596
0
  if (!mContentViewer) {
3597
0
    return NS_OK;
3598
0
  }
3599
0
  nsIDocument* doc = mContentViewer->GetDocument();
3600
0
  if (!doc) {
3601
0
    return NS_OK;
3602
0
  }
3603
0
3604
0
  bool isWyciwyg = false;
3605
0
3606
0
  if (mCurrentURI) {
3607
0
    // Check if the url is wyciwyg
3608
0
    mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
3609
0
  }
3610
0
3611
0
  if (!isWyciwyg) {
3612
0
    // If this docshell is loaded from a wyciwyg: URI, don't
3613
0
    // advertise our charset since it does not in any way reflect
3614
0
    // the actual source charset, which is what we're trying to
3615
0
    // expose here.
3616
0
3617
0
    const Encoding* parentCS = doc->GetDocumentCharacterSet();
3618
0
    int32_t charsetSource = doc->GetDocumentCharacterSetSource();
3619
0
    // set the child's parentCharset
3620
0
    childAsDocShell->SetParentCharset(parentCS,
3621
0
                                      charsetSource,
3622
0
                                      doc->NodePrincipal());
3623
0
  }
3624
0
3625
0
  // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
3626
0
  //        NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3627
0
3628
0
  return NS_OK;
3629
0
}
3630
3631
NS_IMETHODIMP
3632
nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild)
3633
0
{
3634
0
  NS_ENSURE_ARG_POINTER(aChild);
3635
0
3636
0
  RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3637
0
  NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3638
0
3639
0
  nsresult rv = RemoveChildLoader(childAsDocLoader);
3640
0
  NS_ENSURE_SUCCESS(rv, rv);
3641
0
3642
0
  nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
3643
0
  if (childAsDocShell) {
3644
0
    childAsDocShell->DetachBrowsingContext();
3645
0
  }
3646
0
3647
0
  aChild->SetTreeOwner(nullptr);
3648
0
3649
0
  return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
3650
0
}
3651
3652
NS_IMETHODIMP
3653
nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild)
3654
0
{
3655
0
  NS_ENSURE_ARG_POINTER(aChild);
3656
0
3657
#ifdef DEBUG
3658
  if (aIndex < 0) {
3659
    NS_WARNING("Negative index passed to GetChildAt");
3660
  } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
3661
    NS_WARNING("Too large an index passed to GetChildAt");
3662
  }
3663
#endif
3664
3665
0
  nsIDocumentLoader* child = ChildAt(aIndex);
3666
0
  NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
3667
0
3668
0
  return CallQueryInterface(child, aChild);
3669
0
}
3670
3671
NS_IMETHODIMP
3672
nsDocShell::FindChildWithName(const nsAString& aName,
3673
                              bool aRecurse, bool aSameType,
3674
                              nsIDocShellTreeItem* aRequestor,
3675
                              nsIDocShellTreeItem* aOriginalRequestor,
3676
                              nsIDocShellTreeItem** aResult)
3677
0
{
3678
0
  NS_ENSURE_ARG_POINTER(aResult);
3679
0
3680
0
  // if we don't find one, we return NS_OK and a null result
3681
0
  *aResult = nullptr;
3682
0
3683
0
  if (aName.IsEmpty()) {
3684
0
    return NS_OK;
3685
0
  }
3686
0
3687
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
3688
0
  while (iter.HasMore()) {
3689
0
    nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
3690
0
    NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3691
0
    int32_t childType = child->ItemType();
3692
0
3693
0
    if (aSameType && (childType != mItemType)) {
3694
0
      continue;
3695
0
    }
3696
0
3697
0
    bool childNameEquals = false;
3698
0
    child->NameEquals(aName, &childNameEquals);
3699
0
    if (childNameEquals && ItemIsActive(child) &&
3700
0
        CanAccessItem(child, aOriginalRequestor)) {
3701
0
      child.swap(*aResult);
3702
0
      break;
3703
0
    }
3704
0
3705
0
    // Only ask it to check children if it is same type
3706
0
    if (childType != mItemType) {
3707
0
      continue;
3708
0
    }
3709
0
3710
0
    // Only ask the child if it isn't the requestor
3711
0
    if (aRecurse && (aRequestor != child)) {
3712
0
      // See if child contains the shell with the given name
3713
#ifdef DEBUG
3714
      nsresult rv =
3715
#endif
3716
      child->FindChildWithName(aName, true, aSameType,
3717
0
                               static_cast<nsIDocShellTreeItem*>(this),
3718
0
                               aOriginalRequestor, aResult);
3719
0
      NS_ASSERTION(NS_SUCCEEDED(rv), "FindChildWithName should not fail here");
3720
0
      if (*aResult) {
3721
0
        // found it
3722
0
        return NS_OK;
3723
0
      }
3724
0
    }
3725
0
  }
3726
0
  return NS_OK;
3727
0
}
3728
3729
NS_IMETHODIMP
3730
nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry** aResult)
3731
0
{
3732
0
  nsresult rv = NS_OK;
3733
0
3734
0
  NS_ENSURE_ARG_POINTER(aResult);
3735
0
  *aResult = nullptr;
3736
0
3737
0
  // A nsISHEntry for a child is *only* available when the parent is in
3738
0
  // the progress of loading a document too...
3739
0
3740
0
  if (mLSHE) {
3741
0
    /* Before looking for the subframe's url, check
3742
0
     * the expiration status of the parent. If the parent
3743
0
     * has expired from cache, then subframes will not be
3744
0
     * loaded from history in certain situations.
3745
0
     */
3746
0
    bool parentExpired = mLSHE->GetExpirationStatus();
3747
0
3748
0
    /* Get the parent's Load Type so that it can be set on the child too.
3749
0
     * By default give a loadHistory value
3750
0
     */
3751
0
    uint32_t loadType = mLSHE->GetLoadType();
3752
0
    // If the user did a shift-reload on this frameset page,
3753
0
    // we don't want to load the subframes from history.
3754
0
    if (IsForceReloadType(loadType) ||
3755
0
        loadType == LOAD_REFRESH) {
3756
0
      return rv;
3757
0
    }
3758
0
3759
0
    /* If the user pressed reload and the parent frame has expired
3760
0
     *  from cache, we do not want to load the child frame from history.
3761
0
     */
3762
0
    if (parentExpired && (loadType == LOAD_RELOAD_NORMAL)) {
3763
0
      // The parent has expired. Return null.
3764
0
      *aResult = nullptr;
3765
0
      return rv;
3766
0
    }
3767
0
3768
0
    // Get the child subframe from session history.
3769
0
    rv = mLSHE->GetChildAt(aChildOffset, aResult);
3770
0
    if (*aResult) {
3771
0
      (*aResult)->SetLoadType(loadType);
3772
0
    }
3773
0
  }
3774
0
  return rv;
3775
0
}
3776
3777
NS_IMETHODIMP
3778
nsDocShell::AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
3779
                            int32_t aChildOffset, uint32_t aLoadType,
3780
                            bool aCloneChildren)
3781
0
{
3782
0
  nsresult rv = NS_OK;
3783
0
3784
0
  if (mLSHE && aLoadType != LOAD_PUSHSTATE) {
3785
0
    /* You get here if you are currently building a
3786
0
     * hierarchy ie.,you just visited a frameset page
3787
0
     */
3788
0
    if (NS_FAILED(mLSHE->ReplaceChild(aNewEntry))) {
3789
0
      rv = mLSHE->AddChild(aNewEntry, aChildOffset);
3790
0
    }
3791
0
  } else if (!aCloneRef) {
3792
0
    /* This is an initial load in some subframe.  Just append it if we can */
3793
0
    if (mOSHE) {
3794
0
      rv = mOSHE->AddChild(aNewEntry, aChildOffset);
3795
0
    }
3796
0
  } else {
3797
0
    rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
3798
0
                                 aLoadType, aCloneChildren);
3799
0
  }
3800
0
  return rv;
3801
0
}
3802
3803
nsresult
3804
nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
3805
                                    nsISHEntry* aNewEntry,
3806
                                    int32_t aChildOffset,
3807
                                    uint32_t aLoadType,
3808
                                    bool aCloneChildren)
3809
0
{
3810
0
  nsresult rv = NS_OK;
3811
0
  if (mSessionHistory) {
3812
0
    /* You are currently in the rootDocShell.
3813
0
     * You will get here when a subframe has a new url
3814
0
     * to load and you have walked up the tree all the
3815
0
     * way to the top to clone the current SHEntry hierarchy
3816
0
     * and replace the subframe where a new url was loaded with
3817
0
     * a new entry.
3818
0
     */
3819
0
    nsCOMPtr<nsISHEntry> currentHE;
3820
0
    int32_t index = mSessionHistory->Index();
3821
0
    if (index < 0) {
3822
0
      return NS_ERROR_FAILURE;
3823
0
    }
3824
0
3825
0
    rv = mSessionHistory->LegacySHistory()->GetEntryAtIndex(
3826
0
      index, getter_AddRefs(currentHE));
3827
0
    NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
3828
0
3829
0
    nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
3830
0
    if (currentEntry) {
3831
0
      nsCOMPtr<nsISHEntry> nextEntry;
3832
0
      uint32_t cloneID = aCloneRef->GetID();
3833
0
      rv = nsSHistory::CloneAndReplace(currentEntry, this, cloneID,
3834
0
        aNewEntry, aCloneChildren, getter_AddRefs(nextEntry));
3835
0
3836
0
      if (NS_SUCCEEDED(rv)) {
3837
0
        rv = mSessionHistory->LegacySHistory()->AddEntry(nextEntry, true);
3838
0
      }
3839
0
    }
3840
0
  } else {
3841
0
    /* Just pass this along */
3842
0
    nsCOMPtr<nsIDocShell> parent =
3843
0
      do_QueryInterface(GetAsSupports(mParent), &rv);
3844
0
    if (parent) {
3845
0
      rv = static_cast<nsDocShell*>(parent.get())->AddChildSHEntryInternal(
3846
0
        aCloneRef, aNewEntry, aChildOffset, aLoadType, aCloneChildren);
3847
0
    }
3848
0
  }
3849
0
  return rv;
3850
0
}
3851
3852
nsresult
3853
nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
3854
                                    bool aCloneChildren)
3855
0
{
3856
0
  /* You will get here when you are in a subframe and
3857
0
   * a new url has been loaded on you.
3858
0
   * The mOSHE in this subframe will be the previous url's
3859
0
   * mOSHE. This mOSHE will be used as the identification
3860
0
   * for this subframe in the  CloneAndReplace function.
3861
0
   */
3862
0
3863
0
  // In this case, we will end up calling AddEntry, which increases the
3864
0
  // current index by 1
3865
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
3866
0
  if (rootSH) {
3867
0
    mPreviousEntryIndex = rootSH->Index();
3868
0
  }
3869
0
3870
0
  nsresult rv;
3871
0
  nsCOMPtr<nsIDocShell> parent = do_QueryInterface(GetAsSupports(mParent), &rv);
3872
0
  if (parent) {
3873
0
    rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
3874
0
                                 aCloneChildren);
3875
0
  }
3876
0
3877
0
  if (rootSH) {
3878
0
    mLoadedEntryIndex = rootSH->Index();
3879
#ifdef DEBUG_PAGE_CACHE
3880
    printf("Previous index: %d, Loaded index: %d\n\n", mPreviousEntryIndex,
3881
           mLoadedEntryIndex);
3882
#endif
3883
  }
3884
0
3885
0
  return rv;
3886
0
}
3887
3888
NS_IMETHODIMP
3889
nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
3890
0
{
3891
0
  mUseGlobalHistory = aUseGlobalHistory;
3892
0
  if (!aUseGlobalHistory) {
3893
0
    return NS_OK;
3894
0
  }
3895
0
3896
0
  nsCOMPtr<IHistory> history = services::GetHistoryService();
3897
0
  return history ? NS_OK : NS_ERROR_FAILURE;
3898
0
}
3899
3900
NS_IMETHODIMP
3901
nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory)
3902
0
{
3903
0
  *aUseGlobalHistory = mUseGlobalHistory;
3904
0
  return NS_OK;
3905
0
}
3906
3907
NS_IMETHODIMP
3908
nsDocShell::RemoveFromSessionHistory()
3909
0
{
3910
0
  nsCOMPtr<nsIDocShellTreeItem> root;
3911
0
  GetSameTypeRootTreeItem(getter_AddRefs(root));
3912
0
  nsCOMPtr<nsIWebNavigation> rootAsWebnav = do_QueryInterface(root);
3913
0
  if (!rootAsWebnav) {
3914
0
    return NS_OK;
3915
0
  }
3916
0
  RefPtr<ChildSHistory> sessionHistory = rootAsWebnav->GetSessionHistory();
3917
0
  if (!sessionHistory) {
3918
0
    return NS_OK;
3919
0
  }
3920
0
  int32_t index = sessionHistory->Index();
3921
0
  AutoTArray<nsID, 16> ids({mHistoryID});
3922
0
  sessionHistory->LegacySHistory()->RemoveEntries(ids, index);
3923
0
  return NS_OK;
3924
0
}
3925
3926
NS_IMETHODIMP
3927
nsDocShell::SetCreatedDynamically(bool aDynamic)
3928
0
{
3929
0
  mDynamicallyCreated = aDynamic;
3930
0
  return NS_OK;
3931
0
}
3932
3933
NS_IMETHODIMP
3934
nsDocShell::GetCreatedDynamically(bool* aDynamic)
3935
0
{
3936
0
  *aDynamic = mDynamicallyCreated;
3937
0
  return NS_OK;
3938
0
}
3939
3940
NS_IMETHODIMP
3941
nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
3942
0
{
3943
0
  *aOSHE = false;
3944
0
  *aEntry = nullptr;
3945
0
  if (mLSHE) {
3946
0
    NS_ADDREF(*aEntry = mLSHE);
3947
0
  } else if (mOSHE) {
3948
0
    NS_ADDREF(*aEntry = mOSHE);
3949
0
    *aOSHE = true;
3950
0
  }
3951
0
  return NS_OK;
3952
0
}
3953
3954
nsIScriptGlobalObject*
3955
nsDocShell::GetScriptGlobalObject()
3956
0
{
3957
0
  NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
3958
0
  return mScriptGlobal;
3959
0
}
3960
3961
nsIDocument*
3962
nsDocShell::GetDocument()
3963
0
{
3964
0
  NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
3965
0
  return mContentViewer->GetDocument();
3966
0
}
3967
3968
nsPIDOMWindowOuter*
3969
nsDocShell::GetWindow()
3970
0
{
3971
0
  if (NS_FAILED(EnsureScriptEnvironment())) {
3972
0
    return nullptr;
3973
0
  }
3974
0
  return mScriptGlobal->AsOuter();
3975
0
}
3976
3977
NS_IMETHODIMP
3978
nsDocShell::GetDomWindow(mozIDOMWindowProxy** aWindow)
3979
0
{
3980
0
  NS_ENSURE_ARG_POINTER(aWindow);
3981
0
3982
0
  nsresult rv = EnsureScriptEnvironment();
3983
0
  NS_ENSURE_SUCCESS(rv, rv);
3984
0
3985
0
  nsCOMPtr<nsPIDOMWindowOuter> window = mScriptGlobal->AsOuter();
3986
0
  window.forget(aWindow);
3987
0
  return NS_OK;
3988
0
}
3989
3990
NS_IMETHODIMP
3991
nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager)
3992
0
{
3993
0
  RefPtr<ContentFrameMessageManager> mm;
3994
0
  if (RefPtr<TabChild> tabChild = TabChild::GetFrom(this)) {
3995
0
    mm = tabChild->GetMessageManager();
3996
0
  } else if (nsPIDOMWindowOuter* win = GetWindow()) {
3997
0
    mm = win->GetMessageManager();
3998
0
  }
3999
0
  mm.forget(aMessageManager);
4000
0
  return NS_OK;
4001
0
}
4002
4003
NS_IMETHODIMP
4004
nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
4005
0
{
4006
0
  if (mDeviceSizeIsPageSize != aValue) {
4007
0
    mDeviceSizeIsPageSize = aValue;
4008
0
    RefPtr<nsPresContext> presContext;
4009
0
    GetPresContext(getter_AddRefs(presContext));
4010
0
    if (presContext) {
4011
0
      presContext->MediaFeatureValuesChanged({
4012
0
        MediaFeatureChangeReason::DeviceSizeIsPageSizeChange });
4013
0
    }
4014
0
  }
4015
0
  return NS_OK;
4016
0
}
4017
4018
NS_IMETHODIMP
4019
nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
4020
0
{
4021
0
  *aValue = mDeviceSizeIsPageSize;
4022
0
  return NS_OK;
4023
0
}
4024
4025
void
4026
nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
4027
0
{
4028
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4029
0
  if (!rootSH || !aEntry) {
4030
0
    return;
4031
0
  }
4032
0
4033
0
  int32_t count = aEntry->GetChildCount();
4034
0
  AutoTArray<nsID, 16> ids;
4035
0
  for (int32_t i = 0; i < count; ++i) {
4036
0
    nsCOMPtr<nsISHEntry> child;
4037
0
    aEntry->GetChildAt(i, getter_AddRefs(child));
4038
0
    if (child) {
4039
0
      ids.AppendElement(child->DocshellID());
4040
0
    }
4041
0
  }
4042
0
  int32_t index = rootSH->Index();
4043
0
  rootSH->LegacySHistory()->RemoveEntries(ids, index);
4044
0
}
4045
4046
//-------------------------------------
4047
//-- Helper Method for Print discovery
4048
//-------------------------------------
4049
bool
4050
nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
4051
0
{
4052
0
  if (mIsPrintingOrPP && aDisplayErrorDialog) {
4053
0
    DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
4054
0
  }
4055
0
4056
0
  return mIsPrintingOrPP;
4057
0
}
4058
4059
bool
4060
nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
4061
                                bool aCheckIfUnloadFired)
4062
0
{
4063
0
  bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) &&
4064
0
                   (!aCheckIfUnloadFired || !mFiredUnloadEvent);
4065
0
  if (!isAllowed) {
4066
0
    return false;
4067
0
  }
4068
0
  if (!mContentViewer) {
4069
0
    return true;
4070
0
  }
4071
0
  bool firingBeforeUnload;
4072
0
  mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
4073
0
  return !firingBeforeUnload;
4074
0
}
4075
4076
//*****************************************************************************
4077
// nsDocShell::nsIWebNavigation
4078
//*****************************************************************************
4079
4080
NS_IMETHODIMP
4081
nsDocShell::GetCanGoBack(bool* aCanGoBack)
4082
0
{
4083
0
  *aCanGoBack = false;
4084
0
  if (!IsNavigationAllowed(false)) {
4085
0
    return NS_OK; // JS may not handle returning of an error code
4086
0
  }
4087
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4088
0
  if (rootSH) {
4089
0
    *aCanGoBack = rootSH->CanGo(-1);
4090
0
    return NS_OK;
4091
0
  }
4092
0
  return NS_ERROR_FAILURE;
4093
0
}
4094
4095
NS_IMETHODIMP
4096
nsDocShell::GetCanGoForward(bool* aCanGoForward)
4097
0
{
4098
0
  *aCanGoForward = false;
4099
0
  if (!IsNavigationAllowed(false)) {
4100
0
    return NS_OK; // JS may not handle returning of an error code
4101
0
  }
4102
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4103
0
  if (rootSH) {
4104
0
    *aCanGoForward = rootSH->CanGo(1);
4105
0
    return NS_OK;
4106
0
  }
4107
0
  return NS_ERROR_FAILURE;
4108
0
}
4109
4110
NS_IMETHODIMP
4111
nsDocShell::GoBack()
4112
0
{
4113
0
  if (!IsNavigationAllowed()) {
4114
0
    return NS_OK; // JS may not handle returning of an error code
4115
0
  }
4116
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4117
0
  NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE);
4118
0
  ErrorResult rv;
4119
0
  rootSH->Go(-1, rv);
4120
0
  return rv.StealNSResult();
4121
0
}
4122
4123
NS_IMETHODIMP
4124
nsDocShell::GoForward()
4125
0
{
4126
0
  if (!IsNavigationAllowed()) {
4127
0
    return NS_OK; // JS may not handle returning of an error code
4128
0
  }
4129
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4130
0
  NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE);
4131
0
  ErrorResult rv;
4132
0
  rootSH->Go(1, rv);
4133
0
  return rv.StealNSResult();
4134
0
}
4135
4136
// XXX(nika): We may want to stop exposing this API in the child process? Going
4137
// to a specific index from multiple different processes could definitely race.
4138
NS_IMETHODIMP
4139
nsDocShell::GotoIndex(int32_t aIndex)
4140
0
{
4141
0
  if (!IsNavigationAllowed()) {
4142
0
    return NS_OK; // JS may not handle returning of an error code
4143
0
  }
4144
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4145
0
  NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE);
4146
0
  return rootSH->LegacySHistory()->GotoIndex(aIndex);
4147
0
}
4148
4149
NS_IMETHODIMP
4150
nsDocShell::LoadURI(const nsAString& aURI,
4151
                    uint32_t aLoadFlags,
4152
                    nsIURI* aReferringURI,
4153
                    nsIInputStream* aPostStream,
4154
                    nsIInputStream* aHeaderStream,
4155
                    nsIPrincipal* aTriggeringPrincipal)
4156
0
{
4157
0
  return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
4158
0
                            RP_Unset, aPostStream,
4159
0
                            aHeaderStream, nullptr, aTriggeringPrincipal);
4160
0
}
4161
4162
NS_IMETHODIMP
4163
nsDocShell::LoadURIWithOptions(const nsAString& aURI,
4164
                               uint32_t aLoadFlags,
4165
                               nsIURI* aReferringURI,
4166
                               uint32_t aReferrerPolicy,
4167
                               nsIInputStream* aPostStream,
4168
                               nsIInputStream* aHeaderStream,
4169
                               nsIURI* aBaseURI,
4170
                               nsIPrincipal* aTriggeringPrincipal)
4171
0
{
4172
0
  NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
4173
0
4174
0
  if (!IsNavigationAllowed()) {
4175
0
    return NS_OK; // JS may not handle returning of an error code
4176
0
  }
4177
0
  nsCOMPtr<nsIURI> uri;
4178
0
  nsCOMPtr<nsIInputStream> postStream(aPostStream);
4179
0
  nsresult rv = NS_OK;
4180
0
4181
0
  // Create a URI from our string; if that succeeds, we want to
4182
0
  // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
4183
0
  // flag.
4184
0
4185
0
  NS_ConvertUTF16toUTF8 uriString(aURI);
4186
0
  // Cleanup the empty spaces that might be on each end.
4187
0
  uriString.Trim(" ");
4188
0
  // Eliminate embedded newlines, which single-line text fields now allow:
4189
0
  uriString.StripCRLF();
4190
0
  NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
4191
0
4192
0
  rv = NS_NewURI(getter_AddRefs(uri), uriString);
4193
0
  if (uri) {
4194
0
    aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
4195
0
  }
4196
0
4197
0
  nsCOMPtr<nsIURIFixupInfo> fixupInfo;
4198
0
  if (sURIFixup) {
4199
0
    // Call the fixup object.  This will clobber the rv from NS_NewURI
4200
0
    // above, but that's fine with us.  Note that we need to do this even
4201
0
    // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
4202
0
    // (things like view-source:mozilla.org for example).
4203
0
    uint32_t fixupFlags = 0;
4204
0
    if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4205
0
      fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
4206
0
    }
4207
0
    if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
4208
0
      fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
4209
0
    }
4210
0
    nsCOMPtr<nsIInputStream> fixupStream;
4211
0
    rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
4212
0
                                    getter_AddRefs(fixupStream),
4213
0
                                    getter_AddRefs(fixupInfo));
4214
0
4215
0
    if (NS_SUCCEEDED(rv)) {
4216
0
      fixupInfo->GetPreferredURI(getter_AddRefs(uri));
4217
0
      fixupInfo->SetConsumer(GetAsSupports(this));
4218
0
    }
4219
0
4220
0
    if (fixupStream) {
4221
0
      // GetFixupURIInfo only returns a post data stream if it succeeded
4222
0
      // and changed the URI, in which case we should override the
4223
0
      // passed-in post data.
4224
0
      postStream = fixupStream;
4225
0
    }
4226
0
4227
0
    if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4228
0
      nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4229
0
      if (serv) {
4230
0
        serv->NotifyObservers(fixupInfo, "keyword-uri-fixup",
4231
0
                              PromiseFlatString(aURI).get());
4232
0
      }
4233
0
    }
4234
0
  }
4235
0
  // else no fixup service so just use the URI we created and see
4236
0
  // what happens
4237
0
4238
0
  if (NS_ERROR_MALFORMED_URI == rv) {
4239
0
    if (DisplayLoadError(rv, uri, PromiseFlatString(aURI).get(), nullptr) &&
4240
0
        (aLoadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
4241
0
      return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
4242
0
    }
4243
0
  }
4244
0
4245
0
  if (NS_FAILED(rv) || !uri) {
4246
0
    return NS_ERROR_FAILURE;
4247
0
  }
4248
0
4249
0
  PopupControlState popupState;
4250
0
  if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
4251
0
    popupState = openAllowed;
4252
0
    aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
4253
0
  } else {
4254
0
    popupState = openOverridden;
4255
0
  }
4256
0
  nsAutoPopupStatePusher statePusher(popupState);
4257
0
4258
0
  bool forceAllowDataURI =
4259
0
    aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
4260
0
4261
0
  // Don't pass certain flags that aren't needed and end up confusing
4262
0
  // ConvertLoadTypeToDocShellInfoLoadType.  We do need to ensure that they are
4263
0
  // passed to LoadURI though, since it uses them.
4264
0
  uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
4265
0
  aLoadFlags &= ~EXTRA_LOAD_FLAGS;
4266
0
4267
0
  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
4268
0
4269
0
  /*
4270
0
   * If the user "Disables Protection on This Page", we have to make sure to
4271
0
   * remember the users decision when opening links in child tabs [Bug 906190]
4272
0
   */
4273
0
  uint32_t loadType;
4274
0
  if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
4275
0
    loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
4276
0
  } else {
4277
0
    loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
4278
0
  }
4279
0
4280
0
  loadInfo->SetLoadType(loadType);
4281
0
  loadInfo->SetPostDataStream(postStream);
4282
0
  loadInfo->SetReferrer(aReferringURI);
4283
0
  loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
4284
0
  loadInfo->SetHeadersStream(aHeaderStream);
4285
0
  loadInfo->SetBaseURI(aBaseURI);
4286
0
  loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
4287
0
  loadInfo->SetForceAllowDataURI(forceAllowDataURI);
4288
0
4289
0
  if (fixupInfo) {
4290
0
    nsAutoString searchProvider, keyword;
4291
0
    fixupInfo->GetKeywordProviderName(searchProvider);
4292
0
    fixupInfo->GetKeywordAsSent(keyword);
4293
0
    MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
4294
0
  }
4295
0
4296
0
  rv = LoadURI(uri, loadInfo, extraFlags, true);
4297
0
4298
0
  // Save URI string in case it's needed later when
4299
0
  // sending to search engine service in EndPageLoad()
4300
0
  mOriginalUriString = uriString;
4301
0
4302
0
  return rv;
4303
0
}
4304
4305
NS_IMETHODIMP
4306
nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
4307
                             const char16_t* aURL,
4308
                             nsIChannel* aFailedChannel,
4309
                             bool* aDisplayedErrorPage)
4310
0
{
4311
0
  *aDisplayedErrorPage = false;
4312
0
  // Get prompt and string bundle services
4313
0
  nsCOMPtr<nsIPrompt> prompter;
4314
0
  nsCOMPtr<nsIStringBundle> stringBundle;
4315
0
  GetPromptAndStringBundle(getter_AddRefs(prompter),
4316
0
                           getter_AddRefs(stringBundle));
4317
0
4318
0
  NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
4319
0
  NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
4320
0
4321
0
  const char* error = nullptr;
4322
0
  // The key used to select the appropriate error message from the properties file.
4323
0
  const char* errorDescriptionID = nullptr;
4324
0
  const uint32_t kMaxFormatStrArgs = 3;
4325
0
  nsAutoString formatStrs[kMaxFormatStrArgs];
4326
0
  uint32_t formatStrCount = 0;
4327
0
  bool addHostPort = false;
4328
0
  nsresult rv = NS_OK;
4329
0
  nsAutoString messageStr;
4330
0
  nsAutoCString cssClass;
4331
0
  nsAutoCString errorPage;
4332
0
4333
0
  if (mLoadURIDelegate) {
4334
0
    nsCOMPtr<nsIURI> errorPageURI;
4335
0
    rv = mLoadURIDelegate->HandleLoadError(aURI, aError,
4336
0
                                           NS_ERROR_GET_MODULE(aError),
4337
0
                                           getter_AddRefs(errorPageURI));
4338
0
    if (NS_FAILED(rv)) {
4339
0
      *aDisplayedErrorPage = false;
4340
0
      return NS_OK;
4341
0
    }
4342
0
4343
0
    if (errorPageURI) {
4344
0
      *aDisplayedErrorPage = NS_SUCCEEDED(LoadErrorPage(errorPageURI, aURI, aFailedChannel));
4345
0
      return NS_OK;
4346
0
    }
4347
0
  }
4348
0
4349
0
  errorPage.AssignLiteral("neterror");
4350
0
4351
0
  // Turn the error code into a human readable error message.
4352
0
  if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
4353
0
    NS_ENSURE_ARG_POINTER(aURI);
4354
0
4355
0
    // Extract the schemes into a comma delimited list.
4356
0
    nsAutoCString scheme;
4357
0
    aURI->GetScheme(scheme);
4358
0
    CopyASCIItoUTF16(scheme, formatStrs[0]);
4359
0
    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
4360
0
    while (nestedURI) {
4361
0
      nsCOMPtr<nsIURI> tempURI;
4362
0
      nsresult rv2;
4363
0
      rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
4364
0
      if (NS_SUCCEEDED(rv2) && tempURI) {
4365
0
        tempURI->GetScheme(scheme);
4366
0
        formatStrs[0].AppendLiteral(", ");
4367
0
        AppendASCIItoUTF16(scheme, formatStrs[0]);
4368
0
      }
4369
0
      nestedURI = do_QueryInterface(tempURI);
4370
0
    }
4371
0
    formatStrCount = 1;
4372
0
    error = "unknownProtocolFound";
4373
0
  } else if (NS_ERROR_FILE_NOT_FOUND == aError) {
4374
0
    NS_ENSURE_ARG_POINTER(aURI);
4375
0
    error = "fileNotFound";
4376
0
  } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) {
4377
0
    NS_ENSURE_ARG_POINTER(aURI);
4378
0
    error = "fileAccessDenied";
4379
0
  } else if (NS_ERROR_UNKNOWN_HOST == aError) {
4380
0
    NS_ENSURE_ARG_POINTER(aURI);
4381
0
    // Get the host
4382
0
    nsAutoCString host;
4383
0
    nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
4384
0
    innermostURI->GetHost(host);
4385
0
    CopyUTF8toUTF16(host, formatStrs[0]);
4386
0
    formatStrCount = 1;
4387
0
    errorDescriptionID = "dnsNotFound2";
4388
0
    error = "dnsNotFound";
4389
0
  } else if (NS_ERROR_CONNECTION_REFUSED == aError) {
4390
0
    NS_ENSURE_ARG_POINTER(aURI);
4391
0
    addHostPort = true;
4392
0
    error = "connectionFailure";
4393
0
  } else if (NS_ERROR_NET_INTERRUPT == aError) {
4394
0
    NS_ENSURE_ARG_POINTER(aURI);
4395
0
    addHostPort = true;
4396
0
    error = "netInterrupt";
4397
0
  } else if (NS_ERROR_NET_TIMEOUT == aError) {
4398
0
    NS_ENSURE_ARG_POINTER(aURI);
4399
0
    // Get the host
4400
0
    nsAutoCString host;
4401
0
    aURI->GetHost(host);
4402
0
    CopyUTF8toUTF16(host, formatStrs[0]);
4403
0
    formatStrCount = 1;
4404
0
    error = "netTimeout";
4405
0
  } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError ||
4406
0
             NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) {
4407
0
    // CSP error
4408
0
    cssClass.AssignLiteral("neterror");
4409
0
    error = "cspBlocked";
4410
0
  } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
4411
0
    nsCOMPtr<nsINSSErrorsService> nsserr =
4412
0
      do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
4413
0
4414
0
    uint32_t errorClass;
4415
0
    if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
4416
0
      errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
4417
0
    }
4418
0
4419
0
    nsCOMPtr<nsISupports> securityInfo;
4420
0
    nsCOMPtr<nsITransportSecurityInfo> tsi;
4421
0
    if (aFailedChannel) {
4422
0
      aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
4423
0
    }
4424
0
    tsi = do_QueryInterface(securityInfo);
4425
0
    if (tsi) {
4426
0
      uint32_t securityState;
4427
0
      tsi->GetSecurityState(&securityState);
4428
0
      if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
4429
0
        error = "sslv3Used";
4430
0
        addHostPort = true;
4431
0
      } else if (securityState & nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
4432
0
        error = "weakCryptoUsed";
4433
0
        addHostPort = true;
4434
0
      }
4435
0
    } else {
4436
0
      // No channel, let's obtain the generic error message
4437
0
      if (nsserr) {
4438
0
        nsserr->GetErrorMessage(aError, messageStr);
4439
0
      }
4440
0
    }
4441
0
    // We don't have a message string here anymore but DisplayLoadError
4442
0
    // requires a non-empty messageStr.
4443
0
    messageStr.Truncate();
4444
0
    messageStr.AssignLiteral(u" ");
4445
0
    if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
4446
0
      error = "nssBadCert";
4447
0
4448
0
      // If this is an HTTP Strict Transport Security host or a pinned host
4449
0
      // and the certificate is bad, don't allow overrides (RFC 6797 section
4450
0
      // 12.1, HPKP draft spec section 2.6).
4451
0
      uint32_t flags =
4452
0
        UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
4453
0
      bool isStsHost = false;
4454
0
      bool isPinnedHost = false;
4455
0
      if (XRE_IsParentProcess()) {
4456
0
        nsCOMPtr<nsISiteSecurityService> sss =
4457
0
          do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
4458
0
        NS_ENSURE_SUCCESS(rv, rv);
4459
0
        rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
4460
0
                              flags, mOriginAttributes, nullptr, nullptr,
4461
0
                              &isStsHost);
4462
0
        NS_ENSURE_SUCCESS(rv, rv);
4463
0
        rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
4464
0
                              flags, mOriginAttributes, nullptr, nullptr,
4465
0
                              &isPinnedHost);
4466
0
        NS_ENSURE_SUCCESS(rv, rv);
4467
0
      } else {
4468
0
        mozilla::dom::ContentChild* cc =
4469
0
          mozilla::dom::ContentChild::GetSingleton();
4470
0
        mozilla::ipc::URIParams uri;
4471
0
        SerializeURI(aURI, uri);
4472
0
        cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
4473
0
                            mOriginAttributes, &isStsHost);
4474
0
        cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
4475
0
                            mOriginAttributes, &isPinnedHost);
4476
0
      }
4477
0
4478
0
      if (Preferences::GetBool(
4479
0
            "browser.xul.error_pages.expert_bad_cert", false)) {
4480
0
        cssClass.AssignLiteral("expertBadCert");
4481
0
      }
4482
0
4483
0
      // HSTS/pinning takes precedence over the expert bad cert pref. We
4484
0
      // never want to show the "Add Exception" button for these sites.
4485
0
      // In the future we should differentiate between an HSTS host and a
4486
0
      // pinned host and display a more informative message to the user.
4487
0
      if (isStsHost || isPinnedHost) {
4488
0
        cssClass.AssignLiteral("badStsCert");
4489
0
      }
4490
0
4491
0
      uint32_t bucketId;
4492
0
      if (isStsHost) {
4493
0
        // measuring STS separately allows us to measure click through
4494
0
        // rates easily
4495
0
        bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
4496
0
      } else {
4497
0
        bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
4498
0
      }
4499
0
4500
0
      // See if an alternate cert error page is registered
4501
0
      nsAutoCString alternateErrorPage;
4502
0
      nsresult rv =
4503
0
        Preferences::GetCString("security.alternate_certificate_error_page",
4504
0
                                alternateErrorPage);
4505
0
      if (NS_SUCCEEDED(rv)) {
4506
0
        errorPage.Assign(alternateErrorPage);
4507
0
      }
4508
0
4509
0
      if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) {
4510
0
        Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
4511
0
      }
4512
0
    } else {
4513
0
      error = "nssFailure2";
4514
0
    }
4515
0
  } else if (NS_ERROR_PHISHING_URI == aError ||
4516
0
             NS_ERROR_MALWARE_URI == aError ||
4517
0
             NS_ERROR_UNWANTED_URI == aError ||
4518
0
             NS_ERROR_HARMFUL_URI == aError) {
4519
0
    nsAutoCString host;
4520
0
    aURI->GetHost(host);
4521
0
    CopyUTF8toUTF16(host, formatStrs[0]);
4522
0
    formatStrCount = 1;
4523
0
4524
0
    // Malware and phishing detectors may want to use an alternate error
4525
0
    // page, but if the pref's not set, we'll fall back on the standard page
4526
0
    nsAutoCString alternateErrorPage;
4527
0
    nsresult rv = Preferences::GetCString("urlclassifier.alternate_error_page",
4528
0
                                          alternateErrorPage);
4529
0
    if (NS_SUCCEEDED(rv)) {
4530
0
      errorPage.Assign(alternateErrorPage);
4531
0
    }
4532
0
4533
0
    uint32_t bucketId;
4534
0
    bool sendTelemetry = false;
4535
0
    if (NS_ERROR_PHISHING_URI == aError) {
4536
0
      sendTelemetry = true;
4537
0
      error = "deceptiveBlocked";
4538
0
      bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_FRAME
4539
0
                           : IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_TOP;
4540
0
    } else if (NS_ERROR_MALWARE_URI == aError) {
4541
0
      sendTelemetry = true;
4542
0
      error = "malwareBlocked";
4543
0
      bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_FRAME
4544
0
                           : IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_TOP;
4545
0
    } else if (NS_ERROR_UNWANTED_URI == aError) {
4546
0
      sendTelemetry = true;
4547
0
      error = "unwantedBlocked";
4548
0
      bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_FRAME
4549
0
                           : IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_TOP;
4550
0
    } else if (NS_ERROR_HARMFUL_URI == aError) {
4551
0
      sendTelemetry = true;
4552
0
      error = "harmfulBlocked";
4553
0
      bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_FRAME
4554
0
                           : IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_TOP;
4555
0
    }
4556
0
4557
0
    if (sendTelemetry && errorPage.EqualsIgnoreCase("blocked")) {
4558
0
      Telemetry::Accumulate(Telemetry::URLCLASSIFIER_UI_EVENTS, bucketId);
4559
0
    }
4560
0
4561
0
    cssClass.AssignLiteral("blacklist");
4562
0
  } else if (NS_ERROR_CONTENT_CRASHED == aError) {
4563
0
    errorPage.AssignLiteral("tabcrashed");
4564
0
    error = "tabcrashed";
4565
0
4566
0
    nsCOMPtr<EventTarget> handler = mChromeEventHandler;
4567
0
    if (handler) {
4568
0
      nsCOMPtr<Element> element = do_QueryInterface(handler);
4569
0
      element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
4570
0
    }
4571
0
4572
0
    // DisplayLoadError requires a non-empty messageStr to proceed and call
4573
0
    // LoadErrorPage. If the page doesn't have a title, we will use a blank
4574
0
    // space which will be trimmed and thus treated as empty by the front-end.
4575
0
    if (messageStr.IsEmpty()) {
4576
0
      messageStr.AssignLiteral(u" ");
4577
0
    }
4578
0
  } else if (NS_ERROR_BUILDID_MISMATCH == aError) {
4579
0
    errorPage.AssignLiteral("restartrequired");
4580
0
    error = "restartrequired";
4581
0
4582
0
    // DisplayLoadError requires a non-empty messageStr to proceed and call
4583
0
    // LoadErrorPage. If the page doesn't have a title, we will use a blank
4584
0
    // space which will be trimmed and thus treated as empty by the front-end.
4585
0
    if (messageStr.IsEmpty()) {
4586
0
      messageStr.AssignLiteral(u" ");
4587
0
    }
4588
0
  } else {
4589
0
    // Errors requiring simple formatting
4590
0
    switch (aError) {
4591
0
      case NS_ERROR_MALFORMED_URI:
4592
0
        // URI is malformed
4593
0
        error = "malformedURI";
4594
0
        errorDescriptionID = "malformedURI2";
4595
0
        break;
4596
0
      case NS_ERROR_REDIRECT_LOOP:
4597
0
        // Doc failed to load because the server generated too many redirects
4598
0
        error = "redirectLoop";
4599
0
        break;
4600
0
      case NS_ERROR_UNKNOWN_SOCKET_TYPE:
4601
0
        // Doc failed to load because PSM is not installed
4602
0
        error = "unknownSocketType";
4603
0
        break;
4604
0
      case NS_ERROR_NET_RESET:
4605
0
        // Doc failed to load because the server kept reseting the connection
4606
0
        // before we could read any data from it
4607
0
        error = "netReset";
4608
0
        break;
4609
0
      case NS_ERROR_DOCUMENT_NOT_CACHED:
4610
0
        // Doc failed to load because the cache does not contain a copy of
4611
0
        // the document.
4612
0
        error = "notCached";
4613
0
        break;
4614
0
      case NS_ERROR_OFFLINE:
4615
0
        // Doc failed to load because we are offline.
4616
0
        error = "netOffline";
4617
0
        break;
4618
0
      case NS_ERROR_DOCUMENT_IS_PRINTMODE:
4619
0
        // Doc navigation attempted while Printing or Print Preview
4620
0
        error = "isprinting";
4621
0
        break;
4622
0
      case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
4623
0
        // Port blocked for security reasons
4624
0
        addHostPort = true;
4625
0
        error = "deniedPortAccess";
4626
0
        break;
4627
0
      case NS_ERROR_UNKNOWN_PROXY_HOST:
4628
0
        // Proxy hostname could not be resolved.
4629
0
        error = "proxyResolveFailure";
4630
0
        break;
4631
0
      case NS_ERROR_PROXY_CONNECTION_REFUSED:
4632
0
        // Proxy connection was refused.
4633
0
        error = "proxyConnectFailure";
4634
0
        break;
4635
0
      case NS_ERROR_INVALID_CONTENT_ENCODING:
4636
0
        // Bad Content Encoding.
4637
0
        error = "contentEncodingError";
4638
0
        break;
4639
0
      case NS_ERROR_REMOTE_XUL:
4640
0
        error = "remoteXUL";
4641
0
        break;
4642
0
      case NS_ERROR_UNSAFE_CONTENT_TYPE:
4643
0
        // Channel refused to load from an unrecognized content type.
4644
0
        error = "unsafeContentType";
4645
0
        break;
4646
0
      case NS_ERROR_CORRUPTED_CONTENT:
4647
0
        // Broken Content Detected. e.g. Content-MD5 check failure.
4648
0
        error = "corruptedContentErrorv2";
4649
0
        break;
4650
0
      case NS_ERROR_INTERCEPTION_FAILED:
4651
0
        // ServiceWorker intercepted request, but something went wrong.
4652
0
        error = "corruptedContentErrorv2";
4653
0
        break;
4654
0
      case NS_ERROR_NET_INADEQUATE_SECURITY:
4655
0
        // Server negotiated bad TLS for HTTP/2.
4656
0
        error = "inadequateSecurityError";
4657
0
        addHostPort = true;
4658
0
        break;
4659
0
      case NS_ERROR_BLOCKED_BY_POLICY:
4660
0
        // Page blocked by policy
4661
0
        error = "blockedByPolicy";
4662
0
        break;
4663
0
      default:
4664
0
        break;
4665
0
    }
4666
0
  }
4667
0
4668
0
  // Test if the error should be displayed
4669
0
  if (!error) {
4670
0
    return NS_OK;
4671
0
  }
4672
0
4673
0
  if (!errorDescriptionID) {
4674
0
    errorDescriptionID = error;
4675
0
  }
4676
0
4677
0
  // Test if the error needs to be formatted
4678
0
  if (!messageStr.IsEmpty()) {
4679
0
    // already obtained message
4680
0
  } else {
4681
0
    if (addHostPort) {
4682
0
      // Build up the host:port string.
4683
0
      nsAutoCString hostport;
4684
0
      if (aURI) {
4685
0
        aURI->GetHostPort(hostport);
4686
0
      } else {
4687
0
        hostport.Assign('?');
4688
0
      }
4689
0
      CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
4690
0
    }
4691
0
4692
0
    nsAutoCString spec;
4693
0
    rv = NS_ERROR_NOT_AVAILABLE;
4694
0
    if (aURI) {
4695
0
      // displaying "file://" is aesthetically unpleasing and could even be
4696
0
      // confusing to the user
4697
0
      bool isFileURI = false;
4698
0
      rv = aURI->SchemeIs("file", &isFileURI);
4699
0
      if (NS_SUCCEEDED(rv) && isFileURI) {
4700
0
        aURI->GetPathQueryRef(spec);
4701
0
      } else {
4702
0
        aURI->GetSpec(spec);
4703
0
      }
4704
0
4705
0
      nsCOMPtr<nsITextToSubURI> textToSubURI(
4706
0
        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
4707
0
      if (NS_SUCCEEDED(rv)) {
4708
0
        rv = textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), spec,
4709
0
                                            formatStrs[formatStrCount]);
4710
0
      }
4711
0
    } else {
4712
0
      spec.Assign('?');
4713
0
    }
4714
0
    if (NS_FAILED(rv)) {
4715
0
      CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
4716
0
    }
4717
0
    rv = NS_OK;
4718
0
    ++formatStrCount;
4719
0
4720
0
    const char16_t* strs[kMaxFormatStrArgs];
4721
0
    for (uint32_t i = 0; i < formatStrCount; i++) {
4722
0
      strs[i] = formatStrs[i].get();
4723
0
    }
4724
0
    nsAutoString str;
4725
0
    rv = stringBundle->FormatStringFromName(errorDescriptionID, strs, formatStrCount, str);
4726
0
    NS_ENSURE_SUCCESS(rv, rv);
4727
0
    messageStr.Assign(str.get());
4728
0
  }
4729
0
4730
0
  // Display the error as a page or an alert prompt
4731
0
  NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
4732
0
4733
0
  if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) {
4734
0
    bool isSecureURI = false;
4735
0
    rv = aURI->SchemeIs("https", &isSecureURI);
4736
0
    if (NS_SUCCEEDED(rv) && isSecureURI) {
4737
0
      // Maybe TLS intolerant. Treat this as an SSL error.
4738
0
      error = "nssFailure2";
4739
0
    }
4740
0
  }
4741
0
4742
0
  if (UseErrorPages()) {
4743
0
    // Display an error page
4744
0
    nsresult loadedPage = LoadErrorPage(aURI, aURL, errorPage.get(),
4745
0
                                        error, messageStr.get(),
4746
0
                                        cssClass.get(), aFailedChannel);
4747
0
    *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage);
4748
0
  } else {
4749
0
    // The prompter reqires that our private window has a document (or it
4750
0
    // asserts). Satisfy that assertion now since GetDoc will force
4751
0
    // creation of one if it hasn't already been created.
4752
0
    if (mScriptGlobal) {
4753
0
      Unused << mScriptGlobal->GetDoc();
4754
0
    }
4755
0
4756
0
    // Display a message box
4757
0
    prompter->Alert(nullptr, messageStr.get());
4758
0
  }
4759
0
4760
0
  return NS_OK;
4761
0
}
4762
4763
0
#define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride"
4764
4765
nsresult
4766
nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
4767
                          const char* aErrorPage,
4768
                          const char* aErrorType,
4769
                          const char16_t* aDescription,
4770
                          const char* aCSSClass,
4771
                          nsIChannel* aFailedChannel)
4772
0
{
4773
0
  MOZ_ASSERT(!mIsBeingDestroyed);
4774
0
4775
#if defined(DEBUG)
4776
  if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
4777
    nsAutoCString chanName;
4778
    if (aFailedChannel) {
4779
      aFailedChannel->GetName(chanName);
4780
    } else {
4781
      chanName.AssignLiteral("<no channel>");
4782
    }
4783
4784
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
4785
           ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
4786
            aURI ? aURI->GetSpecOrDefault().get() : "",
4787
            NS_ConvertUTF16toUTF8(aURL).get(),
4788
            chanName.get()));
4789
  }
4790
#endif
4791
4792
0
  nsAutoCString url;
4793
0
  if (aURI) {
4794
0
    nsresult rv = aURI->GetSpec(url);
4795
0
    NS_ENSURE_SUCCESS(rv, rv);
4796
0
  } else if (aURL) {
4797
0
    CopyUTF16toUTF8(MakeStringSpan(aURL), url);
4798
0
  } else {
4799
0
    return NS_ERROR_INVALID_POINTER;
4800
0
  }
4801
0
4802
0
  // Create a URL to pass all the error information through to the page.
4803
0
4804
0
#undef SAFE_ESCAPE
4805
0
#define SAFE_ESCAPE(output, input, params)                                     \
4806
0
  if (NS_WARN_IF(!NS_Escape(input, output, params))) {                         \
4807
0
    return NS_ERROR_OUT_OF_MEMORY;                                             \
4808
0
  }
4809
0
4810
0
  nsCString escapedUrl, escapedError, escapedDescription,
4811
0
    escapedCSSClass;
4812
0
  SAFE_ESCAPE(escapedUrl, url, url_Path);
4813
0
  SAFE_ESCAPE(escapedError, nsDependentCString(aErrorType), url_Path);
4814
0
  SAFE_ESCAPE(escapedDescription,
4815
0
              NS_ConvertUTF16toUTF8(aDescription), url_Path);
4816
0
  if (aCSSClass) {
4817
0
    nsCString cssClass(aCSSClass);
4818
0
    SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path);
4819
0
  }
4820
0
  nsCString errorPageUrl("about:");
4821
0
  errorPageUrl.AppendASCII(aErrorPage);
4822
0
  errorPageUrl.AppendLiteral("?e=");
4823
0
4824
0
  errorPageUrl.AppendASCII(escapedError.get());
4825
0
  errorPageUrl.AppendLiteral("&u=");
4826
0
  errorPageUrl.AppendASCII(escapedUrl.get());
4827
0
  if ((strcmp(aErrorPage, "blocked") == 0) &&
4828
0
      Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE, true)) {
4829
0
    errorPageUrl.AppendLiteral("&o=1");
4830
0
  }
4831
0
  if (!escapedCSSClass.IsEmpty()) {
4832
0
    errorPageUrl.AppendLiteral("&s=");
4833
0
    errorPageUrl.AppendASCII(escapedCSSClass.get());
4834
0
  }
4835
0
  errorPageUrl.AppendLiteral("&c=UTF-8");
4836
0
4837
0
  nsAutoCString frameType(FrameTypeToString(mFrameType));
4838
0
  errorPageUrl.AppendLiteral("&f=");
4839
0
  errorPageUrl.AppendASCII(frameType.get());
4840
0
4841
0
  nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
4842
0
  int32_t cpsState;
4843
0
  if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) &&
4844
0
      cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
4845
0
    errorPageUrl.AppendLiteral("&captive=true");
4846
0
  }
4847
0
4848
0
  // netError.xhtml's getDescription only handles the "d" parameter at the
4849
0
  // end of the URL, so append it last.
4850
0
  errorPageUrl.AppendLiteral("&d=");
4851
0
  errorPageUrl.AppendASCII(escapedDescription.get());
4852
0
4853
0
  nsCOMPtr<nsIURI> errorPageURI;
4854
0
  nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
4855
0
  NS_ENSURE_SUCCESS(rv, rv);
4856
0
4857
0
  return LoadErrorPage(errorPageURI, aURI, aFailedChannel);
4858
0
}
4859
4860
nsresult
4861
nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI, nsIChannel* aFailedChannel)
4862
0
{
4863
0
  mFailedChannel = aFailedChannel;
4864
0
  mFailedURI = aFailedURI;
4865
0
  mFailedLoadType = mLoadType;
4866
0
4867
0
  if (mLSHE) {
4868
0
    // Abandon mLSHE's BFCache entry and create a new one.  This way, if
4869
0
    // we go back or forward to another SHEntry with the same doc
4870
0
    // identifier, the error page won't persist.
4871
0
    mLSHE->AbandonBFCacheEntry();
4872
0
  }
4873
0
4874
0
  return InternalLoad(aErrorURI, nullptr, Nothing(), false, false, nullptr, RP_Unset,
4875
0
                      nsContentUtils::GetSystemPrincipal(), nullptr,
4876
0
                      INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
4877
0
                      nullptr, VoidString(), nullptr, nullptr,
4878
0
                      LOAD_ERROR_PAGE, nullptr, true, VoidString(), this,
4879
0
                      nullptr, nullptr, nullptr);
4880
0
}
4881
4882
NS_IMETHODIMP
4883
nsDocShell::Reload(uint32_t aReloadFlags)
4884
0
{
4885
0
  if (!IsNavigationAllowed()) {
4886
0
    return NS_OK; // JS may not handle returning of an error code
4887
0
  }
4888
0
  nsresult rv;
4889
0
  NS_ASSERTION(((aReloadFlags & 0xf) == 0),
4890
0
               "Reload command not updated to use load flags!");
4891
0
  NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
4892
0
               "Don't pass these flags to Reload");
4893
0
4894
0
  uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
4895
0
  NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
4896
0
4897
0
  // Send notifications to the HistoryListener if any, about the impending
4898
0
  // reload
4899
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
4900
0
  bool canReload = true;
4901
0
  if (rootSH) {
4902
0
    rootSH->LegacySHistory()
4903
0
      ->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
4904
0
  }
4905
0
4906
0
  if (!canReload) {
4907
0
    return NS_OK;
4908
0
  }
4909
0
4910
0
  /* If you change this part of code, make sure bug 45297 does not re-occur */
4911
0
  if (mOSHE) {
4912
0
    rv = LoadHistoryEntry(mOSHE, loadType);
4913
0
  } else if (mLSHE) { // In case a reload happened before the current load is done
4914
0
    rv = LoadHistoryEntry(mLSHE, loadType);
4915
0
  } else {
4916
0
    nsCOMPtr<nsIDocument> doc(GetDocument());
4917
0
4918
0
    if (!doc) {
4919
0
      return NS_OK;
4920
0
    }
4921
0
4922
0
    // Do not inherit owner from document
4923
0
    uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
4924
0
    nsAutoString srcdoc;
4925
0
    nsCOMPtr<nsIURI> baseURI;
4926
0
    nsCOMPtr<nsIURI> originalURI;
4927
0
    nsCOMPtr<nsIURI> resultPrincipalURI;
4928
0
    bool loadReplace = false;
4929
0
4930
0
    nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
4931
0
    nsAutoString contentTypeHint;
4932
0
    doc->GetContentType(contentTypeHint);
4933
0
4934
0
    if (doc->IsSrcdocDocument()) {
4935
0
      doc->GetSrcdocData(srcdoc);
4936
0
      flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
4937
0
      baseURI = doc->GetBaseURI();
4938
0
    }
4939
0
    nsCOMPtr<nsIChannel> chan = doc->GetChannel();
4940
0
    if (chan) {
4941
0
      uint32_t loadFlags;
4942
0
      chan->GetLoadFlags(&loadFlags);
4943
0
      loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
4944
0
      nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
4945
0
      if (httpChan) {
4946
0
        httpChan->GetOriginalURI(getter_AddRefs(originalURI));
4947
0
      }
4948
0
4949
0
      nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
4950
0
      if (loadInfo) {
4951
0
        loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
4952
0
      }
4953
0
    }
4954
0
4955
0
    MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
4956
0
4957
0
    // Stack variables to ensure changes to the member variables don't affect to
4958
0
    // the call.
4959
0
    nsCOMPtr<nsIURI> currentURI = mCurrentURI;
4960
0
    nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
4961
0
    uint32_t referrerPolicy = mReferrerPolicy;
4962
0
4963
0
    // Reload always rewrites result principal URI.
4964
0
    Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
4965
0
    emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
4966
0
    rv = InternalLoad(currentURI,
4967
0
                      originalURI,
4968
0
                      emplacedResultPrincipalURI,
4969
0
                      false,
4970
0
                      loadReplace,
4971
0
                      referrerURI,
4972
0
                      referrerPolicy,
4973
0
                      triggeringPrincipal,
4974
0
                      triggeringPrincipal,
4975
0
                      flags,
4976
0
                      EmptyString(),   // No window target
4977
0
                      NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
4978
0
                      VoidString(),    // No forced download
4979
0
                      nullptr,         // No post data
4980
0
                      nullptr,         // No headers data
4981
0
                      loadType,        // Load type
4982
0
                      nullptr,         // No SHEntry
4983
0
                      true,
4984
0
                      srcdoc,          // srcdoc argument for iframe
4985
0
                      this,            // For reloads we are the source
4986
0
                      baseURI,
4987
0
                      nullptr,         // No nsIDocShell
4988
0
                      nullptr);        // No nsIRequest
4989
0
  }
4990
0
4991
0
  return rv;
4992
0
}
4993
4994
NS_IMETHODIMP
4995
nsDocShell::Stop(uint32_t aStopFlags)
4996
0
{
4997
0
  // Revoke any pending event related to content viewer restoration
4998
0
  mRestorePresentationEvent.Revoke();
4999
0
5000
0
  if (mLoadType == LOAD_ERROR_PAGE) {
5001
0
    if (mLSHE) {
5002
0
      // Since error page loads never unset mLSHE, do so now
5003
0
      SetHistoryEntry(&mOSHE, mLSHE);
5004
0
      SetHistoryEntry(&mLSHE, nullptr);
5005
0
    }
5006
0
5007
0
    mFailedChannel = nullptr;
5008
0
    mFailedURI = nullptr;
5009
0
  }
5010
0
5011
0
  if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
5012
0
    // Stop the document loading
5013
0
    if (mContentViewer) {
5014
0
      nsCOMPtr<nsIContentViewer> cv = mContentViewer;
5015
0
      cv->Stop();
5016
0
    }
5017
0
  }
5018
0
5019
0
  if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
5020
0
    // Suspend any timers that were set for this loader.  We'll clear
5021
0
    // them out for good in CreateContentViewer.
5022
0
    if (mRefreshURIList) {
5023
0
      SuspendRefreshURIs();
5024
0
      mSavedRefreshURIList.swap(mRefreshURIList);
5025
0
      mRefreshURIList = nullptr;
5026
0
    }
5027
0
5028
0
    // XXXbz We could also pass |this| to nsIURILoader::Stop.  That will
5029
0
    // just call Stop() on us as an nsIDocumentLoader... We need fewer
5030
0
    // redundant apis!
5031
0
    Stop();
5032
0
  }
5033
0
5034
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5035
0
  while (iter.HasMore()) {
5036
0
    nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
5037
0
    if (shellAsNav) {
5038
0
      shellAsNav->Stop(aStopFlags);
5039
0
    }
5040
0
  }
5041
0
5042
0
  return NS_OK;
5043
0
}
5044
5045
NS_IMETHODIMP
5046
nsDocShell::GetDocument(nsIDocument** aDocument)
5047
0
{
5048
0
  NS_ENSURE_ARG_POINTER(aDocument);
5049
0
  NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
5050
0
5051
0
  nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
5052
0
  if (!doc) {
5053
0
    return NS_ERROR_NOT_AVAILABLE;
5054
0
  }
5055
0
5056
0
  doc.forget(aDocument);
5057
0
  return NS_OK;
5058
0
}
5059
5060
NS_IMETHODIMP
5061
nsDocShell::GetCurrentURI(nsIURI** aURI)
5062
0
{
5063
0
  NS_ENSURE_ARG_POINTER(aURI);
5064
0
5065
0
  nsCOMPtr<nsIURI> uri = mCurrentURI;
5066
0
  uri.forget(aURI);
5067
0
  return NS_OK;
5068
0
}
5069
5070
NS_IMETHODIMP
5071
nsDocShell::GetReferringURI(nsIURI** aURI)
5072
0
{
5073
0
  NS_ENSURE_ARG_POINTER(aURI);
5074
0
5075
0
  *aURI = mReferrerURI;
5076
0
  NS_IF_ADDREF(*aURI);
5077
0
5078
0
  return NS_OK;
5079
0
}
5080
5081
NS_IMETHODIMP
5082
nsDocShell::InitSessionHistory()
5083
0
{
5084
0
  MOZ_ASSERT(!mIsBeingDestroyed);
5085
0
5086
0
  // Make sure that we are the root DocShell, and set a handle to root docshell
5087
0
  // in the session history.
5088
0
  nsCOMPtr<nsIDocShellTreeItem> root;
5089
0
  GetSameTypeRootTreeItem(getter_AddRefs(root));
5090
0
  if (root != this) {
5091
0
    return NS_ERROR_FAILURE;
5092
0
  }
5093
0
5094
0
  mSessionHistory = new ChildSHistory(this);
5095
0
  return NS_OK;
5096
0
}
5097
5098
NS_IMETHODIMP
5099
nsDocShell::GetSessionHistoryXPCOM(nsISupports** aSessionHistory)
5100
0
{
5101
0
  NS_ENSURE_ARG_POINTER(aSessionHistory);
5102
0
  RefPtr<ChildSHistory> shistory = mSessionHistory;
5103
0
  shistory.forget(aSessionHistory);
5104
0
  return NS_OK;
5105
0
}
5106
5107
//*****************************************************************************
5108
// nsDocShell::nsIWebPageDescriptor
5109
//*****************************************************************************
5110
5111
NS_IMETHODIMP
5112
nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType)
5113
0
{
5114
0
  nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
5115
0
5116
0
  // Currently, the opaque 'page descriptor' is an nsISHEntry...
5117
0
  if (!shEntryIn) {
5118
0
    return NS_ERROR_INVALID_POINTER;
5119
0
  }
5120
0
5121
0
  // Now clone shEntryIn, since we might end up modifying it later on, and we
5122
0
  // want a page descriptor to be reusable.
5123
0
  nsCOMPtr<nsISHEntry> shEntry;
5124
0
  nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
5125
0
  NS_ENSURE_SUCCESS(rv, rv);
5126
0
5127
0
  // Give our cloned shEntry a new bfcache entry so this load is independent
5128
0
  // of all other loads.  (This is important, in particular, for bugs 582795
5129
0
  // and 585298.)
5130
0
  rv = shEntry->AbandonBFCacheEntry();
5131
0
  NS_ENSURE_SUCCESS(rv, rv);
5132
0
5133
0
  //
5134
0
  // load the page as view-source
5135
0
  //
5136
0
  if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
5137
0
    nsCString spec, newSpec;
5138
0
5139
0
    // Create a new view-source URI and replace the original.
5140
0
    nsCOMPtr<nsIURI> oldUri = shEntry->GetURI();
5141
0
5142
0
    oldUri->GetSpec(spec);
5143
0
    newSpec.AppendLiteral("view-source:");
5144
0
    newSpec.Append(spec);
5145
0
5146
0
    nsCOMPtr<nsIURI> newUri;
5147
0
    rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
5148
0
    if (NS_FAILED(rv)) {
5149
0
      return rv;
5150
0
    }
5151
0
    shEntry->SetURI(newUri);
5152
0
    shEntry->SetOriginalURI(nullptr);
5153
0
    shEntry->SetResultPrincipalURI(nullptr);
5154
0
    // shEntry's current triggering principal is whoever loaded that page initially.
5155
0
    // But now we're doing another load of the page, via an API that is only exposed
5156
0
    // to system code.  The triggering principal for this load should be the system
5157
0
    // principal.
5158
0
    shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
5159
0
  }
5160
0
5161
0
  rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
5162
0
  return rv;
5163
0
}
5164
5165
NS_IMETHODIMP
5166
nsDocShell::GetCurrentDescriptor(nsISupports** aPageDescriptor)
5167
0
{
5168
0
  MOZ_ASSERT(aPageDescriptor, "Null out param?");
5169
0
5170
0
  *aPageDescriptor = nullptr;
5171
0
5172
0
  nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
5173
0
  if (src) {
5174
0
    nsCOMPtr<nsISHEntry> dest;
5175
0
5176
0
    nsresult rv = src->Clone(getter_AddRefs(dest));
5177
0
    if (NS_FAILED(rv)) {
5178
0
      return rv;
5179
0
    }
5180
0
5181
0
    // null out inappropriate cloned attributes...
5182
0
    dest->SetParent(nullptr);
5183
0
    dest->SetIsSubFrame(false);
5184
0
5185
0
    return CallQueryInterface(dest, aPageDescriptor);
5186
0
  }
5187
0
5188
0
  return NS_ERROR_NOT_AVAILABLE;
5189
0
}
5190
5191
//*****************************************************************************
5192
// nsDocShell::nsIBaseWindow
5193
//*****************************************************************************
5194
5195
NS_IMETHODIMP
5196
nsDocShell::InitWindow(nativeWindow aParentNativeWindow,
5197
                       nsIWidget* aParentWidget, int32_t aX, int32_t aY,
5198
                       int32_t aWidth, int32_t aHeight)
5199
0
{
5200
0
  SetParentWidget(aParentWidget);
5201
0
  SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
5202
0
5203
0
  return NS_OK;
5204
0
}
5205
5206
NS_IMETHODIMP
5207
nsDocShell::Create()
5208
0
{
5209
0
  if (mCreated) {
5210
0
    // We've already been created
5211
0
    return NS_OK;
5212
0
  }
5213
0
5214
0
  NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5215
0
               "Unexpected item type in docshell");
5216
0
5217
0
  NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
5218
0
  mCreated = true;
5219
0
5220
0
  if (gValidateOrigin == 0xffffffff) {
5221
0
    // Check pref to see if we should prevent frameset spoofing
5222
0
    gValidateOrigin =
5223
0
      Preferences::GetBool("browser.frame.validate_origin", true);
5224
0
  }
5225
0
5226
0
  // Should we use XUL error pages instead of alerts if possible?
5227
0
  mUseErrorPages =
5228
0
    Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
5229
0
5230
0
  if (!gAddedPreferencesVarCache) {
5231
0
    Preferences::AddBoolVarCache(&sUseErrorPages,
5232
0
                                 "browser.xul.error_pages.enabled",
5233
0
                                 mUseErrorPages);
5234
0
    gAddedPreferencesVarCache = true;
5235
0
  }
5236
0
5237
0
  mDisableMetaRefreshWhenInactive =
5238
0
    Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
5239
0
                         mDisableMetaRefreshWhenInactive);
5240
0
5241
0
  mDeviceSizeIsPageSize =
5242
0
    Preferences::GetBool("docshell.device_size_is_page_size",
5243
0
                         mDeviceSizeIsPageSize);
5244
0
5245
0
  nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5246
0
  if (serv) {
5247
0
    const char* msg = mItemType == typeContent ?
5248
0
      NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
5249
0
    serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5250
0
  }
5251
0
5252
0
  return NS_OK;
5253
0
}
5254
5255
NS_IMETHODIMP
5256
nsDocShell::Destroy()
5257
0
{
5258
0
  // XXX: We allow this function to be called just once.  If you are going to
5259
0
  // reset new variables in this function, please make sure the variables will
5260
0
  // never be re-initialized.  Adding assertions to check |mIsBeingDestroyed|
5261
0
  // in the setter functions for the variables would be enough.
5262
0
  if (mIsBeingDestroyed) {
5263
0
    return NS_ERROR_DOCSHELL_DYING;
5264
0
  }
5265
0
5266
0
  NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5267
0
               "Unexpected item type in docshell");
5268
0
5269
0
  AssertOriginAttributesMatchPrivateBrowsing();
5270
0
5271
0
  nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5272
0
  if (serv) {
5273
0
    const char* msg = mItemType == typeContent ?
5274
0
      NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
5275
0
    serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5276
0
  }
5277
0
5278
0
  mIsBeingDestroyed = true;
5279
0
5280
0
  // Brak the cycle with the initial client, if present.
5281
0
  mInitialClientSource.reset();
5282
0
5283
0
  // Make sure we don't record profile timeline markers anymore
5284
0
  SetRecordProfileTimelineMarkers(false);
5285
0
5286
0
  // Remove our pref observers
5287
0
  if (mObserveErrorPages) {
5288
0
    mObserveErrorPages = false;
5289
0
  }
5290
0
5291
0
  // Make sure to blow away our mLoadingURI just in case.  No loads
5292
0
  // from inside this pagehide.
5293
0
  mLoadingURI = nullptr;
5294
0
5295
0
  // Fire unload event before we blow anything away.
5296
0
  (void)FirePageHideNotification(true);
5297
0
5298
0
  // Clear pointers to any detached nsEditorData that's lying
5299
0
  // around in shistory entries. Breaks cycle. See bug 430921.
5300
0
  if (mOSHE) {
5301
0
    mOSHE->SetEditorData(nullptr);
5302
0
  }
5303
0
  if (mLSHE) {
5304
0
    mLSHE->SetEditorData(nullptr);
5305
0
  }
5306
0
5307
0
  // Note: mContentListener can be null if Init() failed and we're being
5308
0
  // called from the destructor.
5309
0
  if (mContentListener) {
5310
0
    mContentListener->DropDocShellReference();
5311
0
    mContentListener->SetParentContentListener(nullptr);
5312
0
    // Note that we do NOT set mContentListener to null here; that
5313
0
    // way if someone tries to do a load in us after this point
5314
0
    // the nsDSURIContentListener will block it.  All of which
5315
0
    // means that we should do this before calling Stop(), of
5316
0
    // course.
5317
0
  }
5318
0
5319
0
  // Stop any URLs that are currently being loaded...
5320
0
  Stop(nsIWebNavigation::STOP_ALL);
5321
0
5322
0
  mEditorData = nullptr;
5323
0
5324
0
  // Save the state of the current document, before destroying the window.
5325
0
  // This is needed to capture the state of a frameset when the new document
5326
0
  // causes the frameset to be destroyed...
5327
0
  PersistLayoutHistoryState();
5328
0
5329
0
  // Remove this docshell from its parent's child list
5330
0
  nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
5331
0
    do_QueryInterface(GetAsSupports(mParent));
5332
0
  if (docShellParentAsItem) {
5333
0
    docShellParentAsItem->RemoveChild(this);
5334
0
  }
5335
0
5336
0
  if (mContentViewer) {
5337
0
    mContentViewer->Close(nullptr);
5338
0
    mContentViewer->Destroy();
5339
0
    mContentViewer = nullptr;
5340
0
  }
5341
0
5342
0
  nsDocLoader::Destroy();
5343
0
5344
0
  mParentWidget = nullptr;
5345
0
  mCurrentURI = nullptr;
5346
0
5347
0
  if (mScriptGlobal) {
5348
0
    mScriptGlobal->DetachFromDocShell();
5349
0
    mScriptGlobal = nullptr;
5350
0
  }
5351
0
5352
0
  if (mSessionHistory) {
5353
0
    // We want to destroy these content viewers now rather than
5354
0
    // letting their destruction wait for the session history
5355
0
    // entries to get garbage collected.  (Bug 488394)
5356
0
    mSessionHistory->EvictLocalContentViewers();
5357
0
    mSessionHistory = nullptr;
5358
0
  }
5359
0
5360
0
  mBrowsingContext->Detach();
5361
0
5362
0
  SetTreeOwner(nullptr);
5363
0
5364
0
  mOnePermittedSandboxedNavigator = nullptr;
5365
0
5366
0
  // required to break ref cycle
5367
0
  mSecurityUI = nullptr;
5368
0
5369
0
  // Cancel any timers that were set for this docshell; this is needed
5370
0
  // to break the cycle between us and the timers.
5371
0
  CancelRefreshURITimers();
5372
0
5373
0
  if (UsePrivateBrowsing()) {
5374
0
    mPrivateBrowsingId = 0;
5375
0
    mOriginAttributes.SyncAttributesWithPrivateBrowsing(false);
5376
0
    if (mAffectPrivateSessionLifetime) {
5377
0
      DecreasePrivateDocShellCount();
5378
0
    }
5379
0
  }
5380
0
5381
0
  return NS_OK;
5382
0
}
5383
5384
NS_IMETHODIMP
5385
nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale)
5386
0
{
5387
0
  if (mParentWidget) {
5388
0
    *aScale = mParentWidget->GetDefaultScale().scale;
5389
0
    return NS_OK;
5390
0
  }
5391
0
5392
0
  nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5393
0
  if (ownerWindow) {
5394
0
    return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
5395
0
  }
5396
0
5397
0
  *aScale = 1.0;
5398
0
  return NS_OK;
5399
0
}
5400
5401
NS_IMETHODIMP
5402
nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale)
5403
0
{
5404
0
  if (mParentWidget) {
5405
0
    *aScale = mParentWidget->GetDesktopToDeviceScale().scale;
5406
0
    return NS_OK;
5407
0
  }
5408
0
5409
0
  nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5410
0
  if (ownerWindow) {
5411
0
    return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale);
5412
0
  }
5413
0
5414
0
  *aScale = 1.0;
5415
0
  return NS_OK;
5416
0
}
5417
5418
NS_IMETHODIMP
5419
nsDocShell::SetPosition(int32_t aX, int32_t aY)
5420
0
{
5421
0
  mBounds.MoveTo(aX, aY);
5422
0
5423
0
  if (mContentViewer) {
5424
0
    NS_ENSURE_SUCCESS(mContentViewer->Move(aX, aY), NS_ERROR_FAILURE);
5425
0
  }
5426
0
5427
0
  return NS_OK;
5428
0
}
5429
5430
NS_IMETHODIMP
5431
nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
5432
0
{
5433
0
  nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5434
0
  if (ownerWindow) {
5435
0
    return ownerWindow->SetPositionDesktopPix(aX, aY);
5436
0
  }
5437
0
5438
0
  double scale = 1.0;
5439
0
  GetDevicePixelsPerDesktopPixel(&scale);
5440
0
  return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
5441
0
}
5442
5443
NS_IMETHODIMP
5444
nsDocShell::GetPosition(int32_t* aX, int32_t* aY)
5445
0
{
5446
0
  return GetPositionAndSize(aX, aY, nullptr, nullptr);
5447
0
}
5448
5449
NS_IMETHODIMP
5450
nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint)
5451
0
{
5452
0
  int32_t x = 0, y = 0;
5453
0
  GetPosition(&x, &y);
5454
0
  return SetPositionAndSize(x, y, aWidth, aHeight,
5455
0
                            aRepaint ? nsIBaseWindow::eRepaint : 0);
5456
0
}
5457
5458
NS_IMETHODIMP
5459
nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight)
5460
0
{
5461
0
  return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
5462
0
}
5463
5464
NS_IMETHODIMP
5465
nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
5466
                               int32_t aHeight, uint32_t aFlags)
5467
0
{
5468
0
  mBounds.SetRect(aX, aY, aWidth, aHeight);
5469
0
5470
0
  // Hold strong ref, since SetBounds can make us null out mContentViewer
5471
0
  nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
5472
0
  if (viewer) {
5473
0
    uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize) ?
5474
0
                           nsIContentViewer::eDelayResize : 0;
5475
0
    // XXX Border figured in here or is that handled elsewhere?
5476
0
    nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
5477
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5478
0
  }
5479
0
5480
0
  return NS_OK;
5481
0
}
5482
5483
NS_IMETHODIMP
5484
nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
5485
                               int32_t* aHeight)
5486
0
{
5487
0
  if (mParentWidget) {
5488
0
    // ensure size is up-to-date if window has changed resolution
5489
0
    LayoutDeviceIntRect r = mParentWidget->GetClientBounds();
5490
0
    SetPositionAndSize(mBounds.X(), mBounds.Y(), r.Width(), r.Height(), 0);
5491
0
  }
5492
0
5493
0
  // We should really consider just getting this information from
5494
0
  // our window instead of duplicating the storage and code...
5495
0
  if (aWidth || aHeight) {
5496
0
    // Caller wants to know our size; make sure to give them up to
5497
0
    // date information.
5498
0
    nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
5499
0
    if (doc) {
5500
0
      doc->FlushPendingNotifications(FlushType::Layout);
5501
0
    }
5502
0
  }
5503
0
5504
0
  DoGetPositionAndSize(aX, aY, aWidth, aHeight);
5505
0
  return NS_OK;
5506
0
}
5507
5508
void
5509
nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
5510
                                 int32_t* aHeight)
5511
0
{
5512
0
  if (aX) {
5513
0
    *aX = mBounds.X();
5514
0
  }
5515
0
  if (aY) {
5516
0
    *aY = mBounds.Y();
5517
0
  }
5518
0
  if (aWidth) {
5519
0
    *aWidth = mBounds.Width();
5520
0
  }
5521
0
  if (aHeight) {
5522
0
    *aHeight = mBounds.Height();
5523
0
  }
5524
0
}
5525
5526
NS_IMETHODIMP
5527
nsDocShell::Repaint(bool aForce)
5528
0
{
5529
0
  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
5530
0
  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
5531
0
5532
0
  nsViewManager* viewManager = presShell->GetViewManager();
5533
0
  NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
5534
0
5535
0
  viewManager->InvalidateAllViews();
5536
0
  return NS_OK;
5537
0
}
5538
5539
NS_IMETHODIMP
5540
nsDocShell::GetParentWidget(nsIWidget** aParentWidget)
5541
0
{
5542
0
  NS_ENSURE_ARG_POINTER(aParentWidget);
5543
0
5544
0
  *aParentWidget = mParentWidget;
5545
0
  NS_IF_ADDREF(*aParentWidget);
5546
0
5547
0
  return NS_OK;
5548
0
}
5549
5550
NS_IMETHODIMP
5551
nsDocShell::SetParentWidget(nsIWidget* aParentWidget)
5552
0
{
5553
0
  MOZ_ASSERT(!mIsBeingDestroyed);
5554
0
  mParentWidget = aParentWidget;
5555
0
5556
0
  return NS_OK;
5557
0
}
5558
5559
NS_IMETHODIMP
5560
nsDocShell::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
5561
0
{
5562
0
  NS_ENSURE_ARG_POINTER(aParentNativeWindow);
5563
0
5564
0
  if (mParentWidget) {
5565
0
    *aParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
5566
0
  } else {
5567
0
    *aParentNativeWindow = nullptr;
5568
0
  }
5569
0
5570
0
  return NS_OK;
5571
0
}
5572
5573
NS_IMETHODIMP
5574
nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow)
5575
0
{
5576
0
  return NS_ERROR_NOT_IMPLEMENTED;
5577
0
}
5578
5579
NS_IMETHODIMP
5580
nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
5581
0
{
5582
0
  // the nativeHandle should be accessed from nsIXULWindow
5583
0
  return NS_ERROR_NOT_IMPLEMENTED;
5584
0
}
5585
5586
NS_IMETHODIMP
5587
nsDocShell::GetVisibility(bool* aVisibility)
5588
0
{
5589
0
  NS_ENSURE_ARG_POINTER(aVisibility);
5590
0
5591
0
  *aVisibility = false;
5592
0
5593
0
  if (!mContentViewer) {
5594
0
    return NS_OK;
5595
0
  }
5596
0
5597
0
  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
5598
0
  if (!presShell) {
5599
0
    return NS_OK;
5600
0
  }
5601
0
5602
0
  // get the view manager
5603
0
  nsViewManager* vm = presShell->GetViewManager();
5604
0
  NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
5605
0
5606
0
  // get the root view
5607
0
  nsView* view = vm->GetRootView(); // views are not ref counted
5608
0
  NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
5609
0
5610
0
  // if our root view is hidden, we are not visible
5611
0
  if (view->GetVisibility() == nsViewVisibility_kHide) {
5612
0
    return NS_OK;
5613
0
  }
5614
0
5615
0
  // otherwise, we must walk up the document and view trees checking
5616
0
  // for a hidden view, unless we're an off screen browser, which
5617
0
  // would make this test meaningless.
5618
0
5619
0
  RefPtr<nsDocShell> docShell = this;
5620
0
  RefPtr<nsDocShell> parentItem = docShell->GetParentDocshell();
5621
0
  while (parentItem) {
5622
0
    presShell = docShell->GetPresShell();
5623
0
5624
0
    nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell();
5625
0
5626
0
    // Null-check for crash in bug 267804
5627
0
    if (!pPresShell) {
5628
0
      MOZ_ASSERT_UNREACHABLE("parent docshell has null pres shell");
5629
0
      return NS_OK;
5630
0
    }
5631
0
5632
0
    vm = presShell->GetViewManager();
5633
0
    if (vm) {
5634
0
      view = vm->GetRootView();
5635
0
    }
5636
0
5637
0
    if (view) {
5638
0
      view = view->GetParent(); // anonymous inner view
5639
0
      if (view) {
5640
0
        view = view->GetParent(); // subdocumentframe's view
5641
0
      }
5642
0
    }
5643
0
5644
0
    nsIFrame* frame = view ? view->GetFrame() : nullptr;
5645
0
    bool isDocShellOffScreen = false;
5646
0
    docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
5647
0
    if (frame &&
5648
0
        !frame->IsVisibleConsideringAncestors(
5649
0
          nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
5650
0
        !isDocShellOffScreen) {
5651
0
      return NS_OK;
5652
0
    }
5653
0
5654
0
    docShell = parentItem;
5655
0
    parentItem = docShell->GetParentDocshell();
5656
0
  }
5657
0
5658
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
5659
0
  if (!treeOwnerAsWin) {
5660
0
    *aVisibility = true;
5661
0
    return NS_OK;
5662
0
  }
5663
0
5664
0
  // Check with the tree owner as well to give embedders a chance to
5665
0
  // expose visibility as well.
5666
0
  return treeOwnerAsWin->GetVisibility(aVisibility);
5667
0
}
5668
5669
NS_IMETHODIMP
5670
nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen)
5671
0
{
5672
0
  mIsOffScreenBrowser = aIsOffScreen;
5673
0
  return NS_OK;
5674
0
}
5675
5676
NS_IMETHODIMP
5677
nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen)
5678
0
{
5679
0
  *aIsOffScreen = mIsOffScreenBrowser;
5680
0
  return NS_OK;
5681
0
}
5682
5683
NS_IMETHODIMP
5684
nsDocShell::SetIsActive(bool aIsActive)
5685
0
{
5686
0
  // We disallow setting active on chrome docshells.
5687
0
  if (mItemType == nsIDocShellTreeItem::typeChrome) {
5688
0
    return NS_ERROR_INVALID_ARG;
5689
0
  }
5690
0
5691
0
  // Keep track ourselves.
5692
0
  mIsActive = aIsActive;
5693
0
5694
0
  // Tell the PresShell about it.
5695
0
  nsCOMPtr<nsIPresShell> pshell = GetPresShell();
5696
0
  if (pshell) {
5697
0
    pshell->SetIsActive(aIsActive);
5698
0
  }
5699
0
5700
0
  // Tell the window about it
5701
0
  if (mScriptGlobal) {
5702
0
    mScriptGlobal->SetIsBackground(!aIsActive);
5703
0
    if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
5704
0
      // Update orientation when the top-level browsing context becomes active.
5705
0
      if (aIsActive) {
5706
0
        nsCOMPtr<nsIDocShellTreeItem> parent;
5707
0
        GetSameTypeParent(getter_AddRefs(parent));
5708
0
        if (!parent) {
5709
0
          // We only care about the top-level browsing context.
5710
0
          uint16_t orientation = OrientationLock();
5711
0
          ScreenOrientation::UpdateActiveOrientationLock(orientation);
5712
0
        }
5713
0
      }
5714
0
5715
0
      doc->PostVisibilityUpdateEvent();
5716
0
    }
5717
0
  }
5718
0
5719
0
  // Tell the nsDOMNavigationTiming about it
5720
0
  RefPtr<nsDOMNavigationTiming> timing = mTiming;
5721
0
  if (!timing && mContentViewer) {
5722
0
    nsIDocument* doc = mContentViewer->GetDocument();
5723
0
    if (doc) {
5724
0
      timing = doc->GetNavigationTiming();
5725
0
    }
5726
0
  }
5727
0
  if (timing) {
5728
0
    timing->NotifyDocShellStateChanged(
5729
0
      aIsActive ? nsDOMNavigationTiming::DocShellState::eActive
5730
0
                : nsDOMNavigationTiming::DocShellState::eInactive);
5731
0
  }
5732
0
5733
0
  // Recursively tell all of our children, but don't tell <iframe mozbrowser>
5734
0
  // children; they handle their state separately.
5735
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5736
0
  while (iter.HasMore()) {
5737
0
    nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
5738
0
    if (!docshell) {
5739
0
      continue;
5740
0
    }
5741
0
5742
0
    if (!docshell->GetIsMozBrowser()) {
5743
0
      docshell->SetIsActive(aIsActive);
5744
0
    }
5745
0
  }
5746
0
5747
0
  // Restart or stop meta refresh timers if necessary
5748
0
  if (mDisableMetaRefreshWhenInactive) {
5749
0
    if (mIsActive) {
5750
0
      ResumeRefreshURIs();
5751
0
    } else {
5752
0
      SuspendRefreshURIs();
5753
0
    }
5754
0
  }
5755
0
5756
0
  return NS_OK;
5757
0
}
5758
5759
NS_IMETHODIMP
5760
nsDocShell::GetIsActive(bool* aIsActive)
5761
0
{
5762
0
  *aIsActive = mIsActive;
5763
0
  return NS_OK;
5764
0
}
5765
5766
NS_IMETHODIMP
5767
nsDocShell::SetIsAppTab(bool aIsAppTab)
5768
0
{
5769
0
  mIsAppTab = aIsAppTab;
5770
0
  return NS_OK;
5771
0
}
5772
5773
NS_IMETHODIMP
5774
nsDocShell::GetIsAppTab(bool* aIsAppTab)
5775
0
{
5776
0
  *aIsAppTab = mIsAppTab;
5777
0
  return NS_OK;
5778
0
}
5779
5780
NS_IMETHODIMP
5781
nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags)
5782
0
{
5783
0
  mSandboxFlags = aSandboxFlags;
5784
0
  return NS_OK;
5785
0
}
5786
5787
NS_IMETHODIMP
5788
nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags)
5789
0
{
5790
0
  *aSandboxFlags = mSandboxFlags;
5791
0
  return NS_OK;
5792
0
}
5793
5794
NS_IMETHODIMP
5795
nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
5796
0
{
5797
0
  if (mOnePermittedSandboxedNavigator) {
5798
0
    NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
5799
0
    return NS_OK;
5800
0
  }
5801
0
5802
0
  MOZ_ASSERT(!mIsBeingDestroyed);
5803
0
5804
0
  mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
5805
0
  NS_ASSERTION(mOnePermittedSandboxedNavigator,
5806
0
               "One Permitted Sandboxed Navigator must support weak references.");
5807
0
5808
0
  return NS_OK;
5809
0
}
5810
5811
NS_IMETHODIMP
5812
nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
5813
0
{
5814
0
  NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
5815
0
  nsCOMPtr<nsIDocShell> permittedNavigator =
5816
0
    do_QueryReferent(mOnePermittedSandboxedNavigator);
5817
0
  permittedNavigator.forget(aSandboxedNavigator);
5818
0
  return NS_OK;
5819
0
}
5820
5821
NS_IMETHODIMP
5822
nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
5823
0
{
5824
0
  mDefaultLoadFlags = aDefaultLoadFlags;
5825
0
5826
0
  // Tell the load group to set these flags all requests in the group
5827
0
  if (mLoadGroup) {
5828
0
    mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
5829
0
  } else {
5830
0
    NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
5831
0
  }
5832
0
5833
0
  // Recursively tell all of our children.  We *do not* skip
5834
0
  // <iframe mozbrowser> children - if someone sticks custom flags in this
5835
0
  // docShell then they too get the same flags.
5836
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5837
0
  while (iter.HasMore()) {
5838
0
    nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
5839
0
    if (!docshell) {
5840
0
      continue;
5841
0
    }
5842
0
    docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
5843
0
  }
5844
0
  return NS_OK;
5845
0
}
5846
5847
NS_IMETHODIMP
5848
nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags)
5849
0
{
5850
0
  *aDefaultLoadFlags = mDefaultLoadFlags;
5851
0
  return NS_OK;
5852
0
}
5853
5854
NS_IMETHODIMP
5855
nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
5856
0
{
5857
#ifdef DEBUG
5858
  // if the channel is non-null
5859
  if (aMixedContentChannel) {
5860
    // Get the root docshell.
5861
    nsCOMPtr<nsIDocShellTreeItem> root;
5862
    GetSameTypeRootTreeItem(getter_AddRefs(root));
5863
    NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this),
5864
                         "Setting mMixedContentChannel on a docshell that is "
5865
                         "not the root docshell");
5866
  }
5867
#endif
5868
  mMixedContentChannel = aMixedContentChannel;
5869
0
  return NS_OK;
5870
0
}
5871
5872
NS_IMETHODIMP
5873
nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel)
5874
0
{
5875
0
  NS_ENSURE_ARG_POINTER(aFailedChannel);
5876
0
  nsIDocument* doc = GetDocument();
5877
0
  if (!doc) {
5878
0
    *aFailedChannel = nullptr;
5879
0
    return NS_OK;
5880
0
  }
5881
0
  NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel());
5882
0
  return NS_OK;
5883
0
}
5884
5885
NS_IMETHODIMP
5886
nsDocShell::GetMixedContentChannel(nsIChannel** aMixedContentChannel)
5887
0
{
5888
0
  NS_ENSURE_ARG_POINTER(aMixedContentChannel);
5889
0
  NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
5890
0
  return NS_OK;
5891
0
}
5892
5893
NS_IMETHODIMP
5894
nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection,
5895
                                                  bool* aAllowMixedContent,
5896
                                                  bool* aIsRootDocShell)
5897
0
{
5898
0
  *aRootHasSecureConnection = true;
5899
0
  *aAllowMixedContent = false;
5900
0
  *aIsRootDocShell = false;
5901
0
5902
0
  nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
5903
0
  GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
5904
0
  NS_ASSERTION(sameTypeRoot,
5905
0
               "No document shell root tree item from document shell tree item!");
5906
0
  *aIsRootDocShell =
5907
0
    sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this);
5908
0
5909
0
  // now get the document from sameTypeRoot
5910
0
  nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument();
5911
0
  if (rootDoc) {
5912
0
    nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
5913
0
5914
0
    // For things with system principal (e.g. scratchpad) there is no uri
5915
0
    // aRootHasSecureConnection should be false.
5916
0
    nsCOMPtr<nsIURI> rootUri;
5917
0
    if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
5918
0
        NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
5919
0
        NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
5920
0
      *aRootHasSecureConnection = false;
5921
0
    }
5922
0
5923
0
    // Check the root doc's channel against the root docShell's
5924
0
    // mMixedContentChannel to see if they are the same. If they are the same,
5925
0
    // the user has overriden the block.
5926
0
    nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
5927
0
    nsCOMPtr<nsIChannel> mixedChannel;
5928
0
    rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
5929
0
    *aAllowMixedContent =
5930
0
      mixedChannel && (mixedChannel == rootDoc->GetChannel());
5931
0
  }
5932
0
5933
0
  return NS_OK;
5934
0
}
5935
5936
NS_IMETHODIMP
5937
nsDocShell::SetVisibility(bool aVisibility)
5938
0
{
5939
0
  // Show()/Hide() may change mContentViewer.
5940
0
  nsCOMPtr<nsIContentViewer> cv = mContentViewer;
5941
0
  if (!cv) {
5942
0
    return NS_OK;
5943
0
  }
5944
0
  if (aVisibility) {
5945
0
    cv->Show();
5946
0
  } else {
5947
0
    cv->Hide();
5948
0
  }
5949
0
5950
0
  return NS_OK;
5951
0
}
5952
5953
NS_IMETHODIMP
5954
nsDocShell::GetEnabled(bool* aEnabled)
5955
0
{
5956
0
  NS_ENSURE_ARG_POINTER(aEnabled);
5957
0
  *aEnabled = true;
5958
0
  return NS_ERROR_NOT_IMPLEMENTED;
5959
0
}
5960
5961
NS_IMETHODIMP
5962
nsDocShell::SetEnabled(bool aEnabled)
5963
0
{
5964
0
  return NS_ERROR_NOT_IMPLEMENTED;
5965
0
}
5966
5967
NS_IMETHODIMP
5968
nsDocShell::SetFocus()
5969
0
{
5970
0
  return NS_OK;
5971
0
}
5972
5973
NS_IMETHODIMP
5974
nsDocShell::GetMainWidget(nsIWidget** aMainWidget)
5975
0
{
5976
0
  // We don't create our own widget, so simply return the parent one.
5977
0
  return GetParentWidget(aMainWidget);
5978
0
}
5979
5980
NS_IMETHODIMP
5981
nsDocShell::GetTitle(nsAString& aTitle)
5982
0
{
5983
0
  aTitle = mTitle;
5984
0
  return NS_OK;
5985
0
}
5986
5987
NS_IMETHODIMP
5988
nsDocShell::SetTitle(const nsAString& aTitle)
5989
0
{
5990
0
  // Store local title
5991
0
  mTitle = aTitle;
5992
0
5993
0
  nsCOMPtr<nsIDocShellTreeItem> parent;
5994
0
  GetSameTypeParent(getter_AddRefs(parent));
5995
0
5996
0
  // When title is set on the top object it should then be passed to the
5997
0
  // tree owner.
5998
0
  if (!parent) {
5999
0
    nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
6000
0
    if (treeOwnerAsWin) {
6001
0
      treeOwnerAsWin->SetTitle(aTitle);
6002
0
    }
6003
0
  }
6004
0
6005
0
  AssertOriginAttributesMatchPrivateBrowsing();
6006
0
  if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
6007
0
    UpdateGlobalHistoryTitle(mCurrentURI);
6008
0
  }
6009
0
6010
0
  // Update SessionHistory with the document's title.
6011
0
  if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
6012
0
      mLoadType != LOAD_ERROR_PAGE) {
6013
0
    mOSHE->SetTitle(mTitle);
6014
0
  }
6015
0
6016
0
  return NS_OK;
6017
0
}
6018
6019
nsresult
6020
nsDocShell::GetCurScrollPos(int32_t aScrollOrientation, int32_t* aCurPos)
6021
0
{
6022
0
  NS_ENSURE_ARG_POINTER(aCurPos);
6023
0
6024
0
  nsIScrollableFrame* sf = GetRootScrollFrame();
6025
0
  if (!sf) {
6026
0
    return NS_ERROR_FAILURE;
6027
0
  }
6028
0
6029
0
  nsPoint pt = sf->GetScrollPosition();
6030
0
6031
0
  switch (aScrollOrientation) {
6032
0
    case ScrollOrientation_X:
6033
0
      *aCurPos = pt.x;
6034
0
      return NS_OK;
6035
0
6036
0
    case ScrollOrientation_Y:
6037
0
      *aCurPos = pt.y;
6038
0
      return NS_OK;
6039
0
6040
0
    default:
6041
0
      NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6042
0
  }
6043
0
}
6044
6045
nsresult
6046
nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos,
6047
                              int32_t aCurVerticalPos)
6048
0
{
6049
0
  nsIScrollableFrame* sf = GetRootScrollFrame();
6050
0
  NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6051
0
6052
0
  nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
6053
0
  if (sf->GetScrollStyles().mScrollBehavior ==
6054
0
        NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
6055
0
    scrollMode = nsIScrollableFrame::SMOOTH_MSD;
6056
0
  }
6057
0
6058
0
  sf->ScrollTo(nsPoint(aCurHorizontalPos, aCurVerticalPos), scrollMode);
6059
0
  return NS_OK;
6060
0
}
6061
6062
//*****************************************************************************
6063
// nsDocShell::nsIScrollable
6064
//*****************************************************************************
6065
6066
NS_IMETHODIMP
6067
nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation,
6068
                                           int32_t* aScrollbarPref)
6069
0
{
6070
0
  NS_ENSURE_ARG_POINTER(aScrollbarPref);
6071
0
  switch (aScrollOrientation) {
6072
0
    case ScrollOrientation_X:
6073
0
      *aScrollbarPref = mDefaultScrollbarPref.x;
6074
0
      return NS_OK;
6075
0
6076
0
    case ScrollOrientation_Y:
6077
0
      *aScrollbarPref = mDefaultScrollbarPref.y;
6078
0
      return NS_OK;
6079
0
6080
0
    default:
6081
0
      NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6082
0
  }
6083
0
  return NS_ERROR_FAILURE;
6084
0
}
6085
6086
NS_IMETHODIMP
6087
nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation,
6088
                                           int32_t aScrollbarPref)
6089
0
{
6090
0
  switch (aScrollOrientation) {
6091
0
    case ScrollOrientation_X:
6092
0
      mDefaultScrollbarPref.x = aScrollbarPref;
6093
0
      return NS_OK;
6094
0
6095
0
    case ScrollOrientation_Y:
6096
0
      mDefaultScrollbarPref.y = aScrollbarPref;
6097
0
      return NS_OK;
6098
0
6099
0
    default:
6100
0
      NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6101
0
  }
6102
0
  return NS_ERROR_FAILURE;
6103
0
}
6104
6105
NS_IMETHODIMP
6106
nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible,
6107
                                   bool* aHorizontalVisible)
6108
0
{
6109
0
  nsIScrollableFrame* sf = GetRootScrollFrame();
6110
0
  NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6111
0
6112
0
  uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
6113
0
  if (aVerticalVisible) {
6114
0
    *aVerticalVisible =
6115
0
      (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
6116
0
  }
6117
0
  if (aHorizontalVisible) {
6118
0
    *aHorizontalVisible =
6119
0
      (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
6120
0
  }
6121
0
6122
0
  return NS_OK;
6123
0
}
6124
6125
//*****************************************************************************
6126
// nsDocShell::nsIRefreshURI
6127
//*****************************************************************************
6128
6129
NS_IMETHODIMP
6130
nsDocShell::RefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
6131
                       int32_t aDelay, bool aRepeat,
6132
                       bool aMetaRefresh)
6133
0
{
6134
0
  MOZ_ASSERT(!mIsBeingDestroyed);
6135
0
6136
0
  NS_ENSURE_ARG(aURI);
6137
0
6138
0
  /* Check if Meta refresh/redirects are permitted. Some
6139
0
   * embedded applications may not want to do this.
6140
0
   * Must do this before sending out NOTIFY_REFRESH events
6141
0
   * because listeners may have side effects (e.g. displaying a
6142
0
   * button to manually trigger the refresh later).
6143
0
   */
6144
0
  bool allowRedirects = true;
6145
0
  GetAllowMetaRedirects(&allowRedirects);
6146
0
  if (!allowRedirects) {
6147
0
    return NS_OK;
6148
0
  }
6149
0
6150
0
  // If any web progress listeners are listening for NOTIFY_REFRESH events,
6151
0
  // give them a chance to block this refresh.
6152
0
  bool sameURI;
6153
0
  nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
6154
0
  if (NS_FAILED(rv)) {
6155
0
    sameURI = false;
6156
0
  }
6157
0
  if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
6158
0
    return NS_OK;
6159
0
  }
6160
0
6161
0
  nsCOMPtr<nsITimerCallback> refreshTimer =
6162
0
    new nsRefreshTimer(this, aURI, aPrincipal, aDelay, aRepeat, aMetaRefresh);
6163
0
6164
0
  uint32_t busyFlags = 0;
6165
0
  GetBusyFlags(&busyFlags);
6166
0
6167
0
  if (!mRefreshURIList) {
6168
0
    mRefreshURIList = nsArray::Create();
6169
0
  }
6170
0
6171
0
  if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) {
6172
0
    // We don't  want to create the timer right now. Instead queue up the request
6173
0
    // and trigger the timer in EndPageLoad() or whenever we become active.
6174
0
    mRefreshURIList->AppendElement(refreshTimer);
6175
0
  } else {
6176
0
    // There is no page loading going on right now.  Create the
6177
0
    // timer and fire it right away.
6178
0
    nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
6179
0
    NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
6180
0
6181
0
    nsCOMPtr<nsITimer> timer;
6182
0
    MOZ_TRY_VAR(timer,
6183
0
                NS_NewTimerWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT,
6184
0
                                        win->TabGroup()->EventTargetFor(TaskCategory::Network)));
6185
0
6186
0
    mRefreshURIList->AppendElement(timer);  // owning timer ref
6187
0
  }
6188
0
  return NS_OK;
6189
0
}
6190
6191
nsresult
6192
nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI,
6193
                                     nsIPrincipal* aPrincipal,
6194
                                     int32_t aDelay,
6195
                                     bool aMetaRefresh,
6196
                                     nsITimer* aTimer)
6197
0
{
6198
0
  MOZ_ASSERT(aTimer, "Must have a timer here");
6199
0
6200
0
  // Remove aTimer from mRefreshURIList if needed
6201
0
  if (mRefreshURIList) {
6202
0
    uint32_t n = 0;
6203
0
    mRefreshURIList->GetLength(&n);
6204
0
6205
0
    for (uint32_t i = 0; i < n; ++i) {
6206
0
      nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
6207
0
      if (timer == aTimer) {
6208
0
        mRefreshURIList->RemoveElementAt(i);
6209
0
        break;
6210
0
      }
6211
0
    }
6212
0
  }
6213
0
6214
0
  return ForceRefreshURI(aURI, aPrincipal, aDelay, aMetaRefresh);
6215
0
}
6216
6217
NS_IMETHODIMP
6218
nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDelay, bool aMetaRefresh)
6219
0
{
6220
0
  NS_ENSURE_ARG(aURI);
6221
0
6222
0
  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
6223
0
6224
0
  /* We do need to pass in a referrer, but we don't want it to
6225
0
   * be sent to the server.
6226
0
   */
6227
0
  loadInfo->SetSendReferrer(false);
6228
0
6229
0
  /* for most refreshes the current URI is an appropriate
6230
0
   * internal referrer
6231
0
   */
6232
0
  loadInfo->SetReferrer(mCurrentURI);
6233
0
6234
0
  loadInfo->SetOriginalURI(mCurrentURI);
6235
0
  loadInfo->SetResultPrincipalURI(aURI);
6236
0
  loadInfo->SetResultPrincipalURIIsSome(true);
6237
0
  loadInfo->SetKeepResultPrincipalURIIfSet(true);
6238
0
6239
0
  // Set the triggering pricipal to aPrincipal if available, or current
6240
0
  // document's principal otherwise.
6241
0
  nsCOMPtr<nsIPrincipal> principal = aPrincipal;
6242
0
  if (!principal) {
6243
0
    nsCOMPtr<nsIDocument> doc = GetDocument();
6244
0
    if (!doc) {
6245
0
      return NS_ERROR_FAILURE;
6246
0
    }
6247
0
    principal = doc->NodePrincipal();
6248
0
  }
6249
0
  loadInfo->SetTriggeringPrincipal(principal);
6250
0
  loadInfo->SetPrincipalIsExplicit(true);
6251
0
6252
0
  /* Check if this META refresh causes a redirection
6253
0
   * to another site.
6254
0
   */
6255
0
  bool equalUri = false;
6256
0
  nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
6257
0
  if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
6258
0
      aDelay <= REFRESH_REDIRECT_TIMER) {
6259
0
    /* It is a META refresh based redirection within the threshold time
6260
0
     * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
6261
0
     * Pass a REPLACE flag to LoadURI().
6262
0
     */
6263
0
    loadInfo->SetLoadType(LOAD_NORMAL_REPLACE);
6264
0
6265
0
    /* for redirects we mimic HTTP, which passes the
6266
0
     *  original referrer
6267
0
     */
6268
0
    nsCOMPtr<nsIURI> internalReferrer;
6269
0
    GetReferringURI(getter_AddRefs(internalReferrer));
6270
0
    if (internalReferrer) {
6271
0
      loadInfo->SetReferrer(internalReferrer);
6272
0
    }
6273
0
  } else {
6274
0
    loadInfo->SetLoadType(LOAD_REFRESH);
6275
0
  }
6276
0
6277
0
  /*
6278
0
   * LoadURI(...) will cancel all refresh timers... This causes the
6279
0
   * Timer and its refreshData instance to be released...
6280
0
   */
6281
0
  LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true);
6282
0
6283
0
  return NS_OK;
6284
0
}
6285
6286
nsresult
6287
nsDocShell::SetupRefreshURIFromHeader(nsIURI* aBaseURI,
6288
                                      nsIPrincipal* aPrincipal,
6289
                                      const nsACString& aHeader)
6290
0
{
6291
0
  // Refresh headers are parsed with the following format in mind
6292
0
  // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
6293
0
  // By the time we are here, the following is true:
6294
0
  // header = "REFRESH"
6295
0
  // content = "5; URL=http://uri" // note the URL attribute is
6296
0
  // optional, if it is absent, the currently loaded url is used.
6297
0
  // Also note that the seconds and URL separator can be either
6298
0
  // a ';' or a ','. The ',' separator should be illegal but CNN
6299
0
  // is using it.
6300
0
  //
6301
0
  // We need to handle the following strings, where
6302
0
  //  - X is a set of digits
6303
0
  //  - URI is either a relative or absolute URI
6304
0
  //
6305
0
  // Note that URI should start with "url=" but we allow omission
6306
0
  //
6307
0
  // "" || ";" || ","
6308
0
  //  empty string. use the currently loaded URI
6309
0
  //  and refresh immediately.
6310
0
  // "X" || "X;" || "X,"
6311
0
  //  Refresh the currently loaded URI in X seconds.
6312
0
  // "X; URI" || "X, URI"
6313
0
  //  Refresh using URI as the destination in X seconds.
6314
0
  // "URI" || "; URI" || ", URI"
6315
0
  //  Refresh immediately using URI as the destination.
6316
0
  //
6317
0
  // Currently, anything immediately following the URI, if
6318
0
  // separated by any char in the set "'\"\t\r\n " will be
6319
0
  // ignored. So "10; url=go.html ; foo=bar" will work,
6320
0
  // and so will "10; url='go.html'; foo=bar". However,
6321
0
  // "10; url=go.html; foo=bar" will result in the uri
6322
0
  // "go.html;" since ';' and ',' are valid uri characters.
6323
0
  //
6324
0
  // Note that we need to remove any tokens wrapping the URI.
6325
0
  // These tokens currently include spaces, double and single
6326
0
  // quotes.
6327
0
6328
0
  // when done, seconds is 0 or the given number of seconds
6329
0
  //            uriAttrib is empty or the URI specified
6330
0
  MOZ_ASSERT(aPrincipal);
6331
0
6332
0
  nsAutoCString uriAttrib;
6333
0
  int32_t seconds = 0;
6334
0
  bool specifiesSeconds = false;
6335
0
6336
0
  nsACString::const_iterator iter, tokenStart, doneIterating;
6337
0
6338
0
  aHeader.BeginReading(iter);
6339
0
  aHeader.EndReading(doneIterating);
6340
0
6341
0
  // skip leading whitespace
6342
0
  while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6343
0
    ++iter;
6344
0
  }
6345
0
6346
0
  tokenStart = iter;
6347
0
6348
0
  // skip leading + and -
6349
0
  if (iter != doneIterating && (*iter == '-' || *iter == '+')) {
6350
0
    ++iter;
6351
0
  }
6352
0
6353
0
  // parse number
6354
0
  while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
6355
0
    seconds = seconds * 10 + (*iter - '0');
6356
0
    specifiesSeconds = true;
6357
0
    ++iter;
6358
0
  }
6359
0
6360
0
  if (iter != doneIterating) {
6361
0
    // if we started with a '-', number is negative
6362
0
    if (*tokenStart == '-') {
6363
0
      seconds = -seconds;
6364
0
    }
6365
0
6366
0
    // skip to next ';' or ','
6367
0
    nsACString::const_iterator iterAfterDigit = iter;
6368
0
    while (iter != doneIterating && !(*iter == ';' || *iter == ',')) {
6369
0
      if (specifiesSeconds) {
6370
0
        // Non-whitespace characters here mean that the string is
6371
0
        // malformed but tolerate sites that specify a decimal point,
6372
0
        // even though meta refresh only works on whole seconds.
6373
0
        if (iter == iterAfterDigit &&
6374
0
            !nsCRT::IsAsciiSpace(*iter) && *iter != '.') {
6375
0
          // The characters between the seconds and the next
6376
0
          // section are just garbage!
6377
0
          //   e.g. content="2a0z+,URL=http://www.mozilla.org/"
6378
0
          // Just ignore this redirect.
6379
0
          return NS_ERROR_FAILURE;
6380
0
        } else if (nsCRT::IsAsciiSpace(*iter)) {
6381
0
          // We've had at least one whitespace so tolerate the mistake
6382
0
          // and drop through.
6383
0
          // e.g. content="10 foo"
6384
0
          ++iter;
6385
0
          break;
6386
0
        }
6387
0
      }
6388
0
      ++iter;
6389
0
    }
6390
0
6391
0
    // skip any remaining whitespace
6392
0
    while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6393
0
      ++iter;
6394
0
    }
6395
0
6396
0
    // skip ';' or ','
6397
0
    if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
6398
0
      ++iter;
6399
0
    }
6400
0
6401
0
    // skip whitespace
6402
0
    while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6403
0
      ++iter;
6404
0
    }
6405
0
  }
6406
0
6407
0
  // possible start of URI
6408
0
  tokenStart = iter;
6409
0
6410
0
  // skip "url = " to real start of URI
6411
0
  if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
6412
0
    ++iter;
6413
0
    if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
6414
0
      ++iter;
6415
0
      if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
6416
0
        ++iter;
6417
0
6418
0
        // skip whitespace
6419
0
        while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6420
0
          ++iter;
6421
0
        }
6422
0
6423
0
        if (iter != doneIterating && *iter == '=') {
6424
0
          ++iter;
6425
0
6426
0
          // skip whitespace
6427
0
          while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6428
0
            ++iter;
6429
0
          }
6430
0
6431
0
          // found real start of URI
6432
0
          tokenStart = iter;
6433
0
        }
6434
0
      }
6435
0
    }
6436
0
  }
6437
0
6438
0
  // skip a leading '"' or '\''.
6439
0
6440
0
  bool isQuotedURI = false;
6441
0
  if (tokenStart != doneIterating &&
6442
0
      (*tokenStart == '"' || *tokenStart == '\'')) {
6443
0
    isQuotedURI = true;
6444
0
    ++tokenStart;
6445
0
  }
6446
0
6447
0
  // set iter to start of URI
6448
0
  iter = tokenStart;
6449
0
6450
0
  // tokenStart here points to the beginning of URI
6451
0
6452
0
  // grab the rest of the URI
6453
0
  while (iter != doneIterating) {
6454
0
    if (isQuotedURI && (*iter == '"' || *iter == '\'')) {
6455
0
      break;
6456
0
    }
6457
0
    ++iter;
6458
0
  }
6459
0
6460
0
  // move iter one back if the last character is a '"' or '\''
6461
0
  if (iter != tokenStart && isQuotedURI) {
6462
0
    --iter;
6463
0
    if (!(*iter == '"' || *iter == '\'')) {
6464
0
      ++iter;
6465
0
    }
6466
0
  }
6467
0
6468
0
  // URI is whatever's contained from tokenStart to iter.
6469
0
  // note: if tokenStart == doneIterating, so is iter.
6470
0
6471
0
  nsresult rv = NS_OK;
6472
0
6473
0
  nsCOMPtr<nsIURI> uri;
6474
0
  bool specifiesURI = false;
6475
0
  if (tokenStart == iter) {
6476
0
    uri = aBaseURI;
6477
0
  } else {
6478
0
    uriAttrib = Substring(tokenStart, iter);
6479
0
    // NS_NewURI takes care of any whitespace surrounding the URL
6480
0
    rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
6481
0
    specifiesURI = true;
6482
0
  }
6483
0
6484
0
  // No URI or seconds were specified
6485
0
  if (!specifiesSeconds && !specifiesURI) {
6486
0
    // Do nothing because the alternative is to spin around in a refresh
6487
0
    // loop forever!
6488
0
    return NS_ERROR_FAILURE;
6489
0
  }
6490
0
6491
0
  if (NS_SUCCEEDED(rv)) {
6492
0
    nsCOMPtr<nsIScriptSecurityManager> securityManager(
6493
0
      do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
6494
0
    if (NS_SUCCEEDED(rv)) {
6495
0
      rv = securityManager->CheckLoadURIWithPrincipal(
6496
0
        aPrincipal, uri,
6497
0
        nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
6498
0
6499
0
      if (NS_SUCCEEDED(rv)) {
6500
0
        bool isjs = true;
6501
0
        rv = NS_URIChainHasFlags(
6502
0
          uri, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
6503
0
        NS_ENSURE_SUCCESS(rv, rv);
6504
0
6505
0
        if (isjs) {
6506
0
          return NS_ERROR_FAILURE;
6507
0
        }
6508
0
      }
6509
0
6510
0
      if (NS_SUCCEEDED(rv)) {
6511
0
        // Since we can't travel back in time yet, just pretend
6512
0
        // negative numbers do nothing at all.
6513
0
        if (seconds < 0) {
6514
0
          return NS_ERROR_FAILURE;
6515
0
        }
6516
0
6517
0
        rv = RefreshURI(uri, aPrincipal, seconds * 1000, false, true);
6518
0
      }
6519
0
    }
6520
0
  }
6521
0
  return rv;
6522
0
}
6523
6524
NS_IMETHODIMP
6525
nsDocShell::SetupRefreshURI(nsIChannel* aChannel)
6526
0
{
6527
0
  nsresult rv;
6528
0
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
6529
0
  if (NS_SUCCEEDED(rv)) {
6530
0
    nsAutoCString refreshHeader;
6531
0
    rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
6532
0
                                        refreshHeader);
6533
0
6534
0
    if (!refreshHeader.IsEmpty()) {
6535
0
      nsCOMPtr<nsIScriptSecurityManager> secMan =
6536
0
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
6537
0
      NS_ENSURE_SUCCESS(rv, rv);
6538
0
6539
0
      nsCOMPtr<nsIPrincipal> principal;
6540
0
      rv = secMan->GetChannelResultPrincipal(aChannel,
6541
0
                                             getter_AddRefs(principal));
6542
0
      NS_ENSURE_SUCCESS(rv, rv);
6543
0
6544
0
      SetupReferrerFromChannel(aChannel);
6545
0
      rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
6546
0
      if (NS_SUCCEEDED(rv)) {
6547
0
        return NS_REFRESHURI_HEADER_FOUND;
6548
0
      }
6549
0
    }
6550
0
  }
6551
0
  return rv;
6552
0
}
6553
6554
static void
6555
DoCancelRefreshURITimers(nsIMutableArray* aTimerList)
6556
0
{
6557
0
  if (!aTimerList) {
6558
0
    return;
6559
0
  }
6560
0
6561
0
  uint32_t n = 0;
6562
0
  aTimerList->GetLength(&n);
6563
0
6564
0
  while (n) {
6565
0
    nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
6566
0
6567
0
    aTimerList->RemoveElementAt(n);  // bye bye owning timer ref
6568
0
6569
0
    if (timer) {
6570
0
      timer->Cancel();
6571
0
    }
6572
0
  }
6573
0
}
6574
6575
NS_IMETHODIMP
6576
nsDocShell::CancelRefreshURITimers()
6577
0
{
6578
0
  DoCancelRefreshURITimers(mRefreshURIList);
6579
0
  DoCancelRefreshURITimers(mSavedRefreshURIList);
6580
0
  mRefreshURIList = nullptr;
6581
0
  mSavedRefreshURIList = nullptr;
6582
0
6583
0
  return NS_OK;
6584
0
}
6585
6586
NS_IMETHODIMP
6587
nsDocShell::GetRefreshPending(bool* aResult)
6588
0
{
6589
0
  if (!mRefreshURIList) {
6590
0
    *aResult = false;
6591
0
    return NS_OK;
6592
0
  }
6593
0
6594
0
  uint32_t count;
6595
0
  nsresult rv = mRefreshURIList->GetLength(&count);
6596
0
  if (NS_SUCCEEDED(rv)) {
6597
0
    *aResult = (count != 0);
6598
0
  }
6599
0
  return rv;
6600
0
}
6601
6602
NS_IMETHODIMP
6603
nsDocShell::SuspendRefreshURIs()
6604
0
{
6605
0
  if (mRefreshURIList) {
6606
0
    uint32_t n = 0;
6607
0
    mRefreshURIList->GetLength(&n);
6608
0
6609
0
    for (uint32_t i = 0; i < n; ++i) {
6610
0
      nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
6611
0
      if (!timer) {
6612
0
        continue; // this must be a nsRefreshURI already
6613
0
      }
6614
0
6615
0
      // Replace this timer object with a nsRefreshTimer object.
6616
0
      nsCOMPtr<nsITimerCallback> callback;
6617
0
      timer->GetCallback(getter_AddRefs(callback));
6618
0
6619
0
      timer->Cancel();
6620
0
6621
0
      nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
6622
0
      NS_ASSERTION(rt,
6623
0
                   "RefreshURIList timer callbacks should only be RefreshTimer objects");
6624
0
6625
0
      mRefreshURIList->ReplaceElementAt(rt, i);
6626
0
    }
6627
0
  }
6628
0
6629
0
  // Suspend refresh URIs for our child shells as well.
6630
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6631
0
  while (iter.HasMore()) {
6632
0
    nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
6633
0
    if (shell) {
6634
0
      shell->SuspendRefreshURIs();
6635
0
    }
6636
0
  }
6637
0
6638
0
  return NS_OK;
6639
0
}
6640
6641
NS_IMETHODIMP
6642
nsDocShell::ResumeRefreshURIs()
6643
0
{
6644
0
  RefreshURIFromQueue();
6645
0
6646
0
  // Resume refresh URIs for our child shells as well.
6647
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6648
0
  while (iter.HasMore()) {
6649
0
    nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
6650
0
    if (shell) {
6651
0
      shell->ResumeRefreshURIs();
6652
0
    }
6653
0
  }
6654
0
6655
0
  return NS_OK;
6656
0
}
6657
6658
nsresult
6659
nsDocShell::RefreshURIFromQueue()
6660
0
{
6661
0
  if (!mRefreshURIList) {
6662
0
    return NS_OK;
6663
0
  }
6664
0
  uint32_t n = 0;
6665
0
  mRefreshURIList->GetLength(&n);
6666
0
6667
0
  while (n) {
6668
0
    nsCOMPtr<nsITimerCallback> refreshInfo =
6669
0
        do_QueryElementAt(mRefreshURIList, --n);
6670
0
6671
0
    if (refreshInfo) {
6672
0
      // This is the nsRefreshTimer object, waiting to be
6673
0
      // setup in a timer object and fired.
6674
0
      // Create the timer and  trigger it.
6675
0
      uint32_t delay =
6676
0
        static_cast<nsRefreshTimer*>(
6677
0
          static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
6678
0
      nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
6679
0
      if (win) {
6680
0
        nsCOMPtr<nsITimer> timer;
6681
0
        NS_NewTimerWithCallback(getter_AddRefs(timer),
6682
0
                                refreshInfo, delay, nsITimer::TYPE_ONE_SHOT,
6683
0
                                win->TabGroup()->EventTargetFor(TaskCategory::Network));
6684
0
6685
0
        if (timer) {
6686
0
          // Replace the nsRefreshTimer element in the queue with
6687
0
          // its corresponding timer object, so that in case another
6688
0
          // load comes through before the timer can go off, the timer will
6689
0
          // get cancelled in CancelRefreshURITimer()
6690
0
          mRefreshURIList->ReplaceElementAt(timer, n);
6691
0
        }
6692
0
      }
6693
0
    }
6694
0
  }
6695
0
6696
0
  return NS_OK;
6697
0
}
6698
6699
nsresult
6700
nsDocShell::Embed(nsIContentViewer* aContentViewer,
6701
                  const char* aCommand, nsISupports* aExtraInfo)
6702
0
{
6703
0
  // Save the LayoutHistoryState of the previous document, before
6704
0
  // setting up new document
6705
0
  PersistLayoutHistoryState();
6706
0
6707
0
  nsresult rv = SetupNewViewer(aContentViewer);
6708
0
  NS_ENSURE_SUCCESS(rv, rv);
6709
0
6710
0
  // If we are loading a wyciwyg url from history, change the base URI for
6711
0
  // the document to the original http url that created the document.write().
6712
0
  // This makes sure that all relative urls in a document.written page loaded
6713
0
  // via history work properly.
6714
0
  if (mCurrentURI &&
6715
0
      (mLoadType & LOAD_CMD_HISTORY ||
6716
0
       mLoadType == LOAD_RELOAD_NORMAL ||
6717
0
       mLoadType == LOAD_RELOAD_CHARSET_CHANGE ||
6718
0
       mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE ||
6719
0
       mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)) {
6720
0
    bool isWyciwyg = false;
6721
0
    // Check if the url is wyciwyg
6722
0
    rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
6723
0
    if (isWyciwyg && NS_SUCCEEDED(rv)) {
6724
0
      SetBaseUrlForWyciwyg(aContentViewer);
6725
0
    }
6726
0
  }
6727
0
  // XXX What if SetupNewViewer fails?
6728
0
  if (mLSHE) {
6729
0
    // Restore the editing state, if it's stored in session history.
6730
0
    if (mLSHE->HasDetachedEditor()) {
6731
0
      ReattachEditorToWindow(mLSHE);
6732
0
    }
6733
0
    // Set history.state
6734
0
    SetDocCurrentStateObj(mLSHE);
6735
0
6736
0
    SetHistoryEntry(&mOSHE, mLSHE);
6737
0
  }
6738
0
6739
0
  bool updateHistory = true;
6740
0
6741
0
  // Determine if this type of load should update history
6742
0
  switch (mLoadType) {
6743
0
    case LOAD_NORMAL_REPLACE:
6744
0
    case LOAD_STOP_CONTENT_AND_REPLACE:
6745
0
    case LOAD_RELOAD_BYPASS_CACHE:
6746
0
    case LOAD_RELOAD_BYPASS_PROXY:
6747
0
    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
6748
0
    case LOAD_REPLACE_BYPASS_CACHE:
6749
0
      updateHistory = false;
6750
0
      break;
6751
0
    default:
6752
0
      break;
6753
0
  }
6754
0
6755
0
  if (!updateHistory) {
6756
0
    SetLayoutHistoryState(nullptr);
6757
0
  }
6758
0
6759
0
  return NS_OK;
6760
0
}
6761
6762
6763
//*****************************************************************************
6764
// nsDocShell::nsIWebProgressListener
6765
//*****************************************************************************
6766
6767
NS_IMETHODIMP
6768
nsDocShell::OnProgressChange(nsIWebProgress* aProgress,
6769
                             nsIRequest* aRequest,
6770
                             int32_t aCurSelfProgress,
6771
                             int32_t aMaxSelfProgress,
6772
                             int32_t aCurTotalProgress,
6773
                             int32_t aMaxTotalProgress)
6774
0
{
6775
0
  return NS_OK;
6776
0
}
6777
6778
NS_IMETHODIMP
6779
nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
6780
                          uint32_t aStateFlags, nsresult aStatus)
6781
0
{
6782
0
  if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
6783
0
    // Save timing statistics.
6784
0
    nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
6785
0
    nsCOMPtr<nsIURI> uri;
6786
0
    channel->GetURI(getter_AddRefs(uri));
6787
0
    nsAutoCString aURI;
6788
0
    uri->GetAsciiSpec(aURI);
6789
0
6790
0
    nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
6791
0
    nsCOMPtr<nsIWebProgress> webProgress =
6792
0
      do_QueryInterface(GetAsSupports(this));
6793
0
6794
0
    // We don't update navigation timing for wyciwyg channels
6795
0
    if (this == aProgress && !wcwgChannel) {
6796
0
      mozilla::Unused << MaybeInitTiming();
6797
0
      mTiming->NotifyFetchStart(uri,
6798
0
                                ConvertLoadTypeToNavigationType(mLoadType));
6799
0
    }
6800
0
6801
0
    // Was the wyciwyg document loaded on this docshell?
6802
0
    if (wcwgChannel && !mLSHE && (mItemType == typeContent) &&
6803
0
        aProgress == webProgress.get()) {
6804
0
      bool equalUri = true;
6805
0
      // Store the wyciwyg url in session history, only if it is
6806
0
      // being loaded fresh for the first time. We don't want
6807
0
      // multiple entries for successive loads
6808
0
      if (mCurrentURI &&
6809
0
          NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
6810
0
          !equalUri) {
6811
0
        nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
6812
0
        GetSameTypeParent(getter_AddRefs(parentAsItem));
6813
0
        nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
6814
0
        bool inOnLoadHandler = false;
6815
0
        if (parentDS) {
6816
0
          parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
6817
0
        }
6818
0
        if (inOnLoadHandler) {
6819
0
          // We're handling parent's load event listener, which causes
6820
0
          // document.write in a subdocument.
6821
0
          // Need to clear the session history for all child
6822
0
          // docshells so that we can handle them like they would
6823
0
          // all be added dynamically.
6824
0
          nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
6825
0
          if (parent) {
6826
0
            bool oshe = false;
6827
0
            nsCOMPtr<nsISHEntry> entry;
6828
0
            parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
6829
0
            static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry);
6830
0
          }
6831
0
        }
6832
0
6833
0
        // This is a document.write(). Get the made-up url
6834
0
        // from the channel and store it in session history.
6835
0
        // Pass false for aCloneChildren, since we're creating
6836
0
        // a new DOM here.
6837
0
        AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false,
6838
0
                            getter_AddRefs(mLSHE));
6839
0
        SetCurrentURI(uri, aRequest, true, 0);
6840
0
        // Save history state of the previous page
6841
0
        PersistLayoutHistoryState();
6842
0
        // We'll never get an Embed() for this load, so just go ahead
6843
0
        // and SetHistoryEntry now.
6844
0
        SetHistoryEntry(&mOSHE, mLSHE);
6845
0
      }
6846
0
    }
6847
0
    // Page has begun to load
6848
0
    mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
6849
0
6850
0
    if ((aStateFlags & STATE_RESTORING) == 0) {
6851
0
      // Show the progress cursor if the pref is set
6852
0
      if (nsContentUtils::UseActivityCursor()) {
6853
0
        nsCOMPtr<nsIWidget> mainWidget;
6854
0
        GetMainWidget(getter_AddRefs(mainWidget));
6855
0
        if (mainWidget) {
6856
0
          mainWidget->SetCursor(eCursor_spinning);
6857
0
        }
6858
0
      }
6859
0
    }
6860
0
  } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
6861
0
    // Page is loading
6862
0
    mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
6863
0
  } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
6864
0
    // Page has finished loading
6865
0
    mBusyFlags = BUSY_FLAGS_NONE;
6866
0
6867
0
    // Hide the progress cursor if the pref is set
6868
0
    if (nsContentUtils::UseActivityCursor()) {
6869
0
      nsCOMPtr<nsIWidget> mainWidget;
6870
0
      GetMainWidget(getter_AddRefs(mainWidget));
6871
0
      if (mainWidget) {
6872
0
        mainWidget->SetCursor(eCursor_standard);
6873
0
      }
6874
0
    }
6875
0
  }
6876
0
  if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
6877
0
    nsCOMPtr<nsIWebProgress> webProgress =
6878
0
      do_QueryInterface(GetAsSupports(this));
6879
0
    // Is the document stop notification for this document?
6880
0
    if (aProgress == webProgress.get()) {
6881
0
      nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
6882
0
      EndPageLoad(aProgress, channel, aStatus);
6883
0
    }
6884
0
  }
6885
0
  // note that redirect state changes will go through here as well, but it
6886
0
  // is better to handle those in OnRedirectStateChange where more
6887
0
  // information is available.
6888
0
  return NS_OK;
6889
0
}
6890
6891
NS_IMETHODIMP
6892
nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
6893
                             nsIURI* aURI, uint32_t aFlags)
6894
0
{
6895
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
6896
0
  return NS_OK;
6897
0
}
6898
6899
void
6900
nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
6901
                                  nsIChannel* aNewChannel,
6902
                                  uint32_t aRedirectFlags,
6903
                                  uint32_t aStateFlags)
6904
0
{
6905
0
  NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
6906
0
               "Calling OnRedirectStateChange when there is no redirect");
6907
0
6908
0
  // If mixed content is allowed for the old channel, we forward
6909
0
  // the permission to the new channel if it has the same origin
6910
0
  // as the old one.
6911
0
  if (mMixedContentChannel && mMixedContentChannel == aOldChannel) {
6912
0
    nsresult rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel);
6913
0
    if (NS_SUCCEEDED(rv)) {
6914
0
      SetMixedContentChannel(aNewChannel); // Same origin: forward permission.
6915
0
    } else {
6916
0
      SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel.
6917
0
    }
6918
0
  }
6919
0
6920
0
  if (!(aStateFlags & STATE_IS_DOCUMENT)) {
6921
0
    return;  // not a toplevel document
6922
0
  }
6923
0
6924
0
  nsCOMPtr<nsIURI> oldURI, newURI;
6925
0
  aOldChannel->GetURI(getter_AddRefs(oldURI));
6926
0
  aNewChannel->GetURI(getter_AddRefs(newURI));
6927
0
  if (!oldURI || !newURI) {
6928
0
    return;
6929
0
  }
6930
0
6931
0
  // Below a URI visit is saved (see AddURIVisit method doc).
6932
0
  // The visit chain looks something like:
6933
0
  //   ...
6934
0
  //   Site N - 1
6935
0
  //                =>  Site N
6936
0
  //   (redirect to =>) Site N + 1 (we are here!)
6937
0
6938
0
  // Get N - 1 and transition type
6939
0
  nsCOMPtr<nsIURI> previousURI;
6940
0
  uint32_t previousFlags = 0;
6941
0
  ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
6942
0
6943
0
  if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
6944
0
      ChannelIsPost(aOldChannel)) {
6945
0
    // 1. Internal redirects are ignored because they are specific to the
6946
0
    //    channel implementation.
6947
0
    // 2. POSTs are not saved by global history.
6948
0
    //
6949
0
    // Regardless, we need to propagate the previous visit to the new
6950
0
    // channel.
6951
0
    SaveLastVisit(aNewChannel, previousURI, previousFlags);
6952
0
  } else {
6953
0
    nsCOMPtr<nsIURI> referrer;
6954
0
    // Treat referrer as null if there is an error getting it.
6955
0
    (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer));
6956
0
6957
0
    // Get the HTTP response code, if available.
6958
0
    uint32_t responseStatus = 0;
6959
0
    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
6960
0
    if (httpChannel) {
6961
0
      Unused << httpChannel->GetResponseStatus(&responseStatus);
6962
0
    }
6963
0
6964
0
    // Add visit N -1 => N
6965
0
    AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus);
6966
0
6967
0
    // Since N + 1 could be the final destination, we will not save N => N + 1
6968
0
    // here.  OnNewURI will do that, so we will cache it.
6969
0
    SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
6970
0
  }
6971
0
6972
0
  // check if the new load should go through the application cache.
6973
0
  nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
6974
0
    do_QueryInterface(aNewChannel);
6975
0
  if (appCacheChannel) {
6976
0
    if (GeckoProcessType_Default != XRE_GetProcessType()) {
6977
0
      // Permission will be checked in the parent process.
6978
0
      appCacheChannel->SetChooseApplicationCache(true);
6979
0
    } else {
6980
0
      nsCOMPtr<nsIScriptSecurityManager> secMan =
6981
0
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
6982
0
6983
0
      if (secMan) {
6984
0
        nsCOMPtr<nsIPrincipal> principal;
6985
0
        secMan->GetDocShellCodebasePrincipal(newURI, this,
6986
0
                                             getter_AddRefs(principal));
6987
0
        appCacheChannel->SetChooseApplicationCache(
6988
0
          NS_ShouldCheckAppCache(principal));
6989
0
      }
6990
0
    }
6991
0
  }
6992
0
6993
0
  if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
6994
0
      mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
6995
0
    mLoadType = LOAD_NORMAL_REPLACE;
6996
0
    SetHistoryEntry(&mLSHE, nullptr);
6997
0
  }
6998
0
}
6999
7000
NS_IMETHODIMP
7001
nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress,
7002
                           nsIRequest* aRequest,
7003
                           nsresult aStatus, const char16_t* aMessage)
7004
0
{
7005
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
7006
0
  return NS_OK;
7007
0
}
7008
7009
NS_IMETHODIMP
7010
nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress,
7011
                             nsIRequest* aRequest, uint32_t aState)
7012
0
{
7013
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
7014
0
  return NS_OK;
7015
0
}
7016
7017
nsresult
7018
nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
7019
                        nsIChannel* aChannel, nsresult aStatus)
7020
0
{
7021
0
  if (!aChannel) {
7022
0
    return NS_ERROR_NULL_POINTER;
7023
0
  }
7024
0
7025
0
  // Make sure to discard the initial client if we never created the initial
7026
0
  // about:blank document.  Do this before possibly returning from the method
7027
0
  // due to an error.
7028
0
  mInitialClientSource.reset();
7029
0
7030
0
  nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
7031
0
  if (reporter) {
7032
0
    nsCOMPtr<nsILoadGroup> loadGroup;
7033
0
    aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
7034
0
    if (loadGroup) {
7035
0
      reporter->FlushConsoleReports(loadGroup);
7036
0
    } else {
7037
0
      reporter->FlushConsoleReports(GetDocument());
7038
0
    }
7039
0
  }
7040
0
7041
0
  nsCOMPtr<nsIURI> url;
7042
0
  nsresult rv = aChannel->GetURI(getter_AddRefs(url));
7043
0
  if (NS_FAILED(rv)) {
7044
0
    return rv;
7045
0
  }
7046
0
7047
0
  nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel);
7048
0
  if (timingChannel) {
7049
0
    TimeStamp channelCreationTime;
7050
0
    rv = timingChannel->GetChannelCreation(&channelCreationTime);
7051
0
    if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
7052
0
      Telemetry::AccumulateTimeDelta(Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
7053
0
                                     channelCreationTime);
7054
0
      nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
7055
0
        do_QueryInterface(mLoadGroup);
7056
0
      if (internalLoadGroup) {
7057
0
        internalLoadGroup->OnEndPageLoad(aChannel);
7058
0
      }
7059
0
    }
7060
0
  }
7061
0
7062
0
  // Timing is picked up by the window, we don't need it anymore
7063
0
  mTiming = nullptr;
7064
0
7065
0
  // clean up reload state for meta charset
7066
0
  if (eCharsetReloadRequested == mCharsetReloadState) {
7067
0
    mCharsetReloadState = eCharsetReloadStopOrigional;
7068
0
  } else {
7069
0
    mCharsetReloadState = eCharsetReloadInit;
7070
0
  }
7071
0
7072
0
  // Save a pointer to the currently-loading history entry.
7073
0
  // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
7074
0
  // entry further down in this method.
7075
0
  nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
7076
0
  mozilla::Unused << loadingSHE; // XXX: Not sure if we need this anymore
7077
0
7078
0
  //
7079
0
  // one of many safeguards that prevent death and destruction if
7080
0
  // someone is so very very rude as to bring this window down
7081
0
  // during this load handler.
7082
0
  //
7083
0
  nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
7084
0
7085
0
  // Notify the ContentViewer that the Document has finished loading.  This
7086
0
  // will cause any OnLoad(...) and PopState(...) handlers to fire.
7087
0
  if (!mEODForCurrentDocument && mContentViewer) {
7088
0
    mIsExecutingOnLoadHandler = true;
7089
0
    mContentViewer->LoadComplete(aStatus);
7090
0
    mIsExecutingOnLoadHandler = false;
7091
0
7092
0
    mEODForCurrentDocument = true;
7093
0
7094
0
    // If all documents have completed their loading
7095
0
    // favor native event dispatch priorities
7096
0
    // over performance
7097
0
    if (--gNumberOfDocumentsLoading == 0) {
7098
0
      // Hint to use normal native event dispatch priorities
7099
0
      FavorPerformanceHint(false);
7100
0
    }
7101
0
  }
7102
0
  /* Check if the httpChannel has any cache-control related response headers,
7103
0
   * like no-store, no-cache. If so, update SHEntry so that
7104
0
   * when a user goes back/forward to this page, we appropriately do
7105
0
   * form value restoration or load from server.
7106
0
   */
7107
0
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
7108
0
  if (!httpChannel) {
7109
0
    // HttpChannel could be hiding underneath a Multipart channel.
7110
0
    GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
7111
0
  }
7112
0
7113
0
  if (httpChannel) {
7114
0
    // figure out if SH should be saving layout state.
7115
0
    bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
7116
0
    if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
7117
0
        (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
7118
0
      mLSHE->SetSaveLayoutStateFlag(false);
7119
0
    }
7120
0
  }
7121
0
7122
0
  // Clear mLSHE after calling the onLoadHandlers. This way, if the
7123
0
  // onLoadHandler tries to load something different in
7124
0
  // itself or one of its children, we can deal with it appropriately.
7125
0
  if (mLSHE) {
7126
0
    mLSHE->SetLoadType(LOAD_HISTORY);
7127
0
7128
0
    // Clear the mLSHE reference to indicate document loading is done one
7129
0
    // way or another.
7130
0
    SetHistoryEntry(&mLSHE, nullptr);
7131
0
  }
7132
0
  // if there's a refresh header in the channel, this method
7133
0
  // will set it up for us.
7134
0
  if (mIsActive || !mDisableMetaRefreshWhenInactive)
7135
0
    RefreshURIFromQueue();
7136
0
7137
0
  // Test whether this is the top frame or a subframe
7138
0
  bool isTopFrame = true;
7139
0
  nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
7140
0
  rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
7141
0
  if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
7142
0
    isTopFrame = false;
7143
0
  }
7144
0
7145
0
  //
7146
0
  // If the page load failed, then deal with the error condition...
7147
0
  // Errors are handled as follows:
7148
0
  //   1. Check to see if it's a file not found error or bad content
7149
0
  //      encoding error.
7150
0
  //   2. Send the URI to a keyword server (if enabled)
7151
0
  //   3. If the error was DNS failure, then add www and .com to the URI
7152
0
  //      (if appropriate).
7153
0
  //   4. Throw an error dialog box...
7154
0
  //
7155
0
  if (url && NS_FAILED(aStatus)) {
7156
0
    if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
7157
0
        aStatus == NS_ERROR_FILE_ACCESS_DENIED ||
7158
0
        aStatus == NS_ERROR_CORRUPTED_CONTENT ||
7159
0
        aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
7160
0
      DisplayLoadError(aStatus, url, nullptr, aChannel);
7161
0
      return NS_OK;
7162
0
    }
7163
0
7164
0
    // Handle iframe document not loading error because source was
7165
0
    // a tracking URL. We make a note of this iframe node by including
7166
0
    // it in a dedicated array of blocked tracking nodes under its parent
7167
0
    // document. (document of parent window of blocked document)
7168
0
    if (isTopFrame == false && aStatus == NS_ERROR_TRACKING_URI) {
7169
0
      // frameElement is our nsIContent to be annotated
7170
0
      RefPtr<Element> frameElement;
7171
0
      nsPIDOMWindowOuter* thisWindow = GetWindow();
7172
0
      if (!thisWindow) {
7173
0
        return NS_OK;
7174
0
      }
7175
0
7176
0
      frameElement = thisWindow->GetFrameElement();
7177
0
      if (!frameElement) {
7178
0
        return NS_OK;
7179
0
      }
7180
0
7181
0
      // Parent window
7182
0
      nsCOMPtr<nsIDocShellTreeItem> parentItem;
7183
0
      GetSameTypeParent(getter_AddRefs(parentItem));
7184
0
      if (!parentItem) {
7185
0
        return NS_OK;
7186
0
      }
7187
0
7188
0
      nsCOMPtr<nsIDocument> parentDoc;
7189
0
      parentDoc = parentItem->GetDocument();
7190
0
      if (!parentDoc) {
7191
0
        return NS_OK;
7192
0
      }
7193
0
7194
0
      parentDoc->AddBlockedTrackingNode(frameElement);
7195
0
7196
0
      return NS_OK;
7197
0
    }
7198
0
7199
0
    if (sURIFixup) {
7200
0
      //
7201
0
      // Try and make an alternative URI from the old one
7202
0
      //
7203
0
      nsCOMPtr<nsIURI> newURI;
7204
0
      nsCOMPtr<nsIInputStream> newPostData;
7205
0
7206
0
      nsAutoCString oldSpec;
7207
0
      url->GetSpec(oldSpec);
7208
0
7209
0
      //
7210
0
      // First try keyword fixup
7211
0
      //
7212
0
      nsAutoString keywordProviderName, keywordAsSent;
7213
0
      if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
7214
0
        bool keywordsEnabled = Preferences::GetBool("keyword.enabled", false);
7215
0
7216
0
        nsAutoCString host;
7217
0
        url->GetHost(host);
7218
0
7219
0
        nsAutoCString scheme;
7220
0
        url->GetScheme(scheme);
7221
0
7222
0
        int32_t dotLoc = host.FindChar('.');
7223
0
7224
0
        // we should only perform a keyword search under the following
7225
0
        // conditions:
7226
0
        // (0) Pref keyword.enabled is true
7227
0
        // (1) the url scheme is http (or https)
7228
0
        // (2) the url does not have a protocol scheme
7229
0
        // If we don't enforce such a policy, then we end up doing
7230
0
        // keyword searchs on urls we don't intend like imap, file,
7231
0
        // mailbox, etc. This could lead to a security problem where we
7232
0
        // send data to the keyword server that we shouldn't be.
7233
0
        // Someone needs to clean up keywords in general so we can
7234
0
        // determine on a per url basis if we want keywords
7235
0
        // enabled...this is just a bandaid...
7236
0
        if (keywordsEnabled && !scheme.IsEmpty() &&
7237
0
            (scheme.Find("http") != 0)) {
7238
0
          keywordsEnabled = false;
7239
0
        }
7240
0
7241
0
        if (keywordsEnabled && (kNotFound == dotLoc)) {
7242
0
          nsCOMPtr<nsIURIFixupInfo> info;
7243
0
          // only send non-qualified hosts to the keyword server
7244
0
          if (!mOriginalUriString.IsEmpty()) {
7245
0
            sURIFixup->KeywordToURI(mOriginalUriString,
7246
0
                                    getter_AddRefs(newPostData),
7247
0
                                    getter_AddRefs(info));
7248
0
          } else {
7249
0
            //
7250
0
            // If this string was passed through nsStandardURL by
7251
0
            // chance, then it may have been converted from UTF-8 to
7252
0
            // ACE, which would result in a completely bogus keyword
7253
0
            // query.  Here we try to recover the original Unicode
7254
0
            // value, but this is not 100% correct since the value may
7255
0
            // have been normalized per the IDN normalization rules.
7256
0
            //
7257
0
            // Since we don't have access to the exact original string
7258
0
            // that was entered by the user, this will just have to do.
7259
0
            bool isACE;
7260
0
            nsAutoCString utf8Host;
7261
0
            nsCOMPtr<nsIIDNService> idnSrv =
7262
0
              do_GetService(NS_IDNSERVICE_CONTRACTID);
7263
0
            if (idnSrv &&
7264
0
                NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
7265
0
                NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
7266
0
              sURIFixup->KeywordToURI(utf8Host,
7267
0
                                      getter_AddRefs(newPostData),
7268
0
                                      getter_AddRefs(info));
7269
0
            } else {
7270
0
              sURIFixup->KeywordToURI(host,
7271
0
                                      getter_AddRefs(newPostData),
7272
0
                                      getter_AddRefs(info));
7273
0
            }
7274
0
          }
7275
0
7276
0
          info->GetPreferredURI(getter_AddRefs(newURI));
7277
0
          if (newURI) {
7278
0
            info->GetKeywordAsSent(keywordAsSent);
7279
0
            info->GetKeywordProviderName(keywordProviderName);
7280
0
          }
7281
0
        } // end keywordsEnabled
7282
0
      }
7283
0
7284
0
      //
7285
0
      // Now try change the address, e.g. turn http://foo into
7286
0
      // http://www.foo.com
7287
0
      //
7288
0
      if (aStatus == NS_ERROR_UNKNOWN_HOST ||
7289
0
          aStatus == NS_ERROR_NET_RESET) {
7290
0
        bool doCreateAlternate = true;
7291
0
7292
0
        // Skip fixup for anything except a normal document load
7293
0
        // operation on the topframe.
7294
0
7295
0
        if (mLoadType != LOAD_NORMAL || !isTopFrame) {
7296
0
          doCreateAlternate = false;
7297
0
        } else {
7298
0
          // Test if keyword lookup produced a new URI or not
7299
0
          if (newURI) {
7300
0
            bool sameURI = false;
7301
0
            url->Equals(newURI, &sameURI);
7302
0
            if (!sameURI) {
7303
0
              // Keyword lookup made a new URI so no need to try
7304
0
              // an alternate one.
7305
0
              doCreateAlternate = false;
7306
0
            }
7307
0
          }
7308
0
7309
0
          if (doCreateAlternate) {
7310
0
            // Skip doing this if our channel was redirected, because we
7311
0
            // shouldn't be guessing things about the post-redirect URI.
7312
0
            nsLoadFlags loadFlags = 0;
7313
0
            if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) ||
7314
0
                (loadFlags & nsIChannel::LOAD_REPLACE)) {
7315
0
              doCreateAlternate = false;
7316
0
            }
7317
0
          }
7318
0
        }
7319
0
        if (doCreateAlternate) {
7320
0
          newURI = nullptr;
7321
0
          newPostData = nullptr;
7322
0
          keywordProviderName.Truncate();
7323
0
          keywordAsSent.Truncate();
7324
0
          sURIFixup->CreateFixupURI(oldSpec,
7325
0
                                    nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
7326
0
                                    getter_AddRefs(newPostData),
7327
0
                                    getter_AddRefs(newURI));
7328
0
        }
7329
0
      }
7330
0
7331
0
      // Did we make a new URI that is different to the old one? If so
7332
0
      // load it.
7333
0
      //
7334
0
      if (newURI) {
7335
0
        // Make sure the new URI is different from the old one,
7336
0
        // otherwise there's little point trying to load it again.
7337
0
        bool sameURI = false;
7338
0
        url->Equals(newURI, &sameURI);
7339
0
        if (!sameURI) {
7340
0
          nsAutoCString newSpec;
7341
0
          newURI->GetSpec(newSpec);
7342
0
          NS_ConvertUTF8toUTF16 newSpecW(newSpec);
7343
0
7344
0
          // This notification is meant for Firefox Health Report so it
7345
0
          // can increment counts from the search engine
7346
0
          MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent);
7347
0
7348
0
          nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
7349
0
          nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo
7350
0
            ? loadInfo->TriggeringPrincipal()
7351
0
            : nsContentUtils::GetSystemPrincipal();
7352
0
          return LoadURI(newSpecW,             // URI string
7353
0
                         LOAD_FLAGS_NONE,      // Load flags
7354
0
                         nullptr,              // Referring URI
7355
0
                         newPostData,          // Post data stream
7356
0
                         nullptr,              // Headers stream
7357
0
                         triggeringPrincipal); // TriggeringPrincipal
7358
0
        }
7359
0
      }
7360
0
    }
7361
0
7362
0
    // Well, fixup didn't work :-(
7363
0
    // It is time to throw an error dialog box, and be done with it...
7364
0
7365
0
    // Errors to be shown only on top-level frames
7366
0
    if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
7367
0
         aStatus == NS_ERROR_CONNECTION_REFUSED ||
7368
0
         aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
7369
0
         aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
7370
0
         aStatus == NS_ERROR_BLOCKED_BY_POLICY) &&
7371
0
        (isTopFrame || UseErrorPages())) {
7372
0
      DisplayLoadError(aStatus, url, nullptr, aChannel);
7373
0
    } else if (aStatus == NS_ERROR_NET_TIMEOUT ||
7374
0
               aStatus == NS_ERROR_REDIRECT_LOOP ||
7375
0
               aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
7376
0
               aStatus == NS_ERROR_NET_INTERRUPT ||
7377
0
               aStatus == NS_ERROR_NET_RESET ||
7378
0
               aStatus == NS_ERROR_OFFLINE ||
7379
0
               aStatus == NS_ERROR_MALWARE_URI ||
7380
0
               aStatus == NS_ERROR_PHISHING_URI ||
7381
0
               aStatus == NS_ERROR_UNWANTED_URI ||
7382
0
               aStatus == NS_ERROR_HARMFUL_URI ||
7383
0
               aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
7384
0
               aStatus == NS_ERROR_REMOTE_XUL ||
7385
0
               aStatus == NS_ERROR_INTERCEPTION_FAILED ||
7386
0
               aStatus == NS_ERROR_NET_INADEQUATE_SECURITY ||
7387
0
               NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
7388
0
      // Errors to be shown for any frame
7389
0
      DisplayLoadError(aStatus, url, nullptr, aChannel);
7390
0
    } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
7391
0
      // Non-caching channels will simply return NS_ERROR_OFFLINE.
7392
0
      // Caching channels would have to look at their flags to work
7393
0
      // out which error to return. Or we can fix up the error here.
7394
0
      if (!(mLoadType & LOAD_CMD_HISTORY)) {
7395
0
        aStatus = NS_ERROR_OFFLINE;
7396
0
      }
7397
0
      DisplayLoadError(aStatus, url, nullptr, aChannel);
7398
0
    }
7399
0
  } else if (url && NS_SUCCEEDED(aStatus)) {
7400
0
    // If we have a host
7401
0
    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
7402
0
    if (loadInfo) {
7403
0
      PredictorLearnRedirect(url, aChannel, loadInfo->GetOriginAttributes());
7404
0
    }
7405
0
  }
7406
0
7407
0
  return NS_OK;
7408
0
}
7409
7410
//*****************************************************************************
7411
// nsDocShell: Content Viewer Management
7412
//*****************************************************************************
7413
7414
nsresult
7415
nsDocShell::EnsureContentViewer()
7416
0
{
7417
0
  if (mContentViewer) {
7418
0
    return NS_OK;
7419
0
  }
7420
0
  if (mIsBeingDestroyed) {
7421
0
    return NS_ERROR_FAILURE;
7422
0
  }
7423
0
7424
0
  nsCOMPtr<nsIURI> baseURI;
7425
0
  nsIPrincipal* principal = GetInheritedPrincipal(false);
7426
0
  nsCOMPtr<nsIDocShellTreeItem> parentItem;
7427
0
  GetSameTypeParent(getter_AddRefs(parentItem));
7428
0
  if (parentItem) {
7429
0
    if (nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow()) {
7430
0
      nsCOMPtr<Element> parentElement = domWin->GetFrameElementInternal();
7431
0
      if (parentElement) {
7432
0
        baseURI = parentElement->GetBaseURI();
7433
0
      }
7434
0
    }
7435
0
  }
7436
0
7437
0
  nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
7438
0
7439
0
  NS_ENSURE_STATE(mContentViewer);
7440
0
7441
0
  if (NS_SUCCEEDED(rv)) {
7442
0
    nsCOMPtr<nsIDocument> doc(GetDocument());
7443
0
    NS_ASSERTION(doc,
7444
0
                 "Should have doc if CreateAboutBlankContentViewer "
7445
0
                 "succeeded!");
7446
0
7447
0
    doc->SetIsInitialDocument(true);
7448
0
7449
0
    // Documents created using EnsureContentViewer may be transient
7450
0
    // placeholders created by framescripts before content has a chance to
7451
0
    // load. In some cases, window.open(..., "noopener") will create such a
7452
0
    // document (in a new TabGroup) and then synchronously tear it down, firing
7453
0
    // a "pagehide" event. Doing so violates our assertions about
7454
0
    // DocGroups. It's easier to silence the assertion here than to avoid
7455
0
    // creating the extra document.
7456
0
    doc->IgnoreDocGroupMismatches();
7457
0
  }
7458
0
7459
0
  return rv;
7460
0
}
7461
7462
nsresult
7463
nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
7464
                                          nsIURI* aBaseURI,
7465
                                          bool aTryToSaveOldPresentation,
7466
                                          bool aCheckPermitUnload)
7467
0
{
7468
0
  nsCOMPtr<nsIDocument> blankDoc;
7469
0
  nsCOMPtr<nsIContentViewer> viewer;
7470
0
  nsresult rv = NS_ERROR_FAILURE;
7471
0
7472
0
  /* mCreatingDocument should never be true at this point. However, it's
7473
0
     a theoretical possibility. We want to know about it and make it stop,
7474
0
     and this sounds like a job for an assertion. */
7475
0
  NS_ASSERTION(!mCreatingDocument,
7476
0
               "infinite(?) loop creating document averted");
7477
0
  if (mCreatingDocument) {
7478
0
    return NS_ERROR_FAILURE;
7479
0
  }
7480
0
7481
0
  // mContentViewer->PermitUnload may release |this| docshell.
7482
0
  nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
7483
0
7484
0
  AutoRestore<bool> creatingDocument(mCreatingDocument);
7485
0
  mCreatingDocument = true;
7486
0
7487
0
  if (aPrincipal && !nsContentUtils::IsSystemPrincipal(aPrincipal) &&
7488
0
      mItemType != typeChrome) {
7489
0
    MOZ_ASSERT(aPrincipal->OriginAttributesRef() == mOriginAttributes);
7490
0
  }
7491
0
7492
0
  // Make sure timing is created.  But first record whether we had it
7493
0
  // already, so we don't clobber the timing for an in-progress load.
7494
0
  bool hadTiming = mTiming;
7495
0
  bool toBeReset = MaybeInitTiming();
7496
0
  if (mContentViewer) {
7497
0
    if (aCheckPermitUnload) {
7498
0
      // We've got a content viewer already. Make sure the user
7499
0
      // permits us to discard the current document and replace it
7500
0
      // with about:blank. And also ensure we fire the unload events
7501
0
      // in the current document.
7502
0
7503
0
      // Unload gets fired first for
7504
0
      // document loaded from the session history.
7505
0
      mTiming->NotifyBeforeUnload();
7506
0
7507
0
      bool okToUnload;
7508
0
      rv = mContentViewer->PermitUnload(&okToUnload);
7509
0
7510
0
      if (NS_SUCCEEDED(rv) && !okToUnload) {
7511
0
        // The user chose not to unload the page, interrupt the load.
7512
0
        MaybeResetInitTiming(toBeReset);
7513
0
        return NS_ERROR_FAILURE;
7514
0
      }
7515
0
      if (mTiming) {
7516
0
        mTiming->NotifyUnloadAccepted(mCurrentURI);
7517
0
      }
7518
0
    }
7519
0
7520
0
    mSavingOldViewer = aTryToSaveOldPresentation &&
7521
0
                       CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
7522
0
7523
0
    // Make sure to blow away our mLoadingURI just in case.  No loads
7524
0
    // from inside this pagehide.
7525
0
    mLoadingURI = nullptr;
7526
0
7527
0
    // Stop any in-progress loading, so that we don't accidentally trigger any
7528
0
    // PageShow notifications from Embed() interrupting our loading below.
7529
0
    Stop();
7530
0
7531
0
    // Notify the current document that it is about to be unloaded!!
7532
0
    //
7533
0
    // It is important to fire the unload() notification *before* any state
7534
0
    // is changed within the DocShell - otherwise, javascript will get the
7535
0
    // wrong information :-(
7536
0
    //
7537
0
    (void)FirePageHideNotification(!mSavingOldViewer);
7538
0
    // pagehide notification might destroy this docshell.
7539
0
    if (mIsBeingDestroyed) {
7540
0
      return NS_ERROR_DOCSHELL_DYING;
7541
0
    }
7542
0
  }
7543
0
7544
0
  // Now make sure we don't think we're in the middle of firing unload after
7545
0
  // this point.  This will make us fire unload when the about:blank document
7546
0
  // unloads... but that's ok, more or less.  Would be nice if it fired load
7547
0
  // too, of course.
7548
0
  mFiredUnloadEvent = false;
7549
0
7550
0
  nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
7551
0
    nsContentUtils::FindInternalContentViewer(NS_LITERAL_CSTRING("text/html"));
7552
0
7553
0
  if (docFactory) {
7554
0
    nsCOMPtr<nsIPrincipal> principal;
7555
0
    if (mSandboxFlags & SANDBOXED_ORIGIN) {
7556
0
      if (aPrincipal) {
7557
0
        principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal);
7558
0
      } else {
7559
0
        principal = NullPrincipal::CreateWithInheritedAttributes(this);
7560
0
      }
7561
0
    } else {
7562
0
      principal = aPrincipal;
7563
0
    }
7564
0
7565
0
    MaybeCreateInitialClientSource(principal);
7566
0
7567
0
    // generate (about:blank) document to load
7568
0
    blankDoc = nsContentDLF::CreateBlankDocument(mLoadGroup, principal, this);
7569
0
    if (blankDoc) {
7570
0
      // Hack: set the base URI manually, since this document never
7571
0
      // got Reset() with a channel.
7572
0
      blankDoc->SetBaseURI(aBaseURI);
7573
0
7574
0
      // Copy our sandbox flags to the document. These are immutable
7575
0
      // after being set here.
7576
0
      blankDoc->SetSandboxFlags(mSandboxFlags);
7577
0
7578
0
      // create a content viewer for us and the new document
7579
0
      docFactory->CreateInstanceForDocument(
7580
0
        NS_ISUPPORTS_CAST(nsIDocShell*, this), blankDoc, "view",
7581
0
        getter_AddRefs(viewer));
7582
0
7583
0
      // hook 'em up
7584
0
      if (viewer) {
7585
0
        viewer->SetContainer(this);
7586
0
        rv = Embed(viewer, "", 0);
7587
0
        NS_ENSURE_SUCCESS(rv, rv);
7588
0
7589
0
        SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
7590
0
        rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
7591
0
      }
7592
0
    }
7593
0
  }
7594
0
7595
0
  // The transient about:blank viewer doesn't have a session history entry.
7596
0
  SetHistoryEntry(&mOSHE, nullptr);
7597
0
7598
0
  // Clear out our mTiming like we would in EndPageLoad, if we didn't
7599
0
  // have one before entering this function.
7600
0
  if (!hadTiming) {
7601
0
    mTiming = nullptr;
7602
0
    mBlankTiming = true;
7603
0
  }
7604
0
7605
0
  return rv;
7606
0
}
7607
7608
NS_IMETHODIMP
7609
nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
7610
0
{
7611
0
  return CreateAboutBlankContentViewer(aPrincipal, nullptr);
7612
0
}
7613
7614
NS_IMETHODIMP
7615
nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
7616
0
{
7617
0
  return CreateAboutBlankContentViewer(aPrincipal, nullptr, true, false);
7618
0
}
7619
7620
bool
7621
nsDocShell::CanSavePresentation(uint32_t aLoadType,
7622
                                nsIRequest* aNewRequest,
7623
                                nsIDocument* aNewDocument)
7624
0
{
7625
0
  if (!mOSHE) {
7626
0
    return false;  // no entry to save into
7627
0
  }
7628
0
7629
0
  nsCOMPtr<nsIContentViewer> viewer = mOSHE->GetContentViewer();
7630
0
  if (viewer) {
7631
0
    NS_WARNING("mOSHE already has a content viewer!");
7632
0
    return false;
7633
0
  }
7634
0
7635
0
  // Only save presentation for "normal" loads and link loads.  Anything else
7636
0
  // probably wants to refetch the page, so caching the old presentation
7637
0
  // would be incorrect.
7638
0
  if (aLoadType != LOAD_NORMAL &&
7639
0
      aLoadType != LOAD_HISTORY &&
7640
0
      aLoadType != LOAD_LINK &&
7641
0
      aLoadType != LOAD_STOP_CONTENT &&
7642
0
      aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
7643
0
      aLoadType != LOAD_ERROR_PAGE) {
7644
0
    return false;
7645
0
  }
7646
0
7647
0
  // If the session history entry has the saveLayoutState flag set to false,
7648
0
  // then we should not cache the presentation.
7649
0
  if (!mOSHE->GetSaveLayoutStateFlag()) {
7650
0
    return false;
7651
0
  }
7652
0
7653
0
  // If the document is not done loading, don't cache it.
7654
0
  if (!mScriptGlobal || mScriptGlobal->IsLoading()) {
7655
0
    return false;
7656
0
  }
7657
0
7658
0
  if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) {
7659
0
    return false;
7660
0
  }
7661
0
7662
0
  // Avoid doing the work of saving the presentation state in the case where
7663
0
  // the content viewer cache is disabled.
7664
0
  if (nsSHistory::GetMaxTotalViewers() == 0) {
7665
0
    return false;
7666
0
  }
7667
0
7668
0
  // Don't cache the content viewer if we're in a subframe.
7669
0
  nsCOMPtr<nsIDocShellTreeItem> root;
7670
0
  GetSameTypeParent(getter_AddRefs(root));
7671
0
  if (root && root != this) {
7672
0
    return false;  // this is a subframe load
7673
0
  }
7674
0
7675
0
  // If the document does not want its presentation cached, then don't.
7676
0
  nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
7677
0
  return doc && doc->CanSavePresentation(aNewRequest);
7678
0
}
7679
7680
void
7681
nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry)
7682
0
{
7683
0
  MOZ_ASSERT(!mIsBeingDestroyed);
7684
0
7685
0
  NS_ASSERTION(!mEditorData,
7686
0
               "Why reattach an editor when we already have one?");
7687
0
  NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
7688
0
               "Reattaching when there's not a detached editor.");
7689
0
7690
0
  if (mEditorData || !aSHEntry) {
7691
0
    return;
7692
0
  }
7693
0
7694
0
  mEditorData = aSHEntry->ForgetEditorData();
7695
0
  if (mEditorData) {
7696
#ifdef DEBUG
7697
    nsresult rv =
7698
#endif
7699
      mEditorData->ReattachToWindow(this);
7700
0
    NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
7701
0
  }
7702
0
}
7703
7704
void
7705
nsDocShell::DetachEditorFromWindow()
7706
0
{
7707
0
  if (!mEditorData || mEditorData->WaitingForLoad()) {
7708
0
    // If there's nothing to detach, or if the editor data is actually set
7709
0
    // up for the _new_ page that's coming in, don't detach.
7710
0
    return;
7711
0
  }
7712
0
7713
0
  NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
7714
0
               "Detaching editor when it's already detached.");
7715
0
7716
0
  nsresult res = mEditorData->DetachFromWindow();
7717
0
  NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
7718
0
7719
0
  if (NS_SUCCEEDED(res)) {
7720
0
    // Make mOSHE hold the owning ref to the editor data.
7721
0
    if (mOSHE) {
7722
0
      MOZ_ASSERT(!mIsBeingDestroyed || !mOSHE->HasDetachedEditor(),
7723
0
                 "We should not set the editor data again once after we "
7724
0
                 "detached the editor data during destroying this docshell");
7725
0
      mOSHE->SetEditorData(mEditorData.forget());
7726
0
    } else {
7727
0
      mEditorData = nullptr;
7728
0
    }
7729
0
  }
7730
0
7731
#ifdef DEBUG
7732
  {
7733
    bool isEditable;
7734
    GetEditable(&isEditable);
7735
    NS_ASSERTION(!isEditable,
7736
                 "Window is still editable after detaching editor.");
7737
  }
7738
#endif // DEBUG
7739
}
7740
7741
nsresult
7742
nsDocShell::CaptureState()
7743
0
{
7744
0
  if (!mOSHE || mOSHE == mLSHE) {
7745
0
    // No entry to save into, or we're replacing the existing entry.
7746
0
    return NS_ERROR_FAILURE;
7747
0
  }
7748
0
7749
0
  if (!mScriptGlobal) {
7750
0
    return NS_ERROR_FAILURE;
7751
0
  }
7752
0
7753
0
  nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
7754
0
  NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
7755
0
7756
#ifdef DEBUG_PAGE_CACHE
7757
  nsCOMPtr<nsIURI> uri = mOSHE->GetURI();
7758
  nsAutoCString spec;
7759
  if (uri) {
7760
    uri->GetSpec(spec);
7761
  }
7762
  printf("Saving presentation into session history\n");
7763
  printf("  SH URI: %s\n", spec.get());
7764
#endif
7765
7766
0
  mOSHE->SetWindowState(windowState);
7767
0
7768
0
  // Suspend refresh URIs and save off the timer queue
7769
0
  mOSHE->SetRefreshURIList(mSavedRefreshURIList);
7770
0
7771
0
  // Capture the current content viewer bounds.
7772
0
  if (mContentViewer) {
7773
0
    nsIntRect bounds;
7774
0
    mContentViewer->GetBounds(bounds);
7775
0
    mOSHE->SetViewerBounds(bounds);
7776
0
  }
7777
0
7778
0
  // Capture the docshell hierarchy.
7779
0
  mOSHE->ClearChildShells();
7780
0
7781
0
  uint32_t childCount = mChildList.Length();
7782
0
  for (uint32_t i = 0; i < childCount; ++i) {
7783
0
    nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
7784
0
    NS_ASSERTION(childShell, "null child shell");
7785
0
7786
0
    mOSHE->AddChildShell(childShell);
7787
0
  }
7788
0
7789
0
  mBrowsingContext->CacheChildren();
7790
0
7791
0
  return NS_OK;
7792
0
}
7793
7794
NS_IMETHODIMP
7795
nsDocShell::RestorePresentationEvent::Run()
7796
0
{
7797
0
  if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) {
7798
0
    NS_WARNING("RestoreFromHistory failed");
7799
0
  }
7800
0
  return NS_OK;
7801
0
}
7802
7803
NS_IMETHODIMP
7804
nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop)
7805
0
{
7806
0
  nsresult rv;
7807
0
  if (!aContentViewer) {
7808
0
    rv = EnsureContentViewer();
7809
0
    NS_ENSURE_SUCCESS(rv, rv);
7810
0
7811
0
    aContentViewer = mContentViewer;
7812
0
  }
7813
0
7814
0
  // Dispatch events for restoring the presentation.  We try to simulate
7815
0
  // the progress notifications loading the document would cause, so we add
7816
0
  // the document's channel to the loadgroup to initiate stateChange
7817
0
  // notifications.
7818
0
7819
0
  nsCOMPtr<nsIDocument> doc = aContentViewer->GetDocument();
7820
0
  if (doc) {
7821
0
    nsIChannel* channel = doc->GetChannel();
7822
0
    if (channel) {
7823
0
      mEODForCurrentDocument = false;
7824
0
      mIsRestoringDocument = true;
7825
0
      mLoadGroup->AddRequest(channel, nullptr);
7826
0
      mIsRestoringDocument = false;
7827
0
    }
7828
0
  }
7829
0
7830
0
  if (!aTop) {
7831
0
    // This point corresponds to us having gotten OnStartRequest or
7832
0
    // STATE_START, so do the same thing that CreateContentViewer does at
7833
0
    // this point to ensure that unload/pagehide events for this document
7834
0
    // will fire when it's unloaded again.
7835
0
    mFiredUnloadEvent = false;
7836
0
7837
0
    // For non-top frames, there is no notion of making sure that the
7838
0
    // previous document is in the domwindow when STATE_START notifications
7839
0
    // happen.  We can just call BeginRestore for all of the child shells
7840
0
    // now.
7841
0
    rv = BeginRestoreChildren();
7842
0
    NS_ENSURE_SUCCESS(rv, rv);
7843
0
  }
7844
0
7845
0
  return NS_OK;
7846
0
}
7847
7848
nsresult
7849
nsDocShell::BeginRestoreChildren()
7850
0
{
7851
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7852
0
  while (iter.HasMore()) {
7853
0
    nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
7854
0
    if (child) {
7855
0
      nsresult rv = child->BeginRestore(nullptr, false);
7856
0
      NS_ENSURE_SUCCESS(rv, rv);
7857
0
    }
7858
0
  }
7859
0
  return NS_OK;
7860
0
}
7861
7862
NS_IMETHODIMP
7863
nsDocShell::FinishRestore()
7864
0
{
7865
0
  // First we call finishRestore() on our children.  In the simulated load,
7866
0
  // all of the child frames finish loading before the main document.
7867
0
7868
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7869
0
  while (iter.HasMore()) {
7870
0
    nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
7871
0
    if (child) {
7872
0
      child->FinishRestore();
7873
0
    }
7874
0
  }
7875
0
7876
0
  if (mOSHE && mOSHE->HasDetachedEditor()) {
7877
0
    ReattachEditorToWindow(mOSHE);
7878
0
  }
7879
0
7880
0
  nsCOMPtr<nsIDocument> doc = GetDocument();
7881
0
  if (doc) {
7882
0
    // Finally, we remove the request from the loadgroup.  This will
7883
0
    // cause onStateChange(STATE_STOP) to fire, which will fire the
7884
0
    // pageshow event to the chrome.
7885
0
7886
0
    nsIChannel* channel = doc->GetChannel();
7887
0
    if (channel) {
7888
0
      mIsRestoringDocument = true;
7889
0
      mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
7890
0
      mIsRestoringDocument = false;
7891
0
    }
7892
0
  }
7893
0
7894
0
  return NS_OK;
7895
0
}
7896
7897
NS_IMETHODIMP
7898
nsDocShell::GetRestoringDocument(bool* aRestoring)
7899
0
{
7900
0
  *aRestoring = mIsRestoringDocument;
7901
0
  return NS_OK;
7902
0
}
7903
7904
nsresult
7905
nsDocShell::RestorePresentation(nsISHEntry* aSHEntry, bool* aRestoring)
7906
0
{
7907
0
  MOZ_ASSERT(!mIsBeingDestroyed);
7908
0
7909
0
  NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
7910
0
               "RestorePresentation should only be called for history loads");
7911
0
7912
0
  nsCOMPtr<nsIContentViewer> viewer = aSHEntry->GetContentViewer();
7913
0
7914
#ifdef DEBUG_PAGE_CACHE
7915
  nsCOMPtr<nsIURI> uri = aSHEntry->GetURI();
7916
7917
  nsAutoCString spec;
7918
  if (uri) {
7919
    uri->GetSpec(spec);
7920
  }
7921
#endif
7922
7923
0
  *aRestoring = false;
7924
0
7925
0
  if (!viewer) {
7926
#ifdef DEBUG_PAGE_CACHE
7927
    printf("no saved presentation for uri: %s\n", spec.get());
7928
#endif
7929
    return NS_OK;
7930
0
  }
7931
0
7932
0
  // We need to make sure the content viewer's container is this docshell.
7933
0
  // In subframe navigation, it's possible for the docshell that the
7934
0
  // content viewer was originally loaded into to be replaced with a
7935
0
  // different one.  We don't currently support restoring the presentation
7936
0
  // in that case.
7937
0
7938
0
  nsCOMPtr<nsIDocShell> container;
7939
0
  viewer->GetContainer(getter_AddRefs(container));
7940
0
  if (!::SameCOMIdentity(container, GetAsSupports(this))) {
7941
#ifdef DEBUG_PAGE_CACHE
7942
    printf("No valid container, clearing presentation\n");
7943
#endif
7944
    aSHEntry->SetContentViewer(nullptr);
7945
0
    return NS_ERROR_FAILURE;
7946
0
  }
7947
0
7948
0
  NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
7949
0
7950
#ifdef DEBUG_PAGE_CACHE
7951
  printf("restoring presentation from session history: %s\n", spec.get());
7952
#endif
7953
7954
0
  SetHistoryEntry(&mLSHE, aSHEntry);
7955
0
7956
0
  // Post an event that will remove the request after we've returned
7957
0
  // to the event loop.  This mimics the way it is called by nsIChannel
7958
0
  // implementations.
7959
0
7960
0
  // Revoke any pending restore (just in case)
7961
0
  NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
7962
0
               "should only have one RestorePresentationEvent");
7963
0
  mRestorePresentationEvent.Revoke();
7964
0
7965
0
  RefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
7966
0
  nsresult rv = DispatchToTabGroup(TaskCategory::Other,
7967
0
                                   RefPtr<RestorePresentationEvent>(evt).forget());
7968
0
  if (NS_SUCCEEDED(rv)) {
7969
0
    mRestorePresentationEvent = evt.get();
7970
0
    // The rest of the restore processing will happen on our event
7971
0
    // callback.
7972
0
    *aRestoring = true;
7973
0
  }
7974
0
7975
0
  return rv;
7976
0
}
7977
7978
namespace {
7979
class MOZ_STACK_CLASS PresentationEventForgetter
7980
{
7981
public:
7982
  explicit PresentationEventForgetter(
7983
        nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
7984
          aRestorePresentationEvent)
7985
    : mRestorePresentationEvent(aRestorePresentationEvent)
7986
    , mEvent(aRestorePresentationEvent.get())
7987
0
  {
7988
0
  }
7989
7990
  ~PresentationEventForgetter()
7991
0
  {
7992
0
    Forget();
7993
0
  }
7994
7995
  void Forget()
7996
0
  {
7997
0
    if (mRestorePresentationEvent.get() == mEvent) {
7998
0
      mRestorePresentationEvent.Forget();
7999
0
      mEvent = nullptr;
8000
0
    }
8001
0
  }
8002
8003
private:
8004
  nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
8005
    mRestorePresentationEvent;
8006
  RefPtr<nsDocShell::RestorePresentationEvent> mEvent;
8007
};
8008
8009
} // namespace
8010
8011
bool
8012
nsDocShell::SandboxFlagsImplyCookies(const uint32_t &aSandboxFlags)
8013
0
{
8014
0
  return (aSandboxFlags & (SANDBOXED_ORIGIN | SANDBOXED_SCRIPTS)) == 0;
8015
0
}
8016
8017
nsresult
8018
nsDocShell::RestoreFromHistory()
8019
0
{
8020
0
  MOZ_ASSERT(mRestorePresentationEvent.IsPending());
8021
0
  PresentationEventForgetter forgetter(mRestorePresentationEvent);
8022
0
8023
0
  // This section of code follows the same ordering as CreateContentViewer.
8024
0
  if (!mLSHE) {
8025
0
    return NS_ERROR_FAILURE;
8026
0
  }
8027
0
8028
0
  nsCOMPtr<nsIContentViewer> viewer = mLSHE->GetContentViewer();
8029
0
  if (!viewer) {
8030
0
    return NS_ERROR_FAILURE;
8031
0
  }
8032
0
8033
0
  if (mSavingOldViewer) {
8034
0
    // We determined that it was safe to cache the document presentation
8035
0
    // at the time we initiated the new load.  We need to check whether
8036
0
    // it's still safe to do so, since there may have been DOM mutations
8037
0
    // or new requests initiated.
8038
0
    nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
8039
0
    nsIRequest* request = nullptr;
8040
0
    if (doc) {
8041
0
      request = doc->GetChannel();
8042
0
    }
8043
0
    mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
8044
0
  }
8045
0
8046
0
  nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
8047
0
  nsCOMPtr<nsIContentViewer> newCv(viewer);
8048
0
  int32_t minFontSize = 0;
8049
0
  float textZoom = 1.0f;
8050
0
  float pageZoom = 1.0f;
8051
0
  float overrideDPPX = 0.0f;
8052
0
8053
0
  bool styleDisabled = false;
8054
0
  if (oldCv && newCv) {
8055
0
    oldCv->GetMinFontSize(&minFontSize);
8056
0
    oldCv->GetTextZoom(&textZoom);
8057
0
    oldCv->GetFullZoom(&pageZoom);
8058
0
    oldCv->GetOverrideDPPX(&overrideDPPX);
8059
0
    oldCv->GetAuthorStyleDisabled(&styleDisabled);
8060
0
  }
8061
0
8062
0
  // Protect against mLSHE going away via a load triggered from
8063
0
  // pagehide or unload.
8064
0
  nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
8065
0
8066
0
  // Make sure to blow away our mLoadingURI just in case.  No loads
8067
0
  // from inside this pagehide.
8068
0
  mLoadingURI = nullptr;
8069
0
8070
0
  // Notify the old content viewer that it's being hidden.
8071
0
  FirePageHideNotification(!mSavingOldViewer);
8072
0
  // pagehide notification might destroy this docshell.
8073
0
  if (mIsBeingDestroyed) {
8074
0
    return NS_ERROR_DOCSHELL_DYING;
8075
0
  }
8076
0
8077
0
  // If mLSHE was changed as a result of the pagehide event, then
8078
0
  // something else was loaded.  Don't finish restoring.
8079
0
  if (mLSHE != origLSHE) {
8080
0
    return NS_OK;
8081
0
  }
8082
0
8083
0
  // Add the request to our load group.  We do this before swapping out
8084
0
  // the content viewers so that consumers of STATE_START can access
8085
0
  // the old document.  We only deal with the toplevel load at this time --
8086
0
  // to be consistent with normal document loading, subframes cannot start
8087
0
  // loading until after data arrives, which is after STATE_START completes.
8088
0
8089
0
  RefPtr<RestorePresentationEvent> currentPresentationRestoration =
8090
0
    mRestorePresentationEvent.get();
8091
0
  Stop();
8092
0
  // Make sure we're still restoring the same presentation.
8093
0
  // If we aren't, docshell is in process doing another load already.
8094
0
  NS_ENSURE_STATE(currentPresentationRestoration ==
8095
0
                  mRestorePresentationEvent.get());
8096
0
  BeginRestore(viewer, true);
8097
0
  NS_ENSURE_STATE(currentPresentationRestoration ==
8098
0
                  mRestorePresentationEvent.get());
8099
0
  forgetter.Forget();
8100
0
8101
0
  // Set mFiredUnloadEvent = false so that the unload handler for the
8102
0
  // *new* document will fire.
8103
0
  mFiredUnloadEvent = false;
8104
0
8105
0
  mURIResultedInDocument = true;
8106
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
8107
0
  if (rootSH) {
8108
0
    mPreviousEntryIndex = rootSH->Index();
8109
0
    rootSH->LegacySHistory()->UpdateIndex();
8110
0
    mLoadedEntryIndex = rootSH->Index();
8111
#ifdef DEBUG_PAGE_CACHE
8112
    printf("Previous index: %d, Loaded index: %d\n\n", mPreviousEntryIndex,
8113
           mLoadedEntryIndex);
8114
#endif
8115
  }
8116
0
8117
0
  // Rather than call Embed(), we will retrieve the viewer from the session
8118
0
  // history entry and swap it in.
8119
0
  // XXX can we refactor this so that we can just call Embed()?
8120
0
  PersistLayoutHistoryState();
8121
0
  nsresult rv;
8122
0
  if (mContentViewer) {
8123
0
    if (mSavingOldViewer && NS_FAILED(CaptureState())) {
8124
0
      if (mOSHE) {
8125
0
        mOSHE->SyncPresentationState();
8126
0
      }
8127
0
      mSavingOldViewer = false;
8128
0
    }
8129
0
  }
8130
0
8131
0
  mSavedRefreshURIList = nullptr;
8132
0
8133
0
  // In cases where we use a transient about:blank viewer between loads,
8134
0
  // we never show the transient viewer, so _its_ previous viewer is never
8135
0
  // unhooked from the view hierarchy.  Destroy any such previous viewer now,
8136
0
  // before we grab the root view sibling, so that we don't grab a view
8137
0
  // that's about to go away.
8138
0
8139
0
  if (mContentViewer) {
8140
0
    nsCOMPtr<nsIContentViewer> previousViewer;
8141
0
    mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
8142
0
    if (previousViewer) {
8143
0
      mContentViewer->SetPreviousViewer(nullptr);
8144
0
      previousViewer->Destroy();
8145
0
    }
8146
0
  }
8147
0
8148
0
  // Save off the root view's parent and sibling so that we can insert the
8149
0
  // new content viewer's root view at the same position.  Also save the
8150
0
  // bounds of the root view's widget.
8151
0
8152
0
  nsView* rootViewSibling = nullptr;
8153
0
  nsView* rootViewParent = nullptr;
8154
0
  nsIntRect newBounds(0, 0, 0, 0);
8155
0
8156
0
  nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
8157
0
  if (oldPresShell) {
8158
0
    nsViewManager* vm = oldPresShell->GetViewManager();
8159
0
    if (vm) {
8160
0
      nsView* oldRootView = vm->GetRootView();
8161
0
8162
0
      if (oldRootView) {
8163
0
        rootViewSibling = oldRootView->GetNextSibling();
8164
0
        rootViewParent = oldRootView->GetParent();
8165
0
8166
0
        mContentViewer->GetBounds(newBounds);
8167
0
      }
8168
0
    }
8169
0
  }
8170
0
8171
0
  nsCOMPtr<nsIContent> container;
8172
0
  nsCOMPtr<nsIDocument> sibling;
8173
0
  if (rootViewParent && rootViewParent->GetParent()) {
8174
0
    nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
8175
0
    container = frame ? frame->GetContent() : nullptr;
8176
0
  }
8177
0
  if (rootViewSibling) {
8178
0
    nsIFrame* frame = rootViewSibling->GetFrame();
8179
0
    sibling =
8180
0
      frame ? frame->PresShell()->GetDocument() : nullptr;
8181
0
  }
8182
0
8183
0
  // Transfer ownership to mContentViewer.  By ensuring that either the
8184
0
  // docshell or the session history, but not both, have references to the
8185
0
  // content viewer, we prevent the viewer from being torn down after
8186
0
  // Destroy() is called.
8187
0
8188
0
  if (mContentViewer) {
8189
0
    mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
8190
0
    viewer->SetPreviousViewer(mContentViewer);
8191
0
  }
8192
0
  if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
8193
0
    // We don't plan to save a viewer in mOSHE; tell it to drop
8194
0
    // any other state it's holding.
8195
0
    mOSHE->SyncPresentationState();
8196
0
  }
8197
0
8198
0
  // Order the mContentViewer setup just like Embed does.
8199
0
  mContentViewer = nullptr;
8200
0
8201
0
  // Now that we're about to switch documents, forget all of our children.
8202
0
  // Note that we cached them as needed up in CaptureState above.
8203
0
  DestroyChildren();
8204
0
8205
0
  mContentViewer.swap(viewer);
8206
0
8207
0
  // Grab all of the related presentation from the SHEntry now.
8208
0
  // Clearing the viewer from the SHEntry will clear all of this state.
8209
0
  nsCOMPtr<nsISupports> windowState = mLSHE->GetWindowState();
8210
0
  mLSHE->SetWindowState(nullptr);
8211
0
8212
0
  bool sticky = mLSHE->GetSticky();
8213
0
8214
0
  nsCOMPtr<nsIDocument> document = mContentViewer->GetDocument();
8215
0
8216
0
  nsCOMArray<nsIDocShellTreeItem> childShells;
8217
0
  int32_t i = 0;
8218
0
  nsCOMPtr<nsIDocShellTreeItem> child;
8219
0
  while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
8220
0
         child) {
8221
0
    childShells.AppendObject(child);
8222
0
  }
8223
0
8224
0
  // get the previous content viewer size
8225
0
  nsIntRect oldBounds(0, 0, 0, 0);
8226
0
  mLSHE->GetViewerBounds(oldBounds);
8227
0
8228
0
  // Restore the refresh URI list.  The refresh timers will be restarted
8229
0
  // when EndPageLoad() is called.
8230
0
  nsCOMPtr<nsIMutableArray> refreshURIList = mLSHE->GetRefreshURIList();
8231
0
8232
0
  // Reattach to the window object.
8233
0
  mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
8234
0
  rv = mContentViewer->Open(windowState, mLSHE);
8235
0
  mIsRestoringDocument = false;
8236
0
8237
0
  // Hack to keep nsDocShellEditorData alive across the
8238
0
  // SetContentViewer(nullptr) call below.
8239
0
  nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
8240
0
8241
0
  // Now remove it from the cached presentation.
8242
0
  mLSHE->SetContentViewer(nullptr);
8243
0
  mEODForCurrentDocument = false;
8244
0
8245
0
  mLSHE->SetEditorData(data.forget());
8246
0
8247
#ifdef DEBUG
8248
  {
8249
    nsCOMPtr<nsIMutableArray> refreshURIs = mLSHE->GetRefreshURIList();
8250
    nsCOMPtr<nsIDocShellTreeItem> childShell;
8251
    mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
8252
    NS_ASSERTION(!refreshURIs && !childShell,
8253
                 "SHEntry should have cleared presentation state");
8254
  }
8255
#endif
8256
8257
0
  // Restore the sticky state of the viewer.  The viewer has set this state
8258
0
  // on the history entry in Destroy() just before marking itself non-sticky,
8259
0
  // to avoid teardown of the presentation.
8260
0
  mContentViewer->SetSticky(sticky);
8261
0
8262
0
  NS_ENSURE_SUCCESS(rv, rv);
8263
0
8264
0
  // mLSHE is now our currently-loaded document.
8265
0
  SetHistoryEntry(&mOSHE, mLSHE);
8266
0
8267
0
  // XXX special wyciwyg handling in Embed()?
8268
0
8269
0
  // We aren't going to restore any items from the LayoutHistoryState,
8270
0
  // but we don't want them to stay around in case the page is reloaded.
8271
0
  SetLayoutHistoryState(nullptr);
8272
0
8273
0
  // This is the end of our Embed() replacement
8274
0
8275
0
  mSavingOldViewer = false;
8276
0
  mEODForCurrentDocument = false;
8277
0
8278
0
  // Tell the event loop to favor plevents over user events, see comments
8279
0
  // in CreateContentViewer.
8280
0
  if (++gNumberOfDocumentsLoading == 1) {
8281
0
    FavorPerformanceHint(true);
8282
0
  }
8283
0
8284
0
  if (oldCv && newCv) {
8285
0
    newCv->SetMinFontSize(minFontSize);
8286
0
    newCv->SetTextZoom(textZoom);
8287
0
    newCv->SetFullZoom(pageZoom);
8288
0
    newCv->SetOverrideDPPX(overrideDPPX);
8289
0
    newCv->SetAuthorStyleDisabled(styleDisabled);
8290
0
  }
8291
0
8292
0
  if (document) {
8293
0
    RefPtr<nsDocShell> parent = GetParentDocshell();
8294
0
    if (parent) {
8295
0
      nsCOMPtr<nsIDocument> d = parent->GetDocument();
8296
0
      if (d) {
8297
0
        if (d->EventHandlingSuppressed()) {
8298
0
          document->SuppressEventHandling(d->EventHandlingSuppressed());
8299
0
        }
8300
0
      }
8301
0
    }
8302
0
8303
0
    // Use the uri from the mLSHE we had when we entered this function
8304
0
    // (which need not match the document's URI if anchors are involved),
8305
0
    // since that's the history entry we're loading.  Note that if we use
8306
0
    // origLSHE we don't have to worry about whether the entry in question
8307
0
    // is still mLSHE or whether it's now mOSHE.
8308
0
    nsCOMPtr<nsIURI> uri = origLSHE->GetURI();
8309
0
    SetCurrentURI(uri, document->GetChannel(), true, 0);
8310
0
  }
8311
0
8312
0
  // This is the end of our CreateContentViewer() replacement.
8313
0
  // Now we simulate a load.  First, we restore the state of the javascript
8314
0
  // window object.
8315
0
  nsCOMPtr<nsPIDOMWindowOuter> privWin = GetWindow();
8316
0
  NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
8317
0
8318
0
  // Now, dispatch a title change event which would happen as the
8319
0
  // <head> is parsed.
8320
0
  document->NotifyPossibleTitleChange(false);
8321
0
8322
0
  // Now we simulate appending child docshells for subframes.
8323
0
  for (i = 0; i < childShells.Count(); ++i) {
8324
0
    nsIDocShellTreeItem* childItem = childShells.ObjectAt(i);
8325
0
    nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
8326
0
8327
0
    // Make sure to not clobber the state of the child.  Since AddChild
8328
0
    // always clobbers it, save it off first.
8329
0
    bool allowPlugins;
8330
0
    childShell->GetAllowPlugins(&allowPlugins);
8331
0
8332
0
    bool allowJavascript;
8333
0
    childShell->GetAllowJavascript(&allowJavascript);
8334
0
8335
0
    bool allowRedirects;
8336
0
    childShell->GetAllowMetaRedirects(&allowRedirects);
8337
0
8338
0
    bool allowSubframes;
8339
0
    childShell->GetAllowSubframes(&allowSubframes);
8340
0
8341
0
    bool allowImages;
8342
0
    childShell->GetAllowImages(&allowImages);
8343
0
8344
0
    bool allowMedia = childShell->GetAllowMedia();
8345
0
8346
0
    bool allowDNSPrefetch;
8347
0
    childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
8348
0
8349
0
    bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
8350
0
    bool allowContentRetargetingOnChildren =
8351
0
      childShell->GetAllowContentRetargetingOnChildren();
8352
0
8353
0
    uint32_t defaultLoadFlags;
8354
0
    childShell->GetDefaultLoadFlags(&defaultLoadFlags);
8355
0
8356
0
    // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
8357
0
    // the child inherits our state. Among other things, this means that the
8358
0
    // child inherits our mIsActive mPrivateBrowsingId, which is what we want.
8359
0
    AddChild(childItem);
8360
0
8361
0
    childShell->SetAllowPlugins(allowPlugins);
8362
0
    childShell->SetAllowJavascript(allowJavascript);
8363
0
    childShell->SetAllowMetaRedirects(allowRedirects);
8364
0
    childShell->SetAllowSubframes(allowSubframes);
8365
0
    childShell->SetAllowImages(allowImages);
8366
0
    childShell->SetAllowMedia(allowMedia);
8367
0
    childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
8368
0
    childShell->SetAllowContentRetargeting(allowContentRetargeting);
8369
0
    childShell->SetAllowContentRetargetingOnChildren(
8370
0
      allowContentRetargetingOnChildren);
8371
0
    childShell->SetDefaultLoadFlags(defaultLoadFlags);
8372
0
8373
0
    rv = childShell->BeginRestore(nullptr, false);
8374
0
    NS_ENSURE_SUCCESS(rv, rv);
8375
0
  }
8376
0
8377
0
  // Make sure to restore the window state after adding the child shells back
8378
0
  // to the tree.  This is necessary for Thaw() and Resume() to propagate
8379
0
  // properly.
8380
0
  rv = privWin->RestoreWindowState(windowState);
8381
0
  NS_ENSURE_SUCCESS(rv, rv);
8382
0
8383
0
  nsCOMPtr<nsIPresShell> shell = GetPresShell();
8384
0
8385
0
  // We may be displayed on a different monitor (or in a different
8386
0
  // HiDPI mode) than when we got into the history list.  So we need
8387
0
  // to check if this has happened. See bug 838239.
8388
0
8389
0
  // Because the prescontext normally handles resolution changes via
8390
0
  // a runnable (see nsPresContext::UIResolutionChanged), its device
8391
0
  // context won't be -immediately- updated as a result of calling
8392
0
  // shell->BackingScaleFactorChanged().
8393
0
8394
0
  // But we depend on that device context when adjusting the view size
8395
0
  // via mContentViewer->SetBounds(newBounds) below. So we need to
8396
0
  // explicitly tell it to check for changed resolution here.
8397
0
  if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
8398
0
    shell->BackingScaleFactorChanged();
8399
0
  }
8400
0
8401
0
  nsViewManager* newVM = shell ? shell->GetViewManager() : nullptr;
8402
0
  nsView* newRootView = newVM ? newVM->GetRootView() : nullptr;
8403
0
8404
0
  // Insert the new root view at the correct location in the view tree.
8405
0
  if (container) {
8406
0
    nsSubDocumentFrame* subDocFrame =
8407
0
      do_QueryFrame(container->GetPrimaryFrame());
8408
0
    rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
8409
0
  } else {
8410
0
    rootViewParent = nullptr;
8411
0
  }
8412
0
  if (sibling &&
8413
0
      sibling->GetShell() &&
8414
0
      sibling->GetShell()->GetViewManager()) {
8415
0
    rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
8416
0
  } else {
8417
0
    rootViewSibling = nullptr;
8418
0
  }
8419
0
  if (rootViewParent && newRootView &&
8420
0
      newRootView->GetParent() != rootViewParent) {
8421
0
    nsViewManager* parentVM = rootViewParent->GetViewManager();
8422
0
    if (parentVM) {
8423
0
      // InsertChild(parent, child, sib, true) inserts the child after
8424
0
      // sib in content order, which is before sib in view order. BUT
8425
0
      // when sib is null it inserts at the end of the the document
8426
0
      // order, i.e., first in view order.  But when oldRootSibling is
8427
0
      // null, the old root as at the end of the view list --- last in
8428
0
      // content order --- and we want to call InsertChild(parent, child,
8429
0
      // nullptr, false) in that case.
8430
0
      parentVM->InsertChild(rootViewParent, newRootView,
8431
0
                            rootViewSibling,
8432
0
                            rootViewSibling ? true : false);
8433
0
8434
0
      NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
8435
0
                   "error in InsertChild");
8436
0
    }
8437
0
  }
8438
0
8439
0
  nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow();
8440
0
8441
0
  // If parent is suspended, increase suspension count.
8442
0
  // This can't be done as early as event suppression since this
8443
0
  // depends on docshell tree.
8444
0
  privWinInner->SyncStateFromParentWindow();
8445
0
8446
0
  // Now that all of the child docshells have been put into place, we can
8447
0
  // restart the timers for the window and all of the child frames.
8448
0
  privWinInner->Resume();
8449
0
8450
0
  // Restore the refresh URI list.  The refresh timers will be restarted
8451
0
  // when EndPageLoad() is called.
8452
0
  mRefreshURIList = refreshURIList;
8453
0
8454
0
  // Meta-refresh timers have been restarted for this shell, but not
8455
0
  // for our children.  Walk the child shells and restart their timers.
8456
0
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
8457
0
  while (iter.HasMore()) {
8458
0
    nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
8459
0
    if (child) {
8460
0
      child->ResumeRefreshURIs();
8461
0
    }
8462
0
  }
8463
0
8464
0
  // Make sure this presentation is the same size as the previous
8465
0
  // presentation.  If this is not the same size we showed it at last time,
8466
0
  // then we need to resize the widget.
8467
0
8468
0
  // XXXbryner   This interacts poorly with Firefox's infobar.  If the old
8469
0
  // presentation had the infobar visible, then we will resize the new
8470
0
  // presentation to that smaller size.  However, firing the locationchanged
8471
0
  // event will hide the infobar, which will immediately resize the window
8472
0
  // back to the larger size.  A future optimization might be to restore
8473
0
  // the presentation at the "wrong" size, then fire the locationchanged
8474
0
  // event and check whether the docshell's new size is the same as the
8475
0
  // cached viewer size (skipping the resize if they are equal).
8476
0
8477
0
  if (newRootView) {
8478
0
    if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
8479
#ifdef DEBUG_PAGE_CACHE
8480
      printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
8481
             newBounds.y, newBounds.width, newBounds.height);
8482
#endif
8483
      mContentViewer->SetBounds(newBounds);
8484
0
    } else {
8485
0
      nsIScrollableFrame* rootScrollFrame =
8486
0
        shell->GetRootScrollFrameAsScrollable();
8487
0
      if (rootScrollFrame) {
8488
0
        rootScrollFrame->PostScrolledAreaEventForCurrentArea();
8489
0
      }
8490
0
    }
8491
0
  }
8492
0
8493
0
  // The FinishRestore call below can kill these, null them out so we don't
8494
0
  // have invalid pointer lying around.
8495
0
  newRootView = rootViewSibling = rootViewParent = nullptr;
8496
0
  newVM = nullptr;
8497
0
8498
0
  // Simulate the completion of the load.
8499
0
  nsDocShell::FinishRestore();
8500
0
8501
0
  // Restart plugins, and paint the content.
8502
0
  if (shell) {
8503
0
    shell->Thaw();
8504
0
  }
8505
0
8506
0
  return privWin->FireDelayedDOMEvents();
8507
0
}
8508
8509
nsresult
8510
nsDocShell::CreateContentViewer(const nsACString& aContentType,
8511
                                nsIRequest* aRequest,
8512
                                nsIStreamListener** aContentHandler)
8513
0
{
8514
0
  *aContentHandler = nullptr;
8515
0
8516
0
  if (!mTreeOwner || mIsBeingDestroyed) {
8517
0
    // If we don't have a tree owner, then we're in the process of being
8518
0
    // destroyed. Rather than continue trying to load something, just give up.
8519
0
    return NS_ERROR_DOCSHELL_DYING;
8520
0
  }
8521
0
8522
0
  // Can we check the content type of the current content viewer
8523
0
  // and reuse it without destroying it and re-creating it?
8524
0
8525
0
  NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
8526
0
8527
0
  // Instantiate the content viewer object
8528
0
  nsCOMPtr<nsIContentViewer> viewer;
8529
0
  nsresult rv = NewContentViewerObj(aContentType, aRequest, mLoadGroup,
8530
0
                                    aContentHandler, getter_AddRefs(viewer));
8531
0
8532
0
  if (NS_FAILED(rv)) {
8533
0
    return rv;
8534
0
  }
8535
0
8536
0
  // Notify the current document that it is about to be unloaded!!
8537
0
  //
8538
0
  // It is important to fire the unload() notification *before* any state
8539
0
  // is changed within the DocShell - otherwise, javascript will get the
8540
0
  // wrong information :-(
8541
0
  //
8542
0
8543
0
  if (mSavingOldViewer) {
8544
0
    // We determined that it was safe to cache the document presentation
8545
0
    // at the time we initiated the new load.  We need to check whether
8546
0
    // it's still safe to do so, since there may have been DOM mutations
8547
0
    // or new requests initiated.
8548
0
    nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
8549
0
    mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc);
8550
0
  }
8551
0
8552
0
  NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
8553
0
8554
0
  nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
8555
0
  if (aOpenedChannel) {
8556
0
    aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
8557
0
  }
8558
0
  FirePageHideNotification(!mSavingOldViewer);
8559
0
  if (mIsBeingDestroyed) {
8560
0
    // Force to stop the newly created orphaned viewer.
8561
0
    viewer->Stop();
8562
0
    return NS_ERROR_DOCSHELL_DYING;
8563
0
  }
8564
0
  mLoadingURI = nullptr;
8565
0
8566
0
  // Set mFiredUnloadEvent = false so that the unload handler for the
8567
0
  // *new* document will fire.
8568
0
  mFiredUnloadEvent = false;
8569
0
8570
0
  // we've created a new document so go ahead and call
8571
0
  // OnLoadingSite(), but don't fire OnLocationChange()
8572
0
  // notifications before we've called Embed(). See bug 284993.
8573
0
  mURIResultedInDocument = true;
8574
0
  bool errorOnLocationChangeNeeded = false;
8575
0
  nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
8576
0
  nsCOMPtr<nsIURI> failedURI;
8577
0
8578
0
  if (mLoadType == LOAD_ERROR_PAGE) {
8579
0
    // We need to set the SH entry and our current URI here and not
8580
0
    // at the moment we load the page. We want the same behavior
8581
0
    // of Stop() as for a normal page load. See bug 514232 for details.
8582
0
8583
0
    // Revert mLoadType to load type to state the page load failed,
8584
0
    // following function calls need it.
8585
0
    mLoadType = mFailedLoadType;
8586
0
8587
0
8588
0
    nsIDocument* doc = viewer->GetDocument();
8589
0
    if (doc) {
8590
0
      doc->SetFailedChannel(failedChannel);
8591
0
    }
8592
0
8593
0
    nsCOMPtr<nsIPrincipal> triggeringPrincipal;
8594
0
    if (failedChannel) {
8595
0
      // Make sure we have a URI to set currentURI.
8596
0
      NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
8597
0
    }
8598
0
     else {
8599
0
       // if there is no failed channel we have to explicitly provide
8600
0
       // a triggeringPrincipal for the history entry.
8601
0
       triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
8602
0
    }
8603
0
8604
0
    if (!failedURI) {
8605
0
      failedURI = mFailedURI;
8606
0
    }
8607
0
    if (!failedURI) {
8608
0
      // We need a URI object to store a session history entry, so make up a URI
8609
0
      NS_NewURI(getter_AddRefs(failedURI), "about:blank");
8610
0
    }
8611
0
8612
0
    // When we don't have failedURI, something wrong will happen. See
8613
0
    // bug 291876.
8614
0
    MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
8615
0
8616
0
    mFailedChannel = nullptr;
8617
0
    mFailedURI = nullptr;
8618
0
8619
0
    // Create an shistory entry for the old load.
8620
0
    if (failedURI) {
8621
0
      errorOnLocationChangeNeeded = OnNewURI(
8622
0
        failedURI, failedChannel, triggeringPrincipal,
8623
0
        nullptr, mLoadType, false, false, false);
8624
0
    }
8625
0
8626
0
    // Be sure to have a correct mLSHE, it may have been cleared by
8627
0
    // EndPageLoad. See bug 302115.
8628
0
    if (mSessionHistory && !mLSHE) {
8629
0
      int32_t idx = mSessionHistory->LegacySHistory()->GetRequestedIndex();
8630
0
      if (idx == -1) {
8631
0
        idx = mSessionHistory->Index();
8632
0
      }
8633
0
      mSessionHistory->LegacySHistory()->
8634
0
        GetEntryAtIndex(idx, getter_AddRefs(mLSHE));
8635
0
    }
8636
0
8637
0
    mLoadType = LOAD_ERROR_PAGE;
8638
0
  }
8639
0
8640
0
  bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
8641
0
8642
0
  // let's try resetting the load group if we need to...
8643
0
  nsCOMPtr<nsILoadGroup> currentLoadGroup;
8644
0
  NS_ENSURE_SUCCESS(
8645
0
    aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),
8646
0
    NS_ERROR_FAILURE);
8647
0
8648
0
  if (currentLoadGroup != mLoadGroup) {
8649
0
    nsLoadFlags loadFlags = 0;
8650
0
8651
0
    // Cancel any URIs that are currently loading...
8652
0
    // XXX: Need to do this eventually      Stop();
8653
0
    //
8654
0
    // Retarget the document to this loadgroup...
8655
0
    //
8656
0
    /* First attach the channel to the right loadgroup
8657
0
     * and then remove from the old loadgroup. This
8658
0
     * puts the notifications in the right order and
8659
0
     * we don't null-out mLSHE in OnStateChange() for
8660
0
     * all redirected urls
8661
0
     */
8662
0
    aOpenedChannel->SetLoadGroup(mLoadGroup);
8663
0
8664
0
    // Mark the channel as being a document URI...
8665
0
    aOpenedChannel->GetLoadFlags(&loadFlags);
8666
0
    loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
8667
0
    if (SandboxFlagsImplyCookies(mSandboxFlags)) {
8668
0
      loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
8669
0
    }
8670
0
8671
0
    aOpenedChannel->SetLoadFlags(loadFlags);
8672
0
8673
0
    mLoadGroup->AddRequest(aRequest, nullptr);
8674
0
    if (currentLoadGroup) {
8675
0
      currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED);
8676
0
    }
8677
0
8678
0
    // Update the notification callbacks, so that progress and
8679
0
    // status information are sent to the right docshell...
8680
0
    aOpenedChannel->SetNotificationCallbacks(this);
8681
0
  }
8682
0
8683
0
  NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE);
8684
0
8685
0
  mSavedRefreshURIList = nullptr;
8686
0
  mSavingOldViewer = false;
8687
0
  mEODForCurrentDocument = false;
8688
0
8689
0
  // if this document is part of a multipart document,
8690
0
  // the ID can be used to distinguish it from the other parts.
8691
0
  nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
8692
0
  if (multiPartChannel) {
8693
0
    nsCOMPtr<nsIPresShell> shell = GetPresShell();
8694
0
    if (NS_SUCCEEDED(rv) && shell) {
8695
0
      nsIDocument* doc = shell->GetDocument();
8696
0
      if (doc) {
8697
0
        uint32_t partID;
8698
0
        multiPartChannel->GetPartID(&partID);
8699
0
        doc->SetPartID(partID);
8700
0
      }
8701
0
    }
8702
0
  }
8703
0
8704
0
  // Give hint to native plevent dispatch mechanism. If a document
8705
0
  // is loading the native plevent dispatch mechanism should favor
8706
0
  // performance over normal native event dispatch priorities.
8707
0
  if (++gNumberOfDocumentsLoading == 1) {
8708
0
    // Hint to favor performance for the plevent notification mechanism.
8709
0
    // We want the pages to load as fast as possible even if its means
8710
0
    // native messages might be starved.
8711
0
    FavorPerformanceHint(true);
8712
0
  }
8713
0
8714
0
  if (errorOnLocationChangeNeeded){
8715
0
    FireOnLocationChange(this, failedChannel, failedURI,
8716
0
                         LOCATION_CHANGE_ERROR_PAGE);
8717
0
  } else if (onLocationChangeNeeded) {
8718
0
    FireOnLocationChange(this, aRequest, mCurrentURI, 0);
8719
0
  }
8720
0
8721
0
  return NS_OK;
8722
0
}
8723
8724
nsresult
8725
nsDocShell::NewContentViewerObj(const nsACString& aContentType,
8726
                                nsIRequest* aRequest, nsILoadGroup* aLoadGroup,
8727
                                nsIStreamListener** aContentHandler,
8728
                                nsIContentViewer** aViewer)
8729
0
{
8730
0
  nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
8731
0
8732
0
  nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
8733
0
    nsContentUtils::FindInternalContentViewer(aContentType);
8734
0
  if (!docLoaderFactory) {
8735
0
    return NS_ERROR_FAILURE;
8736
0
  }
8737
0
8738
0
  // Now create an instance of the content viewer nsLayoutDLF makes the
8739
0
  // determination if it should be a "view-source" instead of "view"
8740
0
  nsresult rv = docLoaderFactory->CreateInstance("view",
8741
0
                                                 aOpenedChannel,
8742
0
                                                 aLoadGroup, aContentType,
8743
0
                                                 this,
8744
0
                                                 nullptr,
8745
0
                                                 aContentHandler,
8746
0
                                                 aViewer);
8747
0
  NS_ENSURE_SUCCESS(rv, rv);
8748
0
8749
0
  (*aViewer)->SetContainer(this);
8750
0
  return NS_OK;
8751
0
}
8752
8753
nsresult
8754
nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer)
8755
0
{
8756
0
  MOZ_ASSERT(!mIsBeingDestroyed);
8757
0
8758
0
  //
8759
0
  // Copy content viewer state from previous or parent content viewer.
8760
0
  //
8761
0
  // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
8762
0
  //
8763
0
  // Do NOT to maintain a reference to the old content viewer outside
8764
0
  // of this "copying" block, or it will not be destroyed until the end of
8765
0
  // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
8766
0
  //
8767
0
  // In this block of code, if we get an error result, we return it
8768
0
  // but if we get a null pointer, that's perfectly legal for parent
8769
0
  // and parentContentViewer.
8770
0
  //
8771
0
8772
0
  int32_t x = 0;
8773
0
  int32_t y = 0;
8774
0
  int32_t cx = 0;
8775
0
  int32_t cy = 0;
8776
0
8777
0
  // This will get the size from the current content viewer or from the
8778
0
  // Init settings
8779
0
  DoGetPositionAndSize(&x, &y, &cx, &cy);
8780
0
8781
0
  nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
8782
0
  NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
8783
0
                    NS_ERROR_FAILURE);
8784
0
  nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
8785
0
8786
0
  const Encoding* forceCharset = nullptr;
8787
0
  const Encoding* hintCharset = nullptr;
8788
0
  int32_t hintCharsetSource;
8789
0
  int32_t minFontSize;
8790
0
  float textZoom;
8791
0
  float pageZoom;
8792
0
  float overrideDPPX;
8793
0
  bool styleDisabled;
8794
0
  // |newMUDV| also serves as a flag to set the data from the above vars
8795
0
  nsCOMPtr<nsIContentViewer> newCv;
8796
0
8797
0
  if (mContentViewer || parent) {
8798
0
    nsCOMPtr<nsIContentViewer> oldCv;
8799
0
    if (mContentViewer) {
8800
0
      // Get any interesting state from old content viewer
8801
0
      // XXX: it would be far better to just reuse the document viewer ,
8802
0
      //      since we know we're just displaying the same document as before
8803
0
      oldCv = mContentViewer;
8804
0
8805
0
      // Tell the old content viewer to hibernate in session history when
8806
0
      // it is destroyed.
8807
0
8808
0
      if (mSavingOldViewer && NS_FAILED(CaptureState())) {
8809
0
        if (mOSHE) {
8810
0
          mOSHE->SyncPresentationState();
8811
0
        }
8812
0
        mSavingOldViewer = false;
8813
0
      }
8814
0
    } else {
8815
0
      // No old content viewer, so get state from parent's content viewer
8816
0
      parent->GetContentViewer(getter_AddRefs(oldCv));
8817
0
    }
8818
0
8819
0
    if (oldCv) {
8820
0
      newCv = aNewViewer;
8821
0
      if (newCv) {
8822
0
        forceCharset = oldCv->GetForceCharset();
8823
0
        hintCharset = oldCv->GetHintCharset();
8824
0
        NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource),
8825
0
                          NS_ERROR_FAILURE);
8826
0
        NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize),
8827
0
                          NS_ERROR_FAILURE);
8828
0
        NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom),
8829
0
                          NS_ERROR_FAILURE);
8830
0
        NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom),
8831
0
                          NS_ERROR_FAILURE);
8832
0
        NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX),
8833
0
                          NS_ERROR_FAILURE);
8834
0
        NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled),
8835
0
                          NS_ERROR_FAILURE);
8836
0
      }
8837
0
    }
8838
0
  }
8839
0
8840
0
  nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
8841
0
  bool isActive = false;
8842
0
  // Ensure that the content viewer is destroyed *after* the GC - bug 71515
8843
0
  nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
8844
0
  if (contentViewer) {
8845
0
    // Stop any activity that may be happening in the old document before
8846
0
    // releasing it...
8847
0
    contentViewer->Stop();
8848
0
8849
0
    // Try to extract the canvas background color from the old
8850
0
    // presentation shell, so we can use it for the next document.
8851
0
    nsCOMPtr<nsIPresShell> shell;
8852
0
    contentViewer->GetPresShell(getter_AddRefs(shell));
8853
0
8854
0
    if (shell) {
8855
0
      bgcolor = shell->GetCanvasBackground();
8856
0
      isActive = shell->IsActive();
8857
0
    }
8858
0
8859
0
    contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
8860
0
    aNewViewer->SetPreviousViewer(contentViewer);
8861
0
  }
8862
0
  if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
8863
0
    // We don't plan to save a viewer in mOSHE; tell it to drop
8864
0
    // any other state it's holding.
8865
0
    mOSHE->SyncPresentationState();
8866
0
  }
8867
0
8868
0
  mContentViewer = nullptr;
8869
0
8870
0
  // Now that we're about to switch documents, forget all of our children.
8871
0
  // Note that we cached them as needed up in CaptureState above.
8872
0
  DestroyChildren();
8873
0
8874
0
  mContentViewer = aNewViewer;
8875
0
8876
0
  nsCOMPtr<nsIWidget> widget;
8877
0
  NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
8878
0
8879
0
  nsIntRect bounds(x, y, cx, cy);
8880
0
8881
0
  mContentViewer->SetNavigationTiming(mTiming);
8882
0
8883
0
  if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
8884
0
    mContentViewer = nullptr;
8885
0
    NS_WARNING("ContentViewer Initialization failed");
8886
0
    return NS_ERROR_FAILURE;
8887
0
  }
8888
0
8889
0
  // If we have old state to copy, set the old state onto the new content
8890
0
  // viewer
8891
0
  if (newCv) {
8892
0
    newCv->SetForceCharset(forceCharset);
8893
0
    newCv->SetHintCharset(hintCharset);
8894
0
    NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource),
8895
0
                      NS_ERROR_FAILURE);
8896
0
    NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize),
8897
0
                      NS_ERROR_FAILURE);
8898
0
    NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom),
8899
0
                      NS_ERROR_FAILURE);
8900
0
    NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom),
8901
0
                      NS_ERROR_FAILURE);
8902
0
    NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX),
8903
0
                      NS_ERROR_FAILURE);
8904
0
    NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
8905
0
                      NS_ERROR_FAILURE);
8906
0
  }
8907
0
8908
0
  // Stuff the bgcolor from the old pres shell into the new
8909
0
  // pres shell. This improves page load continuity.
8910
0
  nsCOMPtr<nsIPresShell> shell;
8911
0
  mContentViewer->GetPresShell(getter_AddRefs(shell));
8912
0
8913
0
  if (shell) {
8914
0
    shell->SetCanvasBackground(bgcolor);
8915
0
    if (isActive) {
8916
0
      shell->SetIsActive(isActive);
8917
0
    }
8918
0
  }
8919
0
8920
0
  // XXX: It looks like the LayoutState gets restored again in Embed()
8921
0
  //      right after the call to SetupNewViewer(...)
8922
0
8923
0
  // We don't show the mContentViewer yet, since we want to draw the old page
8924
0
  // until we have enough of the new page to show.  Just return with the new
8925
0
  // viewer still set to hidden.
8926
0
8927
0
  return NS_OK;
8928
0
}
8929
8930
nsresult
8931
nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry)
8932
0
{
8933
0
  NS_ENSURE_STATE(mContentViewer);
8934
0
  nsCOMPtr<nsIDocument> document = GetDocument();
8935
0
  NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
8936
0
8937
0
  nsCOMPtr<nsIStructuredCloneContainer> scContainer;
8938
0
  if (aShEntry) {
8939
0
    scContainer = aShEntry->GetStateData();
8940
0
8941
0
    // If aShEntry is null, just set the document's state object to null.
8942
0
  }
8943
0
8944
0
  // It's OK for scContainer too be null here; that just means there's no
8945
0
  // state data associated with this history entry.
8946
0
  document->SetStateObject(scContainer);
8947
0
8948
0
  return NS_OK;
8949
0
}
8950
8951
nsresult
8952
nsDocShell::CheckLoadingPermissions()
8953
0
{
8954
0
  // This method checks whether the caller may load content into
8955
0
  // this docshell. Even though we've done our best to hide windows
8956
0
  // from code that doesn't have the right to access them, it's
8957
0
  // still possible for an evil site to open a window and access
8958
0
  // frames in the new window through window.frames[] (which is
8959
0
  // allAccess for historic reasons), so we still need to do this
8960
0
  // check on load.
8961
0
  nsresult rv = NS_OK;
8962
0
8963
0
  if (!gValidateOrigin || !IsFrame()) {
8964
0
    // Origin validation was turned off, or we're not a frame.
8965
0
    // Permit all loads.
8966
0
8967
0
    return rv;
8968
0
  }
8969
0
8970
0
  // Note - The check for a current JSContext here isn't necessarily sensical.
8971
0
  // It's just designed to preserve the old semantics during a mass-conversion
8972
0
  // patch.
8973
0
  if (!nsContentUtils::GetCurrentJSContext()) {
8974
0
    return NS_OK;
8975
0
  }
8976
0
8977
0
  // Check if the caller is from the same origin as this docshell,
8978
0
  // or any of its ancestors.
8979
0
  nsCOMPtr<nsIDocShellTreeItem> item(this);
8980
0
  do {
8981
0
    nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(item);
8982
0
    nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
8983
0
8984
0
    nsIPrincipal* p;
8985
0
    if (!sop || !(p = sop->GetPrincipal())) {
8986
0
      return NS_ERROR_UNEXPECTED;
8987
0
    }
8988
0
8989
0
    if (nsContentUtils::SubjectPrincipal()->Subsumes(p)) {
8990
0
      // Same origin, permit load
8991
0
      return NS_OK;
8992
0
    }
8993
0
8994
0
    nsCOMPtr<nsIDocShellTreeItem> tmp;
8995
0
    item->GetSameTypeParent(getter_AddRefs(tmp));
8996
0
    item.swap(tmp);
8997
0
  } while (item);
8998
0
8999
0
  return NS_ERROR_DOM_PROP_ACCESS_DENIED;
9000
0
}
9001
9002
//*****************************************************************************
9003
// nsDocShell: Site Loading
9004
//*****************************************************************************
9005
9006
void
9007
nsDocShell::CopyFavicon(nsIURI* aOldURI,
9008
                        nsIURI* aNewURI,
9009
                        nsIPrincipal* aLoadingPrincipal,
9010
                        bool aInPrivateBrowsing)
9011
0
{
9012
0
  if (XRE_IsContentProcess()) {
9013
0
    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
9014
0
    if (contentChild) {
9015
0
      mozilla::ipc::URIParams oldURI, newURI;
9016
0
      SerializeURI(aOldURI, oldURI);
9017
0
      SerializeURI(aNewURI, newURI);
9018
0
      contentChild->SendCopyFavicon(oldURI, newURI,
9019
0
                                    IPC::Principal(aLoadingPrincipal),
9020
0
                                    aInPrivateBrowsing);
9021
0
    }
9022
0
    return;
9023
0
  }
9024
0
9025
0
#ifdef MOZ_PLACES
9026
0
  nsCOMPtr<nsIFaviconService> favSvc =
9027
0
    do_GetService("@mozilla.org/browser/favicon-service;1");
9028
0
  if (favSvc) {
9029
0
    favSvc->CopyFavicons(aOldURI, aNewURI,
9030
0
      aInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE
9031
0
                         : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr);
9032
0
  }
9033
0
#endif
9034
0
}
9035
9036
class InternalLoadEvent : public Runnable
9037
{
9038
public:
9039
  InternalLoadEvent(nsDocShell* aDocShell,
9040
                    nsIURI* aURI,
9041
                    nsIURI* aOriginalURI,
9042
                    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
9043
                    bool aKeepResultPrincipalURIIfSet,
9044
                    bool aLoadReplace,
9045
                    nsIURI* aReferrer, uint32_t aReferrerPolicy,
9046
                    nsIPrincipal* aTriggeringPrincipal,
9047
                    nsIPrincipal* aPrincipalToInherit,
9048
                    uint32_t aFlags,
9049
                    const char* aTypeHint,
9050
                    nsIInputStream* aPostData,
9051
                    nsIInputStream* aHeadersData,
9052
                    uint32_t aLoadType,
9053
                    nsISHEntry* aSHEntry,
9054
                    bool aFirstParty,
9055
                    const nsAString& aSrcdoc,
9056
                    nsIDocShell* aSourceDocShell,
9057
                    nsIURI* aBaseURI)
9058
    : mozilla::Runnable("InternalLoadEvent")
9059
    , mSrcdoc(aSrcdoc)
9060
    , mDocShell(aDocShell)
9061
    , mURI(aURI)
9062
    , mOriginalURI(aOriginalURI)
9063
    , mResultPrincipalURI(aResultPrincipalURI)
9064
    , mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet)
9065
    , mLoadReplace(aLoadReplace)
9066
    , mReferrer(aReferrer)
9067
    , mReferrerPolicy(aReferrerPolicy)
9068
    , mTriggeringPrincipal(aTriggeringPrincipal)
9069
    , mPrincipalToInherit(aPrincipalToInherit)
9070
    , mPostData(aPostData)
9071
    , mHeadersData(aHeadersData)
9072
    , mSHEntry(aSHEntry)
9073
    , mFlags(aFlags)
9074
    , mLoadType(aLoadType)
9075
    , mFirstParty(aFirstParty)
9076
    , mSourceDocShell(aSourceDocShell)
9077
    , mBaseURI(aBaseURI)
9078
0
  {
9079
0
    // Make sure to keep null things null as needed
9080
0
    if (aTypeHint) {
9081
0
      mTypeHint = aTypeHint;
9082
0
    } else {
9083
0
      mTypeHint.SetIsVoid(true);
9084
0
    }
9085
0
  }
9086
9087
  NS_IMETHOD
9088
  Run() override
9089
0
  {
9090
0
    return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
9091
0
                                   mKeepResultPrincipalURIIfSet,
9092
0
                                   mLoadReplace,
9093
0
                                   mReferrer,
9094
0
                                   mReferrerPolicy,
9095
0
                                   mTriggeringPrincipal, mPrincipalToInherit,
9096
0
                                   mFlags, EmptyString(),
9097
0
                                   mTypeHint.IsVoid() ? nullptr
9098
0
                                                      : mTypeHint.get(),
9099
0
                                   VoidString(), mPostData,
9100
0
                                   mHeadersData, mLoadType, mSHEntry,
9101
0
                                   mFirstParty, mSrcdoc, mSourceDocShell,
9102
0
                                   mBaseURI, nullptr,
9103
0
                                   nullptr);
9104
0
  }
9105
9106
private:
9107
  nsCString mTypeHint;
9108
  nsString mSrcdoc;
9109
9110
  RefPtr<nsDocShell> mDocShell;
9111
  nsCOMPtr<nsIURI> mURI;
9112
  nsCOMPtr<nsIURI> mOriginalURI;
9113
  Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
9114
  bool mKeepResultPrincipalURIIfSet;
9115
  bool mLoadReplace;
9116
  nsCOMPtr<nsIURI> mReferrer;
9117
  uint32_t mReferrerPolicy;
9118
  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
9119
  nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
9120
  nsCOMPtr<nsIInputStream> mPostData;
9121
  nsCOMPtr<nsIInputStream> mHeadersData;
9122
  nsCOMPtr<nsISHEntry> mSHEntry;
9123
  uint32_t mFlags;
9124
  uint32_t mLoadType;
9125
  bool mFirstParty;
9126
  nsCOMPtr<nsIDocShell> mSourceDocShell;
9127
  nsCOMPtr<nsIURI> mBaseURI;
9128
};
9129
9130
/**
9131
 * Returns true if we started an asynchronous load (i.e., from the network), but
9132
 * the document we're loading there hasn't yet become this docshell's active
9133
 * document.
9134
 *
9135
 * When JustStartedNetworkLoad is true, you should be careful about modifying
9136
 * mLoadType and mLSHE.  These are both set when the asynchronous load first
9137
 * starts, and the load expects that, when it eventually runs InternalLoad,
9138
 * mLoadType and mLSHE will have their original values.
9139
 */
9140
bool
9141
nsDocShell::JustStartedNetworkLoad()
9142
0
{
9143
0
  return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
9144
0
}
9145
9146
nsresult
9147
nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
9148
                                        nsIPrincipal** aResult)
9149
0
{
9150
0
  nsCOMPtr<nsIPrincipal> prin =
9151
0
    BasePrincipal::CreateCodebasePrincipal(aReferrer, mOriginAttributes);
9152
0
  prin.forget(aResult);
9153
0
9154
0
  return *aResult ? NS_OK : NS_ERROR_FAILURE;
9155
0
}
9156
9157
NS_IMETHODIMP
9158
nsDocShell::InternalLoad(nsIURI* aURI,
9159
                         nsIURI* aOriginalURI,
9160
                         Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
9161
                         bool aKeepResultPrincipalURIIfSet,
9162
                         bool aLoadReplace,
9163
                         nsIURI* aReferrer,
9164
                         uint32_t aReferrerPolicy,
9165
                         nsIPrincipal* aTriggeringPrincipal,
9166
                         nsIPrincipal* aPrincipalToInherit,
9167
                         uint32_t aFlags,
9168
                         const nsAString& aWindowTarget,
9169
                         const char* aTypeHint,
9170
                         const nsAString& aFileName,
9171
                         nsIInputStream* aPostData,
9172
                         nsIInputStream* aHeadersData,
9173
                         uint32_t aLoadType,
9174
                         nsISHEntry* aSHEntry,
9175
                         bool aFirstParty,
9176
                         const nsAString& aSrcdoc,
9177
                         nsIDocShell* aSourceDocShell,
9178
                         nsIURI* aBaseURI,
9179
                         nsIDocShell** aDocShell,
9180
                         nsIRequest** aRequest)
9181
0
{
9182
0
  MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
9183
0
9184
0
  nsresult rv = NS_OK;
9185
0
  mOriginalUriString.Truncate();
9186
0
9187
0
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
9188
0
          ("DOCSHELL %p InternalLoad %s\n",
9189
0
           this, aURI ? aURI->GetSpecOrDefault().get() : ""));
9190
0
  // Initialize aDocShell/aRequest
9191
0
  if (aDocShell) {
9192
0
    *aDocShell = nullptr;
9193
0
  }
9194
0
  if (aRequest) {
9195
0
    *aRequest = nullptr;
9196
0
  }
9197
0
9198
0
  if (!aURI) {
9199
0
    return NS_ERROR_NULL_POINTER;
9200
0
  }
9201
0
9202
0
  NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
9203
0
9204
0
  NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
9205
0
9206
0
  rv = EnsureScriptEnvironment();
9207
0
  if (NS_FAILED(rv)) {
9208
0
    return rv;
9209
0
  }
9210
0
9211
0
  // wyciwyg urls can only be loaded through history. Any normal load of
9212
0
  // wyciwyg through docshell is  illegal. Disallow such loads.
9213
0
  if (aLoadType & LOAD_CMD_NORMAL) {
9214
0
    bool isWyciwyg = false;
9215
0
    rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
9216
0
    if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) {
9217
0
      return NS_ERROR_FAILURE;
9218
0
    }
9219
0
  }
9220
0
9221
0
  bool isJavaScript = false;
9222
0
  if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) {
9223
0
    isJavaScript = false;
9224
0
  }
9225
0
9226
0
  bool isTargetTopLevelDocShell = false;
9227
0
  nsCOMPtr<nsIDocShell> targetDocShell;
9228
0
  if (!aWindowTarget.IsEmpty()) {
9229
0
    // Locate the target DocShell.
9230
0
    nsCOMPtr<nsIDocShellTreeItem> targetItem;
9231
0
    // Only _self, _parent, and _top are supported in noopener case.  But we
9232
0
    // have to be careful to not apply that to the noreferrer case.  See bug
9233
0
    // 1358469.
9234
0
    bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
9235
0
                            (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
9236
0
    if (allowNamedTarget ||
9237
0
        aWindowTarget.LowerCaseEqualsLiteral("_self") ||
9238
0
        aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
9239
0
        aWindowTarget.LowerCaseEqualsLiteral("_top")) {
9240
0
      rv = FindItemWithName(aWindowTarget, nullptr, this, false,
9241
0
                            getter_AddRefs(targetItem));
9242
0
      NS_ENSURE_SUCCESS(rv, rv);
9243
0
    }
9244
0
9245
0
    targetDocShell = do_QueryInterface(targetItem);
9246
0
    if (targetDocShell) {
9247
0
      // If the targetDocShell and the rootDocShell are the same, then the
9248
0
      // targetDocShell is the top level document and hence we should
9249
0
      // consider this TYPE_DOCUMENT
9250
0
      //
9251
0
      // For example:
9252
0
      // 1. target="_top"
9253
0
      // 2. target="_parent", where this docshell is in the 2nd level of
9254
0
      //    docshell tree.
9255
0
      nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
9256
0
      targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
9257
0
      NS_ASSERTION(sameTypeRoot,
9258
0
                   "No document shell root tree item from targetDocShell!");
9259
0
      nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
9260
0
      NS_ASSERTION(rootShell,
9261
0
                   "No root docshell from document shell root tree item.");
9262
0
      isTargetTopLevelDocShell = targetDocShell == rootShell;
9263
0
    } else {
9264
0
      // If the targetDocShell doesn't exist, then this is a new docShell
9265
0
      // and we should consider this a TYPE_DOCUMENT load
9266
0
      //
9267
0
      // For example, when target="_blank"
9268
0
      isTargetTopLevelDocShell = true;
9269
0
    }
9270
0
  }
9271
0
9272
0
  // The contentType will be INTERNAL_(I)FRAME if:
9273
0
  // 1. This docshell is for iframe.
9274
0
  // 2. AND aWindowTarget is not a new window, nor a top-level window.
9275
0
  //
9276
0
  // This variable will be used when we call NS_CheckContentLoadPolicy, and
9277
0
  // later when we call DoURILoad.
9278
0
  uint32_t contentType;
9279
0
  if (IsFrame() && !isTargetTopLevelDocShell) {
9280
0
    nsCOMPtr<Element> requestingElement =
9281
0
      mScriptGlobal->AsOuter()->GetFrameElementInternal();
9282
0
    if (requestingElement) {
9283
0
      contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe) ?
9284
0
        nsIContentPolicy::TYPE_INTERNAL_IFRAME : nsIContentPolicy::TYPE_INTERNAL_FRAME;
9285
0
    } else {
9286
0
      // If we have lost our frame element by now, just assume we're
9287
0
      // an iframe since that's more common.
9288
0
      contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
9289
0
    }
9290
0
  } else {
9291
0
    contentType = nsIContentPolicy::TYPE_DOCUMENT;
9292
0
    isTargetTopLevelDocShell = true;
9293
0
  }
9294
0
9295
0
  // If there's no targetDocShell, that means we are about to create a new
9296
0
  // window (or aWindowTarget is empty). Perform a content policy check before
9297
0
  // creating the window. Please note for all other docshell loads
9298
0
  // content policy checks are performed within the contentSecurityManager
9299
0
  // when the channel is about to be openend.
9300
0
  if (!targetDocShell && !aWindowTarget.IsEmpty()) {
9301
0
    MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
9302
0
               "opening a new window requires type to be TYPE_DOCUMENT");
9303
0
9304
0
    nsISupports* requestingContext = nullptr;
9305
0
    if (XRE_IsContentProcess()) {
9306
0
      // In e10s the child process doesn't have access to the element that
9307
0
      // contains the browsing context (because that element is in the chrome
9308
0
      // process). So we just pass mScriptGlobal.
9309
0
      requestingContext = ToSupports(mScriptGlobal);
9310
0
    } else {
9311
0
      // This is for loading non-e10s tabs and toplevel windows of various
9312
0
      // sorts.
9313
0
      // For the toplevel window cases, requestingElement will be null.
9314
0
      nsCOMPtr<Element> requestingElement =
9315
0
        mScriptGlobal->AsOuter()->GetFrameElementInternal();
9316
0
      requestingContext = requestingElement;
9317
0
    }
9318
0
9319
0
    // Ideally we should use the same loadinfo as within DoURILoad which
9320
0
    // should match this one when both are applicable.
9321
0
    nsCOMPtr<nsPIDOMWindowOuter> loadingWindow = mScriptGlobal->AsOuter();
9322
0
    nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
9323
0
      new LoadInfo(loadingWindow,
9324
0
                   aTriggeringPrincipal,
9325
0
                   requestingContext,
9326
0
                   nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK);
9327
0
9328
0
    // Since Content Policy checks are performed within docShell as well as
9329
0
    // the ContentSecurityManager we need a reliable way to let certain
9330
0
    // nsIContentPolicy consumers ignore duplicate calls.
9331
0
    secCheckLoadInfo->SetSkipContentPolicyCheckForWebRequest(true);
9332
0
9333
0
    int16_t shouldLoad = nsIContentPolicy::ACCEPT;
9334
0
    rv = NS_CheckContentLoadPolicy(aURI,
9335
0
                                   secCheckLoadInfo,
9336
0
                                   EmptyCString(),  // mime guess
9337
0
                                   &shouldLoad);
9338
0
9339
0
    if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
9340
0
      if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
9341
0
        return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
9342
0
      }
9343
0
9344
0
      return NS_ERROR_CONTENT_BLOCKED;
9345
0
    }
9346
0
  }
9347
0
9348
0
  nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
9349
0
  //
9350
0
  // Get a principal from the current document if necessary.  Note that we only
9351
0
  // do this for URIs that inherit a security context and local file URIs;
9352
0
  // in particular we do NOT do this for about:blank.  This way, random
9353
0
  // about:blank loads that have no principal (which basically means they were
9354
0
  // done by someone from chrome manually messing with our nsIWebNavigation
9355
0
  // or by C++ setting document.location) don't get a funky principal.  If
9356
0
  // callers want something interesting to happen with the about:blank
9357
0
  // principal in this case, they should pass aPrincipalToInherit in.
9358
0
  //
9359
0
  {
9360
0
    bool inherits;
9361
0
    // One more twist: Don't inherit the principal for external loads.
9362
0
    if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
9363
0
        (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
9364
0
         NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
9365
0
                                                                 &inherits)) &&
9366
0
         inherits) {
9367
0
      principalToInherit = GetInheritedPrincipal(true);
9368
0
    }
9369
0
  }
9370
0
9371
0
  nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument()
9372
0
                                    : nullptr;
9373
0
9374
0
  const bool isDocumentAuxSandboxed = doc &&
9375
0
    (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
9376
0
9377
0
  if (aURI && mLoadURIDelegate && aLoadType != LOAD_ERROR_PAGE &&
9378
0
      (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
9379
0
    // Dispatch only load requests for the current or a new window to the
9380
0
    // delegate, e.g., to allow for GeckoView apps to handle the load event
9381
0
    // outside of Gecko.
9382
0
    const int where = (aWindowTarget.IsEmpty() || targetDocShell)
9383
0
                      ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
9384
0
                      : nsIBrowserDOMWindow::OPEN_NEWWINDOW;
9385
0
9386
0
    if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW && isDocumentAuxSandboxed) {
9387
0
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9388
0
    }
9389
0
9390
0
    bool loadURIHandled = false;
9391
0
    rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
9392
0
                                   &loadURIHandled);
9393
0
    if (NS_SUCCEEDED(rv) && loadURIHandled) {
9394
0
      // The request has been handled, nothing to do here.
9395
0
      return NS_OK;
9396
0
    }
9397
0
  }
9398
0
9399
0
  //
9400
0
  // Resolve the window target before going any further...
9401
0
  // If the load has been targeted to another DocShell, then transfer the
9402
0
  // load to it...
9403
0
  //
9404
0
  if (!aWindowTarget.IsEmpty()) {
9405
0
    // We've already done our owner-inheriting.  Mask out that bit, so we
9406
0
    // don't try inheriting an owner from the target window if we came up
9407
0
    // with a null owner above.
9408
0
    aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
9409
0
9410
0
    bool isNewWindow = false;
9411
0
    if (!targetDocShell) {
9412
0
      // If the docshell's document is sandboxed, only open a new window
9413
0
      // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
9414
0
      // (i.e. if allow-popups is specified)
9415
0
      NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
9416
0
      if (isDocumentAuxSandboxed) {
9417
0
        return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9418
0
      }
9419
0
9420
0
      nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
9421
0
      NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
9422
0
9423
0
      nsCOMPtr<nsPIDOMWindowOuter> newWin;
9424
0
      nsAutoCString spec;
9425
0
      if (aURI) {
9426
0
        aURI->GetSpec(spec);
9427
0
      }
9428
0
      // If we are a noopener load, we just hand the whole thing over to our
9429
0
      // window.
9430
0
      if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
9431
0
        // Various asserts that we know to hold because NO_OPENER loads can only
9432
0
        // happen for links.
9433
0
        MOZ_ASSERT(!aLoadReplace);
9434
0
        MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
9435
0
        MOZ_ASSERT((aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
9436
0
                   INTERNAL_LOAD_FLAGS_NO_OPENER ||
9437
0
                   (aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
9438
0
                   (INTERNAL_LOAD_FLAGS_NO_OPENER |
9439
0
                    INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
9440
0
        MOZ_ASSERT(!aPostData);
9441
0
        MOZ_ASSERT(!aHeadersData);
9442
0
        // If OnLinkClickSync was invoked inside the onload handler, the load
9443
0
        // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
9444
0
        // LOAD_LINK.
9445
0
        MOZ_ASSERT(aLoadType == LOAD_LINK ||
9446
0
                   aLoadType == LOAD_NORMAL_REPLACE);
9447
0
        MOZ_ASSERT(!aSHEntry);
9448
0
        MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
9449
0
9450
0
        RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
9451
0
9452
0
        // Set up our loadinfo so it will do the load as much like we would have
9453
0
        // as possible.
9454
0
        loadInfo->SetReferrer(aReferrer);
9455
0
        loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
9456
0
        loadInfo->SetSendReferrer(!(aFlags &
9457
0
                                    INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
9458
0
        loadInfo->SetOriginalURI(aOriginalURI);
9459
0
        loadInfo->SetMaybeResultPrincipalURI(aResultPrincipalURI);
9460
0
        loadInfo->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet);
9461
0
        loadInfo->SetLoadReplace(aLoadReplace);
9462
0
        loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
9463
0
        loadInfo->SetInheritPrincipal(
9464
0
          aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
9465
0
        // Explicit principal because we do not want any guesses as to what the
9466
0
        // principal to inherit is: it should be aTriggeringPrincipal.
9467
0
        loadInfo->SetPrincipalIsExplicit(true);
9468
0
        loadInfo->SetLoadType(LOAD_LINK);
9469
0
        loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
9470
0
9471
0
        rv = win->Open(NS_ConvertUTF8toUTF16(spec),
9472
0
                       aWindowTarget, // window name
9473
0
                       EmptyString(), // Features
9474
0
                       loadInfo,
9475
0
                       true, // aForceNoOpener
9476
0
                       getter_AddRefs(newWin));
9477
0
        MOZ_ASSERT(!newWin);
9478
0
        return rv;
9479
0
      }
9480
0
9481
0
      rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
9482
0
                               aWindowTarget,  // window name
9483
0
                               EmptyString(), // Features
9484
0
                               getter_AddRefs(newWin));
9485
0
9486
0
      // In some cases the Open call doesn't actually result in a new
9487
0
      // window being opened.  We can detect these cases by examining the
9488
0
      // document in |newWin|, if any.
9489
0
      nsCOMPtr<nsPIDOMWindowOuter> piNewWin = do_QueryInterface(newWin);
9490
0
      if (piNewWin) {
9491
0
        nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
9492
0
        if (!newDoc || newDoc->IsInitialDocument()) {
9493
0
          isNewWindow = true;
9494
0
          aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
9495
0
        }
9496
0
      }
9497
0
9498
0
      nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
9499
0
      targetDocShell = do_QueryInterface(webNav);
9500
0
    }
9501
0
9502
0
    //
9503
0
    // Transfer the load to the target DocShell...  Pass nullptr as the
9504
0
    // window target name from to prevent recursive retargeting!
9505
0
    //
9506
0
    if (NS_SUCCEEDED(rv) && targetDocShell) {
9507
0
      rv = targetDocShell->InternalLoad(aURI,
9508
0
                                        aOriginalURI,
9509
0
                                        aResultPrincipalURI,
9510
0
                                        aKeepResultPrincipalURIIfSet,
9511
0
                                        aLoadReplace,
9512
0
                                        aReferrer,
9513
0
                                        aReferrerPolicy,
9514
0
                                        aTriggeringPrincipal,
9515
0
                                        principalToInherit,
9516
0
                                        aFlags,
9517
0
                                        EmptyString(),   // No window target
9518
0
                                        aTypeHint,
9519
0
                                        VoidString(),    // No forced download
9520
0
                                        aPostData,
9521
0
                                        aHeadersData,
9522
0
                                        aLoadType,
9523
0
                                        aSHEntry,
9524
0
                                        aFirstParty,
9525
0
                                        aSrcdoc,
9526
0
                                        aSourceDocShell,
9527
0
                                        aBaseURI,
9528
0
                                        aDocShell,
9529
0
                                        aRequest);
9530
0
      if (rv == NS_ERROR_NO_CONTENT) {
9531
0
        // XXXbz except we never reach this code!
9532
0
        if (isNewWindow) {
9533
0
          //
9534
0
          // At this point, a new window has been created, but the
9535
0
          // URI did not have any data associated with it...
9536
0
          //
9537
0
          // So, the best we can do, is to tear down the new window
9538
0
          // that was just created!
9539
0
          //
9540
0
          if (nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow()) {
9541
0
            domWin->Close();
9542
0
          }
9543
0
        }
9544
0
        //
9545
0
        // NS_ERROR_NO_CONTENT should not be returned to the
9546
0
        // caller... This is an internal error code indicating that
9547
0
        // the URI had no data associated with it - probably a
9548
0
        // helper-app style protocol (ie. mailto://)
9549
0
        //
9550
0
        rv = NS_OK;
9551
0
      } else if (isNewWindow) {
9552
0
        // XXX: Once new windows are created hidden, the new
9553
0
        //      window will need to be made visible...  For now,
9554
0
        //      do nothing.
9555
0
      }
9556
0
9557
0
      if (NS_SUCCEEDED(rv)) {
9558
0
        // Switch to target tab if we're currently focused window.
9559
0
        // Take loadDivertedInBackground into account so the behavior would be
9560
0
        // the same as how the tab first opened.
9561
0
        bool isTargetActive = false;
9562
0
        targetDocShell->GetIsActive(&isTargetActive);
9563
0
        nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
9564
0
        if (mIsActive && !isTargetActive && domWin &&
9565
0
            !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) {
9566
0
          if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) {
9567
0
            return NS_ERROR_FAILURE;
9568
0
          }
9569
0
        }
9570
0
      }
9571
0
    }
9572
0
9573
0
    // Else we ran out of memory, or were a popup and got blocked,
9574
0
    // or something.
9575
0
9576
0
    return rv;
9577
0
  }
9578
0
9579
0
  //
9580
0
  // Load is being targetted at this docshell so return an error if the
9581
0
  // docshell is in the process of being destroyed.
9582
0
  //
9583
0
  if (mIsBeingDestroyed) {
9584
0
    return NS_ERROR_FAILURE;
9585
0
  }
9586
0
9587
0
  NS_ENSURE_STATE(!HasUnloadedParent());
9588
0
9589
0
  rv = CheckLoadingPermissions();
9590
0
  if (NS_FAILED(rv)) {
9591
0
    return rv;
9592
0
  }
9593
0
9594
0
  if (mFiredUnloadEvent) {
9595
0
    if (IsOKToLoadURI(aURI)) {
9596
0
      MOZ_ASSERT(aWindowTarget.IsEmpty(),
9597
0
                 "Shouldn't have a window target here!");
9598
0
9599
0
      // If this is a replace load, make whatever load triggered
9600
0
      // the unload event also a replace load, so we don't
9601
0
      // create extra history entries.
9602
0
      if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
9603
0
        mLoadType = LOAD_NORMAL_REPLACE;
9604
0
      }
9605
0
9606
0
      // Do this asynchronously
9607
0
      nsCOMPtr<nsIRunnable> ev =
9608
0
        new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
9609
0
                              aKeepResultPrincipalURIIfSet,
9610
0
                              aLoadReplace, aReferrer, aReferrerPolicy,
9611
0
                              aTriggeringPrincipal, principalToInherit,
9612
0
                              aFlags, aTypeHint, aPostData,
9613
0
                              aHeadersData, aLoadType, aSHEntry, aFirstParty,
9614
0
                              aSrcdoc, aSourceDocShell, aBaseURI);
9615
0
      return DispatchToTabGroup(TaskCategory::Other, ev.forget());
9616
0
    }
9617
0
9618
0
    // Just ignore this load attempt
9619
0
    return NS_OK;
9620
0
  }
9621
0
9622
0
  // If a source docshell has been passed, check to see if we are sandboxed
9623
0
  // from it as the result of an iframe or CSP sandbox.
9624
0
  if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
9625
0
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
9626
0
  }
9627
0
9628
0
  // If this docshell is owned by a frameloader, make sure to cancel
9629
0
  // possible frameloader initialization before loading a new page.
9630
0
  nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
9631
0
  if (parent) {
9632
0
    nsCOMPtr<nsIDocument> doc = parent->GetDocument();
9633
0
    if (doc) {
9634
0
      doc->TryCancelFrameLoaderInitialization(this);
9635
0
    }
9636
0
  }
9637
0
9638
0
  bool loadFromExternal = false;
9639
0
9640
0
  // Before going any further vet loads initiated by external programs.
9641
0
  if (aLoadType == LOAD_NORMAL_EXTERNAL) {
9642
0
    loadFromExternal = true;
9643
0
    // Disallow external chrome: loads targetted at content windows
9644
0
    bool isChrome = false;
9645
0
    if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
9646
0
      NS_WARNING("blocked external chrome: url -- use '--chrome' option");
9647
0
      return NS_ERROR_FAILURE;
9648
0
    }
9649
0
9650
0
    // clear the decks to prevent context bleed-through (bug 298255)
9651
0
    rv = CreateAboutBlankContentViewer(nullptr, nullptr);
9652
0
    if (NS_FAILED(rv)) {
9653
0
      return NS_ERROR_FAILURE;
9654
0
    }
9655
0
9656
0
    // reset loadType so we don't have to add lots of tests for
9657
0
    // LOAD_NORMAL_EXTERNAL after this point
9658
0
    aLoadType = LOAD_NORMAL;
9659
0
  }
9660
0
9661
0
  mAllowKeywordFixup =
9662
0
    (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
9663
0
  mURIResultedInDocument = false;  // reset the clock...
9664
0
9665
0
  if (aLoadType == LOAD_NORMAL ||
9666
0
      aLoadType == LOAD_STOP_CONTENT ||
9667
0
      LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
9668
0
      aLoadType == LOAD_HISTORY ||
9669
0
      aLoadType == LOAD_LINK) {
9670
0
    nsCOMPtr<nsIURI> currentURI = mCurrentURI;
9671
0
9672
0
    nsAutoCString curHash, newHash;
9673
0
    bool curURIHasRef = false, newURIHasRef = false;
9674
0
9675
0
    nsresult rvURINew = aURI->GetRef(newHash);
9676
0
    if (NS_SUCCEEDED(rvURINew)) {
9677
0
      rvURINew = aURI->GetHasRef(&newURIHasRef);
9678
0
    }
9679
0
9680
0
    bool sameExceptHashes = false;
9681
0
    if (currentURI && NS_SUCCEEDED(rvURINew)) {
9682
0
      nsresult rvURIOld = currentURI->GetRef(curHash);
9683
0
      if (NS_SUCCEEDED(rvURIOld)) {
9684
0
        rvURIOld = currentURI->GetHasRef(&curURIHasRef);
9685
0
      }
9686
0
      if (NS_SUCCEEDED(rvURIOld)) {
9687
0
        if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
9688
0
          sameExceptHashes = false;
9689
0
        }
9690
0
      }
9691
0
    }
9692
0
9693
0
    if (!sameExceptHashes && sURIFixup && currentURI &&
9694
0
        NS_SUCCEEDED(rvURINew)) {
9695
0
      // Maybe aURI came from the exposable form of currentURI?
9696
0
      nsCOMPtr<nsIURI> currentExposableURI;
9697
0
      rv = sURIFixup->CreateExposableURI(currentURI,
9698
0
                                         getter_AddRefs(currentExposableURI));
9699
0
      NS_ENSURE_SUCCESS(rv, rv);
9700
0
      nsresult rvURIOld = currentExposableURI->GetRef(curHash);
9701
0
      if (NS_SUCCEEDED(rvURIOld)) {
9702
0
        rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef);
9703
0
      }
9704
0
      if (NS_SUCCEEDED(rvURIOld)) {
9705
0
        if (NS_FAILED(currentExposableURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
9706
0
          sameExceptHashes = false;
9707
0
        }
9708
0
      }
9709
0
    }
9710
0
9711
0
    bool historyNavBetweenSameDoc = false;
9712
0
    if (mOSHE && aSHEntry) {
9713
0
      // We're doing a history load.
9714
0
9715
0
      mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
9716
0
9717
#ifdef DEBUG
9718
      if (historyNavBetweenSameDoc) {
9719
        nsCOMPtr<nsIInputStream> currentPostData = mOSHE->GetPostData();
9720
        NS_ASSERTION(currentPostData == aPostData,
9721
                     "Different POST data for entries for the same page?");
9722
      }
9723
#endif
9724
    }
9725
0
9726
0
    // A short-circuited load happens when we navigate between two SHEntries
9727
0
    // for the same document.  We do a short-circuited load under two
9728
0
    // circumstances.  Either
9729
0
    //
9730
0
    //  a) we're navigating between two different SHEntries which share a
9731
0
    //     document, or
9732
0
    //
9733
0
    //  b) we're navigating to a new shentry whose URI differs from the
9734
0
    //     current URI only in its hash, the new hash is non-empty, and
9735
0
    //     we're not doing a POST.
9736
0
    //
9737
0
    // The restriction tha the SHEntries in (a) must be different ensures
9738
0
    // that history.go(0) and the like trigger full refreshes, rather than
9739
0
    // short-circuited loads.
9740
0
    bool doShortCircuitedLoad =
9741
0
      (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
9742
0
      (!aSHEntry && !aPostData &&
9743
0
       sameExceptHashes && newURIHasRef);
9744
0
9745
0
    if (doShortCircuitedLoad) {
9746
0
      // Save the position of the scrollers.
9747
0
      nscoord cx = 0, cy = 0;
9748
0
      GetCurScrollPos(ScrollOrientation_X, &cx);
9749
0
      GetCurScrollPos(ScrollOrientation_Y, &cy);
9750
0
9751
0
      // Reset mLoadType to its original value once we exit this block,
9752
0
      // because this short-circuited load might have started after a
9753
0
      // normal, network load, and we don't want to clobber its load type.
9754
0
      // See bug 737307.
9755
0
      AutoRestore<uint32_t> loadTypeResetter(mLoadType);
9756
0
9757
0
      // If a non-short-circuit load (i.e., a network load) is pending,
9758
0
      // make this a replacement load, so that we don't add a SHEntry here
9759
0
      // and the network load goes into the SHEntry it expects to.
9760
0
      if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
9761
0
        mLoadType = LOAD_NORMAL_REPLACE;
9762
0
      } else {
9763
0
        mLoadType = aLoadType;
9764
0
      }
9765
0
9766
0
      mURIResultedInDocument = true;
9767
0
9768
0
      nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
9769
0
9770
0
      /* we need to assign mLSHE to aSHEntry right here, so that on History
9771
0
       * loads, SetCurrentURI() called from OnNewURI() will send proper
9772
0
       * onLocationChange() notifications to the browser to update
9773
0
       * back/forward buttons.
9774
0
       */
9775
0
      SetHistoryEntry(&mLSHE, aSHEntry);
9776
0
9777
0
      // Set the doc's URI according to the new history entry's URI.
9778
0
      nsCOMPtr<nsIDocument> doc = GetDocument();
9779
0
      NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
9780
0
      doc->SetDocumentURI(aURI);
9781
0
9782
0
      /* This is a anchor traversal with in the same page.
9783
0
       * call OnNewURI() so that, this traversal will be
9784
0
       * recorded in session and global history.
9785
0
       */
9786
0
      nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
9787
0
      if (mOSHE) {
9788
0
        newURITriggeringPrincipal = mOSHE->GetTriggeringPrincipal();
9789
0
        newURIPrincipalToInherit = mOSHE->GetPrincipalToInherit();
9790
0
      } else {
9791
0
        newURITriggeringPrincipal = aTriggeringPrincipal;
9792
0
        newURIPrincipalToInherit = doc->NodePrincipal();
9793
0
      }
9794
0
      // Pass true for aCloneSHChildren, since we're not
9795
0
      // changing documents here, so all of our subframes are
9796
0
      // still relevant to the new session history entry.
9797
0
      //
9798
0
      // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
9799
0
      // flag on firing onLocationChange(...).
9800
0
      // Anyway, aCloneSHChildren param is simply reflecting
9801
0
      // doShortCircuitedLoad in this scope.
9802
0
      OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit,
9803
0
               mLoadType, true, true, true);
9804
0
9805
0
      nsCOMPtr<nsIInputStream> postData;
9806
0
      uint32_t cacheKey = 0;
9807
0
9808
0
      bool scrollRestorationIsManual = false;
9809
0
      if (mOSHE) {
9810
0
        /* save current position of scroller(s) (bug 59774) */
9811
0
        mOSHE->SetScrollPosition(cx, cy);
9812
0
        scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
9813
0
        // Get the postdata and page ident from the current page, if
9814
0
        // the new load is being done via normal means.  Note that
9815
0
        // "normal means" can be checked for just by checking for
9816
0
        // LOAD_CMD_NORMAL, given the loadType and allowScroll check
9817
0
        // above -- it filters out some LOAD_CMD_NORMAL cases that we
9818
0
        // wouldn't want here.
9819
0
        if (aLoadType & LOAD_CMD_NORMAL) {
9820
0
          postData = mOSHE->GetPostData();
9821
0
          cacheKey = mOSHE->GetCacheKey();
9822
0
9823
0
          // Link our new SHEntry to the old SHEntry's back/forward
9824
0
          // cache data, since the two SHEntries correspond to the
9825
0
          // same document.
9826
0
          if (mLSHE) {
9827
0
            if (!aSHEntry) {
9828
0
              // If we're not doing a history load, scroll restoration
9829
0
              // should be inherited from the previous session history entry.
9830
0
              mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
9831
0
            }
9832
0
            mLSHE->AdoptBFCacheEntry(mOSHE);
9833
0
          }
9834
0
        }
9835
0
      }
9836
0
9837
0
      // If we're doing a history load, use its scroll restoration state.
9838
0
      if (aSHEntry) {
9839
0
        scrollRestorationIsManual = aSHEntry->GetScrollRestorationIsManual();
9840
0
      }
9841
0
9842
0
      /* Assign mOSHE to mLSHE. This will either be a new entry created
9843
0
       * by OnNewURI() for normal loads or aSHEntry for history loads.
9844
0
       */
9845
0
      if (mLSHE) {
9846
0
        SetHistoryEntry(&mOSHE, mLSHE);
9847
0
        // Save the postData obtained from the previous page
9848
0
        // in to the session history entry created for the
9849
0
        // anchor page, so that any history load of the anchor
9850
0
        // page will restore the appropriate postData.
9851
0
        if (postData) {
9852
0
          mOSHE->SetPostData(postData);
9853
0
        }
9854
0
9855
0
        // Make sure we won't just repost without hitting the
9856
0
        // cache first
9857
0
        if (cacheKey != 0) {
9858
0
          mOSHE->SetCacheKey(cacheKey);
9859
0
        }
9860
0
      }
9861
0
9862
0
      /* Restore the original LSHE if we were loading something
9863
0
       * while short-circuited load was initiated.
9864
0
       */
9865
0
      SetHistoryEntry(&mLSHE, oldLSHE);
9866
0
      /* Set the title for the SH entry for this target url. so that
9867
0
       * SH menus in go/back/forward buttons won't be empty for this.
9868
0
       */
9869
0
      if (mSessionHistory) {
9870
0
        int32_t index = mSessionHistory->Index();
9871
0
        nsCOMPtr<nsISHEntry> shEntry;
9872
0
        mSessionHistory->LegacySHistory()->GetEntryAtIndex(
9873
0
          index, getter_AddRefs(shEntry));
9874
0
        NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
9875
0
        shEntry->SetTitle(mTitle);
9876
0
      }
9877
0
9878
0
      /* Set the title for the Global History entry for this anchor url.
9879
0
       */
9880
0
      UpdateGlobalHistoryTitle(aURI);
9881
0
9882
0
      SetDocCurrentStateObj(mOSHE);
9883
0
9884
0
      // Inform the favicon service that the favicon for oldURI also
9885
0
      // applies to aURI.
9886
0
      CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
9887
0
9888
0
      RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal;
9889
0
      RefPtr<nsGlobalWindowInner> win = scriptGlobal ?
9890
0
        scriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
9891
0
9892
0
      // ScrollToAnchor doesn't necessarily cause us to scroll the window;
9893
0
      // the function decides whether a scroll is appropriate based on the
9894
0
      // arguments it receives.  But even if we don't end up scrolling,
9895
0
      // ScrollToAnchor performs other important tasks, such as informing
9896
0
      // the presShell that we have a new hash.  See bug 680257.
9897
0
      rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
9898
0
      NS_ENSURE_SUCCESS(rv, rv);
9899
0
9900
0
      /* restore previous position of scroller(s), if we're moving
9901
0
       * back in history (bug 59774)
9902
0
       */
9903
0
      nscoord bx = 0;
9904
0
      nscoord by = 0;
9905
0
      bool needsScrollPosUpdate = false;
9906
0
      if (mOSHE && (aLoadType == LOAD_HISTORY ||
9907
0
                    aLoadType == LOAD_RELOAD_NORMAL) &&
9908
0
          !scrollRestorationIsManual) {
9909
0
        needsScrollPosUpdate = true;
9910
0
        mOSHE->GetScrollPosition(&bx, &by);
9911
0
      }
9912
0
9913
0
      // Dispatch the popstate and hashchange events, as appropriate.
9914
0
      //
9915
0
      // The event dispatch below can cause us to re-enter script and
9916
0
      // destroy the docshell, nulling out mScriptGlobal. Hold a stack
9917
0
      // reference to avoid null derefs. See bug 914521.
9918
0
      if (win) {
9919
0
        // Fire a hashchange event URIs differ, and only in their hashes.
9920
0
        bool doHashchange = sameExceptHashes &&
9921
0
                            (curURIHasRef != newURIHasRef || !curHash.Equals(newHash));
9922
0
9923
0
        if (historyNavBetweenSameDoc || doHashchange) {
9924
0
          win->DispatchSyncPopState();
9925
0
        }
9926
0
9927
0
        if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) {
9928
0
          SetCurScrollPosEx(bx, by);
9929
0
        }
9930
0
9931
0
        if (doHashchange) {
9932
0
          // Note that currentURI hasn't changed because it's on the
9933
0
          // stack, so we can just use it directly as the old URI.
9934
0
          win->DispatchAsyncHashchange(currentURI, aURI);
9935
0
        }
9936
0
      }
9937
0
9938
0
      return NS_OK;
9939
0
    }
9940
0
  }
9941
0
9942
0
  // mContentViewer->PermitUnload can destroy |this| docShell, which
9943
0
  // causes the next call of CanSavePresentation to crash.
9944
0
  // Hold onto |this| until we return, to prevent a crash from happening.
9945
0
  // (bug#331040)
9946
0
  nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
9947
0
9948
0
  // Don't init timing for javascript:, since it generally doesn't
9949
0
  // actually start a load or anything.  If it does, we'll init
9950
0
  // timing then, from OnStateChange.
9951
0
9952
0
  // XXXbz mTiming should know what channel it's for, so we don't
9953
0
  // need this hackery.
9954
0
  bool toBeReset = false;
9955
0
  if (!isJavaScript) {
9956
0
    toBeReset = MaybeInitTiming();
9957
0
  }
9958
0
  bool timeBeforeUnload = aFileName.IsVoid();
9959
0
  if (mTiming && timeBeforeUnload) {
9960
0
    mTiming->NotifyBeforeUnload();
9961
0
  }
9962
0
  // Check if the page doesn't want to be unloaded. The javascript:
9963
0
  // protocol handler deals with this for javascript: URLs.
9964
0
  if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
9965
0
    bool okToUnload;
9966
0
    rv = mContentViewer->PermitUnload(&okToUnload);
9967
0
9968
0
    if (NS_SUCCEEDED(rv) && !okToUnload) {
9969
0
      // The user chose not to unload the page, interrupt the
9970
0
      // load.
9971
0
      MaybeResetInitTiming(toBeReset);
9972
0
      return NS_OK;
9973
0
    }
9974
0
  }
9975
0
9976
0
  if (mTiming && timeBeforeUnload) {
9977
0
    mTiming->NotifyUnloadAccepted(mCurrentURI);
9978
0
  }
9979
0
9980
0
  // Check if the webbrowser chrome wants the load to proceed; this can be
9981
0
  // used to cancel attempts to load URIs in the wrong process.
9982
0
  nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
9983
0
  if (browserChrome3) {
9984
0
    bool shouldLoad;
9985
0
    rv = browserChrome3->ShouldLoadURI(this, aURI, aReferrer, !!aPostData,
9986
0
                                       aTriggeringPrincipal, &shouldLoad);
9987
0
    if (NS_SUCCEEDED(rv) && !shouldLoad) {
9988
0
      return NS_OK;
9989
0
    }
9990
0
  }
9991
0
9992
0
  // Whenever a top-level browsing context is navigated, the user agent MUST
9993
0
  // lock the orientation of the document to the document's default
9994
0
  // orientation. We don't explicitly check for a top-level browsing context
9995
0
  // here because orientation is only set on top-level browsing contexts.
9996
0
  if (OrientationLock() != hal::eScreenOrientation_None) {
9997
#ifdef DEBUG
9998
    nsCOMPtr<nsIDocShellTreeItem> parent;
9999
    GetSameTypeParent(getter_AddRefs(parent));
10000
    MOZ_ASSERT(!parent);
10001
#endif
10002
    SetOrientationLock(hal::eScreenOrientation_None);
10003
0
    if (mIsActive) {
10004
0
      ScreenOrientation::UpdateActiveOrientationLock(
10005
0
        hal::eScreenOrientation_None);
10006
0
    }
10007
0
  }
10008
0
10009
0
  // Check for saving the presentation here, before calling Stop().
10010
0
  // This is necessary so that we can catch any pending requests.
10011
0
  // Since the new request has not been created yet, we pass null for the
10012
0
  // new request parameter.
10013
0
  // Also pass nullptr for the document, since it doesn't affect the return
10014
0
  // value for our purposes here.
10015
0
  bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
10016
0
10017
0
  // Don't stop current network activity for javascript: URL's since
10018
0
  // they might not result in any data, and thus nothing should be
10019
0
  // stopped in those cases. In the case where they do result in
10020
0
  // data, the javascript: URL channel takes care of stopping
10021
0
  // current network activity.
10022
0
  if (!isJavaScript && aFileName.IsVoid()) {
10023
0
    // Stop any current network activity.
10024
0
    // Also stop content if this is a zombie doc. otherwise
10025
0
    // the onload will be delayed by other loads initiated in the
10026
0
    // background by the first document that
10027
0
    // didn't fully load before the next load was initiated.
10028
0
    // If not a zombie, don't stop content until data
10029
0
    // starts arriving from the new URI...
10030
0
10031
0
    nsCOMPtr<nsIContentViewer> zombieViewer;
10032
0
    if (mContentViewer) {
10033
0
      mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
10034
0
    }
10035
0
10036
0
    if (zombieViewer ||
10037
0
        LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
10038
0
      rv = Stop(nsIWebNavigation::STOP_ALL);
10039
0
    } else {
10040
0
      rv = Stop(nsIWebNavigation::STOP_NETWORK);
10041
0
    }
10042
0
10043
0
    if (NS_FAILED(rv)) {
10044
0
      return rv;
10045
0
    }
10046
0
  }
10047
0
10048
0
  mLoadType = aLoadType;
10049
0
10050
0
  // mLSHE should be assigned to aSHEntry, only after Stop() has
10051
0
  // been called. But when loading an error page, do not clear the
10052
0
  // mLSHE for the real page.
10053
0
  if (mLoadType != LOAD_ERROR_PAGE) {
10054
0
    SetHistoryEntry(&mLSHE, aSHEntry);
10055
0
    if (aSHEntry) {
10056
0
      // We're making history navigation or a reload. Make sure our history ID
10057
0
      // points to the same ID as SHEntry's docshell ID.
10058
0
      mHistoryID = aSHEntry->DocshellID();
10059
0
    }
10060
0
  }
10061
0
10062
0
  mSavingOldViewer = savePresentation;
10063
0
10064
0
  // If we have a saved content viewer in history, restore and show it now.
10065
0
  if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
10066
0
    // It's possible that the previous viewer of mContentViewer is the
10067
0
    // viewer that will end up in aSHEntry when it gets closed.  If that's
10068
0
    // the case, we need to go ahead and force it into its shentry so we
10069
0
    // can restore it.
10070
0
    if (mContentViewer) {
10071
0
      nsCOMPtr<nsIContentViewer> prevViewer;
10072
0
      mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
10073
0
      if (prevViewer) {
10074
#ifdef DEBUG
10075
        nsCOMPtr<nsIContentViewer> prevPrevViewer;
10076
        prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
10077
        NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
10078
#endif
10079
        nsCOMPtr<nsISHEntry> viewerEntry;
10080
0
        prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
10081
0
        if (viewerEntry == aSHEntry) {
10082
0
          // Make sure this viewer ends up in the right place
10083
0
          mContentViewer->SetPreviousViewer(nullptr);
10084
0
          prevViewer->Destroy();
10085
0
        }
10086
0
      }
10087
0
    }
10088
0
    nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
10089
0
    bool restoring;
10090
0
    rv = RestorePresentation(aSHEntry, &restoring);
10091
0
    if (restoring) {
10092
0
      return rv;
10093
0
    }
10094
0
10095
0
    // We failed to restore the presentation, so clean up.
10096
0
    // Both the old and new history entries could potentially be in
10097
0
    // an inconsistent state.
10098
0
    if (NS_FAILED(rv)) {
10099
0
      if (oldEntry) {
10100
0
        oldEntry->SyncPresentationState();
10101
0
      }
10102
0
10103
0
      aSHEntry->SyncPresentationState();
10104
0
    }
10105
0
  }
10106
0
10107
0
  nsAutoString srcdoc;
10108
0
  if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) {
10109
0
    srcdoc = aSrcdoc;
10110
0
  } else {
10111
0
    srcdoc = VoidString();
10112
0
  }
10113
0
10114
0
  bool isTopLevelDoc = mItemType == typeContent &&
10115
0
                       (isTargetTopLevelDocShell ||
10116
0
                        GetIsMozBrowser());
10117
0
10118
0
  OriginAttributes attrs = GetOriginAttributes();
10119
0
  attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
10120
0
10121
0
  PredictorLearn(aURI, nullptr,
10122
0
                 nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
10123
0
  PredictorPredict(aURI, nullptr,
10124
0
                   nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
10125
0
10126
0
  nsCOMPtr<nsIRequest> req;
10127
0
  rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI,
10128
0
                 aKeepResultPrincipalURIIfSet, aLoadReplace,
10129
0
                 loadFromExternal,
10130
0
                 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
10131
0
                 (aFlags & INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC),
10132
0
                 aReferrer,
10133
0
                 !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
10134
0
                 aReferrerPolicy,
10135
0
                 aTriggeringPrincipal, principalToInherit, aTypeHint,
10136
0
                 aFileName, aPostData, aHeadersData,
10137
0
                 aFirstParty, aDocShell, getter_AddRefs(req),
10138
0
                 (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
10139
0
                 (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
10140
0
                 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
10141
0
                 srcdoc, aBaseURI, contentType);
10142
0
  if (req && aRequest) {
10143
0
    NS_ADDREF(*aRequest = req);
10144
0
  }
10145
0
10146
0
  if (NS_FAILED(rv)) {
10147
0
    nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
10148
0
    if (DisplayLoadError(rv, aURI, nullptr, chan) &&
10149
0
        (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
10150
0
      return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
10151
0
    }
10152
0
10153
0
    // We won't report any error if this is an unknown protocol error. The reason
10154
0
    // behind this is that it will allow enumeration of external protocols if
10155
0
    // we report an error for each unknown protocol.
10156
0
    if (NS_ERROR_UNKNOWN_PROTOCOL == rv) {
10157
0
      return NS_OK;
10158
0
    }
10159
0
  }
10160
0
10161
0
  return rv;
10162
0
}
10163
10164
nsIPrincipal*
10165
nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
10166
0
{
10167
0
  nsCOMPtr<nsIDocument> document;
10168
0
  bool inheritedFromCurrent = false;
10169
0
10170
0
  if (aConsiderCurrentDocument && mContentViewer) {
10171
0
    document = mContentViewer->GetDocument();
10172
0
    inheritedFromCurrent = true;
10173
0
  }
10174
0
10175
0
  if (!document) {
10176
0
    nsCOMPtr<nsIDocShellTreeItem> parentItem;
10177
0
    GetSameTypeParent(getter_AddRefs(parentItem));
10178
0
    if (parentItem) {
10179
0
      document = parentItem->GetDocument();
10180
0
    }
10181
0
  }
10182
0
10183
0
  if (!document) {
10184
0
    if (!aConsiderCurrentDocument) {
10185
0
      return nullptr;
10186
0
    }
10187
0
10188
0
    // Make sure we end up with _something_ as the principal no matter
10189
0
    // what.If this fails, we'll just get a null docViewer and bail.
10190
0
    EnsureContentViewer();
10191
0
    if (!mContentViewer) {
10192
0
      return nullptr;
10193
0
    }
10194
0
    document = mContentViewer->GetDocument();
10195
0
  }
10196
0
10197
0
  //-- Get the document's principal
10198
0
  if (document) {
10199
0
    nsIPrincipal* docPrincipal = document->NodePrincipal();
10200
0
10201
0
    // Don't allow loads in typeContent docShells to inherit the system
10202
0
    // principal from existing documents.
10203
0
    if (inheritedFromCurrent &&
10204
0
        mItemType == typeContent &&
10205
0
        nsContentUtils::IsSystemPrincipal(docPrincipal)) {
10206
0
      return nullptr;
10207
0
    }
10208
0
10209
0
    return docPrincipal;
10210
0
  }
10211
0
10212
0
  return nullptr;
10213
0
}
10214
10215
// CSPs upgrade-insecure-requests directive applies to same origin top level
10216
// navigations. Using the SOP would return false for the case when an https
10217
// page triggers and http page to load, even though that http page would be
10218
// upgraded to https later. Hence we have to use that custom function instead
10219
// of simply calling aTriggeringPrincipal->Equals(aResultPrincipal).
10220
static bool
10221
IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
10222
                             nsIPrincipal* aResultPrincipal)
10223
0
{
10224
0
  MOZ_ASSERT(aTriggeringPrincipal);
10225
0
  MOZ_ASSERT(aResultPrincipal);
10226
0
10227
0
  // we only have to make sure that the following truth table holds:
10228
0
  // aTriggeringPrincipal         | aResultPrincipal             | Result
10229
0
  // ----------------------------------------------------------------
10230
0
  // http://example.com/foo.html  | http://example.com/bar.html  | true
10231
0
  // https://example.com/foo.html | https://example.com/bar.html | true
10232
0
  // https://example.com/foo.html | http://example.com/bar.html  | true
10233
0
  if (aTriggeringPrincipal->Equals(aResultPrincipal)) {
10234
0
    return true;
10235
0
  }
10236
0
10237
0
  if (!aResultPrincipal->GetIsCodebasePrincipal()) {
10238
0
    return false;
10239
0
  }
10240
0
10241
0
  nsCOMPtr<nsIURI> resultURI;
10242
0
  nsresult rv = aResultPrincipal->GetURI(getter_AddRefs(resultURI));
10243
0
  NS_ENSURE_SUCCESS(rv, false);
10244
0
10245
0
  nsAutoCString resultScheme;
10246
0
  rv = resultURI->GetScheme(resultScheme);
10247
0
  NS_ENSURE_SUCCESS(rv, false);
10248
0
  if (!resultScheme.EqualsLiteral("http")) {
10249
0
    return false;
10250
0
  }
10251
0
10252
0
  nsAutoCString tmpResultSpec;
10253
0
  rv = resultURI->GetSpec(tmpResultSpec);
10254
0
  NS_ENSURE_SUCCESS(rv, false);
10255
0
  // replace http with https
10256
0
  tmpResultSpec.ReplaceLiteral(0, 4, "https");
10257
0
10258
0
  nsCOMPtr<nsIURI> tmpResultURI;
10259
0
  rv = NS_NewURI(getter_AddRefs(tmpResultURI), tmpResultSpec);
10260
0
  NS_ENSURE_SUCCESS(rv, false);
10261
0
10262
0
  mozilla::OriginAttributes tmpOA =
10263
0
    BasePrincipal::Cast(aResultPrincipal)->OriginAttributesRef();
10264
0
10265
0
  nsCOMPtr<nsIPrincipal> tmpResultPrincipal =
10266
0
    BasePrincipal::CreateCodebasePrincipal(tmpResultURI, tmpOA);
10267
0
10268
0
  return aTriggeringPrincipal->Equals(tmpResultPrincipal);
10269
0
}
10270
10271
nsresult
10272
nsDocShell::DoURILoad(nsIURI* aURI,
10273
                      nsIURI* aOriginalURI,
10274
                      Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
10275
                      bool aKeepResultPrincipalURIIfSet,
10276
                      bool aLoadReplace,
10277
                      bool aLoadFromExternal,
10278
                      bool aForceAllowDataURI,
10279
                      bool aOriginalFrameSrc,
10280
                      nsIURI* aReferrerURI,
10281
                      bool aSendReferrer,
10282
                      uint32_t aReferrerPolicy,
10283
                      nsIPrincipal* aTriggeringPrincipal,
10284
                      nsIPrincipal* aPrincipalToInherit,
10285
                      const char* aTypeHint,
10286
                      const nsAString& aFileName,
10287
                      nsIInputStream* aPostData,
10288
                      nsIInputStream* aHeadersData,
10289
                      bool aFirstParty,
10290
                      nsIDocShell** aDocShell,
10291
                      nsIRequest** aRequest,
10292
                      bool aIsNewWindowTarget,
10293
                      bool aBypassClassifier,
10294
                      bool aForceAllowCookies,
10295
                      const nsAString& aSrcdoc,
10296
                      nsIURI* aBaseURI,
10297
                      nsContentPolicyType aContentPolicyType)
10298
0
{
10299
0
  // Double-check that we're still around to load this URI.
10300
0
  if (mIsBeingDestroyed) {
10301
0
    // Return NS_OK despite not doing anything to avoid throwing exceptions from
10302
0
    // nsLocation::SetHref if the unload handler of the existing page tears us
10303
0
    // down.
10304
0
    return NS_OK;
10305
0
  }
10306
0
10307
0
  nsresult rv;
10308
0
  nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
10309
0
  if (NS_FAILED(rv)) {
10310
0
    return rv;
10311
0
  }
10312
0
10313
0
  if (IsFrame()) {
10314
0
10315
0
    MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
10316
0
               aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME,
10317
0
               "DoURILoad thinks this is a frame and InternalLoad does not");
10318
0
10319
0
    // Only allow view-source scheme in top-level docshells. view-source is
10320
0
    // the only scheme to which this applies at the moment due to potential
10321
0
    // timing attacks to read data from cross-origin iframes. If this widens
10322
0
    // we should add a protocol flag for whether the scheme is allowed in
10323
0
    // frames and use something like nsNetUtil::NS_URIChainHasFlags.
10324
0
    nsCOMPtr<nsIURI> tempURI = aURI;
10325
0
    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
10326
0
    while (nestedURI) {
10327
0
      // view-source should always be an nsINestedURI, loop and check the
10328
0
      // scheme on this and all inner URIs that are also nested URIs.
10329
0
      bool isViewSource = false;
10330
0
      rv = tempURI->SchemeIs("view-source", &isViewSource);
10331
0
      if (NS_FAILED(rv) || isViewSource) {
10332
0
        return NS_ERROR_UNKNOWN_PROTOCOL;
10333
0
      }
10334
0
      nestedURI->GetInnerURI(getter_AddRefs(tempURI));
10335
0
      nestedURI = do_QueryInterface(tempURI);
10336
0
    }
10337
0
  } else {
10338
0
    MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
10339
0
    "DoURILoad thinks this is a document and InternalLoad does not");
10340
0
  }
10341
0
10342
0
  // open a channel for the url
10343
0
  nsCOMPtr<nsIChannel> channel;
10344
0
10345
0
  bool isSrcdoc = !aSrcdoc.IsVoid();
10346
0
10347
0
  // There are two cases we care about:
10348
0
  // * Top-level load: In this case, loadingNode is null, but loadingWindow
10349
0
  //   is our mScriptGlobal. We pass null for loadingPrincipal in this case.
10350
0
  // * Subframe load: loadingWindow is null, but loadingNode is the frame
10351
0
  //   element for the load. loadingPrincipal is the NodePrincipal of the frame
10352
0
  //   element.
10353
0
  nsCOMPtr<nsINode> loadingNode;
10354
0
  nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
10355
0
  nsCOMPtr<nsIPrincipal> loadingPrincipal;
10356
0
  nsCOMPtr<nsISupports> topLevelLoadingContext;
10357
0
10358
0
  if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
10359
0
    loadingNode = nullptr;
10360
0
    loadingPrincipal = nullptr;
10361
0
    loadingWindow = mScriptGlobal->AsOuter();
10362
0
    if (XRE_IsContentProcess()) {
10363
0
      // In e10s the child process doesn't have access to the element that
10364
0
      // contains the browsing context (because that element is in the chrome
10365
0
      // process).
10366
0
      nsCOMPtr<nsITabChild> tabChild = GetTabChild();
10367
0
      topLevelLoadingContext = ToSupports(tabChild);
10368
0
    } else {
10369
0
      // This is for loading non-e10s tabs and toplevel windows of various
10370
0
      // sorts.
10371
0
      // For the toplevel window cases, requestingElement will be null.
10372
0
      nsCOMPtr<Element> requestingElement =
10373
0
        loadingWindow->GetFrameElementInternal();
10374
0
      topLevelLoadingContext = requestingElement;
10375
0
    }
10376
0
  } else {
10377
0
    loadingWindow = nullptr;
10378
0
    loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
10379
0
    if (loadingNode) {
10380
0
      // If we have a loading node, then use that as our loadingPrincipal.
10381
0
      loadingPrincipal = loadingNode->NodePrincipal();
10382
#ifdef DEBUG
10383
      // Get the docshell type for requestingElement.
10384
      nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc();
10385
      nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
10386
      // requestingElement docshell type = current docshell type.
10387
      MOZ_ASSERT(mItemType == elementDocShell->ItemType(),
10388
                "subframes should have the same docshell type as their parent");
10389
#endif
10390
0
    } else {
10391
0
      // If this isn't a top-level load and mScriptGlobal's frame element is
10392
0
      // null, then the element got removed from the DOM while we were trying
10393
0
      // to load this resource. This docshell is scheduled for destruction
10394
0
      // already, so bail out here.
10395
0
      return NS_OK;
10396
0
    }
10397
0
  }
10398
0
10399
0
  // Getting the right triggeringPrincipal needs to be updated and is only
10400
0
  // ready for use once bug 1182569 landed. Until then, we cannot rely on
10401
0
  // the triggeringPrincipal for TYPE_DOCUMENT loads.
10402
0
  MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
10403
0
10404
0
  bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
10405
0
10406
0
  // We want to inherit aPrincipalToInherit when:
10407
0
  // 1. ChannelShouldInheritPrincipal returns true.
10408
0
  // 2. aURI is not data: URI, or data: URI is not configured as unique opaque
10409
0
  //    origin.
10410
0
  bool inheritAttrs = false, inheritPrincipal = false;
10411
0
10412
0
  if (aPrincipalToInherit) {
10413
0
    inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
10414
0
      aPrincipalToInherit,
10415
0
      aURI,
10416
0
      true, // aInheritForAboutBlank
10417
0
      isSrcdoc);
10418
0
10419
0
    bool isData;
10420
0
    bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
10421
0
                             NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) &&
10422
0
                             isData;
10423
0
    inheritPrincipal = inheritAttrs && !isURIUniqueOrigin;
10424
0
  }
10425
0
10426
0
  nsLoadFlags loadFlags = mDefaultLoadFlags;
10427
0
  nsSecurityFlags securityFlags =
10428
0
    nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
10429
0
10430
0
  if (aFirstParty) {
10431
0
    // tag first party URL loads
10432
0
    loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
10433
0
  }
10434
0
10435
0
  if (mLoadType == LOAD_ERROR_PAGE) {
10436
0
    // Error pages are LOAD_BACKGROUND
10437
0
    loadFlags |= nsIChannel::LOAD_BACKGROUND;
10438
0
    securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
10439
0
  }
10440
0
10441
0
  if (inheritPrincipal) {
10442
0
    securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
10443
0
  }
10444
0
  if (isSandBoxed) {
10445
0
    securityFlags |= nsILoadInfo::SEC_SANDBOXED;
10446
0
  }
10447
0
10448
0
  nsCOMPtr<nsILoadInfo> loadInfo =
10449
0
    (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
10450
0
      new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext,
10451
0
                   securityFlags) :
10452
0
      new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
10453
0
                   securityFlags, aContentPolicyType);
10454
0
10455
0
  if (aPrincipalToInherit) {
10456
0
    loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
10457
0
  }
10458
0
  loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal);
10459
0
  loadInfo->SetForceAllowDataURI(aForceAllowDataURI);
10460
0
  loadInfo->SetOriginalFrameSrcLoad(aOriginalFrameSrc);
10461
0
10462
0
  // We have to do this in case our OriginAttributes are different from the
10463
0
  // OriginAttributes of the parent document. Or in case there isn't a
10464
0
  // parent document.
10465
0
  bool isTopLevelDoc = mItemType == typeContent &&
10466
0
                       (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
10467
0
                        GetIsMozBrowser());
10468
0
10469
0
  OriginAttributes attrs;
10470
0
10471
0
  // Inherit origin attributes from aPrincipalToInherit if inheritAttrs is true.
10472
0
  // Otherwise we just use the origin attributes from docshell.
10473
0
  if (inheritAttrs) {
10474
0
    MOZ_ASSERT(aPrincipalToInherit, "We should have aPrincipalToInherit here.");
10475
0
    attrs = aPrincipalToInherit->OriginAttributesRef();
10476
0
    // If firstPartyIsolation is not enabled, then PrincipalToInherit should
10477
0
    // have the same origin attributes with docshell.
10478
0
    MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(), attrs == GetOriginAttributes());
10479
0
  } else {
10480
0
    attrs = GetOriginAttributes();
10481
0
    attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
10482
0
  }
10483
0
10484
0
  rv = loadInfo->SetOriginAttributes(attrs);
10485
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
10486
0
    return rv;
10487
0
  }
10488
0
10489
0
  // Document loads should set the reload flag on the channel so that it
10490
0
  // can be exposed on the service worker FetchEvent.
10491
0
  rv = loadInfo->SetIsDocshellReload(mLoadType & LOAD_CMD_RELOAD);
10492
0
  NS_ENSURE_SUCCESS(rv, rv);
10493
0
10494
0
  if (!isSrcdoc) {
10495
0
    rv = NS_NewChannelInternal(getter_AddRefs(channel),
10496
0
                               aURI,
10497
0
                               loadInfo,
10498
0
                               nullptr,   // PerformanceStorage
10499
0
                               nullptr,   // loadGroup
10500
0
                               static_cast<nsIInterfaceRequestor*>(this),
10501
0
                               loadFlags);
10502
0
10503
0
    if (NS_FAILED(rv)) {
10504
0
      if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
10505
0
        // This is a uri with a protocol scheme we don't know how
10506
0
        // to handle.  Embedders might still be interested in
10507
0
        // handling the load, though, so we fire a notification
10508
0
        // before throwing the load away.
10509
0
        bool abort = false;
10510
0
        nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
10511
0
        if (NS_SUCCEEDED(rv2) && abort) {
10512
0
          // Hey, they're handling the load for us!  How convenient!
10513
0
          return NS_OK;
10514
0
        }
10515
0
      }
10516
0
      return rv;
10517
0
    }
10518
0
10519
0
    if (aBaseURI) {
10520
0
        nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
10521
0
        if (vsc) {
10522
0
            rv = vsc->SetBaseURI(aBaseURI);
10523
0
            MOZ_ASSERT(NS_SUCCEEDED(rv));
10524
0
        }
10525
0
    }
10526
0
  } else {
10527
0
    nsAutoCString scheme;
10528
0
    rv = aURI->GetScheme(scheme);
10529
0
    NS_ENSURE_SUCCESS(rv, rv);
10530
0
    bool isViewSource;
10531
0
    aURI->SchemeIs("view-source", &isViewSource);
10532
0
10533
0
    if (isViewSource) {
10534
0
      nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
10535
0
      NS_ENSURE_TRUE(vsh, NS_ERROR_FAILURE);
10536
0
10537
0
      rv = vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc,
10538
0
                                 loadInfo, getter_AddRefs(channel));
10539
0
    } else {
10540
0
      rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
10541
0
                                            aURI,
10542
0
                                            aSrcdoc,
10543
0
                                            NS_LITERAL_CSTRING("text/html"),
10544
0
                                            loadInfo,
10545
0
                                            true);
10546
0
      NS_ENSURE_SUCCESS(rv, rv);
10547
0
      nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
10548
0
      MOZ_ASSERT(isc);
10549
0
      isc->SetBaseURI(aBaseURI);
10550
0
    }
10551
0
  }
10552
0
10553
0
  // Navigational requests that are same origin need to be upgraded in case
10554
0
  // upgrade-insecure-requests is present. Please note that in that case
10555
0
  // the triggeringPrincipal is holding the CSP that potentially
10556
0
  // holds upgrade-insecure-requests.
10557
0
  nsCOMPtr<nsIContentSecurityPolicy> csp;
10558
0
  aTriggeringPrincipal->GetCsp(getter_AddRefs(csp));
10559
0
  if (csp) {
10560
0
    bool upgradeInsecureRequests = false;
10561
0
    csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
10562
0
    if (upgradeInsecureRequests) {
10563
0
      // only upgrade if the navigation is same origin
10564
0
      nsCOMPtr<nsIPrincipal> resultPrincipal;
10565
0
      rv = nsContentUtils::GetSecurityManager()->
10566
0
             GetChannelResultPrincipal(channel,
10567
0
                                       getter_AddRefs(resultPrincipal));
10568
0
      NS_ENSURE_SUCCESS(rv, rv);
10569
0
      if (IsConsideredSameOriginForUIR(aTriggeringPrincipal, resultPrincipal)) {
10570
0
        static_cast<LoadInfo*>(loadInfo.get())->SetUpgradeInsecureRequests();
10571
0
      }
10572
0
    }
10573
0
  }
10574
0
10575
0
10576
0
  nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
10577
0
    do_QueryInterface(channel);
10578
0
  if (appCacheChannel) {
10579
0
    // Any document load should not inherit application cache.
10580
0
    appCacheChannel->SetInheritApplicationCache(false);
10581
0
10582
0
    // Loads with the correct permissions should check for a matching
10583
0
    // application cache.
10584
0
    if (GeckoProcessType_Default != XRE_GetProcessType()) {
10585
0
      // Permission will be checked in the parent process
10586
0
      appCacheChannel->SetChooseApplicationCache(true);
10587
0
    } else {
10588
0
      nsCOMPtr<nsIScriptSecurityManager> secMan =
10589
0
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
10590
0
10591
0
      if (secMan) {
10592
0
        nsCOMPtr<nsIPrincipal> principal;
10593
0
        secMan->GetDocShellCodebasePrincipal(aURI, this,
10594
0
                                             getter_AddRefs(principal));
10595
0
        appCacheChannel->SetChooseApplicationCache(
10596
0
          NS_ShouldCheckAppCache(principal));
10597
0
      }
10598
0
    }
10599
0
  }
10600
0
10601
0
  // Make sure to give the caller a channel if we managed to create one
10602
0
  // This is important for correct error page/session history interaction
10603
0
  if (aRequest) {
10604
0
    NS_ADDREF(*aRequest = channel);
10605
0
  }
10606
0
10607
0
  if (aOriginalURI) {
10608
0
    channel->SetOriginalURI(aOriginalURI);
10609
0
    // The LOAD_REPLACE flag and its handling here will be removed as part
10610
0
    // of bug 1319110.  For now preserve its restoration here to not break
10611
0
    // any code expecting it being set specially on redirected channels.
10612
0
    // If the flag has originally been set to change result of
10613
0
    // NS_GetFinalChannelURI it won't have any effect and also won't cause
10614
0
    // any harm.
10615
0
    if (aLoadReplace) {
10616
0
      uint32_t loadFlags;
10617
0
      channel->GetLoadFlags(&loadFlags);
10618
0
      NS_ENSURE_SUCCESS(rv, rv);
10619
0
      channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
10620
0
    }
10621
0
  } else {
10622
0
    channel->SetOriginalURI(aURI);
10623
0
  }
10624
0
10625
0
  nsCOMPtr<nsIURI> rpURI;
10626
0
  loadInfo->GetResultPrincipalURI(getter_AddRefs(rpURI));
10627
0
  if (aResultPrincipalURI &&
10628
0
      (!aKeepResultPrincipalURIIfSet || !rpURI)) {
10629
0
    // Unconditionally override, we want the replay to be equal to what has
10630
0
    // been captured.
10631
0
    loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref());
10632
0
  }
10633
0
10634
0
  if (aTypeHint && *aTypeHint) {
10635
0
    channel->SetContentType(nsDependentCString(aTypeHint));
10636
0
    mContentTypeHint = aTypeHint;
10637
0
  } else {
10638
0
    mContentTypeHint.Truncate();
10639
0
  }
10640
0
10641
0
  if (!aFileName.IsVoid()) {
10642
0
    rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
10643
0
    NS_ENSURE_SUCCESS(rv, rv);
10644
0
    if (!aFileName.IsEmpty()) {
10645
0
      rv = channel->SetContentDispositionFilename(aFileName);
10646
0
      NS_ENSURE_SUCCESS(rv, rv);
10647
0
    }
10648
0
  }
10649
0
10650
0
  if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
10651
0
      mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
10652
0
    rv = SetMixedContentChannel(channel);
10653
0
    NS_ENSURE_SUCCESS(rv, rv);
10654
0
  } else if (mMixedContentChannel) {
10655
0
    /*
10656
0
     * If the user "Disables Protection on This Page", we call
10657
0
     * SetMixedContentChannel for the first time, otherwise
10658
0
     * mMixedContentChannel is still null.
10659
0
     * Later, if the new channel passes a same orign check, we remember the
10660
0
     * users decision by calling SetMixedContentChannel using the new channel.
10661
0
     * This way, the user does not have to click the disable protection button
10662
0
     * over and over for browsing the same site.
10663
0
     */
10664
0
    rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
10665
0
    if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
10666
0
      SetMixedContentChannel(nullptr);
10667
0
    }
10668
0
  }
10669
0
10670
0
  // hack
10671
0
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
10672
0
  nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
10673
0
    do_QueryInterface(channel));
10674
0
  if (httpChannelInternal) {
10675
0
    if (aForceAllowCookies) {
10676
0
      rv = httpChannelInternal->SetThirdPartyFlags(
10677
0
        nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
10678
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
10679
0
    }
10680
0
    if (aFirstParty) {
10681
0
      rv = httpChannelInternal->SetDocumentURI(aURI);
10682
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
10683
0
    } else {
10684
0
      rv = httpChannelInternal->SetDocumentURI(aReferrerURI);
10685
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
10686
0
    }
10687
0
    rv = httpChannelInternal->SetRedirectMode(
10688
0
      nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
10689
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
10690
0
  }
10691
0
10692
0
  nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
10693
0
  if (props) {
10694
0
    // save true referrer for those who need it (e.g. xpinstall whitelisting)
10695
0
    // Currently only http and ftp channels support this.
10696
0
    props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
10697
0
                                  aReferrerURI);
10698
0
  }
10699
0
10700
0
  nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
10701
0
  /* Get the cache Key from SH */
10702
0
  uint32_t cacheKey = 0;
10703
0
  if (cacheChannel) {
10704
0
    if (mLSHE) {
10705
0
      cacheKey = mLSHE->GetCacheKey();
10706
0
    } else if (mOSHE) {  // for reload cases
10707
0
      cacheKey = mOSHE->GetCacheKey();
10708
0
    }
10709
0
  }
10710
0
10711
0
  // figure out if we need to set the post data stream on the channel...
10712
0
  if (aPostData) {
10713
0
    nsCOMPtr<nsIFormPOSTActionChannel> postChannel(do_QueryInterface(channel));
10714
0
    if (postChannel) {
10715
0
      // XXX it's a bit of a hack to rewind the postdata stream here but
10716
0
      // it has to be done in case the post data is being reused multiple
10717
0
      // times.
10718
0
      nsCOMPtr<nsISeekableStream> postDataSeekable =
10719
0
        do_QueryInterface(aPostData);
10720
0
      if (postDataSeekable) {
10721
0
        rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
10722
0
        NS_ENSURE_SUCCESS(rv, rv);
10723
0
      }
10724
0
10725
0
      // we really need to have a content type associated with this stream!!
10726
0
      postChannel->SetUploadStream(aPostData, EmptyCString(), -1);
10727
0
    }
10728
0
10729
0
    /* If there is a valid postdata *and* it is a History Load,
10730
0
     * set up the cache key on the channel, to retrieve the
10731
0
     * data *only* from the cache. If it is a normal reload, the
10732
0
     * cache is free to go to the server for updated postdata.
10733
0
     */
10734
0
    if (cacheChannel && cacheKey != 0) {
10735
0
      if (mLoadType == LOAD_HISTORY ||
10736
0
          mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
10737
0
        cacheChannel->SetCacheKey(cacheKey);
10738
0
        uint32_t loadFlags;
10739
0
        if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
10740
0
          channel->SetLoadFlags(
10741
0
            loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
10742
0
        }
10743
0
      } else if (mLoadType == LOAD_RELOAD_NORMAL) {
10744
0
        cacheChannel->SetCacheKey(cacheKey);
10745
0
      }
10746
0
    }
10747
0
  } else {
10748
0
    /* If there is no postdata, set the cache key on the channel, and
10749
0
     * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
10750
0
     * will be free to get it from net if it is not found in cache.
10751
0
     * New cache may use it creatively on CGI pages with GET
10752
0
     * method and even on those that say "no-cache"
10753
0
     */
10754
0
    if (mLoadType == LOAD_HISTORY ||
10755
0
        mLoadType == LOAD_RELOAD_NORMAL ||
10756
0
        mLoadType == LOAD_RELOAD_CHARSET_CHANGE ||
10757
0
        mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE ||
10758
0
        mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE) {
10759
0
      if (cacheChannel && cacheKey != 0) {
10760
0
        cacheChannel->SetCacheKey(cacheKey);
10761
0
      }
10762
0
    }
10763
0
  }
10764
0
10765
0
  if (httpChannel) {
10766
0
    if (aHeadersData) {
10767
0
      rv = AddHeadersToChannel(aHeadersData, httpChannel);
10768
0
    }
10769
0
    // Set the referrer explicitly
10770
0
    if (aReferrerURI && aSendReferrer) {
10771
0
      // Referrer is currenly only set for link clicks here.
10772
0
      rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
10773
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
10774
0
    }
10775
0
  }
10776
0
10777
0
  nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
10778
0
  if (scriptChannel) {
10779
0
    // Allow execution against our context if the principals match
10780
0
    scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
10781
0
  }
10782
0
10783
0
  if (aIsNewWindowTarget) {
10784
0
    nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
10785
0
    if (props) {
10786
0
      props->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
10787
0
                               true);
10788
0
    }
10789
0
  }
10790
0
10791
0
  nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
10792
0
  if (timedChannel) {
10793
0
    timedChannel->SetTimingEnabled(true);
10794
0
10795
0
    nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10796
0
    if (IsFrame() && win) {
10797
0
      nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
10798
0
      if (frameElement) {
10799
0
        timedChannel->SetInitiatorType(frameElement->LocalName());
10800
0
      }
10801
0
    }
10802
0
  }
10803
0
10804
0
  // Mark the http channel as UrgentStart for top level document loading
10805
0
  // in active tab.
10806
0
  if (mIsActive || (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY))) {
10807
0
    if (httpChannel && isTopLevelDoc) {
10808
0
      nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
10809
0
      if (cos) {
10810
0
        cos->AddClassFlags(nsIClassOfService::UrgentStart);
10811
0
      }
10812
0
    }
10813
0
  }
10814
0
10815
0
  rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
10816
0
10817
0
  //
10818
0
  // If the channel load failed, we failed and nsIWebProgress just ain't
10819
0
  // gonna happen.
10820
0
  //
10821
0
  if (NS_SUCCEEDED(rv)) {
10822
0
    if (aDocShell) {
10823
0
      *aDocShell = this;
10824
0
      NS_ADDREF(*aDocShell);
10825
0
    }
10826
0
  }
10827
0
10828
0
  return rv;
10829
0
}
10830
10831
static nsresult
10832
AppendSegmentToString(nsIInputStream* aIn,
10833
                      void* aClosure,
10834
                      const char* aFromRawSegment,
10835
                      uint32_t aToOffset,
10836
                      uint32_t aCount,
10837
                      uint32_t* aWriteCount)
10838
0
{
10839
0
  // aFromSegment now contains aCount bytes of data.
10840
0
10841
0
  nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure);
10842
0
  buf->Append(aFromRawSegment, aCount);
10843
0
10844
0
  // Indicate that we have consumed all of aFromSegment
10845
0
  *aWriteCount = aCount;
10846
0
  return NS_OK;
10847
0
}
10848
10849
nsresult
10850
nsDocShell::AddHeadersToChannel(nsIInputStream* aHeadersData,
10851
                                nsIChannel* aGenericChannel)
10852
0
{
10853
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
10854
0
  NS_ENSURE_STATE(httpChannel);
10855
0
10856
0
  uint32_t numRead;
10857
0
  nsAutoCString headersString;
10858
0
  nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
10859
0
                                           &headersString,
10860
0
                                           UINT32_MAX,
10861
0
                                           &numRead);
10862
0
  NS_ENSURE_SUCCESS(rv, rv);
10863
0
10864
0
  // used during the manipulation of the String from the InputStream
10865
0
  nsAutoCString headerName;
10866
0
  nsAutoCString headerValue;
10867
0
  int32_t crlf;
10868
0
  int32_t colon;
10869
0
10870
0
  //
10871
0
  // Iterate over the headersString: for each "\r\n" delimited chunk,
10872
0
  // add the value as a header to the nsIHttpChannel
10873
0
  //
10874
0
10875
0
  static const char kWhitespace[] = "\b\t\r\n ";
10876
0
  while (true) {
10877
0
    crlf = headersString.Find("\r\n");
10878
0
    if (crlf == kNotFound) {
10879
0
      return NS_OK;
10880
0
    }
10881
0
10882
0
    const nsACString& oneHeader = StringHead(headersString, crlf);
10883
0
10884
0
    colon = oneHeader.FindChar(':');
10885
0
    if (colon == kNotFound) {
10886
0
      return NS_ERROR_UNEXPECTED;
10887
0
    }
10888
0
10889
0
    headerName = StringHead(oneHeader, colon);
10890
0
    headerValue = Substring(oneHeader, colon + 1);
10891
0
10892
0
    headerName.Trim(kWhitespace);
10893
0
    headerValue.Trim(kWhitespace);
10894
0
10895
0
    headersString.Cut(0, crlf + 2);
10896
0
10897
0
    //
10898
0
    // FINALLY: we can set the header!
10899
0
    //
10900
0
10901
0
    rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
10902
0
    NS_ENSURE_SUCCESS(rv, rv);
10903
0
  }
10904
0
10905
0
  MOZ_ASSERT_UNREACHABLE("oops");
10906
0
  return NS_ERROR_UNEXPECTED;
10907
0
}
10908
10909
nsresult
10910
nsDocShell::DoChannelLoad(nsIChannel* aChannel,
10911
                          nsIURILoader* aURILoader,
10912
                          bool aBypassClassifier)
10913
0
{
10914
0
  nsresult rv;
10915
0
  // Mark the channel as being a document URI and allow content sniffing...
10916
0
  nsLoadFlags loadFlags = 0;
10917
0
  (void)aChannel->GetLoadFlags(&loadFlags);
10918
0
  loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
10919
0
               nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
10920
0
10921
0
  if (SandboxFlagsImplyCookies(mSandboxFlags)) {
10922
0
    loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
10923
0
  }
10924
0
  // Load attributes depend on load type...
10925
0
  switch (mLoadType) {
10926
0
    case LOAD_HISTORY: {
10927
0
      // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
10928
0
      // push/replaceState (bug 669671).
10929
0
      bool uriModified = false;
10930
0
      if (mLSHE) {
10931
0
        uriModified = mLSHE->GetURIWasModified();
10932
0
      }
10933
0
10934
0
      if (!uriModified) {
10935
0
        loadFlags |= nsIRequest::VALIDATE_NEVER;
10936
0
      }
10937
0
      break;
10938
0
    }
10939
0
10940
0
    case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
10941
0
    case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
10942
0
      loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
10943
0
        nsIRequest::LOAD_FRESH_CONNECTION;
10944
0
      MOZ_FALLTHROUGH;
10945
0
10946
0
    case LOAD_RELOAD_CHARSET_CHANGE: {
10947
0
      // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only want
10948
0
      // to force cache load for this channel, not the whole loadGroup.
10949
0
      nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(aChannel);
10950
0
      if (cachingChannel) {
10951
0
        cachingChannel->SetAllowStaleCacheContent(true);
10952
0
      }
10953
0
      break;
10954
0
    }
10955
0
10956
0
    case LOAD_RELOAD_NORMAL:
10957
0
    case LOAD_REFRESH:
10958
0
      loadFlags |= nsIRequest::VALIDATE_ALWAYS;
10959
0
      break;
10960
0
10961
0
    case LOAD_NORMAL_BYPASS_CACHE:
10962
0
    case LOAD_NORMAL_BYPASS_PROXY:
10963
0
    case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
10964
0
    case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
10965
0
    case LOAD_RELOAD_BYPASS_CACHE:
10966
0
    case LOAD_RELOAD_BYPASS_PROXY:
10967
0
    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
10968
0
    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
10969
0
    case LOAD_REPLACE_BYPASS_CACHE:
10970
0
      loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
10971
0
                   nsIRequest::LOAD_FRESH_CONNECTION;
10972
0
      break;
10973
0
10974
0
    case LOAD_NORMAL:
10975
0
    case LOAD_LINK:
10976
0
      // Set cache checking flags
10977
0
      switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
10978
0
        case 0:
10979
0
          loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
10980
0
          break;
10981
0
        case 1:
10982
0
          loadFlags |= nsIRequest::VALIDATE_ALWAYS;
10983
0
          break;
10984
0
        case 2:
10985
0
          loadFlags |= nsIRequest::VALIDATE_NEVER;
10986
0
          break;
10987
0
      }
10988
0
      break;
10989
0
  }
10990
0
10991
0
  if (!aBypassClassifier) {
10992
0
    loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
10993
0
  }
10994
0
10995
0
  // If the user pressed shift-reload, then do not allow ServiceWorker
10996
0
  // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
10997
0
  if (IsForceReloading()) {
10998
0
    loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
10999
0
  }
11000
0
11001
0
  (void)aChannel->SetLoadFlags(loadFlags);
11002
0
11003
0
  uint32_t openFlags = 0;
11004
0
  if (mLoadType == LOAD_LINK) {
11005
0
    openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
11006
0
  }
11007
0
  if (!mAllowContentRetargeting) {
11008
0
    openFlags |= nsIURILoader::DONT_RETARGET;
11009
0
  }
11010
0
11011
0
  // If anything fails here, make sure to clear our initial ClientSource.
11012
0
  auto cleanupInitialClient = MakeScopeExit([&] {
11013
0
    mInitialClientSource.reset();
11014
0
  });
11015
0
11016
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
11017
0
  NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
11018
0
11019
0
  MaybeCreateInitialClientSource();
11020
0
11021
0
  // Since we are loading a document we need to make sure the proper reserved
11022
0
  // and initial client data is stored on the nsILoadInfo.  The
11023
0
  // ClientChannelHelper does this and ensures that it is propagated properly
11024
0
  // on redirects.  We pass no reserved client here so that the helper will
11025
0
  // create the reserved ClientSource if necessary.
11026
0
  Maybe<ClientInfo> noReservedClient;
11027
0
  rv = AddClientChannelHelper(aChannel,
11028
0
                              std::move(noReservedClient),
11029
0
                              GetInitialClientInfo(),
11030
0
                              win->EventTargetFor(TaskCategory::Other));
11031
0
  NS_ENSURE_SUCCESS(rv, rv);
11032
0
11033
0
  rv = aURILoader->OpenURI(aChannel, openFlags, this);
11034
0
  NS_ENSURE_SUCCESS(rv, rv);
11035
0
11036
0
  // We're about to load a new page and it may take time before necko
11037
0
  // gives back any data, so main thread might have a chance to process a
11038
0
  // collector slice
11039
0
  nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL);
11040
0
11041
0
  // Success.  Keep the initial ClientSource if it exists.
11042
0
  cleanupInitialClient.release();
11043
0
11044
0
  return NS_OK;
11045
0
}
11046
11047
nsresult
11048
nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
11049
                           nsACString& aNewHash, uint32_t aLoadType)
11050
0
{
11051
0
  if (!mCurrentURI) {
11052
0
    return NS_OK;
11053
0
  }
11054
0
11055
0
  nsCOMPtr<nsIPresShell> shell = GetPresShell();
11056
0
  if (!shell) {
11057
0
    // If we failed to get the shell, or if there is no shell,
11058
0
    // nothing left to do here.
11059
0
    return NS_OK;
11060
0
  }
11061
0
11062
0
  nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
11063
0
  if (rootScroll) {
11064
0
    rootScroll->ClearDidHistoryRestore();
11065
0
  }
11066
0
11067
0
  // If we have no new anchor, we do not want to scroll, unless there is a
11068
0
  // current anchor and we are doing a history load.  So return if we have no
11069
0
  // new anchor, and there is no current anchor or the load is not a history
11070
0
  // load.
11071
0
  if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef) {
11072
0
    return NS_OK;
11073
0
  }
11074
0
11075
0
  // Both the new and current URIs refer to the same page. We can now
11076
0
  // browse to the hash stored in the new URI.
11077
0
11078
0
  if (!aNewHash.IsEmpty()) {
11079
0
    // anchor is there, but if it's a load from history,
11080
0
    // we don't have any anchor jumping to do
11081
0
    bool scroll = aLoadType != LOAD_HISTORY &&
11082
0
                  aLoadType != LOAD_RELOAD_NORMAL;
11083
0
11084
0
    // We assume that the bytes are in UTF-8, as it says in the
11085
0
    // spec:
11086
0
    // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
11087
0
11088
0
    // We try the UTF-8 string first, and then try the document's
11089
0
    // charset (see below).  If the string is not UTF-8,
11090
0
    // conversion will fail and give us an empty Unicode string.
11091
0
    // In that case, we should just fall through to using the
11092
0
    // page's charset.
11093
0
    nsresult rv = NS_ERROR_FAILURE;
11094
0
    NS_ConvertUTF8toUTF16 uStr(aNewHash);
11095
0
    if (!uStr.IsEmpty()) {
11096
0
      rv = shell->GoToAnchor(uStr, scroll,
11097
0
                             nsIPresShell::SCROLL_SMOOTH_AUTO);
11098
0
    }
11099
0
11100
0
    if (NS_FAILED(rv)) {
11101
0
      char* str = ToNewCString(aNewHash);
11102
0
      if (!str) {
11103
0
        return NS_ERROR_OUT_OF_MEMORY;
11104
0
      }
11105
0
      nsUnescape(str);
11106
0
      NS_ConvertUTF8toUTF16 utf16Str(str);
11107
0
      if (!utf16Str.IsEmpty()) {
11108
0
        rv = shell->GoToAnchor(utf16Str, scroll,
11109
0
                               nsIPresShell::SCROLL_SMOOTH_AUTO);
11110
0
      }
11111
0
      free(str);
11112
0
    }
11113
0
11114
0
    // Above will fail if the anchor name is not UTF-8.  Need to
11115
0
    // convert from document charset to unicode.
11116
0
    if (NS_FAILED(rv)) {
11117
0
      // Get a document charset
11118
0
      NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
11119
0
      nsIDocument* doc = mContentViewer->GetDocument();
11120
0
      NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
11121
0
      nsAutoCString charset;
11122
0
      doc->GetDocumentCharacterSet()->Name(charset);
11123
0
11124
0
      nsCOMPtr<nsITextToSubURI> textToSubURI =
11125
0
        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
11126
0
      NS_ENSURE_SUCCESS(rv, rv);
11127
0
11128
0
      // Unescape and convert to unicode
11129
0
      nsAutoString uStr;
11130
0
11131
0
      rv = textToSubURI->UnEscapeAndConvert(charset, aNewHash, uStr);
11132
0
      NS_ENSURE_SUCCESS(rv, rv);
11133
0
11134
0
      // Ignore return value of GoToAnchor, since it will return an error
11135
0
      // if there is no such anchor in the document, which is actually a
11136
0
      // success condition for us (we want to update the session history
11137
0
      // with the new URI no matter whether we actually scrolled
11138
0
      // somewhere).
11139
0
      //
11140
0
      // When aNewHash contains "%00", unescaped string may be empty.
11141
0
      // And GoToAnchor asserts if we ask it to scroll to an empty ref.
11142
0
      shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(),
11143
0
                        nsIPresShell::SCROLL_SMOOTH_AUTO);
11144
0
    }
11145
0
  } else {
11146
0
    // Tell the shell it's at an anchor, without scrolling.
11147
0
    shell->GoToAnchor(EmptyString(), false);
11148
0
11149
0
    // An empty anchor was found, but if it's a load from history,
11150
0
    // we don't have to jump to the top of the page. Scrollbar
11151
0
    // position will be restored by the caller, based on positions
11152
0
    // stored in session history.
11153
0
    if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) {
11154
0
      return NS_OK;
11155
0
    }
11156
0
    // An empty anchor. Scroll to the top of the page.  Ignore the
11157
0
    // return value; failure to scroll here (e.g. if there is no
11158
0
    // root scrollframe) is not grounds for canceling the load!
11159
0
    SetCurScrollPosEx(0, 0);
11160
0
  }
11161
0
11162
0
  return NS_OK;
11163
0
}
11164
11165
void
11166
nsDocShell::SetupReferrerFromChannel(nsIChannel* aChannel)
11167
0
{
11168
0
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11169
0
  if (httpChannel) {
11170
0
    nsCOMPtr<nsIURI> referrer;
11171
0
    nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
11172
0
    if (NS_SUCCEEDED(rv)) {
11173
0
      SetReferrerURI(referrer);
11174
0
    }
11175
0
    uint32_t referrerPolicy;
11176
0
    rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
11177
0
    if (NS_SUCCEEDED(rv)) {
11178
0
      SetReferrerPolicy(referrerPolicy);
11179
0
    }
11180
0
  }
11181
0
}
11182
11183
bool
11184
nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
11185
                     nsIPrincipal* aTriggeringPrincipal,
11186
                     nsIPrincipal* aPrincipalToInherit,
11187
                     uint32_t aLoadType, bool aFireOnLocationChange,
11188
                     bool aAddToGlobalHistory, bool aCloneSHChildren)
11189
0
{
11190
0
  MOZ_ASSERT(aURI, "uri is null");
11191
0
  MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
11192
0
11193
0
  MOZ_ASSERT(!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal));
11194
0
11195
#if defined(DEBUG)
11196
  if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
11197
    nsAutoCString chanName;
11198
    if (aChannel) {
11199
      aChannel->GetName(chanName);
11200
    } else {
11201
      chanName.AssignLiteral("<no channel>");
11202
    }
11203
11204
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
11205
            ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
11206
             this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
11207
  }
11208
#endif
11209
11210
0
  bool equalUri = false;
11211
0
11212
0
  // Get the post data and the HTTP response code from the channel.
11213
0
  uint32_t responseStatus = 0;
11214
0
  nsCOMPtr<nsIInputStream> inputStream;
11215
0
  if (aChannel) {
11216
0
    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11217
0
11218
0
    // Check if the HTTPChannel is hiding under a multiPartChannel
11219
0
    if (!httpChannel) {
11220
0
      GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11221
0
    }
11222
0
11223
0
    if (httpChannel) {
11224
0
      nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11225
0
      if (uploadChannel) {
11226
0
        uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11227
0
      }
11228
0
11229
0
      // If the response status indicates an error, unlink this session
11230
0
      // history entry from any entries sharing its document.
11231
0
      nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
11232
0
      if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
11233
0
        mLSHE->AbandonBFCacheEntry();
11234
0
      }
11235
0
    }
11236
0
  }
11237
0
11238
0
  // Determine if this type of load should update history.
11239
0
  bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY ||
11240
0
                          aLoadType == LOAD_ERROR_PAGE ||
11241
0
                          aLoadType & LOAD_CMD_HISTORY);
11242
0
11243
0
  // We don't update session history on reload unless we're loading
11244
0
  // an iframe in shift-reload case.
11245
0
  bool updateSHistory = updateGHistory &&
11246
0
                        (!(aLoadType & LOAD_CMD_RELOAD) ||
11247
0
                         (IsForceReloadType(aLoadType) && IsFrame()));
11248
0
11249
0
  // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
11250
0
  // current frame or in the root docshell.
11251
0
  RefPtr<ChildSHistory> rootSH = mSessionHistory;
11252
0
  if (!rootSH) {
11253
0
    // Get the handle to SH from the root docshell
11254
0
    rootSH = GetRootSessionHistory();
11255
0
  }
11256
0
  if (!rootSH) {
11257
0
    updateSHistory = false;
11258
0
    updateGHistory = false; // XXX Why global history too?
11259
0
  }
11260
0
11261
0
  // Check if the url to be loaded is the same as the one already loaded.
11262
0
  if (mCurrentURI) {
11263
0
    aURI->Equals(mCurrentURI, &equalUri);
11264
0
  }
11265
0
11266
#ifdef DEBUG
11267
  bool shAvailable = (rootSH != nullptr);
11268
11269
  // XXX This log message is almost useless because |updateSHistory|
11270
  //     and |updateGHistory| are not correct at this point.
11271
11272
  MOZ_LOG(gDocShellLog, LogLevel::Debug,
11273
         ("  shAvailable=%i updateSHistory=%i updateGHistory=%i"
11274
          " equalURI=%i\n",
11275
          shAvailable, updateSHistory, updateGHistory, equalUri));
11276
11277
  if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
11278
    // XXX mCurrentURI can be changed from any caller regardless what actual
11279
    // loaded document is, so testing mCurrentURI isn't really a reliable way.
11280
    // Session restore is one example which changes current URI in order to
11281
    // show address before loading. See bug 1301399.
11282
    NS_ASSERTION(NS_IsAboutBlank(mCurrentURI),
11283
                 "no SHEntry for a non-transient viewer?");
11284
  }
11285
#endif
11286
11287
0
  /* If the url to be loaded is the same as the one already there,
11288
0
   * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
11289
0
   * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
11290
0
   * AddToSessionHistory() won't mess with the current SHEntry and
11291
0
   * if this page has any frame children, it also will be handled
11292
0
   * properly. see bug 83684
11293
0
   *
11294
0
   * NB: If mOSHE is null but we have a current URI, then it means
11295
0
   * that we must be at the transient about:blank content viewer
11296
0
   * (asserted above) and we should let the normal load continue,
11297
0
   * since there's nothing to replace.
11298
0
   *
11299
0
   * XXX Hopefully changing the loadType at this time will not hurt
11300
0
   *  anywhere. The other way to take care of sequentially repeating
11301
0
   *  frameset pages is to add new methods to nsIDocShellTreeItem.
11302
0
   * Hopefully I don't have to do that.
11303
0
   */
11304
0
  if (equalUri &&
11305
0
      mOSHE &&
11306
0
      (mLoadType == LOAD_NORMAL ||
11307
0
       mLoadType == LOAD_LINK ||
11308
0
       mLoadType == LOAD_STOP_CONTENT) &&
11309
0
      !inputStream) {
11310
0
    mLoadType = LOAD_NORMAL_REPLACE;
11311
0
  }
11312
0
11313
0
  // If this is a refresh to the currently loaded url, we don't
11314
0
  // have to update session or global history.
11315
0
  if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
11316
0
    SetHistoryEntry(&mLSHE, mOSHE);
11317
0
  }
11318
0
11319
0
  /* If the user pressed shift-reload, cache will create a new cache key
11320
0
   * for the page. Save the new cacheKey in Session History.
11321
0
   * see bug 90098
11322
0
   */
11323
0
  if (aChannel && IsForceReloadType(aLoadType)) {
11324
0
    MOZ_ASSERT(!updateSHistory || IsFrame(),
11325
0
               "We shouldn't be updating session history for forced"
11326
0
               " reloads unless we're in a newly created iframe!");
11327
0
11328
0
    nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel));
11329
0
    uint32_t cacheKey = 0;
11330
0
    // Get the Cache Key and store it in SH.
11331
0
    if (cacheChannel) {
11332
0
      cacheChannel->GetCacheKey(&cacheKey);
11333
0
    }
11334
0
    // If we already have a loading history entry, store the new cache key
11335
0
    // in it.  Otherwise, since we're doing a reload and won't be updating
11336
0
    // our history entry, store the cache key in our current history entry.
11337
0
    if (mLSHE) {
11338
0
      mLSHE->SetCacheKey(cacheKey);
11339
0
    } else if (mOSHE) {
11340
0
      mOSHE->SetCacheKey(cacheKey);
11341
0
    }
11342
0
11343
0
    // Since we're force-reloading, clear all the sub frame history.
11344
0
    ClearFrameHistory(mLSHE);
11345
0
    ClearFrameHistory(mOSHE);
11346
0
  }
11347
0
11348
0
  // Clear subframe history on refresh.
11349
0
  // XXX: history.go(0) won't go this path as aLoadType is LOAD_HISTORY in this
11350
0
  // case. One should re-validate after bug 1331865 fixed.
11351
0
  if (aLoadType == LOAD_REFRESH) {
11352
0
    ClearFrameHistory(mLSHE);
11353
0
    ClearFrameHistory(mOSHE);
11354
0
  }
11355
0
11356
0
  if (updateSHistory) {
11357
0
    // Update session history if necessary...
11358
0
    if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
11359
0
      /* This is  a fresh page getting loaded for the first time
11360
0
       *.Create a Entry for it and add it to SH, if this is the
11361
0
       * rootDocShell
11362
0
       */
11363
0
      (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
11364
0
                                aPrincipalToInherit, aCloneSHChildren,
11365
0
                                getter_AddRefs(mLSHE));
11366
0
    }
11367
0
  } else if (mSessionHistory && mLSHE && mURIResultedInDocument) {
11368
0
    // Even if we don't add anything to SHistory, ensure the current index
11369
0
    // points to the same SHEntry as our mLSHE.
11370
0
    int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex();
11371
0
    if (index == -1) {
11372
0
      index = mSessionHistory->Index();
11373
0
    }
11374
0
    nsCOMPtr<nsISHEntry> currentSH;
11375
0
    mSessionHistory->LegacySHistory()->GetEntryAtIndex(
11376
0
      index, getter_AddRefs(currentSH));
11377
0
    if (currentSH != mLSHE) {
11378
0
      mSessionHistory->LegacySHistory()->ReplaceEntry(index, mLSHE);
11379
0
    }
11380
0
  }
11381
0
11382
0
  // If this is a POST request, we do not want to include this in global
11383
0
  // history.
11384
0
  if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
11385
0
    nsCOMPtr<nsIURI> previousURI;
11386
0
    uint32_t previousFlags = 0;
11387
0
11388
0
    if (aLoadType & LOAD_CMD_RELOAD) {
11389
0
      // On a reload request, we don't set redirecting flags.
11390
0
      previousURI = aURI;
11391
0
    } else {
11392
0
      ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags);
11393
0
    }
11394
0
11395
0
    // Note: We don't use |referrer| when our global history is
11396
0
    //       based on IHistory.
11397
0
    nsCOMPtr<nsIURI> referrer;
11398
0
    // Treat referrer as null if there is an error getting it.
11399
0
    (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
11400
0
11401
0
    AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
11402
0
  }
11403
0
11404
0
  // If this was a history load or a refresh, or it was a history load but
11405
0
  // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index
11406
0
  // in session history.
11407
0
  if (rootSH &&
11408
0
       ((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) ||
11409
0
         mLoadType == LOAD_NORMAL_REPLACE)) {
11410
0
    mPreviousEntryIndex = rootSH->Index();
11411
0
    rootSH->LegacySHistory()->UpdateIndex();
11412
0
    mLoadedEntryIndex = rootSH->Index();
11413
#ifdef DEBUG_PAGE_CACHE
11414
    printf("Previous index: %d, Loaded index: %d\n\n",
11415
           mPreviousEntryIndex, mLoadedEntryIndex);
11416
#endif
11417
  }
11418
0
11419
0
  // aCloneSHChildren exactly means "we are not loading a new document".
11420
0
  uint32_t locationFlags =
11421
0
    aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
11422
0
11423
0
  bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
11424
0
                                              aFireOnLocationChange,
11425
0
                                              locationFlags);
11426
0
  // Make sure to store the referrer from the channel, if any
11427
0
  SetupReferrerFromChannel(aChannel);
11428
0
  return onLocationChangeNeeded;
11429
0
}
11430
11431
bool
11432
nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange,
11433
                          bool aAddToGlobalHistory)
11434
0
{
11435
0
  nsCOMPtr<nsIURI> uri;
11436
0
  // If this a redirect, use the final url (uri)
11437
0
  // else use the original url
11438
0
  //
11439
0
  // Note that this should match what documents do (see nsDocument::Reset).
11440
0
  NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
11441
0
  NS_ENSURE_TRUE(uri, false);
11442
0
11443
0
  // Pass false for aCloneSHChildren, since we're loading a new page here.
11444
0
  return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType, aFireOnLocationChange,
11445
0
                  aAddToGlobalHistory, false);
11446
0
}
11447
11448
void
11449
nsDocShell::SetReferrerURI(nsIURI* aURI)
11450
0
{
11451
0
  mReferrerURI = aURI;  // This assigment addrefs
11452
0
}
11453
11454
void
11455
nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy)
11456
0
{
11457
0
  mReferrerPolicy = aReferrerPolicy;
11458
0
}
11459
11460
//*****************************************************************************
11461
// nsDocShell: Session History
11462
//*****************************************************************************
11463
11464
NS_IMETHODIMP
11465
nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
11466
                     const nsAString& aURL, bool aReplace, JSContext* aCx)
11467
0
{
11468
0
  // Implements History.pushState and History.replaceState
11469
0
11470
0
  // Here's what we do, roughly in the order specified by HTML5:
11471
0
  // 1. Serialize aData using structured clone.
11472
0
  // 2. If the third argument is present,
11473
0
  //     a. Resolve the url, relative to the first script's base URL
11474
0
  //     b. If (a) fails, raise a SECURITY_ERR
11475
0
  //     c. Compare the resulting absolute URL to the document's address.  If
11476
0
  //        any part of the URLs difer other than the <path>, <query>, and
11477
0
  //        <fragment> components, raise a SECURITY_ERR and abort.
11478
0
  // 3. If !aReplace:
11479
0
  //     Remove from the session history all entries after the current entry,
11480
0
  //     as we would after a regular navigation, and save the current
11481
0
  //     entry's scroll position (bug 590573).
11482
0
  // 4. As apropriate, either add a state object entry to the session history
11483
0
  //    after the current entry with the following properties, or modify the
11484
0
  //    current session history entry to set
11485
0
  //      a. cloned data as the state object,
11486
0
  //      b. if the third argument was present, the absolute URL found in
11487
0
  //         step 2
11488
0
  //    Also clear the new history entry's POST data (see bug 580069).
11489
0
  // 5. If aReplace is false (i.e. we're doing a pushState instead of a
11490
0
  //    replaceState), notify bfcache that we've navigated to a new page.
11491
0
  // 6. If the third argument is present, set the document's current address
11492
0
  //    to the absolute URL found in step 2.
11493
0
  //
11494
0
  // It's important that this function not run arbitrary scripts after step 1
11495
0
  // and before completing step 5.  For example, if a script called
11496
0
  // history.back() before we completed step 5, bfcache might destroy an
11497
0
  // active content viewer.  Since EvictOutOfRangeContentViewers at the end of
11498
0
  // step 5 might run script, we can't just put a script blocker around the
11499
0
  // critical section.
11500
0
  //
11501
0
  // Note that we completely ignore the aTitle parameter.
11502
0
11503
0
  nsresult rv;
11504
0
11505
0
  // Don't clobber the load type of an existing network load.
11506
0
  AutoRestore<uint32_t> loadTypeResetter(mLoadType);
11507
0
11508
0
  // pushState effectively becomes replaceState when we've started a network
11509
0
  // load but haven't adopted its document yet.  This mirrors what we do with
11510
0
  // changes to the hash at this stage of the game.
11511
0
  if (JustStartedNetworkLoad()) {
11512
0
    aReplace = true;
11513
0
  }
11514
0
11515
0
  nsCOMPtr<nsIDocument> document = GetDocument();
11516
0
  NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
11517
0
11518
0
  // Step 1: Serialize aData using structured clone.
11519
0
  nsCOMPtr<nsIStructuredCloneContainer> scContainer;
11520
0
11521
0
  // scContainer->Init might cause arbitrary JS to run, and this code might
11522
0
  // navigate the page we're on, potentially to a different origin! (bug
11523
0
  // 634834)  To protect against this, we abort if our principal changes due
11524
0
  // to the InitFromJSVal() call.
11525
0
  {
11526
0
    nsCOMPtr<nsIDocument> origDocument = GetDocument();
11527
0
    if (!origDocument) {
11528
0
      return NS_ERROR_DOM_SECURITY_ERR;
11529
0
    }
11530
0
    nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
11531
0
11532
0
    scContainer = new nsStructuredCloneContainer();
11533
0
    rv = scContainer->InitFromJSVal(aData, aCx);
11534
0
    NS_ENSURE_SUCCESS(rv, rv);
11535
0
11536
0
    nsCOMPtr<nsIDocument> newDocument = GetDocument();
11537
0
    if (!newDocument) {
11538
0
      return NS_ERROR_DOM_SECURITY_ERR;
11539
0
    }
11540
0
    nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
11541
0
11542
0
    bool principalsEqual = false;
11543
0
    origPrincipal->Equals(newPrincipal, &principalsEqual);
11544
0
    NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
11545
0
  }
11546
0
11547
0
  // Check that the state object isn't too long.
11548
0
  // Default max length: 640k bytes.
11549
0
  int32_t maxStateObjSize =
11550
0
    Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
11551
0
  if (maxStateObjSize < 0) {
11552
0
    maxStateObjSize = 0;
11553
0
  }
11554
0
11555
0
  uint64_t scSize;
11556
0
  rv = scContainer->GetSerializedNBytes(&scSize);
11557
0
  NS_ENSURE_SUCCESS(rv, rv);
11558
0
11559
0
  NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE);
11560
0
11561
0
  // Step 2: Resolve aURL
11562
0
  bool equalURIs = true;
11563
0
  nsCOMPtr<nsIURI> currentURI;
11564
0
  if (sURIFixup && mCurrentURI) {
11565
0
    rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(currentURI));
11566
0
    NS_ENSURE_SUCCESS(rv, rv);
11567
0
  } else {
11568
0
    currentURI = mCurrentURI;
11569
0
  }
11570
0
  nsCOMPtr<nsIURI> oldURI = currentURI;
11571
0
  nsCOMPtr<nsIURI> newURI;
11572
0
  if (aURL.Length() == 0) {
11573
0
    newURI = currentURI;
11574
0
  } else {
11575
0
    // 2a: Resolve aURL relative to mURI
11576
0
11577
0
    nsIURI* docBaseURI = document->GetDocBaseURI();
11578
0
    if (!docBaseURI) {
11579
0
      return NS_ERROR_FAILURE;
11580
0
    }
11581
0
11582
0
    nsAutoCString spec;
11583
0
    docBaseURI->GetSpec(spec);
11584
0
11585
0
    rv = NS_NewURI(getter_AddRefs(newURI), aURL,
11586
0
                   document->GetDocumentCharacterSet(), docBaseURI);
11587
0
11588
0
    // 2b: If 2a fails, raise a SECURITY_ERR
11589
0
    if (NS_FAILED(rv)) {
11590
0
      return NS_ERROR_DOM_SECURITY_ERR;
11591
0
    }
11592
0
11593
0
    // 2c: Same-origin check.
11594
0
    if (!nsContentUtils::URIIsLocalFile(newURI)) {
11595
0
      // In addition to checking that the security manager says that
11596
0
      // the new URI has the same origin as our current URI, we also
11597
0
      // check that the two URIs have the same userpass. (The
11598
0
      // security manager says that |http://foo.com| and
11599
0
      // |http://me@foo.com| have the same origin.)  currentURI
11600
0
      // won't contain the password part of the userpass, so this
11601
0
      // means that it's never valid to specify a password in a
11602
0
      // pushState or replaceState URI.
11603
0
11604
0
      nsCOMPtr<nsIScriptSecurityManager> secMan =
11605
0
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
11606
0
      NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
11607
0
11608
0
      // It's very important that we check that newURI is of the same
11609
0
      // origin as currentURI, not docBaseURI, because a page can
11610
0
      // set docBaseURI arbitrarily to any domain.
11611
0
      nsAutoCString currentUserPass, newUserPass;
11612
0
      NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
11613
0
                        NS_ERROR_FAILURE);
11614
0
      NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE);
11615
0
      bool isPrivateWin =
11616
0
        document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0;
11617
0
      if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true, isPrivateWin)) ||
11618
0
          !currentUserPass.Equals(newUserPass)) {
11619
0
        return NS_ERROR_DOM_SECURITY_ERR;
11620
0
      }
11621
0
    } else {
11622
0
      // It's a file:// URI
11623
0
      nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
11624
0
        do_QueryInterface(document);
11625
0
11626
0
      if (!docScriptObj) {
11627
0
        return NS_ERROR_DOM_SECURITY_ERR;
11628
0
      }
11629
0
11630
0
      nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
11631
0
11632
0
      if (!principal ||
11633
0
          NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
11634
0
        return NS_ERROR_DOM_SECURITY_ERR;
11635
0
      }
11636
0
    }
11637
0
11638
0
    if (currentURI) {
11639
0
      currentURI->Equals(newURI, &equalURIs);
11640
0
    } else {
11641
0
      equalURIs = false;
11642
0
    }
11643
0
11644
0
  } // end of same-origin check
11645
0
11646
0
  // Step 3: Create a new entry in the session history. This will erase
11647
0
  // all SHEntries after the new entry and make this entry the current
11648
0
  // one.  This operation may modify mOSHE, which we need later, so we
11649
0
  // keep a reference here.
11650
0
  NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
11651
0
  nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
11652
0
11653
0
  mLoadType = LOAD_PUSHSTATE;
11654
0
11655
0
  nsCOMPtr<nsISHEntry> newSHEntry;
11656
0
  if (!aReplace) {
11657
0
    // Save the current scroll position (bug 590573).
11658
0
    nscoord cx = 0, cy = 0;
11659
0
    GetCurScrollPos(ScrollOrientation_X, &cx);
11660
0
    GetCurScrollPos(ScrollOrientation_Y, &cy);
11661
0
    mOSHE->SetScrollPosition(cx, cy);
11662
0
11663
0
    bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
11664
0
11665
0
    // Since we're not changing which page we have loaded, pass
11666
0
    // true for aCloneChildren.
11667
0
    rv = AddToSessionHistory(newURI, nullptr,
11668
0
                             document->NodePrincipal(), // triggeringPrincipal
11669
0
                             nullptr, true,
11670
0
                             getter_AddRefs(newSHEntry));
11671
0
    NS_ENSURE_SUCCESS(rv, rv);
11672
0
11673
0
    NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
11674
0
11675
0
    // Session history entries created by pushState inherit scroll restoration
11676
0
    // mode from the current entry.
11677
0
    newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
11678
0
11679
0
    // Link the new SHEntry to the old SHEntry's BFCache entry, since the
11680
0
    // two entries correspond to the same document.
11681
0
    NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
11682
0
11683
0
    // Set the new SHEntry's title (bug 655273).
11684
0
    nsString title;
11685
0
    mOSHE->GetTitle(title);
11686
0
    newSHEntry->SetTitle(title);
11687
0
11688
0
    // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
11689
0
    // we'll just set mOSHE here.
11690
0
    mOSHE = newSHEntry;
11691
0
11692
0
  } else {
11693
0
    newSHEntry = mOSHE;
11694
0
    newSHEntry->SetURI(newURI);
11695
0
    newSHEntry->SetOriginalURI(newURI);
11696
0
    newSHEntry->SetLoadReplace(false);
11697
0
  }
11698
0
11699
0
  // Step 4: Modify new/original session history entry and clear its POST
11700
0
  // data, if there is any.
11701
0
  newSHEntry->SetStateData(scContainer);
11702
0
  newSHEntry->SetPostData(nullptr);
11703
0
11704
0
  // If this push/replaceState changed the document's current URI and the new
11705
0
  // URI differs from the old URI in more than the hash, or if the old
11706
0
  // SHEntry's URI was modified in this way by a push/replaceState call
11707
0
  // set URIWasModified to true for the current SHEntry (bug 669671).
11708
0
  bool sameExceptHashes = true;
11709
0
  newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
11710
0
  bool oldURIWasModified = oldOSHE->GetURIWasModified();
11711
0
  newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
11712
0
11713
0
  // Step 5: If aReplace is false, indicating that we're doing a pushState
11714
0
  // rather than a replaceState, notify bfcache that we've added a page to
11715
0
  // the history so it can evict content viewers if appropriate. Otherwise
11716
0
  // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
11717
0
  // was replaced.
11718
0
  RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
11719
0
  NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
11720
0
11721
0
  if (!aReplace) {
11722
0
    int32_t curIndex = rootSH->Index();
11723
0
    if (curIndex > -1) {
11724
0
      rootSH->LegacySHistory()->EvictOutOfRangeContentViewers(curIndex);
11725
0
    }
11726
0
  } else {
11727
0
    nsCOMPtr<nsISHEntry> rootSHEntry = nsSHistory::GetRootSHEntry(newSHEntry);
11728
0
11729
0
    int32_t index = rootSH->LegacySHistory()->GetIndexOfEntry(rootSHEntry);
11730
0
    if (index > -1) {
11731
0
      rootSH->LegacySHistory()->ReplaceEntry(index, rootSHEntry);
11732
0
    }
11733
0
  }
11734
0
11735
0
  // Step 6: If the document's URI changed, update document's URI and update
11736
0
  // global history.
11737
0
  //
11738
0
  // We need to call FireOnLocationChange so that the browser's address bar
11739
0
  // gets updated and the back button is enabled, but we only need to
11740
0
  // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
11741
0
  // since SetCurrentURI will call FireOnLocationChange for us.
11742
0
  //
11743
0
  // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
11744
0
  // nullptr for aRequest param to FireOnLocationChange(...). Such an update
11745
0
  // notification is allowed only when we know docshell is not loading a new
11746
0
  // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
11747
0
  // FireOnLocationChange(...) breaks security UI.
11748
0
  //
11749
0
  // If the docshell is shutting down, don't update the document URI, as we
11750
0
  // can't load into a docshell that is being destroyed.
11751
0
  if (!equalURIs && !mIsBeingDestroyed) {
11752
0
    document->SetDocumentURI(newURI);
11753
0
    // We can't trust SetCurrentURI to do always fire locationchange events
11754
0
    // when we expect it to, so we hack around that by doing it ourselves...
11755
0
    SetCurrentURI(newURI, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT);
11756
0
    if (mLoadType != LOAD_ERROR_PAGE) {
11757
0
      FireDummyOnLocationChange();
11758
0
    }
11759
0
11760
0
    AddURIVisit(newURI, oldURI, oldURI, 0);
11761
0
11762
0
    // AddURIVisit doesn't set the title for the new URI in global history,
11763
0
    // so do that here.
11764
0
    UpdateGlobalHistoryTitle(newURI);
11765
0
11766
0
    // Inform the favicon service that our old favicon applies to this new
11767
0
    // URI.
11768
0
    CopyFavicon(oldURI, newURI, document->NodePrincipal(), UsePrivateBrowsing());
11769
0
  } else {
11770
0
    FireDummyOnLocationChange();
11771
0
  }
11772
0
  document->SetStateObject(scContainer);
11773
0
11774
0
  return NS_OK;
11775
0
}
11776
11777
NS_IMETHODIMP
11778
nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual)
11779
0
{
11780
0
  *aIsManual = false;
11781
0
  if (mOSHE) {
11782
0
    *aIsManual = mOSHE->GetScrollRestorationIsManual();
11783
0
  }
11784
0
11785
0
  return NS_OK;
11786
0
}
11787
11788
NS_IMETHODIMP
11789
nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual)
11790
0
{
11791
0
  if (mOSHE) {
11792
0
    mOSHE->SetScrollRestorationIsManual(aIsManual);
11793
0
  }
11794
0
11795
0
  return NS_OK;
11796
0
}
11797
11798
bool
11799
nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel)
11800
0
{
11801
0
  // I believe none of the about: urls should go in the history. But then
11802
0
  // that could just be me... If the intent is only deny about:blank then we
11803
0
  // should just do a spec compare, rather than two gets of the scheme and
11804
0
  // then the path.  -Gagan
11805
0
  nsresult rv;
11806
0
  nsAutoCString buf;
11807
0
11808
0
  rv = aURI->GetScheme(buf);
11809
0
  if (NS_FAILED(rv)) {
11810
0
    return false;
11811
0
  }
11812
0
11813
0
  if (buf.EqualsLiteral("about")) {
11814
0
    rv = aURI->GetPathQueryRef(buf);
11815
0
    if (NS_FAILED(rv)) {
11816
0
      return false;
11817
0
    }
11818
0
11819
0
    if (buf.EqualsLiteral("blank")) {
11820
0
      return false;
11821
0
    }
11822
0
    // We only want to add about:newtab if it's not privileged:
11823
0
    if (buf.EqualsLiteral("newtab")) {
11824
0
      NS_ENSURE_TRUE(aChannel, false);
11825
0
      nsCOMPtr<nsIPrincipal> resultPrincipal;
11826
0
      rv = nsContentUtils::GetSecurityManager()->
11827
0
             GetChannelResultPrincipal(aChannel,
11828
0
                                       getter_AddRefs(resultPrincipal));
11829
0
      NS_ENSURE_SUCCESS(rv, false);
11830
0
      return !nsContentUtils::IsSystemPrincipal(resultPrincipal);
11831
0
    }
11832
0
  }
11833
0
11834
0
  return true;
11835
0
}
11836
11837
nsresult
11838
nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
11839
                                nsIPrincipal* aTriggeringPrincipal,
11840
                                nsIPrincipal* aPrincipalToInherit,
11841
                                bool aCloneChildren,
11842
                                nsISHEntry** aNewEntry)
11843
0
{
11844
0
  MOZ_ASSERT(aURI, "uri is null");
11845
0
  MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
11846
0
11847
#if defined(DEBUG)
11848
  if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
11849
    nsAutoCString chanName;
11850
    if (aChannel) {
11851
      aChannel->GetName(chanName);
11852
    } else {
11853
      chanName.AssignLiteral("<no channel>");
11854
    }
11855
11856
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
11857
            ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
11858
             this, aURI->GetSpecOrDefault().get(), chanName.get()));
11859
  }
11860
#endif
11861
11862
0
  nsresult rv = NS_OK;
11863
0
  nsCOMPtr<nsISHEntry> entry;
11864
0
11865
0
  // Get a handle to the root docshell
11866
0
  nsCOMPtr<nsIDocShellTreeItem> root;
11867
0
  GetSameTypeRootTreeItem(getter_AddRefs(root));
11868
0
  /*
11869
0
   * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
11870
0
   * the existing SH entry in the page and replace the url and
11871
0
   * other vitalities.
11872
0
   */
11873
0
  if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
11874
0
      root != static_cast<nsIDocShellTreeItem*>(this)) {
11875
0
    // This is a subframe
11876
0
    entry = mOSHE;
11877
0
    if (entry) {
11878
0
      int32_t childCount = entry->GetChildCount();
11879
0
      // Remove all children of this entry
11880
0
      for (int32_t i = childCount - 1; i >= 0; i--) {
11881
0
        nsCOMPtr<nsISHEntry> child;
11882
0
        entry->GetChildAt(i, getter_AddRefs(child));
11883
0
        entry->RemoveChild(child);
11884
0
      }
11885
0
      entry->AbandonBFCacheEntry();
11886
0
    }
11887
0
  }
11888
0
11889
0
  // Create a new entry if necessary.
11890
0
  if (!entry) {
11891
0
    entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
11892
0
11893
0
    if (!entry) {
11894
0
      return NS_ERROR_OUT_OF_MEMORY;
11895
0
    }
11896
0
  }
11897
0
11898
0
  // Get the post data & referrer
11899
0
  nsCOMPtr<nsIInputStream> inputStream;
11900
0
  nsCOMPtr<nsIURI> originalURI;
11901
0
  nsCOMPtr<nsIURI> resultPrincipalURI;
11902
0
  bool loadReplace = false;
11903
0
  nsCOMPtr<nsIURI> referrerURI;
11904
0
  uint32_t referrerPolicy = RP_Unset;
11905
0
  uint32_t cacheKey = 0;
11906
0
  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
11907
0
  nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
11908
0
  bool expired = false;
11909
0
  bool discardLayoutState = false;
11910
0
  nsCOMPtr<nsICacheInfoChannel> cacheChannel;
11911
0
  if (aChannel) {
11912
0
    cacheChannel = do_QueryInterface(aChannel);
11913
0
11914
0
    /* If there is a caching channel, get the Cache Key and store it
11915
0
     * in SH.
11916
0
     */
11917
0
    if (cacheChannel) {
11918
0
      cacheChannel->GetCacheKey(&cacheKey);
11919
0
    }
11920
0
    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11921
0
11922
0
    // Check if the httpChannel is hiding under a multipartChannel
11923
0
    if (!httpChannel) {
11924
0
      GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11925
0
    }
11926
0
    if (httpChannel) {
11927
0
      nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11928
0
      if (uploadChannel) {
11929
0
        uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11930
0
      }
11931
0
      httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
11932
0
      uint32_t loadFlags;
11933
0
      aChannel->GetLoadFlags(&loadFlags);
11934
0
      loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
11935
0
      rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI));
11936
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
11937
0
      rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
11938
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
11939
0
11940
0
      discardLayoutState = ShouldDiscardLayoutState(httpChannel);
11941
0
    }
11942
0
11943
0
    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
11944
0
    if (loadInfo) {
11945
0
      if (!triggeringPrincipal) {
11946
0
        triggeringPrincipal = loadInfo->TriggeringPrincipal();
11947
0
      }
11948
0
11949
0
      loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
11950
0
11951
0
      // For now keep storing just the principal in the SHEntry.
11952
0
      if (!principalToInherit) {
11953
0
        if (loadInfo->GetLoadingSandboxed()) {
11954
0
          if (loadInfo->LoadingPrincipal()) {
11955
0
            principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
11956
0
            loadInfo->LoadingPrincipal());
11957
0
          } else {
11958
0
            // get the OriginAttributes
11959
0
            OriginAttributes attrs;
11960
0
            loadInfo->GetOriginAttributes(&attrs);
11961
0
            principalToInherit = NullPrincipal::Create(attrs);
11962
0
          }
11963
0
        } else {
11964
0
          principalToInherit = loadInfo->PrincipalToInherit();
11965
0
        }
11966
0
      }
11967
0
    }
11968
0
  }
11969
0
11970
0
  // Title is set in nsDocShell::SetTitle()
11971
0
  entry->Create(aURI,                // uri
11972
0
                EmptyString(),       // Title
11973
0
                inputStream,         // Post data stream
11974
0
                nullptr,             // LayoutHistory state
11975
0
                cacheKey,            // CacheKey
11976
0
                mContentTypeHint,    // Content-type
11977
0
                triggeringPrincipal, // Channel or provided principal
11978
0
                principalToInherit,
11979
0
                mHistoryID,
11980
0
                mDynamicallyCreated);
11981
0
11982
0
  entry->SetOriginalURI(originalURI);
11983
0
  entry->SetResultPrincipalURI(resultPrincipalURI);
11984
0
  entry->SetLoadReplace(loadReplace);
11985
0
  entry->SetReferrerURI(referrerURI);
11986
0
  entry->SetReferrerPolicy(referrerPolicy);
11987
0
  nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
11988
0
  if (inStrmChan) {
11989
0
    bool isSrcdocChannel;
11990
0
    inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
11991
0
    if (isSrcdocChannel) {
11992
0
      nsAutoString srcdoc;
11993
0
      inStrmChan->GetSrcdocData(srcdoc);
11994
0
      entry->SetSrcdocData(srcdoc);
11995
0
      nsCOMPtr<nsIURI> baseURI;
11996
0
      inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
11997
0
      entry->SetBaseURI(baseURI);
11998
0
    }
11999
0
  }
12000
0
  /* If cache got a 'no-store', ask SH not to store
12001
0
   * HistoryLayoutState. By default, SH will set this
12002
0
   * flag to true and save HistoryLayoutState.
12003
0
   */
12004
0
  if (discardLayoutState) {
12005
0
    entry->SetSaveLayoutStateFlag(false);
12006
0
  }
12007
0
  if (cacheChannel) {
12008
0
    // Check if the page has expired from cache
12009
0
    uint32_t expTime = 0;
12010
0
    cacheChannel->GetCacheTokenExpirationTime(&expTime);
12011
0
    uint32_t now = PRTimeToSeconds(PR_Now());
12012
0
    if (expTime <= now) {
12013
0
      expired = true;
12014
0
    }
12015
0
  }
12016
0
  if (expired) {
12017
0
    entry->SetExpirationStatus(true);
12018
0
  }
12019
0
12020
0
  if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) {
12021
0
    // If we need to clone our children onto the new session
12022
0
    // history entry, do so now.
12023
0
    if (aCloneChildren && mOSHE) {
12024
0
      uint32_t cloneID = mOSHE->GetID();
12025
0
      nsCOMPtr<nsISHEntry> newEntry;
12026
0
      nsSHistory::CloneAndReplace(mOSHE, this, cloneID, entry, true,
12027
0
                                  getter_AddRefs(newEntry));
12028
0
      NS_ASSERTION(entry == newEntry,
12029
0
                   "The new session history should be in the new entry");
12030
0
    }
12031
0
12032
0
    // This is the root docshell
12033
0
    bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
12034
0
    if (!addToSHistory) {
12035
0
      // Replace current entry in session history; If the requested index is
12036
0
      // valid, it indicates the loading was triggered by a history load, and
12037
0
      // we should replace the entry at requested index instead.
12038
0
      int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex();
12039
0
      if (index == -1) {
12040
0
        index = mSessionHistory->Index();
12041
0
      }
12042
0
12043
0
      // Replace the current entry with the new entry
12044
0
      if (index >= 0) {
12045
0
        rv = mSessionHistory->LegacySHistory()->ReplaceEntry(index, entry);
12046
0
      } else {
12047
0
        // If we're trying to replace an inexistant shistory entry, append.
12048
0
        addToSHistory = true;
12049
0
      }
12050
0
    }
12051
0
12052
0
    if (addToSHistory) {
12053
0
      // Add to session history
12054
0
      mPreviousEntryIndex = mSessionHistory->Index();
12055
0
12056
0
      bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel);
12057
0
      rv = mSessionHistory->LegacySHistory()->AddEntry(entry, shouldPersist);
12058
0
      mLoadedEntryIndex = mSessionHistory->Index();
12059
#ifdef DEBUG_PAGE_CACHE
12060
      printf("Previous index: %d, Loaded index: %d\n\n",
12061
             mPreviousEntryIndex, mLoadedEntryIndex);
12062
#endif
12063
    }
12064
0
  } else {
12065
0
    // This is a subframe.
12066
0
    if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
12067
0
      rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren);
12068
0
    }
12069
0
  }
12070
0
12071
0
  // Return the new SH entry...
12072
0
  if (aNewEntry) {
12073
0
    *aNewEntry = nullptr;
12074
0
    if (NS_SUCCEEDED(rv)) {
12075
0
      entry.forget(aNewEntry);
12076
0
    }
12077
0
  }
12078
0
12079
0
  return rv;
12080
0
}
12081
12082
nsresult
12083
nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
12084
0
{
12085
0
  if (!IsNavigationAllowed()) {
12086
0
    return NS_OK;
12087
0
  }
12088
0
12089
0
  NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
12090
0
12091
0
  nsCOMPtr<nsIURI> uri = aEntry->GetURI();
12092
0
  nsCOMPtr<nsIURI> originalURI = aEntry->GetOriginalURI();
12093
0
  nsCOMPtr<nsIURI> resultPrincipalURI = aEntry->GetResultPrincipalURI();
12094
0
  bool loadReplace = aEntry->GetLoadReplace();
12095
0
  nsCOMPtr<nsIURI> referrerURI = aEntry->GetReferrerURI();
12096
0
  uint32_t referrerPolicy = aEntry->GetReferrerPolicy();
12097
0
  nsCOMPtr<nsIInputStream> postData = aEntry->GetPostData();
12098
0
  nsAutoCString contentType;
12099
0
  aEntry->GetContentType(contentType);
12100
0
  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aEntry->GetTriggeringPrincipal();
12101
0
  nsCOMPtr<nsIPrincipal> principalToInherit = aEntry->GetPrincipalToInherit();
12102
0
12103
0
  // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
12104
0
  // that's the only thing holding a ref to aEntry that will cause aEntry to
12105
0
  // die while we're loading it.  So hold a strong ref to aEntry here, just
12106
0
  // in case.
12107
0
  nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
12108
0
  bool isJS;
12109
0
  nsresult rv = uri->SchemeIs("javascript", &isJS);
12110
0
  if (NS_FAILED(rv) || isJS) {
12111
0
    // We're loading a URL that will execute script from inside asyncOpen.
12112
0
    // Replace the current document with about:blank now to prevent
12113
0
    // anything from the current document from leaking into any JavaScript
12114
0
    // code in the URL.
12115
0
    // Don't cache the presentation if we're going to just reload the
12116
0
    // current entry. Caching would lead to trying to save the different
12117
0
    // content viewers in the same nsISHEntry object.
12118
0
    rv = CreateAboutBlankContentViewer(principalToInherit, nullptr,
12119
0
                                       aEntry != mOSHE);
12120
0
12121
0
    if (NS_FAILED(rv)) {
12122
0
      // The creation of the intermittent about:blank content
12123
0
      // viewer failed for some reason (potentially because the
12124
0
      // user prevented it). Interrupt the history load.
12125
0
      return NS_OK;
12126
0
    }
12127
0
12128
0
    if (!triggeringPrincipal) {
12129
0
      // Ensure that we have a triggeringPrincipal.  Otherwise javascript:
12130
0
      // URIs will pick it up from the about:blank page we just loaded,
12131
0
      // and we don't really want even that in this case.
12132
0
      triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this);
12133
0
    }
12134
0
  }
12135
0
12136
0
  /* If there is a valid postdata *and* the user pressed
12137
0
   * reload or shift-reload, take user's permission before we
12138
0
   * repost the data to the server.
12139
0
   */
12140
0
  if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
12141
0
    bool repost;
12142
0
    rv = ConfirmRepost(&repost);
12143
0
    if (NS_FAILED(rv)) {
12144
0
      return rv;
12145
0
    }
12146
0
12147
0
    // If the user pressed cancel in the dialog, return.  We're done here.
12148
0
    if (!repost) {
12149
0
      return NS_BINDING_ABORTED;
12150
0
    }
12151
0
  }
12152
0
12153
0
  // Do not inherit principal from document (security-critical!);
12154
0
  uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
12155
0
12156
0
  nsAutoString srcdoc;
12157
0
  nsCOMPtr<nsIURI> baseURI;
12158
0
  if (aEntry->GetIsSrcdocEntry()) {
12159
0
    aEntry->GetSrcdocData(srcdoc);
12160
0
    baseURI = aEntry->GetBaseURI();
12161
0
    flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
12162
0
  } else {
12163
0
    srcdoc = VoidString();
12164
0
  }
12165
0
12166
0
  // If there is no valid triggeringPrincipal, we deny the load
12167
0
  MOZ_ASSERT(triggeringPrincipal, "need a valid triggeringPrincipal to load from history");
12168
0
  if (!triggeringPrincipal) {
12169
0
    return NS_ERROR_FAILURE;
12170
0
  }
12171
0
12172
0
  // Passing nullptr as aSourceDocShell gives the same behaviour as before
12173
0
  // aSourceDocShell was introduced. According to spec we should be passing
12174
0
  // the source browsing context that was used when the history entry was
12175
0
  // first created. bug 947716 has been created to address this issue.
12176
0
  Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
12177
0
  emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
12178
0
  rv = InternalLoad(uri,
12179
0
                    originalURI,
12180
0
                    emplacedResultPrincipalURI,
12181
0
                    false,
12182
0
                    loadReplace,
12183
0
                    referrerURI,
12184
0
                    referrerPolicy,
12185
0
                    triggeringPrincipal,
12186
0
                    principalToInherit,
12187
0
                    flags,
12188
0
                    EmptyString(),      // No window target
12189
0
                    contentType.get(),  // Type hint
12190
0
                    VoidString(),       // No forced file download
12191
0
                    postData,           // Post data stream
12192
0
                    nullptr,            // No headers stream
12193
0
                    aLoadType,          // Load type
12194
0
                    aEntry,             // SHEntry
12195
0
                    true,
12196
0
                    srcdoc,
12197
0
                    nullptr,            // Source docshell, see comment above
12198
0
                    baseURI,
12199
0
                    nullptr,            // No nsIDocShell
12200
0
                    nullptr);           // No nsIRequest
12201
0
  return rv;
12202
0
}
12203
12204
NS_IMETHODIMP
12205
nsDocShell::GetShouldSaveLayoutState(bool* aShould)
12206
0
{
12207
0
  *aShould = false;
12208
0
  if (mOSHE) {
12209
0
    // Don't capture historystate and save it in history
12210
0
    // if the page asked not to do so.
12211
0
    *aShould = mOSHE->GetSaveLayoutStateFlag();
12212
0
  }
12213
0
12214
0
  return NS_OK;
12215
0
}
12216
12217
nsresult
12218
nsDocShell::PersistLayoutHistoryState()
12219
0
{
12220
0
  nsresult rv = NS_OK;
12221
0
12222
0
  if (mOSHE) {
12223
0
    bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
12224
0
    nsCOMPtr<nsIPresShell> shell = GetPresShell();
12225
0
    nsCOMPtr<nsILayoutHistoryState> layoutState;
12226
0
    if (shell) {
12227
0
      rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
12228
0
    } else if (scrollRestorationIsManual) {
12229
0
      // Even if we don't have layout anymore, we may want to reset the current
12230
0
      // scroll state in layout history.
12231
0
      GetLayoutHistoryState(getter_AddRefs(layoutState));
12232
0
    }
12233
0
12234
0
    if (scrollRestorationIsManual && layoutState) {
12235
0
      layoutState->ResetScrollState();
12236
0
    }
12237
0
  }
12238
0
12239
0
  return rv;
12240
0
}
12241
12242
void
12243
nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry)
12244
0
{
12245
0
  if (aOldEntry == mOSHE) {
12246
0
    mOSHE = aNewEntry;
12247
0
  }
12248
0
12249
0
  if (aOldEntry == mLSHE) {
12250
0
    mLSHE = aNewEntry;
12251
0
  }
12252
0
}
12253
12254
void
12255
nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry)
12256
0
{
12257
0
  // We need to sync up the docshell and session history trees for
12258
0
  // subframe navigation.  If the load was in a subframe, we forward up to
12259
0
  // the root docshell, which will then recursively sync up all docshells
12260
0
  // to their corresponding entries in the new session history tree.
12261
0
  // If we don't do this, then we can cache a content viewer on the wrong
12262
0
  // cloned entry, and subsequently restore it at the wrong time.
12263
0
12264
0
  nsISHEntry* newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
12265
0
  if (newRootEntry) {
12266
0
    // newRootEntry is now the new root entry.
12267
0
    // Find the old root entry as well.
12268
0
12269
0
    // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
12270
0
    // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
12271
0
    nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr);
12272
0
    if (oldRootEntry) {
12273
0
      nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
12274
0
      GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
12275
0
      nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
12276
0
      if (rootShell) { // if we're the root just set it, nothing to swap
12277
0
        nsSHistory::SwapEntriesData data = { this, newRootEntry };
12278
0
        nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell);
12279
0
        nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
12280
0
12281
#ifdef DEBUG
12282
        nsresult rv =
12283
#endif
12284
        nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data);
12285
0
        NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
12286
0
      }
12287
0
    }
12288
0
  }
12289
0
12290
0
  *aPtr = aEntry;
12291
0
}
12292
12293
already_AddRefed<ChildSHistory>
12294
nsDocShell::GetRootSessionHistory()
12295
0
{
12296
0
  nsCOMPtr<nsIDocShellTreeItem> root;
12297
0
  nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
12298
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
12299
0
    return nullptr;
12300
0
  }
12301
0
  nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(root);
12302
0
  if (!webnav) {
12303
0
    return nullptr;
12304
0
  }
12305
0
  return webnav->GetSessionHistory();
12306
0
}
12307
12308
nsresult
12309
nsDocShell::GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn)
12310
0
{
12311
0
  NS_ENSURE_ARG_POINTER(aReturn);
12312
0
  if (!aChannel) {
12313
0
    return NS_ERROR_FAILURE;
12314
0
  }
12315
0
12316
0
  nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
12317
0
  if (multiPartChannel) {
12318
0
    nsCOMPtr<nsIChannel> baseChannel;
12319
0
    multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
12320
0
    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
12321
0
    *aReturn = httpChannel;
12322
0
    NS_IF_ADDREF(*aReturn);
12323
0
  }
12324
0
  return NS_OK;
12325
0
}
12326
12327
bool
12328
nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel)
12329
0
{
12330
0
  // By default layout State will be saved.
12331
0
  if (!aChannel) {
12332
0
    return false;
12333
0
  }
12334
0
12335
0
  // figure out if SH should be saving layout state
12336
0
  bool noStore = false;
12337
0
  Unused << aChannel->IsNoStoreResponse(&noStore);
12338
0
  return noStore;
12339
0
}
12340
12341
NS_IMETHODIMP
12342
nsDocShell::GetEditor(nsIEditor** aEditor)
12343
0
{
12344
0
  NS_ENSURE_ARG_POINTER(aEditor);
12345
0
  RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorInternal();
12346
0
  htmlEditor.forget(aEditor);
12347
0
  return NS_OK;
12348
0
}
12349
12350
NS_IMETHODIMP
12351
nsDocShell::SetEditor(nsIEditor* aEditor)
12352
0
{
12353
0
  HTMLEditor* htmlEditor = aEditor ? aEditor->AsHTMLEditor() : nullptr;
12354
0
  // If TextEditor comes, throw an error.
12355
0
  if (aEditor && !htmlEditor) {
12356
0
    return NS_ERROR_INVALID_ARG;
12357
0
  }
12358
0
  return SetHTMLEditorInternal(htmlEditor);
12359
0
}
12360
12361
HTMLEditor*
12362
nsDocShell::GetHTMLEditorInternal()
12363
0
{
12364
0
  return mEditorData ? mEditorData->GetHTMLEditor() : nullptr;
12365
0
}
12366
12367
nsresult
12368
nsDocShell::SetHTMLEditorInternal(HTMLEditor* aHTMLEditor)
12369
0
{
12370
0
  if (!aHTMLEditor && !mEditorData) {
12371
0
    return NS_OK;
12372
0
  }
12373
0
12374
0
  nsresult rv = EnsureEditorData();
12375
0
  if (NS_FAILED(rv)) {
12376
0
    return rv;
12377
0
  }
12378
0
12379
0
  return mEditorData->SetHTMLEditor(aHTMLEditor);
12380
0
}
12381
12382
NS_IMETHODIMP
12383
nsDocShell::GetEditable(bool* aEditable)
12384
0
{
12385
0
  NS_ENSURE_ARG_POINTER(aEditable);
12386
0
  *aEditable = mEditorData && mEditorData->GetEditable();
12387
0
  return NS_OK;
12388
0
}
12389
12390
NS_IMETHODIMP
12391
nsDocShell::GetHasEditingSession(bool* aHasEditingSession)
12392
0
{
12393
0
  NS_ENSURE_ARG_POINTER(aHasEditingSession);
12394
0
12395
0
  if (mEditorData) {
12396
0
    nsCOMPtr<nsIEditingSession> editingSession;
12397
0
    mEditorData->GetEditingSession(getter_AddRefs(editingSession));
12398
0
    *aHasEditingSession = (editingSession.get() != nullptr);
12399
0
  } else {
12400
0
    *aHasEditingSession = false;
12401
0
  }
12402
0
12403
0
  return NS_OK;
12404
0
}
12405
12406
NS_IMETHODIMP
12407
nsDocShell::MakeEditable(bool aInWaitForUriLoad)
12408
0
{
12409
0
  nsresult rv = EnsureEditorData();
12410
0
  if (NS_FAILED(rv)) {
12411
0
    return rv;
12412
0
  }
12413
0
12414
0
  return mEditorData->MakeEditable(aInWaitForUriLoad);
12415
0
}
12416
12417
bool
12418
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
12419
0
{
12420
0
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
12421
0
  if (!httpChannel) {
12422
0
    return false;
12423
0
  }
12424
0
12425
0
  nsAutoCString method;
12426
0
  Unused << httpChannel->GetRequestMethod(method);
12427
0
  return method.EqualsLiteral("POST");
12428
0
}
12429
12430
void
12431
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
12432
                             nsIURI** aURI,
12433
                             uint32_t* aChannelRedirectFlags)
12434
0
{
12435
0
  nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
12436
0
  if (!props) {
12437
0
    return;
12438
0
  }
12439
0
12440
0
  nsresult rv = props->GetPropertyAsInterface(
12441
0
    NS_LITERAL_STRING("docshell.previousURI"),
12442
0
    NS_GET_IID(nsIURI),
12443
0
    reinterpret_cast<void**>(aURI));
12444
0
12445
0
  if (NS_FAILED(rv)) {
12446
0
    // There is no last visit for this channel, so this must be the first
12447
0
    // link.  Link the visit to the referrer of this request, if any.
12448
0
    // Treat referrer as null if there is an error getting it.
12449
0
    (void)NS_GetReferrerFromChannel(aChannel, aURI);
12450
0
  } else {
12451
0
    rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12452
0
                                    aChannelRedirectFlags);
12453
0
12454
0
    NS_WARNING_ASSERTION(
12455
0
      NS_SUCCEEDED(rv),
12456
0
      "Could not fetch previous flags, URI will be treated like referrer");
12457
0
  }
12458
0
}
12459
12460
void
12461
nsDocShell::SaveLastVisit(nsIChannel* aChannel,
12462
                          nsIURI* aURI,
12463
                          uint32_t aChannelRedirectFlags)
12464
0
{
12465
0
  nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
12466
0
  if (!props || !aURI) {
12467
0
    return;
12468
0
  }
12469
0
12470
0
  props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
12471
0
                                aURI);
12472
0
  props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
12473
0
                             aChannelRedirectFlags);
12474
0
}
12475
12476
void
12477
nsDocShell::AddURIVisit(nsIURI* aURI,
12478
                        nsIURI* aReferrerURI,
12479
                        nsIURI* aPreviousURI,
12480
                        uint32_t aChannelRedirectFlags,
12481
                        uint32_t aResponseStatus)
12482
0
{
12483
0
  MOZ_ASSERT(aURI, "Visited URI is null!");
12484
0
  MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
12485
0
             mLoadType != LOAD_BYPASS_HISTORY,
12486
0
             "Do not add error or bypass pages to global history");
12487
0
12488
0
  // Only content-type docshells save URI visits.  Also don't do
12489
0
  // anything here if we're not supposed to use global history.
12490
0
  if (mItemType != typeContent || !mUseGlobalHistory || UsePrivateBrowsing()) {
12491
0
    return;
12492
0
  }
12493
0
12494
0
  nsCOMPtr<IHistory> history = services::GetHistoryService();
12495
0
12496
0
  if (history) {
12497
0
    uint32_t visitURIFlags = 0;
12498
0
12499
0
    if (!IsFrame()) {
12500
0
      visitURIFlags |= IHistory::TOP_LEVEL;
12501
0
    }
12502
0
12503
0
    if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
12504
0
      visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
12505
0
    } else if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) {
12506
0
      visitURIFlags |= IHistory::REDIRECT_PERMANENT;
12507
0
    } else {
12508
0
      MOZ_ASSERT(!aChannelRedirectFlags,
12509
0
                 "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
12510
0
                 "if any flags in aChannelRedirectFlags is set.");
12511
0
    }
12512
0
12513
0
    if (aResponseStatus >= 300 && aResponseStatus < 400) {
12514
0
      visitURIFlags |= IHistory::REDIRECT_SOURCE;
12515
0
      if (aResponseStatus == 301 || aResponseStatus == 308) {
12516
0
        visitURIFlags |= IHistory::REDIRECT_SOURCE_PERMANENT;
12517
0
      }
12518
0
    }
12519
0
    // Errors 400-501 and 505 are considered unrecoverable, in the sense a
12520
0
    // simple retry attempt by the user is unlikely to solve them.
12521
0
    // 408 is special cased, since may actually indicate a temporary
12522
0
    // connection problem.
12523
0
    else if (aResponseStatus != 408 &&
12524
0
             ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
12525
0
              aResponseStatus == 505)) {
12526
0
      visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
12527
0
    }
12528
0
12529
0
    (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
12530
0
  }
12531
0
}
12532
12533
//*****************************************************************************
12534
// nsDocShell: Helper Routines
12535
//*****************************************************************************
12536
12537
NS_IMETHODIMP
12538
nsDocShell::SetLoadType(uint32_t aLoadType)
12539
0
{
12540
0
  mLoadType = aLoadType;
12541
0
  return NS_OK;
12542
0
}
12543
12544
NS_IMETHODIMP
12545
nsDocShell::GetLoadType(uint32_t* aLoadType)
12546
0
{
12547
0
  *aLoadType = mLoadType;
12548
0
  return NS_OK;
12549
0
}
12550
12551
nsresult
12552
nsDocShell::ConfirmRepost(bool* aRepost)
12553
0
{
12554
0
  nsCOMPtr<nsIPrompt> prompter;
12555
0
  CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
12556
0
  if (!prompter) {
12557
0
    return NS_ERROR_NOT_AVAILABLE;
12558
0
  }
12559
0
12560
0
  nsCOMPtr<nsIStringBundleService> stringBundleService =
12561
0
    mozilla::services::GetStringBundleService();
12562
0
  if (!stringBundleService) {
12563
0
    return NS_ERROR_FAILURE;
12564
0
  }
12565
0
12566
0
  nsCOMPtr<nsIStringBundle> appBundle;
12567
0
  nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
12568
0
                                                  getter_AddRefs(appBundle));
12569
0
  NS_ENSURE_SUCCESS(rv, rv);
12570
0
12571
0
  nsCOMPtr<nsIStringBundle> brandBundle;
12572
0
  rv = stringBundleService->CreateBundle(kBrandBundleURL,
12573
0
                                         getter_AddRefs(brandBundle));
12574
0
  NS_ENSURE_SUCCESS(rv, rv);
12575
0
12576
0
  NS_ASSERTION(prompter && brandBundle && appBundle,
12577
0
               "Unable to set up repost prompter.");
12578
0
12579
0
  nsAutoString brandName;
12580
0
  rv = brandBundle->GetStringFromName("brandShortName", brandName);
12581
0
12582
0
  nsAutoString msgString, button0Title;
12583
0
  if (NS_FAILED(rv)) { // No brand, use the generic version.
12584
0
    rv = appBundle->GetStringFromName("confirmRepostPrompt", msgString);
12585
0
  } else {
12586
0
    // Brand available - if the app has an override file with formatting, the
12587
0
    // app name will be included. Without an override, the prompt will look
12588
0
    // like the generic version.
12589
0
    const char16_t* formatStrings[] = { brandName.get() };
12590
0
    rv = appBundle->FormatStringFromName("confirmRepostPrompt",
12591
0
                                         formatStrings,
12592
0
                                         ArrayLength(formatStrings),
12593
0
                                         msgString);
12594
0
  }
12595
0
  if (NS_FAILED(rv)) {
12596
0
    return rv;
12597
0
  }
12598
0
12599
0
  rv = appBundle->GetStringFromName("resendButton.label", button0Title);
12600
0
  if (NS_FAILED(rv)) {
12601
0
    return rv;
12602
0
  }
12603
0
12604
0
  // Make the repost prompt tab modal to prevent malicious pages from locking
12605
0
  // up the browser, see bug 1412559 for an example.
12606
0
  if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompter)) {
12607
0
    promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
12608
0
  }
12609
0
12610
0
  int32_t buttonPressed;
12611
0
  // The actual value here is irrelevant, but we can't pass an invalid
12612
0
  // bool through XPConnect.
12613
0
  bool checkState = false;
12614
0
  rv = prompter->ConfirmEx(
12615
0
    nullptr, msgString.get(),
12616
0
    (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
12617
0
      (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
12618
0
    button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed);
12619
0
  if (NS_FAILED(rv)) {
12620
0
    return rv;
12621
0
  }
12622
0
12623
0
  *aRepost = (buttonPressed == 0);
12624
0
  return NS_OK;
12625
0
}
12626
12627
nsresult
12628
nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
12629
                                     nsIStringBundle** aStringBundle)
12630
0
{
12631
0
  NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt),
12632
0
                    NS_ERROR_FAILURE);
12633
0
12634
0
  nsCOMPtr<nsIStringBundleService> stringBundleService =
12635
0
    mozilla::services::GetStringBundleService();
12636
0
  NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
12637
0
12638
0
  NS_ENSURE_SUCCESS(
12639
0
    stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle),
12640
0
    NS_ERROR_FAILURE);
12641
0
12642
0
  return NS_OK;
12643
0
}
12644
12645
nsIScrollableFrame*
12646
nsDocShell::GetRootScrollFrame()
12647
0
{
12648
0
  nsCOMPtr<nsIPresShell> shell = GetPresShell();
12649
0
  NS_ENSURE_TRUE(shell, nullptr);
12650
0
12651
0
  return shell->GetRootScrollFrameAsScrollable();
12652
0
}
12653
12654
nsresult
12655
nsDocShell::EnsureScriptEnvironment()
12656
0
{
12657
0
  if (mScriptGlobal) {
12658
0
    return NS_OK;
12659
0
  }
12660
0
12661
0
  if (mIsBeingDestroyed) {
12662
0
    return NS_ERROR_NOT_AVAILABLE;
12663
0
  }
12664
0
12665
#ifdef DEBUG
12666
  NS_ASSERTION(!mInEnsureScriptEnv,
12667
               "Infinite loop! Calling EnsureScriptEnvironment() from "
12668
               "within EnsureScriptEnvironment()!");
12669
12670
  // Yeah, this isn't re-entrant safe, but that's ok since if we
12671
  // re-enter this method, we'll infinitely loop...
12672
  AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
12673
  mInEnsureScriptEnv = true;
12674
#endif
12675
12676
0
  nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
12677
0
  NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
12678
0
12679
0
  uint32_t chromeFlags;
12680
0
  browserChrome->GetChromeFlags(&chromeFlags);
12681
0
12682
0
  // If our window is modal and we're not opened as chrome, make
12683
0
  // this window a modal content window.
12684
0
  mScriptGlobal = NS_NewScriptGlobalObject(mItemType == typeChrome);
12685
0
  MOZ_ASSERT(mScriptGlobal);
12686
0
12687
0
  mScriptGlobal->SetDocShell(this);
12688
0
12689
0
  // Ensure the script object is set up to run script.
12690
0
  return mScriptGlobal->EnsureScriptEnvironment();
12691
0
}
12692
12693
nsresult
12694
nsDocShell::EnsureEditorData()
12695
0
{
12696
0
  MOZ_ASSERT(!mIsBeingDestroyed);
12697
0
12698
0
  bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
12699
0
  if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
12700
0
    // We shouldn't recreate the editor data if it already exists, or
12701
0
    // we're shutting down, or we already have a detached editor data
12702
0
    // stored in the session history. We should only have one editordata
12703
0
    // per docshell.
12704
0
    mEditorData = new nsDocShellEditorData(this);
12705
0
  }
12706
0
12707
0
  return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
12708
0
}
12709
12710
nsresult
12711
nsDocShell::EnsureFind()
12712
0
{
12713
0
  if (!mFind) {
12714
0
    mFind = new nsWebBrowserFind();
12715
0
  }
12716
0
12717
0
  // we promise that the nsIWebBrowserFind that we return has been set
12718
0
  // up to point to the focused, or content window, so we have to
12719
0
  // set that up each time.
12720
0
12721
0
  nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
12722
0
  NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
12723
0
12724
0
  // default to our window
12725
0
  nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO);
12726
0
  nsCOMPtr<nsPIDOMWindowOuter> windowToSearch;
12727
0
  nsFocusManager::GetFocusedDescendant(ourWindow,
12728
0
                                       nsFocusManager::eIncludeAllDescendants,
12729
0
                                       getter_AddRefs(windowToSearch));
12730
0
12731
0
  nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
12732
0
  if (!findInFrames) {
12733
0
    return NS_ERROR_NO_INTERFACE;
12734
0
  }
12735
0
12736
0
  nsresult rv = findInFrames->SetRootSearchFrame(ourWindow);
12737
0
  if (NS_FAILED(rv)) {
12738
0
    return rv;
12739
0
  }
12740
0
  rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
12741
0
  if (NS_FAILED(rv)) {
12742
0
    return rv;
12743
0
  }
12744
0
12745
0
  return NS_OK;
12746
0
}
12747
12748
bool
12749
nsDocShell::IsFrame()
12750
0
{
12751
0
  nsCOMPtr<nsIDocShellTreeItem> parent;
12752
0
  GetSameTypeParent(getter_AddRefs(parent));
12753
0
  return !!parent;
12754
0
}
12755
12756
NS_IMETHODIMP
12757
nsDocShell::IsBeingDestroyed(bool* aDoomed)
12758
0
{
12759
0
  NS_ENSURE_ARG(aDoomed);
12760
0
  *aDoomed = mIsBeingDestroyed;
12761
0
  return NS_OK;
12762
0
}
12763
12764
NS_IMETHODIMP
12765
nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult)
12766
0
{
12767
0
  NS_ENSURE_ARG(aResult);
12768
0
  *aResult = mIsExecutingOnLoadHandler;
12769
0
  return NS_OK;
12770
0
}
12771
12772
NS_IMETHODIMP
12773
nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState)
12774
0
{
12775
0
  if (mOSHE) {
12776
0
    nsCOMPtr<nsILayoutHistoryState> state = mOSHE->GetLayoutHistoryState();
12777
0
    state.forget(aLayoutHistoryState);
12778
0
  }
12779
0
  return NS_OK;
12780
0
}
12781
12782
NS_IMETHODIMP
12783
nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
12784
0
{
12785
0
  if (mOSHE) {
12786
0
    mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
12787
0
  }
12788
0
  return NS_OK;
12789
0
}
12790
12791
nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
12792
    nsIInterfaceRequestor* aRequestor)
12793
0
{
12794
0
  if (aRequestor) {
12795
0
    mWeakPtr = do_GetWeakReference(aRequestor);
12796
0
  }
12797
0
}
12798
12799
nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
12800
0
{
12801
0
  mWeakPtr = nullptr;
12802
0
}
12803
12804
NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
12805
12806
NS_IMETHODIMP
12807
nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID,
12808
                                                  void** aSink)
12809
0
{
12810
0
  NS_ENSURE_ARG_POINTER(aSink);
12811
0
  nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
12812
0
  if (ifReq) {
12813
0
    return ifReq->GetInterface(aIID, aSink);
12814
0
  }
12815
0
  *aSink = nullptr;
12816
0
  return NS_NOINTERFACE;
12817
0
}
12818
12819
nsresult
12820
nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer)
12821
0
{
12822
0
  if (!aContentViewer) {
12823
0
    return NS_ERROR_FAILURE;
12824
0
  }
12825
0
12826
0
  nsCOMPtr<nsIURI> baseURI;
12827
0
  nsresult rv = NS_ERROR_NOT_AVAILABLE;
12828
0
12829
0
  if (sURIFixup) {
12830
0
    rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI));
12831
0
  }
12832
0
12833
0
  // Get the current document and set the base uri
12834
0
  if (baseURI) {
12835
0
    nsIDocument* document = aContentViewer->GetDocument();
12836
0
    if (document) {
12837
0
      document->SetBaseURI(baseURI);
12838
0
    }
12839
0
  }
12840
0
  return rv;
12841
0
}
12842
12843
//*****************************************************************************
12844
// nsDocShell::nsIAuthPromptProvider
12845
//*****************************************************************************
12846
12847
NS_IMETHODIMP
12848
nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID,
12849
                          void** aResult)
12850
0
{
12851
0
  // a priority prompt request will override a false mAllowAuth setting
12852
0
  bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
12853
0
12854
0
  if (!mAllowAuth && !priorityPrompt) {
12855
0
    return NS_ERROR_NOT_AVAILABLE;
12856
0
  }
12857
0
12858
0
  // we're either allowing auth, or it's a proxy request
12859
0
  nsresult rv;
12860
0
  nsCOMPtr<nsIPromptFactory> wwatch =
12861
0
    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
12862
0
  NS_ENSURE_SUCCESS(rv, rv);
12863
0
12864
0
  rv = EnsureScriptEnvironment();
12865
0
  NS_ENSURE_SUCCESS(rv, rv);
12866
0
12867
0
  // Get the an auth prompter for our window so that the parenting
12868
0
  // of the dialogs works as it should when using tabs.
12869
0
12870
0
  return wwatch->GetPrompt(mScriptGlobal->AsOuter(), aIID,
12871
0
                           reinterpret_cast<void**>(aResult));
12872
0
}
12873
12874
//*****************************************************************************
12875
// nsDocShell::nsILoadContext
12876
//*****************************************************************************
12877
12878
NS_IMETHODIMP
12879
nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow)
12880
0
{
12881
0
  CallGetInterface(this, aWindow);
12882
0
  return NS_OK;
12883
0
}
12884
12885
NS_IMETHODIMP
12886
nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow)
12887
0
{
12888
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
12889
0
  if (win) {
12890
0
    win = win->GetTop();
12891
0
  }
12892
0
  win.forget(aWindow);
12893
0
  return NS_OK;
12894
0
}
12895
12896
NS_IMETHODIMP
12897
nsDocShell::GetTopFrameElement(Element** aElement)
12898
0
{
12899
0
  *aElement = nullptr;
12900
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
12901
0
  if (!win) {
12902
0
    return NS_OK;
12903
0
  }
12904
0
12905
0
  nsCOMPtr<nsPIDOMWindowOuter> top = win->GetScriptableTop();
12906
0
  NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
12907
0
12908
0
  // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
12909
0
  // inside <iframe mozbrowser>, we want to return the iframe, not null.
12910
0
  // And we want to cross the content/chrome boundary.
12911
0
  RefPtr<Element> elt = top->GetFrameElementInternal();
12912
0
  elt.forget(aElement);
12913
0
  return NS_OK;
12914
0
}
12915
12916
NS_IMETHODIMP
12917
nsDocShell::GetNestedFrameId(uint64_t* aId)
12918
0
{
12919
0
  *aId = 0;
12920
0
  return NS_OK;
12921
0
}
12922
12923
NS_IMETHODIMP
12924
nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection)
12925
0
{
12926
0
  *aUseTrackingProtection  = false;
12927
0
12928
0
  bool cbEnabled = StaticPrefs::browser_contentblocking_enabled();
12929
0
  static bool sTPEnabled = false;
12930
0
  static bool sTPInPBEnabled = false;
12931
0
  static bool sPrefsInit = false;
12932
0
12933
0
  if (!sPrefsInit) {
12934
0
    sPrefsInit = true;
12935
0
    Preferences::AddBoolVarCache(&sTPEnabled,
12936
0
      "privacy.trackingprotection.enabled", false);
12937
0
    Preferences::AddBoolVarCache(&sTPInPBEnabled,
12938
0
      "privacy.trackingprotection.pbmode.enabled", false);
12939
0
  }
12940
0
12941
0
  if (mUseTrackingProtection || (cbEnabled && sTPEnabled) ||
12942
0
      (cbEnabled && UsePrivateBrowsing() && sTPInPBEnabled)) {
12943
0
    *aUseTrackingProtection = true;
12944
0
    return NS_OK;
12945
0
  }
12946
0
12947
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
12948
0
  if (parent) {
12949
0
    return parent->GetUseTrackingProtection(aUseTrackingProtection);
12950
0
  }
12951
0
12952
0
  return NS_OK;
12953
0
}
12954
12955
NS_IMETHODIMP
12956
nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection)
12957
0
{
12958
0
  mUseTrackingProtection = aUseTrackingProtection;
12959
0
  return NS_OK;
12960
0
}
12961
12962
NS_IMETHODIMP
12963
nsDocShell::GetIsContent(bool* aIsContent)
12964
0
{
12965
0
  *aIsContent = (mItemType == typeContent);
12966
0
  return NS_OK;
12967
0
}
12968
12969
bool
12970
nsDocShell::IsOKToLoadURI(nsIURI* aURI)
12971
0
{
12972
0
  MOZ_ASSERT(aURI, "Must have a URI!");
12973
0
12974
0
  if (!mFiredUnloadEvent) {
12975
0
    return true;
12976
0
  }
12977
0
12978
0
  if (!mLoadingURI) {
12979
0
    return false;
12980
0
  }
12981
0
12982
0
12983
0
  bool isPrivateWin = false;
12984
0
  nsIDocument *doc = GetDocument();
12985
0
  if (doc) {
12986
0
    isPrivateWin =
12987
0
      doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0;
12988
0
  }
12989
0
12990
0
  nsCOMPtr<nsIScriptSecurityManager> secMan =
12991
0
    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
12992
0
  return secMan &&
12993
0
         NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false, isPrivateWin));
12994
0
}
12995
12996
//
12997
// Routines for selection and clipboard
12998
//
12999
nsresult
13000
nsDocShell::GetControllerForCommand(const char* aCommand,
13001
                                    nsIController** aResult)
13002
0
{
13003
0
  NS_ENSURE_ARG_POINTER(aResult);
13004
0
  *aResult = nullptr;
13005
0
13006
0
  NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
13007
0
13008
0
  nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
13009
0
  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
13010
0
13011
0
  return root->GetControllerForCommand(aCommand, false /* for any window */,
13012
0
                                       aResult);
13013
0
}
13014
13015
NS_IMETHODIMP
13016
nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult)
13017
0
{
13018
0
  NS_ENSURE_ARG_POINTER(aResult);
13019
0
  *aResult = false;
13020
0
13021
0
  nsresult rv = NS_ERROR_FAILURE;
13022
0
13023
0
  nsCOMPtr<nsIController> controller;
13024
0
  rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13025
0
  if (controller) {
13026
0
    rv = controller->IsCommandEnabled(aCommand, aResult);
13027
0
  }
13028
0
13029
0
  return rv;
13030
0
}
13031
13032
NS_IMETHODIMP
13033
nsDocShell::DoCommand(const char* aCommand)
13034
0
{
13035
0
  nsresult rv = NS_ERROR_FAILURE;
13036
0
13037
0
  nsCOMPtr<nsIController> controller;
13038
0
  rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13039
0
  if (controller) {
13040
0
    rv = controller->DoCommand(aCommand);
13041
0
  }
13042
0
13043
0
  return rv;
13044
0
}
13045
13046
NS_IMETHODIMP
13047
nsDocShell::DoCommandWithParams(const char* aCommand, nsICommandParams* aParams)
13048
0
{
13049
0
  nsCOMPtr<nsIController> controller;
13050
0
  nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13051
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
13052
0
    return rv;
13053
0
  }
13054
0
13055
0
  nsCOMPtr<nsICommandController> commandController =
13056
0
    do_QueryInterface(controller, &rv);
13057
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
13058
0
    return rv;
13059
0
  }
13060
0
13061
0
  return commandController->DoCommandWithParams(aCommand, aParams);
13062
0
}
13063
13064
nsresult
13065
nsDocShell::EnsureCommandHandler()
13066
0
{
13067
0
  if (!mCommandManager) {
13068
0
    nsCOMPtr<nsPICommandUpdater> commandUpdater = new nsCommandManager();
13069
0
13070
0
    nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow();
13071
0
    nsresult rv = commandUpdater->Init(domWindow);
13072
0
    if (NS_SUCCEEDED(rv)) {
13073
0
      mCommandManager = do_QueryInterface(commandUpdater);
13074
0
    }
13075
0
  }
13076
0
13077
0
  return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
13078
0
}
13079
13080
// link handling
13081
13082
class OnLinkClickEvent : public Runnable
13083
{
13084
public:
13085
  OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
13086
                   nsIURI* aURI,
13087
                   const char16_t* aTargetSpec,
13088
                   const nsAString& aFileName,
13089
                   nsIInputStream* aPostDataStream,
13090
                   nsIInputStream* aHeadersDataStream,
13091
                   bool aNoOpenerImplied,
13092
                   bool aIsUserTriggered,
13093
                   bool aIsTrusted,
13094
                   nsIPrincipal* aTriggeringPrincipal);
13095
13096
  NS_IMETHOD Run() override
13097
0
  {
13098
0
    nsAutoPopupStatePusher popupStatePusher(mPopupState);
13099
0
13100
0
    // We need to set up an AutoJSAPI here for the following reason: When we do
13101
0
    // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
13102
0
    // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
13103
0
    // So we need to fake things so that we don't look like native code as far
13104
0
    // as LegacyIsCallerNativeCode() is concerned.
13105
0
    AutoJSAPI jsapi;
13106
0
    if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
13107
0
      mHandler->OnLinkClickSync(mContent, mURI,
13108
0
                                mTargetSpec.get(), mFileName,
13109
0
                                mPostDataStream,
13110
0
                                mHeadersDataStream, mNoOpenerImplied,
13111
0
                                nullptr, nullptr, mIsUserTriggered,
13112
0
                                mTriggeringPrincipal);
13113
0
    }
13114
0
    return NS_OK;
13115
0
  }
13116
13117
private:
13118
  RefPtr<nsDocShell> mHandler;
13119
  nsCOMPtr<nsIURI> mURI;
13120
  nsString mTargetSpec;
13121
  nsString mFileName;
13122
  nsCOMPtr<nsIInputStream> mPostDataStream;
13123
  nsCOMPtr<nsIInputStream> mHeadersDataStream;
13124
  nsCOMPtr<nsIContent> mContent;
13125
  PopupControlState mPopupState;
13126
  bool mNoOpenerImplied;
13127
  bool mIsUserTriggered;
13128
  bool mIsTrusted;
13129
  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
13130
};
13131
13132
OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
13133
                                   nsIContent* aContent,
13134
                                   nsIURI* aURI,
13135
                                   const char16_t* aTargetSpec,
13136
                                   const nsAString& aFileName,
13137
                                   nsIInputStream* aPostDataStream,
13138
                                   nsIInputStream* aHeadersDataStream,
13139
                                   bool aNoOpenerImplied,
13140
                                   bool aIsUserTriggered,
13141
                                   bool aIsTrusted,
13142
                                   nsIPrincipal* aTriggeringPrincipal)
13143
  : mozilla::Runnable("OnLinkClickEvent")
13144
  , mHandler(aHandler)
13145
  , mURI(aURI)
13146
  , mTargetSpec(aTargetSpec)
13147
  , mFileName(aFileName)
13148
  , mPostDataStream(aPostDataStream)
13149
  , mHeadersDataStream(aHeadersDataStream)
13150
  , mContent(aContent)
13151
  , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
13152
  , mNoOpenerImplied(aNoOpenerImplied)
13153
  , mIsUserTriggered(aIsUserTriggered)
13154
  , mIsTrusted(aIsTrusted)
13155
  , mTriggeringPrincipal(aTriggeringPrincipal)
13156
0
{
13157
0
}
13158
13159
NS_IMETHODIMP
13160
nsDocShell::OnLinkClick(nsIContent* aContent,
13161
                        nsIURI* aURI,
13162
                        const char16_t* aTargetSpec,
13163
                        const nsAString& aFileName,
13164
                        nsIInputStream* aPostDataStream,
13165
                        nsIInputStream* aHeadersDataStream,
13166
                        bool aIsUserTriggered,
13167
                        bool aIsTrusted,
13168
                        nsIPrincipal* aTriggeringPrincipal)
13169
0
{
13170
0
  NS_ASSERTION(NS_IsMainThread(), "wrong thread");
13171
0
13172
0
  if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
13173
0
    return NS_OK;
13174
0
  }
13175
0
13176
0
  // On history navigation through Back/Forward buttons, don't execute
13177
0
  // automatic JavaScript redirection such as |anchorElement.click()| or
13178
0
  // |formElement.submit()|.
13179
0
  //
13180
0
  // XXX |formElement.submit()| bypasses this checkpoint because it calls
13181
0
  //     nsDocShell::OnLinkClickSync(...) instead.
13182
0
  if (ShouldBlockLoadingForBackButton()) {
13183
0
    return NS_OK;
13184
0
  }
13185
0
13186
0
  if (aContent->IsEditable()) {
13187
0
    return NS_OK;
13188
0
  }
13189
0
13190
0
  nsresult rv = NS_ERROR_FAILURE;
13191
0
  nsAutoString target;
13192
0
13193
0
  nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
13194
0
  bool noOpenerImplied = false;
13195
0
  if (browserChrome3) {
13196
0
    nsAutoString oldTarget(aTargetSpec);
13197
0
    rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
13198
0
                                               aContent, mIsAppTab, target);
13199
0
    if (!oldTarget.Equals(target)) {
13200
0
      noOpenerImplied = true;
13201
0
    }
13202
0
  }
13203
0
13204
0
  if (NS_FAILED(rv)) {
13205
0
    target = aTargetSpec;
13206
0
  }
13207
0
13208
0
  nsCOMPtr<nsIRunnable> ev =
13209
0
    new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
13210
0
                         aPostDataStream, aHeadersDataStream, noOpenerImplied,
13211
0
                         aIsUserTriggered, aIsTrusted, aTriggeringPrincipal);
13212
0
  return DispatchToTabGroup(TaskCategory::UI, ev.forget());
13213
0
}
13214
13215
static bool
13216
IsElementAnchorOrArea(nsIContent* aContent)
13217
0
{
13218
0
  // Make sure we are dealing with either an <A> or <AREA> element in the HTML
13219
0
  // or XHTML namespace.
13220
0
  return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
13221
0
}
13222
13223
NS_IMETHODIMP
13224
nsDocShell::OnLinkClickSync(nsIContent* aContent,
13225
                            nsIURI* aURI,
13226
                            const char16_t* aTargetSpec,
13227
                            const nsAString& aFileName,
13228
                            nsIInputStream* aPostDataStream,
13229
                            nsIInputStream* aHeadersDataStream,
13230
                            bool aNoOpenerImplied,
13231
                            nsIDocShell** aDocShell,
13232
                            nsIRequest** aRequest,
13233
                            bool aIsUserTriggered,
13234
                            nsIPrincipal* aTriggeringPrincipal)
13235
0
{
13236
0
  // Initialize the DocShell / Request
13237
0
  if (aDocShell) {
13238
0
    *aDocShell = nullptr;
13239
0
  }
13240
0
  if (aRequest) {
13241
0
    *aRequest = nullptr;
13242
0
  }
13243
0
13244
0
  if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
13245
0
    return NS_OK;
13246
0
  }
13247
0
13248
0
  // XXX When the linking node was HTMLFormElement, it is synchronous event.
13249
0
  //     That is, the caller of this method is not |OnLinkClickEvent::Run()|
13250
0
  //     but |HTMLFormElement::SubmitSubmission(...)|.
13251
0
  if (aContent->IsHTMLElement(nsGkAtoms::form) &&
13252
0
      ShouldBlockLoadingForBackButton()) {
13253
0
    return NS_OK;
13254
0
  }
13255
0
13256
0
  if (aContent->IsEditable()) {
13257
0
    return NS_OK;
13258
0
  }
13259
0
13260
0
  {
13261
0
    // defer to an external protocol handler if necessary...
13262
0
    nsCOMPtr<nsIExternalProtocolService> extProtService =
13263
0
      do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
13264
0
    if (extProtService) {
13265
0
      nsAutoCString scheme;
13266
0
      aURI->GetScheme(scheme);
13267
0
      if (!scheme.IsEmpty()) {
13268
0
        // if the URL scheme does not correspond to an exposed protocol, then we
13269
0
        // need to hand this link click over to the external protocol handler.
13270
0
        bool isExposed;
13271
0
        nsresult rv =
13272
0
          extProtService->IsExposedProtocol(scheme.get(), &isExposed);
13273
0
        if (NS_SUCCEEDED(rv) && !isExposed) {
13274
0
          return extProtService->LoadURI(aURI, this);
13275
0
        }
13276
0
      }
13277
0
    }
13278
0
  }
13279
0
13280
0
  uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
13281
0
  if (IsElementAnchorOrArea(aContent)) {
13282
0
    MOZ_ASSERT(aContent->IsHTMLElement());
13283
0
    nsAutoString referrer;
13284
0
    aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
13285
0
    nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
13286
0
    while (tok.hasMoreTokens()) {
13287
0
      const nsAString& token = tok.nextToken();
13288
0
      if (token.LowerCaseEqualsLiteral("noreferrer")) {
13289
0
        flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
13290
0
                 INTERNAL_LOAD_FLAGS_NO_OPENER;
13291
0
        // We now have all the flags we could possibly have, so just stop.
13292
0
        break;
13293
0
      }
13294
0
      if (token.LowerCaseEqualsLiteral("noopener")) {
13295
0
        flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13296
0
      }
13297
0
    }
13298
0
    if (aNoOpenerImplied) {
13299
0
      flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13300
0
    }
13301
0
  }
13302
0
13303
0
  // Get the owner document of the link that was clicked, this will be
13304
0
  // the document that the link is in, or the last document that the
13305
0
  // link was in. From that document, we'll get the URI to use as the
13306
0
  // referer, since the current URI in this docshell may be a
13307
0
  // new document that we're in the process of loading.
13308
0
  nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
13309
0
  NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
13310
0
13311
0
  // Now check that the refererDoc's inner window is the current inner
13312
0
  // window for mScriptGlobal.  If it's not, then we don't want to
13313
0
  // follow this link.
13314
0
  nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow();
13315
0
  NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
13316
0
  if (!mScriptGlobal ||
13317
0
      mScriptGlobal->AsOuter()->GetCurrentInnerWindow() != refererInner) {
13318
0
    // We're no longer the current inner window
13319
0
    return NS_OK;
13320
0
  }
13321
0
13322
0
  nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
13323
0
  uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
13324
0
13325
0
  // get referrer attribute from clicked link and parse it
13326
0
  // if per element referrer is enabled, the element referrer overrules
13327
0
  // the document wide referrer
13328
0
  if (IsElementAnchorOrArea(aContent)) {
13329
0
    net::ReferrerPolicy refPolEnum =
13330
0
      aContent->AsElement()->GetReferrerPolicyAsEnum();
13331
0
    if (refPolEnum != RP_Unset) {
13332
0
      refererPolicy = refPolEnum;
13333
0
    }
13334
0
  }
13335
0
13336
0
  // referer could be null here in some odd cases, but that's ok,
13337
0
  // we'll just load the link w/o sending a referer in those cases.
13338
0
13339
0
  nsAutoString target(aTargetSpec);
13340
0
13341
0
  // If this is an anchor element, grab its type property to use as a hint
13342
0
  nsAutoString typeHint;
13343
0
  RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::FromNode(aContent);
13344
0
  if (anchor) {
13345
0
    anchor->GetType(typeHint);
13346
0
    NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
13347
0
    nsAutoCString type, dummy;
13348
0
    NS_ParseRequestContentType(utf8Hint, type, dummy);
13349
0
    CopyUTF8toUTF16(type, typeHint);
13350
0
  }
13351
0
13352
0
  // if the triggeringPrincipal is not passed explicitly, then we
13353
0
  // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
13354
0
  nsCOMPtr<nsIPrincipal> triggeringPrincipal =
13355
0
    aTriggeringPrincipal ? aTriggeringPrincipal
13356
0
                         : aContent->NodePrincipal();
13357
0
13358
0
  // Link click (or form submission) can be triggered inside an onload handler,
13359
0
  // and we don't want to add history entry in this case.
13360
0
  bool inOnLoadHandler = false;
13361
0
  GetIsExecutingOnLoadHandler(&inOnLoadHandler);
13362
0
  uint32_t loadType = inOnLoadHandler ? LOAD_NORMAL_REPLACE : LOAD_LINK;
13363
0
13364
0
  if (aIsUserTriggered) {
13365
0
    flags |= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED;
13366
0
  }
13367
0
13368
0
  nsresult rv = InternalLoad(aURI,                      // New URI
13369
0
                             nullptr,                   // Original URI
13370
0
                             Nothing(),                 // Let the protocol handler assign it
13371
0
                             false,
13372
0
                             false,                     // LoadReplace
13373
0
                             referer,                   // Referer URI
13374
0
                             refererPolicy,             // Referer policy
13375
0
                             triggeringPrincipal,
13376
0
                             aContent->NodePrincipal(),
13377
0
                             flags,
13378
0
                             target,                    // Window target
13379
0
                             NS_LossyConvertUTF16toASCII(typeHint).get(),
13380
0
                             aFileName,                 // Download as file
13381
0
                             aPostDataStream,           // Post data stream
13382
0
                             aHeadersDataStream,        // Headers stream
13383
0
                             loadType,                  // Load type
13384
0
                             nullptr,                   // No SHEntry
13385
0
                             true,                      // first party site
13386
0
                             VoidString(),              // No srcdoc
13387
0
                             this,                      // We are the source
13388
0
                             nullptr,                   // baseURI not needed
13389
0
                             aDocShell,                 // DocShell out-param
13390
0
                             aRequest);                 // Request out-param
13391
0
  if (NS_SUCCEEDED(rv)) {
13392
0
    nsPingListener::DispatchPings(this, aContent, aURI, referer, refererPolicy);
13393
0
  }
13394
0
  return rv;
13395
0
}
13396
13397
NS_IMETHODIMP
13398
nsDocShell::OnOverLink(nsIContent* aContent,
13399
                       nsIURI* aURI,
13400
                       const char16_t* aTargetSpec)
13401
0
{
13402
0
  if (aContent->IsEditable()) {
13403
0
    return NS_OK;
13404
0
  }
13405
0
13406
0
  nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
13407
0
  nsresult rv = NS_ERROR_FAILURE;
13408
0
13409
0
  nsCOMPtr<nsIWebBrowserChrome> browserChrome;
13410
0
  if (!browserChrome2) {
13411
0
    browserChrome = do_GetInterface(mTreeOwner);
13412
0
    if (!browserChrome) {
13413
0
      return rv;
13414
0
    }
13415
0
  }
13416
0
13417
0
  nsAutoCString spec;
13418
0
  rv = aURI->GetDisplaySpec(spec);
13419
0
  NS_ENSURE_SUCCESS(rv, rv);
13420
0
13421
0
  NS_ConvertUTF8toUTF16 uStr(spec);
13422
0
13423
0
  PredictorPredict(aURI, mCurrentURI,
13424
0
                   nsINetworkPredictor::PREDICT_LINK,
13425
0
                   aContent->NodePrincipal()->OriginAttributesRef(),
13426
0
                   nullptr);
13427
0
13428
0
  if (browserChrome2) {
13429
0
    rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
13430
0
                                              uStr, aContent);
13431
0
  } else {
13432
0
    rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
13433
0
  }
13434
0
  return rv;
13435
0
}
13436
13437
NS_IMETHODIMP
13438
nsDocShell::OnLeaveLink()
13439
0
{
13440
0
  nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
13441
0
  nsresult rv = NS_ERROR_FAILURE;
13442
0
13443
0
  if (browserChrome) {
13444
0
    rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
13445
0
                                  EmptyString().get());
13446
0
  }
13447
0
  return rv;
13448
0
}
13449
13450
bool
13451
nsDocShell::ShouldBlockLoadingForBackButton()
13452
0
{
13453
0
  if (!(mLoadType & LOAD_CMD_HISTORY) ||
13454
0
      EventStateManager::IsHandlingUserInput() ||
13455
0
      !Preferences::GetBool("accessibility.blockjsredirection")) {
13456
0
    return false;
13457
0
  }
13458
0
13459
0
  bool canGoForward = false;
13460
0
  GetCanGoForward(&canGoForward);
13461
0
  return canGoForward;
13462
0
}
13463
13464
bool
13465
nsDocShell::PluginsAllowedInCurrentDoc()
13466
0
{
13467
0
13468
0
  if (!mContentViewer) {
13469
0
    return false;
13470
0
  }
13471
0
13472
0
  nsIDocument* doc = mContentViewer->GetDocument();
13473
0
  if (!doc) {
13474
0
    return false;
13475
0
  }
13476
0
13477
0
  return doc->GetAllowPlugins();
13478
0
}
13479
13480
//----------------------------------------------------------------------
13481
// Web Shell Services API
13482
13483
// This functions is only called when a new charset is detected in loading a
13484
// document.
13485
nsresult
13486
nsDocShell::CharsetChangeReloadDocument(const char* aCharset, int32_t aSource)
13487
0
{
13488
0
  // XXX hack. keep the aCharset and aSource wait to pick it up
13489
0
  nsCOMPtr<nsIContentViewer> cv;
13490
0
  NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
13491
0
  if (cv) {
13492
0
    int32_t hint;
13493
0
    cv->GetHintCharacterSetSource(&hint);
13494
0
    if (aSource > hint) {
13495
0
      nsCString charset(aCharset);
13496
0
      cv->SetHintCharacterSet(charset);
13497
0
      cv->SetHintCharacterSetSource(aSource);
13498
0
      if (eCharsetReloadRequested != mCharsetReloadState) {
13499
0
        mCharsetReloadState = eCharsetReloadRequested;
13500
0
        switch (mLoadType) {
13501
0
        case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
13502
0
          return Reload(LOAD_FLAGS_CHARSET_CHANGE |
13503
0
                        LOAD_FLAGS_BYPASS_CACHE |
13504
0
                        LOAD_FLAGS_BYPASS_PROXY);
13505
0
        case LOAD_RELOAD_BYPASS_CACHE:
13506
0
          return Reload(LOAD_FLAGS_CHARSET_CHANGE |
13507
0
                        LOAD_FLAGS_BYPASS_CACHE);
13508
0
        default:
13509
0
          return Reload(LOAD_FLAGS_CHARSET_CHANGE);
13510
0
        }
13511
0
      }
13512
0
    }
13513
0
  }
13514
0
  // return failure if this request is not accepted due to mCharsetReloadState
13515
0
  return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
13516
0
}
13517
13518
nsresult
13519
nsDocShell::CharsetChangeStopDocumentLoad()
13520
0
{
13521
0
  if (eCharsetReloadRequested != mCharsetReloadState) {
13522
0
    Stop(nsIWebNavigation::STOP_ALL);
13523
0
    return NS_OK;
13524
0
  }
13525
0
  // return failer if this request is not accepted due to mCharsetReloadState
13526
0
  return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
13527
0
}
13528
13529
NS_IMETHODIMP
13530
nsDocShell::SetIsPrinting(bool aIsPrinting)
13531
0
{
13532
0
  mIsPrintingOrPP = aIsPrinting;
13533
0
  return NS_OK;
13534
0
}
13535
13536
NS_IMETHODIMP
13537
nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
13538
0
{
13539
0
  *aPrintPreview = nullptr;
13540
0
#if NS_PRINT_PREVIEW
13541
0
  nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
13542
0
  if (!print || !print->IsInitializedForPrintPreview()) {
13543
0
    // XXX: Creating a brand new content viewer to host preview every
13544
0
    // time we enter here seems overwork. We could skip ahead to where
13545
0
    // we QI the mContentViewer if the current URI is either about:blank
13546
0
    // or about:printpreview.
13547
0
    Stop(nsIWebNavigation::STOP_ALL);
13548
0
    nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithInheritedAttributes(this);
13549
0
    nsCOMPtr<nsIURI> uri;
13550
0
    NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview"));
13551
0
    nsresult rv = CreateAboutBlankContentViewer(principal, uri);
13552
0
    NS_ENSURE_SUCCESS(rv, rv);
13553
0
    // Here we manually set current URI since we have just created a
13554
0
    // brand new content viewer (about:blank) to host preview.
13555
0
    SetCurrentURI(uri, nullptr, true, 0);
13556
0
    print = do_QueryInterface(mContentViewer);
13557
0
    NS_ENSURE_STATE(print);
13558
0
    print->InitializeForPrintPreview();
13559
0
  }
13560
0
  nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
13561
0
  result.forget(aPrintPreview);
13562
0
  return NS_OK;
13563
#else
13564
  return NS_ERROR_NOT_IMPLEMENTED;
13565
#endif
13566
}
13567
13568
#ifdef DEBUG
13569
unsigned long nsDocShell::gNumberOfDocShells = 0;
13570
#endif
13571
13572
NS_IMETHODIMP
13573
nsDocShell::GetCanExecuteScripts(bool* aResult)
13574
0
{
13575
0
  *aResult = mCanExecuteScripts;
13576
0
  return NS_OK;
13577
0
}
13578
13579
/* [infallible] */ NS_IMETHODIMP
13580
nsDocShell::SetFrameType(uint32_t aFrameType)
13581
0
{
13582
0
  mFrameType = aFrameType;
13583
0
  return NS_OK;
13584
0
}
13585
13586
/* [infallible] */ NS_IMETHODIMP
13587
nsDocShell::GetFrameType(uint32_t* aFrameType)
13588
0
{
13589
0
  *aFrameType = mFrameType;
13590
0
  return NS_OK;
13591
0
}
13592
13593
/* [infallible] */ NS_IMETHODIMP
13594
nsDocShell::GetIsMozBrowser(bool* aIsMozBrowser)
13595
0
{
13596
0
  *aIsMozBrowser = (mFrameType == FRAME_TYPE_BROWSER);
13597
0
  return NS_OK;
13598
0
}
13599
13600
uint32_t
13601
nsDocShell::GetInheritedFrameType()
13602
0
{
13603
0
  if (mFrameType != FRAME_TYPE_REGULAR) {
13604
0
    return mFrameType;
13605
0
  }
13606
0
13607
0
  nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
13608
0
  GetSameTypeParent(getter_AddRefs(parentAsItem));
13609
0
13610
0
  nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
13611
0
  if (!parent) {
13612
0
    return FRAME_TYPE_REGULAR;
13613
0
  }
13614
0
13615
0
  return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
13616
0
}
13617
13618
/* [infallible] */ NS_IMETHODIMP
13619
nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement)
13620
0
{
13621
0
  bool result = mFrameType == FRAME_TYPE_BROWSER &&
13622
0
                mOriginAttributes.mInIsolatedMozBrowser;
13623
0
  *aIsIsolatedMozBrowserElement = result;
13624
0
  return NS_OK;
13625
0
}
13626
13627
/* [infallible] */ NS_IMETHODIMP
13628
nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
13629
0
{
13630
0
  MOZ_ASSERT(!mOriginAttributes.mInIsolatedMozBrowser ||
13631
0
             (GetInheritedFrameType() == FRAME_TYPE_BROWSER),
13632
0
             "Isolated mozbrowser should only be true inside browser frames");
13633
0
  bool result = (GetInheritedFrameType() == FRAME_TYPE_BROWSER) &&
13634
0
                mOriginAttributes.mInIsolatedMozBrowser;
13635
0
  *aIsInIsolatedMozBrowserElement = result;
13636
0
  return NS_OK;
13637
0
}
13638
13639
/* [infallible] */ NS_IMETHODIMP
13640
nsDocShell::GetIsInMozBrowser(bool* aIsInMozBrowser)
13641
0
{
13642
0
  *aIsInMozBrowser = (GetInheritedFrameType() == FRAME_TYPE_BROWSER);
13643
0
  return NS_OK;
13644
0
}
13645
13646
/* [infallible] */ NS_IMETHODIMP
13647
nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell)
13648
0
{
13649
0
  *aIsTopLevelContentDocShell = false;
13650
0
13651
0
  if (mItemType == typeContent) {
13652
0
    nsCOMPtr<nsIDocShellTreeItem> root;
13653
0
    GetSameTypeRootTreeItem(getter_AddRefs(root));
13654
0
    *aIsTopLevelContentDocShell = root.get() == static_cast<nsIDocShellTreeItem*>(this);
13655
0
  }
13656
0
13657
0
  return NS_OK;
13658
0
}
13659
13660
// Implements nsILoadContext.originAttributes
13661
NS_IMETHODIMP
13662
nsDocShell::GetScriptableOriginAttributes(JS::MutableHandle<JS::Value> aVal)
13663
0
{
13664
0
  JSContext* cx = nsContentUtils::GetCurrentJSContext();
13665
0
  MOZ_ASSERT(cx);
13666
0
13667
0
  return GetOriginAttributes(cx, aVal);
13668
0
}
13669
13670
// Implements nsIDocShell.GetOriginAttributes()
13671
NS_IMETHODIMP
13672
nsDocShell::GetOriginAttributes(JSContext* aCx,
13673
                                JS::MutableHandle<JS::Value> aVal)
13674
0
{
13675
0
  bool ok = ToJSValue(aCx, mOriginAttributes, aVal);
13676
0
  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
13677
0
  return NS_OK;
13678
0
}
13679
13680
bool
13681
nsDocShell::CanSetOriginAttributes()
13682
0
{
13683
0
  MOZ_ASSERT(mChildList.IsEmpty());
13684
0
  if (!mChildList.IsEmpty()) {
13685
0
    return false;
13686
0
  }
13687
0
13688
0
  // TODO: Bug 1273058 - mContentViewer should be null when setting origin
13689
0
  // attributes.
13690
0
  if (mContentViewer) {
13691
0
    nsIDocument* doc = mContentViewer->GetDocument();
13692
0
    if (doc) {
13693
0
      nsIURI* uri = doc->GetDocumentURI();
13694
0
      if (!uri) {
13695
0
        return false;
13696
0
      }
13697
0
      nsCString uriSpec = uri->GetSpecOrDefault();
13698
0
      MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
13699
0
      if (!uriSpec.EqualsLiteral("about:blank")) {
13700
0
        return false;
13701
0
      }
13702
0
    }
13703
0
  }
13704
0
13705
0
  return true;
13706
0
}
13707
13708
bool
13709
nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal,
13710
                                                nsIURI* aURI)
13711
0
{
13712
0
  MOZ_ASSERT(aPrincipal);
13713
0
  MOZ_ASSERT(aURI);
13714
0
13715
0
  if (UsePrivateBrowsing() || mSandboxFlags) {
13716
0
    return false;
13717
0
  }
13718
0
13719
0
  nsCOMPtr<nsIDocShellTreeItem> parent;
13720
0
  GetSameTypeParent(getter_AddRefs(parent));
13721
0
  nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
13722
0
  nsPIDOMWindowInner* parentInner =
13723
0
    parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
13724
0
13725
0
  nsContentUtils::StorageAccess storage =
13726
0
    nsContentUtils::StorageAllowedForNewWindow(aPrincipal, aURI, parentInner);
13727
0
13728
0
  return storage == nsContentUtils::StorageAccess::eAllow;
13729
0
}
13730
13731
nsresult
13732
nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs)
13733
0
{
13734
0
  MOZ_ASSERT(!mIsBeingDestroyed);
13735
0
13736
0
  if (!CanSetOriginAttributes()) {
13737
0
    return NS_ERROR_FAILURE;
13738
0
  }
13739
0
13740
0
  AssertOriginAttributesMatchPrivateBrowsing();
13741
0
  mOriginAttributes = aAttrs;
13742
0
13743
0
  bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
13744
0
  // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
13745
0
  if (mItemType == typeChrome && isPrivate) {
13746
0
    mOriginAttributes.mPrivateBrowsingId = 0;
13747
0
  }
13748
0
13749
0
  SetPrivateBrowsing(isPrivate);
13750
0
  AssertOriginAttributesMatchPrivateBrowsing();
13751
0
13752
0
  return NS_OK;
13753
0
}
13754
13755
NS_IMETHODIMP
13756
nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes,
13757
                                             JSContext* aCx)
13758
0
{
13759
0
  if (!aOriginAttributes.isObject()) {
13760
0
    return NS_ERROR_INVALID_ARG;
13761
0
  }
13762
0
13763
0
  OriginAttributes attrs;
13764
0
  if (!attrs.Init(aCx, aOriginAttributes)) {
13765
0
    return NS_ERROR_INVALID_ARG;
13766
0
  }
13767
0
13768
0
  return SetOriginAttributes(attrs);
13769
0
}
13770
13771
NS_IMETHODIMP
13772
nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
13773
                                JSContext* aCx)
13774
0
{
13775
0
  OriginAttributes attrs;
13776
0
  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
13777
0
    return NS_ERROR_INVALID_ARG;
13778
0
  }
13779
0
13780
0
  return SetOriginAttributes(attrs);
13781
0
}
13782
13783
NS_IMETHODIMP
13784
nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
13785
0
{
13786
0
  if (nsIPresShell* presShell = GetPresShell()) {
13787
0
    *aOut = presShell->AsyncPanZoomEnabled();
13788
0
    return NS_OK;
13789
0
  }
13790
0
13791
0
  // If we don't have a presShell, fall back to the default platform value of
13792
0
  // whether or not APZ is enabled.
13793
0
  *aOut = gfxPlatform::AsyncPanZoomEnabled();
13794
0
  return NS_OK;
13795
0
}
13796
13797
bool
13798
nsDocShell::HasUnloadedParent()
13799
0
{
13800
0
  RefPtr<nsDocShell> parent = GetParentDocshell();
13801
0
  while (parent) {
13802
0
    bool inUnload = false;
13803
0
    parent->GetIsInUnload(&inUnload);
13804
0
    if (inUnload) {
13805
0
      return true;
13806
0
    }
13807
0
    parent = parent->GetParentDocshell();
13808
0
  }
13809
0
  return false;
13810
0
}
13811
13812
void
13813
nsDocShell::UpdateGlobalHistoryTitle(nsIURI* aURI)
13814
0
{
13815
0
  if (mUseGlobalHistory && !UsePrivateBrowsing()) {
13816
0
    nsCOMPtr<IHistory> history = services::GetHistoryService();
13817
0
    if (history) {
13818
0
      history->SetURITitle(aURI, mTitle);
13819
0
    }
13820
0
  }
13821
0
}
13822
13823
bool
13824
nsDocShell::IsInvisible()
13825
0
{
13826
0
  return mInvisible;
13827
0
}
13828
13829
void
13830
nsDocShell::SetInvisible(bool aInvisible)
13831
0
{
13832
0
  mInvisible = aInvisible;
13833
0
}
13834
13835
void
13836
nsDocShell::SetOpener(nsITabParent* aOpener)
13837
0
{
13838
0
  mOpener = do_GetWeakReference(aOpener);
13839
0
}
13840
13841
nsITabParent*
13842
nsDocShell::GetOpener()
13843
0
{
13844
0
  nsCOMPtr<nsITabParent> opener(do_QueryReferent(mOpener));
13845
0
  return opener;
13846
0
}
13847
13848
// The caller owns |aAsyncCause| here.
13849
void
13850
nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
13851
                                         const char16_t* aFunctionName,
13852
                                         const char16_t* aFilename,
13853
                                         const uint32_t aLineNumber,
13854
                                         JS::Handle<JS::Value> aAsyncStack,
13855
                                         const char* aAsyncCause)
13856
0
{
13857
0
  // If first start, mark interval start.
13858
0
  if (mJSRunToCompletionDepth == 0) {
13859
0
    RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
13860
0
    if (timelines && timelines->HasConsumer(this)) {
13861
0
      timelines->AddMarkerForDocShell(this,
13862
0
        mozilla::MakeUnique<JavascriptTimelineMarker>(
13863
0
          aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START,
13864
0
          aAsyncStack, aAsyncCause));
13865
0
    }
13866
0
  }
13867
0
13868
0
  mJSRunToCompletionDepth++;
13869
0
}
13870
13871
void
13872
nsDocShell::NotifyJSRunToCompletionStop()
13873
0
{
13874
0
  mJSRunToCompletionDepth--;
13875
0
13876
0
  // If last stop, mark interval end.
13877
0
  if (mJSRunToCompletionDepth == 0) {
13878
0
    RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
13879
0
    if (timelines && timelines->HasConsumer(this)) {
13880
0
      timelines->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
13881
0
    }
13882
0
  }
13883
0
}
13884
13885
void
13886
nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
13887
                                            const nsString& aKeyword)
13888
0
{
13889
0
  if (aProvider.IsEmpty()) {
13890
0
    return;
13891
0
  }
13892
0
13893
0
  if (XRE_IsContentProcess()) {
13894
0
    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
13895
0
    if (contentChild) {
13896
0
      contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword);
13897
0
    }
13898
0
    return;
13899
0
  }
13900
0
13901
0
#ifdef MOZ_TOOLKIT_SEARCH
13902
0
  nsCOMPtr<nsIBrowserSearchService> searchSvc =
13903
0
    do_GetService("@mozilla.org/browser/search-service;1");
13904
0
  if (searchSvc) {
13905
0
    nsCOMPtr<nsISearchEngine> searchEngine;
13906
0
    searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
13907
0
    if (searchEngine) {
13908
0
      nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
13909
0
      if (obsSvc) {
13910
0
        // Note that "keyword-search" refers to a search via the url
13911
0
        // bar, not a bookmarks keyword search.
13912
0
        obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
13913
0
      }
13914
0
    }
13915
0
  }
13916
0
#endif
13917
0
}
13918
13919
NS_IMETHODIMP
13920
nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, nsIChannel* aChannel,
13921
                                      bool* aShouldIntercept)
13922
0
{
13923
0
  return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel,
13924
0
                                                         aShouldIntercept);
13925
0
}
13926
13927
NS_IMETHODIMP
13928
nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
13929
0
{
13930
0
  return mInterceptController->ChannelIntercepted(aChannel);
13931
0
}
13932
13933
bool
13934
nsDocShell::InFrameSwap()
13935
0
{
13936
0
  RefPtr<nsDocShell> shell = this;
13937
0
  do {
13938
0
    if (shell->mInFrameSwap) {
13939
0
      return true;
13940
0
    }
13941
0
    shell = shell->GetParentDocshell();
13942
0
  } while (shell);
13943
0
  return false;
13944
0
}
13945
13946
UniquePtr<ClientSource>
13947
nsDocShell::TakeInitialClientSource()
13948
0
{
13949
0
  return std::move(mInitialClientSource);
13950
0
}
13951
13952
NS_IMETHODIMP
13953
nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError)
13954
0
{
13955
0
  if (mContentViewer) {
13956
0
    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
13957
0
    if (doc) {
13958
0
      doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
13959
0
    }
13960
0
  }
13961
0
  return NS_OK;
13962
0
}
13963
13964
NS_IMETHODIMP
13965
nsDocShell::GetEditingSession(nsIEditingSession** aEditSession)
13966
0
{
13967
0
  if (!NS_SUCCEEDED(EnsureEditorData())) {
13968
0
    return NS_ERROR_FAILURE;
13969
0
  }
13970
0
13971
0
  mEditorData->GetEditingSession(aEditSession);
13972
0
  return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
13973
0
}
13974
13975
NS_IMETHODIMP
13976
nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild)
13977
0
{
13978
0
  *aTabChild = GetTabChild().take();
13979
0
  return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
13980
0
}
13981
13982
already_AddRefed<nsITabChild>
13983
nsDocShell::GetTabChild()
13984
0
{
13985
0
  nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
13986
0
  nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
13987
0
  return tc.forget();
13988
0
}
13989
13990
nsICommandManager*
13991
nsDocShell::GetCommandManager()
13992
0
{
13993
0
  NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
13994
0
  return mCommandManager;
13995
0
}
13996
13997
NS_IMETHODIMP
13998
nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult)
13999
0
{
14000
0
  MOZ_ASSERT(aResult);
14001
0
14002
0
  nsPIDOMWindowOuter* outer = GetWindow();
14003
0
  MOZ_ASSERT(outer);
14004
0
14005
0
  // If we are not toplevel then we are not the only toplevel window in the tab
14006
0
  // group.
14007
0
  if (outer->GetScriptableParentOrNull()) {
14008
0
    *aResult = false;
14009
0
    return NS_OK;
14010
0
  }
14011
0
14012
0
  // If we have any other toplevel windows in our tab group, then we are not the
14013
0
  // only toplevel window in the tab group.
14014
0
  nsTArray<nsPIDOMWindowOuter*> toplevelWindows =
14015
0
    outer->TabGroup()->GetTopLevelWindows();
14016
0
  if (toplevelWindows.Length() > 1) {
14017
0
    *aResult = false;
14018
0
    return NS_OK;
14019
0
  }
14020
0
  MOZ_ASSERT(toplevelWindows.Length() == 1);
14021
0
  MOZ_ASSERT(toplevelWindows[0] == outer);
14022
0
14023
0
  *aResult = true;
14024
0
  return NS_OK;
14025
0
}
14026
14027
NS_IMETHODIMP
14028
nsDocShell::GetAwaitingLargeAlloc(bool* aResult)
14029
0
{
14030
0
  MOZ_ASSERT(aResult);
14031
0
  nsCOMPtr<nsITabChild> tabChild = GetTabChild();
14032
0
  if (!tabChild) {
14033
0
    *aResult = false;
14034
0
    return NS_OK;
14035
0
  }
14036
0
  *aResult = static_cast<TabChild*>(tabChild.get())->IsAwaitingLargeAlloc();
14037
0
  return NS_OK;
14038
0
}
14039
14040
NS_IMETHODIMP_(void)
14041
nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs)
14042
0
{
14043
0
  aAttrs = mOriginAttributes;
14044
0
}
14045
14046
HTMLEditor*
14047
nsIDocShell::GetHTMLEditor()
14048
0
{
14049
0
  nsDocShell* docShell = static_cast<nsDocShell*>(this);
14050
0
  return docShell->GetHTMLEditorInternal();
14051
0
}
14052
14053
nsresult
14054
nsIDocShell::SetHTMLEditor(HTMLEditor* aHTMLEditor)
14055
0
{
14056
0
  nsDocShell* docShell = static_cast<nsDocShell*>(this);
14057
0
  return docShell->SetHTMLEditorInternal(aHTMLEditor);
14058
0
}
14059
14060
NS_IMETHODIMP
14061
nsDocShell::GetDisplayMode(uint32_t* aDisplayMode)
14062
0
{
14063
0
  NS_ENSURE_ARG_POINTER(aDisplayMode);
14064
0
  *aDisplayMode = mDisplayMode;
14065
0
  return NS_OK;
14066
0
}
14067
14068
NS_IMETHODIMP
14069
nsDocShell::SetDisplayMode(uint32_t aDisplayMode)
14070
0
{
14071
0
  if (!(aDisplayMode == nsIDocShell::DISPLAY_MODE_BROWSER ||
14072
0
        aDisplayMode == nsIDocShell::DISPLAY_MODE_STANDALONE ||
14073
0
        aDisplayMode == nsIDocShell::DISPLAY_MODE_FULLSCREEN ||
14074
0
        aDisplayMode == nsIDocShell::DISPLAY_MODE_MINIMAL_UI)) {
14075
0
    return NS_ERROR_INVALID_ARG;
14076
0
  }
14077
0
14078
0
  if (aDisplayMode != mDisplayMode) {
14079
0
    mDisplayMode = aDisplayMode;
14080
0
14081
0
    RefPtr<nsPresContext> presContext;
14082
0
    if (NS_SUCCEEDED(GetPresContext(getter_AddRefs(presContext)))) {
14083
0
      presContext->MediaFeatureValuesChangedAllDocuments({
14084
0
        MediaFeatureChangeReason::DisplayModeChange });
14085
0
    }
14086
0
  }
14087
0
14088
0
  return NS_OK;
14089
0
}
14090
14091
NS_IMETHODIMP
14092
nsDocShell::SetColorMatrix(float* aMatrix, uint32_t aMatrixLen)
14093
0
{
14094
0
  if (aMatrixLen == 20) {
14095
0
    mColorMatrix.reset(new gfx::Matrix5x4());
14096
0
    MOZ_ASSERT(aMatrixLen * sizeof(*aMatrix) == sizeof(mColorMatrix->components));
14097
0
    memcpy(mColorMatrix->components, aMatrix, sizeof(mColorMatrix->components));
14098
0
  } else if (aMatrixLen == 0) {
14099
0
    mColorMatrix.reset();
14100
0
  } else {
14101
0
    return NS_ERROR_INVALID_ARG;
14102
0
  }
14103
0
14104
0
  nsIPresShell* presShell = GetPresShell();
14105
0
  if (!presShell) {
14106
0
    return NS_ERROR_FAILURE;
14107
0
  }
14108
0
14109
0
  nsIFrame* frame = presShell->GetRootFrame();
14110
0
  if (!frame) {
14111
0
    return NS_ERROR_FAILURE;
14112
0
  }
14113
0
14114
0
  frame->SchedulePaint();
14115
0
14116
0
  return NS_OK;
14117
0
}
14118
14119
NS_IMETHODIMP
14120
nsDocShell::GetColorMatrix(uint32_t* aMatrixLen, float** aMatrix)
14121
0
{
14122
0
  NS_ENSURE_ARG_POINTER(aMatrixLen);
14123
0
  *aMatrixLen = 0;
14124
0
14125
0
  NS_ENSURE_ARG_POINTER(aMatrix);
14126
0
  *aMatrix = nullptr;
14127
0
14128
0
  if (mColorMatrix) {
14129
0
    *aMatrix = (float*)moz_xmalloc(20 * sizeof(float));
14130
0
    MOZ_ASSERT(20 * sizeof(float) == sizeof(mColorMatrix->components));
14131
0
    *aMatrixLen = 20;
14132
0
    memcpy(*aMatrix, mColorMatrix->components, 20 * sizeof(float));
14133
0
  }
14134
0
14135
0
  return NS_OK;
14136
0
}
14137
14138
bool
14139
nsDocShell::IsForceReloading()
14140
0
{
14141
0
  return IsForceReloadType(mLoadType);
14142
0
}
14143
14144
already_AddRefed<BrowsingContext>
14145
nsDocShell::GetBrowsingContext() const
14146
0
{
14147
0
  RefPtr<BrowsingContext> browsingContext = mBrowsingContext;
14148
0
  return browsingContext.forget();
14149
0
}
14150
14151
NS_IMETHODIMP
14152
nsDocShell::GetBrowsingContext(BrowsingContext** aBrowsingContext)
14153
0
{
14154
0
  *aBrowsingContext = do_AddRef(mBrowsingContext).take();
14155
0
  return NS_OK;
14156
0
}
14157
14158
void
14159
nsIDocShell::AttachBrowsingContext(nsIDocShell* aParentDocShell)
14160
0
{
14161
0
  RefPtr<BrowsingContext> childContext =
14162
0
    nsDocShell::Cast(this)->GetBrowsingContext();
14163
0
  RefPtr<BrowsingContext> parentContext;
14164
0
  if (aParentDocShell) {
14165
0
    parentContext =
14166
0
      nsDocShell::Cast(aParentDocShell)->GetBrowsingContext();
14167
0
  }
14168
0
  childContext->Attach(parentContext);
14169
0
}
14170
14171
void
14172
nsIDocShell::DetachBrowsingContext()
14173
0
{
14174
0
  RefPtr<BrowsingContext> browsingContext =
14175
0
    nsDocShell::Cast(this)->GetBrowsingContext();
14176
0
  browsingContext->Detach();
14177
0
}