nsDocShell.cpp 438 KB
Newer Older
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
4
5
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6

7
8
9
10
#include "nsDocShell.h"

#include <algorithm>

11
#ifdef XP_WIN
12
13
#  include <process.h>
#  define getpid _getpid
14
#else
15
#  include <unistd.h>  // for getpid()
16
17
#endif

18
#include "mozilla/ArrayUtils.h"
19
20
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
21
#include "mozilla/BasePrincipal.h"
22
#include "mozilla/Casting.h"
23
#include "mozilla/Components.h"
24
#include "mozilla/DebugOnly.h"
25
26
27
28
29
#include "mozilla/Encoding.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Logging.h"
30
#include "mozilla/MediaFeatureChange.h"
31
#include "mozilla/Preferences.h"
32
#include "mozilla/PresShell.h"
33
#include "mozilla/ResultExtensions.h"
34
#include "mozilla/ScrollTypes.h"
35
#include "mozilla/Services.h"
36
37
38
39
40
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_extensions.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StaticPrefs_ui.h"
41
#include "mozilla/StartupTimeline.h"
42
#include "mozilla/StorageAccess.h"
43
44
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
45
#include "mozilla/WidgetUtils.h"
46

47
48
49
50
51
#include "mozilla/dom/ClientChannelHelper.h"
#include "mozilla/dom/ClientHandle.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
52
#include "mozilla/dom/ContentChild.h"
53
#include "mozilla/dom/ContentFrameMessageManager.h"
54
#include "mozilla/dom/DocGroup.h"
55
#include "mozilla/dom/Element.h"
56
#include "mozilla/dom/HTMLAnchorElement.h"
57
58
#include "mozilla/dom/PerformanceNavigation.h"
#include "mozilla/dom/PermissionMessageUtils.h"
59
#include "mozilla/dom/PopupBlocker.h"
60
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
61
#include "mozilla/dom/ScreenOrientation.h"
62
#include "mozilla/dom/ScriptSettings.h"
63
#include "mozilla/dom/ServiceWorkerInterceptController.h"
64
#include "mozilla/dom/ServiceWorkerUtils.h"
65
#include "mozilla/dom/SessionStorageManager.h"
66
#include "mozilla/dom/BrowserChild.h"
67
#include "mozilla/dom/TabGroup.h"
68
#include "mozilla/dom/ToJSValue.h"
69
#include "mozilla/dom/UserActivation.h"
70
#include "mozilla/dom/ChildSHistory.h"
71
#include "mozilla/dom/nsCSPContext.h"
72
#include "mozilla/dom/LoadURIOptionsBinding.h"
73
#include "mozilla/dom/JSWindowActorChild.h"
74

75
#include "mozilla/net/DocumentChannelChild.h"
76
#include "mozilla/net/UrlClassifierFeatureFactory.h"
77
#include "ReferrerInfo.h"
78
79
80
81
82
83
84
85
86
87
88
89
90

#include "nsIApplicationCacheChannel.h"
#include "nsIApplicationCacheContainer.h"
#include "nsIAppShell.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIAuthPrompt.h"
#include "nsIAuthPrompt2.h"
#include "nsICachingChannel.h"
#include "nsICaptivePortalService.h"
#include "nsIChannel.h"
#include "nsIChannelEventSink.h"
#include "nsIClassOfService.h"
#include "nsIConsoleReportCollector.h"
91
#include "nsIContent.h"
92
#include "nsIContentInlines.h"
93
94
95
96
97
98
#include "nsIContentSecurityPolicy.h"
#include "nsIContentViewer.h"
#include "nsIController.h"
#include "nsICookieService.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
99
#include "mozilla/dom/Document.h"
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "nsIDocumentLoaderFactory.h"
#include "nsIDOMWindow.h"
#include "nsIEditingSession.h"
#include "nsIExternalProtocolService.h"
#include "nsIFormPOSTActionChannel.h"
#include "nsIFrame.h"
#include "nsIGlobalObject.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIIDNService.h"
#include "nsIInputStreamChannel.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIJARChannel.h"
#include "nsILayoutHistoryState.h"
#include "nsILoadInfo.h"
#include "nsIMultiPartChannel.h"
#include "nsINestedURI.h"
#include "nsINetworkPredictor.h"
#include "nsINode.h"
#include "nsINSSErrorsService.h"
#include "nsIObserverService.h"
#include "nsIOService.h"
#include "nsIPrincipal.h"
#include "nsIPrivacyTransitionObserver.h"
#include "nsIPrompt.h"
#include "nsIPromptFactory.h"
#include "nsIReflowObserver.h"
#include "nsIScriptChannel.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScrollableFrame.h"
#include "nsIScrollObserver.h"
#include "nsISecureBrowserUI.h"
#include "nsISecurityUITelemetry.h"
#include "nsISeekableStream.h"
#include "nsISelectionDisplay.h"
#include "nsISHEntry.h"
#include "nsISHistory.h"
#include "nsISiteSecurityService.h"
#include "nsISocketProvider.h"
#include "nsIStringBundle.h"
#include "nsIStructuredCloneContainer.h"
#include "nsISupportsPrimitives.h"
143
#include "nsIBrowserChild.h"
144
145
146
147
148
149
150
#include "nsITextToSubURI.h"
#include "nsITimedChannel.h"
#include "nsITimer.h"
#include "nsITransportSecurityInfo.h"
#include "nsIUploadChannel.h"
#include "nsIURIFixup.h"
#include "nsIURILoader.h"
151
#include "nsIURIMutator.h"
152
153
154
155
156
157
158
159
160
161
162
#include "nsIURL.h"
#include "nsIViewSourceChannel.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebBrowserChrome3.h"
#include "nsIWebBrowserChromeFocus.h"
#include "nsIWebBrowserFind.h"
#include "nsIWebProgress.h"
#include "nsIWidget.h"
#include "nsIWindowWatcher.h"
#include "nsIWritablePropertyBag2.h"

163
#include "nsCommandManager.h"
164
165
166
167
168
169
170
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"

#include "IHistory.h"
#include "IUrlClassifierUITelemetry.h"

#include "mozIThirdPartyUtil.h"
171

172
173
#include "nsArray.h"
#include "nsArrayUtils.h"
174
175
176
#include "nsAutoPtr.h"
#include "nsCExternalHandlerService.h"
#include "nsContentDLF.h"
177
#include "nsContentPolicyUtils.h"  // NS_CheckContentLoadPolicy(...)
178
#include "nsContentSecurityManager.h"
179
#include "nsContentUtils.h"
180
#include "nsCURILoader.h"
181
#include "nsDocShellCID.h"
182
183
#include "nsDocShellEditorData.h"
#include "nsDocShellEnumerator.h"
184
#include "nsDocShellLoadState.h"
185
#include "nsDocShellLoadTypes.h"
186
#include "nsDOMCID.h"
187
188
#include "nsDOMNavigationTiming.h"
#include "nsDSURIContentListener.h"
189
#include "nsEditingSession.h"
190
191
192
193
#include "nsError.h"
#include "nsEscape.h"
#include "nsFocusManager.h"
#include "nsGlobalWindow.h"
194
#include "nsISearchService.h"
195
#include "nsJSEnvironment.h"
196
#include "nsNetCID.h"
197
#include "nsNetUtil.h"
198
#include "nsObjectLoadingContent.h"
199
#include "nsPingListener.h"
200
#include "nsPoint.h"
201
#include "nsQueryObject.h"
202
#include "nsQueryActor.h"
203
#include "nsRect.h"
204
#include "nsRefreshTimer.h"
205
206
207
208
#include "nsSandboxFlags.h"
#include "nsSHistory.h"
#include "nsStructuredCloneContainer.h"
#include "nsSubDocumentFrame.h"
209
#include "nsView.h"
210
#include "nsViewManager.h"
211
#include "nsViewSourceHandler.h"
212
#include "nsWebBrowserFind.h"
213
#include "nsWhitespaceTokenizer.h"
214
215
#include "nsWidgetsCID.h"
#include "nsXULAppAPI.h"
216

217
#include "GeckoProfiler.h"
218
#include "mozilla/NullPrincipal.h"
219
220
221
#include "Navigator.h"
#include "prenv.h"
#include "URIUtils.h"
222

223
#include "timeline/JavascriptTimelineMarker.h"
224

225
#ifdef MOZ_PLACES
226
227
#  include "nsIFaviconService.h"
#  include "mozIPlacesPendingOperation.h"
228
#endif
229

230
#if NS_PRINT_PREVIEW
231
232
#  include "nsIDocumentViewerPrint.h"
#  include "nsIWebBrowserPrint.h"
233
234
#endif

235
236
237
238
#ifdef MOZ_GECKO_PROFILER
#  include "ProfilerMarkerPayload.h"
#endif

239
using namespace mozilla;
240
using namespace mozilla::dom;
241
using namespace mozilla::net;
242

243
244
245
246
247
248
249
250
251
252
253
// Threshold value in ms for META refresh based redirects
#define REFRESH_REDIRECT_TIMER 15000

// Hint for native dispatch of events on how long to delay after
// all documents have loaded in milliseconds before favoring normal
// native event dispatch priorites over performance
// Can be overridden with docshell.event_starvation_delay_hint pref.
#define NS_EVENT_STARVATION_DELAY_HINT 2000

static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);

254
255
256
// Number of documents currently loading
static int32_t gNumberOfDocumentsLoading = 0;

257
// Global count of existing docshells.
258
static int32_t gDocShellCount = 0;
259

260
// Global count of docshells with the private attribute set
261
static uint32_t gNumberOfPrivateDocShells = 0;
262

263
#ifdef DEBUG
264
static mozilla::LazyLogModule gDocShellLog("nsDocShell");
265
266
static mozilla::LazyLogModule gDocShellAndDOMWindowLeakLogging(
    "DocShellAndDOMWindowLeak");
267
#endif
268
static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");
269
extern mozilla::LazyLogModule gPageCacheLog;
270

271
272
273
const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
const char kAppstringsBundleURL[] =
    "chrome://global/locale/appstrings.properties";
274

275
276
277
// Global reference to the URI fixup service.
nsIURIFixup* nsDocShell::sURIFixup = nullptr;

278
static void FavorPerformanceHint(bool aPerfOverStarvation) {
279
280
281
  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
  if (appShell) {
    appShell->FavorPerformanceHint(
282
283
284
        aPerfOverStarvation,
        Preferences::GetUint("docshell.event_starvation_delay_hint",
                             NS_EVENT_STARVATION_DELAY_HINT));
285
286
287
  }
}

288
static void IncreasePrivateDocShellCount() {
289
  gNumberOfPrivateDocShells++;
290
  if (gNumberOfPrivateDocShells > 1 || !XRE_IsContentProcess()) {
291
292
    return;
  }
293

294
295
  mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
  cc->SendPrivateDocShellsExist(true);
296
297
}

298
static void DecreasePrivateDocShellCount() {
299
300
301
  MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
  gNumberOfPrivateDocShells--;
  if (!gNumberOfPrivateDocShells) {
302
    if (XRE_IsContentProcess()) {
303
304
305
306
      dom::ContentChild* cc = dom::ContentChild::GetSingleton();
      cc->SendPrivateDocShellsExist(false);
      return;
    }
307

308
309
310
    nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
    if (obsvc) {
      obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
311
    }
312
  }
313
314
}

315
316
nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
                       uint64_t aContentWindowID)
317
    : nsDocLoader(),
318
      mHistoryID(aBrowsingContext->GetHistoryID()),
319
      mContentWindowID(aContentWindowID),
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
      mBrowsingContext(aBrowsingContext),
      mForcedCharset(nullptr),
      mParentCharset(nullptr),
      mTreeOwner(nullptr),
      mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
      mCharsetReloadState(eCharsetReloadInit),
      mOrientationLock(hal::eScreenOrientation_None),
      mParentCharsetSource(0),
      mMarginWidth(-1),
      mMarginHeight(-1),
      mItemType(aBrowsingContext->IsContent() ? typeContent : typeChrome),
      mPreviousEntryIndex(-1),
      mLoadedEntryIndex(-1),
      mChildOffset(0),
      mBusyFlags(BUSY_FLAGS_NONE),
      mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
      mLoadType(0),
      mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
      mFailedLoadType(0),
      mFrameType(FRAME_TYPE_REGULAR),
      mPrivateBrowsingId(0),
      mDisplayMode(nsIDocShell::DISPLAY_MODE_BROWSER),
      mJSRunToCompletionDepth(0),
      mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE),
      mMetaViewportOverride(nsIDocShell::META_VIEWPORT_OVERRIDE_NONE),
      mFullscreenAllowed(CHECK_ATTRIBUTES),
346
      mCreatingDocument(false),
347
#ifdef DEBUG
348
      mInEnsureScriptEnv(false),
349
#endif
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
      mCreated(false),
      mAllowSubframes(true),
      mAllowPlugins(true),
      mAllowJavascript(true),
      mAllowMetaRedirects(true),
      mAllowImages(true),
      mAllowMedia(true),
      mAllowDNSPrefetch(true),
      mAllowWindowControl(true),
      mAllowContentRetargeting(true),
      mAllowContentRetargetingOnChildren(true),
      mUseErrorPages(false),
      mUseStrictSecurityChecks(false),
      mObserveErrorPages(true),
      mCSSErrorReportingEnabled(false),
      mAllowAuth(mItemType == typeContent),
      mAllowKeywordFixup(false),
      mIsOffScreenBrowser(false),
      mDisableMetaRefreshWhenInactive(false),
      mIsAppTab(false),
      mUseGlobalHistory(false),
      mUseRemoteTabs(false),
372
      mUseRemoteSubframes(false),
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
      mUseTrackingProtection(false),
      mDeviceSizeIsPageSize(false),
      mWindowDraggingAllowed(false),
      mInFrameSwap(false),
      mInheritPrivateBrowsingId(true),
      mCanExecuteScripts(false),
      mFiredUnloadEvent(false),
      mEODForCurrentDocument(false),
      mURIResultedInDocument(false),
      mIsBeingDestroyed(false),
      mIsExecutingOnLoadHandler(false),
      mIsPrintingOrPP(false),
      mSavingOldViewer(false),
      mDynamicallyCreated(false),
      mAffectPrivateSessionLifetime(true),
      mInvisible(false),
      mHasLoadedNonBlankURI(false),
      mBlankTiming(false),
391
      mTitleValidForCurrentURI(false),
392
      mIsFrame(false),
393
      mSkipBrowsingContextDetachOnDestroy(false),
394
395
      mWatchedByDevtools(false),
      mIsNavigating(false) {
396
  AssertOriginAttributesMatchPrivateBrowsing();
397

398
399
400
401
402
  // If no outer window ID was provided, generate a new one.
  if (aContentWindowID == 0) {
    mContentWindowID = nsContentUtils::GenerateWindowId();
  }

403
404
405
406
  if (gDocShellCount++ == 0) {
    NS_ASSERTION(sURIFixup == nullptr,
                 "Huh, sURIFixup not null in first nsDocShell ctor!");

407
408
    nsCOMPtr<nsIURIFixup> uriFixup = components::URIFixup::Service();
    uriFixup.forget(&sURIFixup);
409
  }
410

411
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
412
413
414
415

#ifdef DEBUG
  // We're counting the number of |nsDocShells| to help find leaks
  ++gNumberOfDocShells;
416
417
418
  MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
          ("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n", (void*)this,
           gNumberOfDocShells, getpid(), nsIDToCString(mHistoryID).get()));
419
#endif
420
421
}

422
nsDocShell::~nsDocShell() {
423
  MOZ_ASSERT(!mObserved);
424

425
426
427
  // Avoid notifying observers while we're in the dtor.
  mIsBeingDestroyed = true;

428
  Destroy();
429

430
  if (mSessionHistory) {
431
    mSessionHistory->LegacySHistory()->ClearRootBrowsingContext();
432
  }
433

434
435
436
  if (--gDocShellCount == 0) {
    NS_IF_RELEASE(sURIFixup);
  }
437

438
  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this));
439
440

#ifdef DEBUG
441
442
443
444
445
446
447
448
449
450
  if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
    nsAutoCString url;
    if (mLastOpenedURI) {
      url = mLastOpenedURI->GetSpecOrDefault();

      // Data URLs can be very long, so truncate to avoid flooding the log.
      const uint32_t maxURLLength = 1000;
      if (url.Length() > maxURLLength) {
        url.Truncate(maxURLLength);
      }
451
    }
452
453
454
455
456
457
458

    // We're counting the number of |nsDocShells| to help find leaks
    --gNumberOfDocShells;
    MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
            ("--DOCSHELL %p == %ld [pid = %d] [id = %s] [url = %s]\n",
             (void*)this, gNumberOfDocShells, getpid(),
             nsIDToCString(mHistoryID).get(), url.get()));
459
  }
460
#endif
461
462
}

463
464
/* static */
already_AddRefed<nsDocShell> nsDocShell::Create(
465
    BrowsingContext* aBrowsingContext, uint64_t aContentWindowID) {
466
  MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
467

468
  nsresult rv;
469
  RefPtr<nsDocShell> ds = new nsDocShell(aBrowsingContext, aContentWindowID);
470

471
472
473
474
475
  // Initialize the underlying nsDocLoader.
  rv = ds->nsDocLoader::Init();
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }
476

477
478
479
480
481
482
  // Create our ContentListener
  ds->mContentListener = new nsDSURIContentListener(ds);
  rv = ds->mContentListener->Init();
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }
483

484
485
486
  // If parent intercept is not enabled then we must forward to
  // the network controller from docshell.  We also enable if we're
  // in the parent process in order to support non-e10s configurations.
487
488
  // Note: This check is duplicated in SharedWorkerInterfaceRequestor's
  // constructor.
489
  if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
490
    ds->mInterceptController = new ServiceWorkerInterceptController();
491
  }
492

493
494
  // We want to hold a strong ref to the loadgroup, so it better hold a weak
  // ref to us...  use an InterfaceRequestorProxy to do this.
495
496
  nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(ds);
  ds->mLoadGroup->SetNotificationCallbacks(proxy);
497

498
499
500
501
502
503
  // XXX(nika): We have our BrowsingContext, so we might be able to skip this.
  // It could be nice to directly set up our DocLoader tree?
  rv = nsDocLoader::AddDocLoaderAsChildOfRoot(ds);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }
504

505
506
507
508
  // Add |ds| as a progress listener to itself.  A little weird, but simpler
  // than reproducing all the listener-notification logic in overrides of the
  // various methods via which nsDocLoader can be notified.   Note that this
  // holds an nsWeakPtr to |ds|, so it's ok.
509
510
  rv = ds->AddProgressListener(ds, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
                                       nsIWebProgress::NOTIFY_STATE_NETWORK);
511
512
513
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }
514

515
516
517
518
519
520
521
522
  // If our parent is present in this process, set up our parent now.
  RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
  if (parent && parent->GetDocShell()) {
    parent->GetDocShell()->AddChild(ds);
  }

  // Make |ds| the primary DocShell for the given context.
  aBrowsingContext->SetDocShell(ds);
523

524
  return ds.forget();
525
526
}

527
void nsDocShell::DestroyChildren() {
528
529
530
531
532
  nsCOMPtr<nsIDocShellTreeItem> shell;
  nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  while (iter.HasMore()) {
    shell = do_QueryObject(iter.GetNext());
    NS_ASSERTION(shell, "docshell has null child");
533

534
535
    if (shell) {
      shell->SetTreeOwner(nullptr);
536
    }
537
  }
538

539
  nsDocLoader::DestroyChildren();
540
541
}

542
543
544
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell, nsDocLoader,
                                   mSessionStorageManager, mScriptGlobal,
                                   mInitialClientSource, mSessionHistory,
545
                                   mBrowsingContext, mChromeEventHandler)
546

547
548
NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
549

550
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
551
552
553
554
555
556
557
558
559
560
561
562
  NS_INTERFACE_MAP_ENTRY(nsIDocShell)
  NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
  NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
  NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
  NS_INTERFACE_MAP_ENTRY(nsIScrollable)
  NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
  NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
  NS_INTERFACE_MAP_ENTRY(nsILoadContext)
  NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
563
564
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,
                                     mInterceptController)
565
  NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
566
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
567

568
NS_IMETHODIMP
569
nsDocShell::GetInterface(const nsIID& aIID, void** aSink) {
570
  MOZ_ASSERT(aSink, "null out param");
571

572
  *aSink = nullptr;
573

574
575
  if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
    NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
576
    *aSink = static_cast<nsICommandManager*>(mCommandManager.get());
577
578
579
  } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
    *aSink = mContentListener;
  } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
580
              aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
581
582
              aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
              aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
583
              aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
584
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
585
    return mScriptGlobal->QueryInterface(aIID, aSink);
586
  } else if (aIID.Equals(NS_GET_IID(Document)) &&
587
             NS_SUCCEEDED(EnsureContentViewer())) {
588
    RefPtr<Document> doc = mContentViewer->GetDocument();
589
590
591
592
    doc.forget(aSink);
    return *aSink ? NS_OK : NS_NOINTERFACE;
  } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
    *aSink = nullptr;
593

594
    // Return application cache associated with this docshell, if any
595

596
597
598
599
600
    nsCOMPtr<nsIContentViewer> contentViewer;
    GetContentViewer(getter_AddRefs(contentViewer));
    if (!contentViewer) {
      return NS_ERROR_NO_INTERFACE;
    }
601

602
    RefPtr<Document> doc = contentViewer->GetDocument();
603
604
    NS_ASSERTION(doc, "Should have a document.");
    if (!doc) {
605
606
      return NS_ERROR_NO_INTERFACE;
    }
607

608
#if defined(DEBUG)
609
610
611
    MOZ_LOG(
        gDocShellLog, LogLevel::Debug,
        ("nsDocShell[%p]: returning app cache container %p", this, doc.get()));
612
#endif
613
    return doc->QueryInterface(aIID, aSink);
614
  } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
615
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
616
617
    nsresult rv;
    nsCOMPtr<nsIWindowWatcher> wwatch =
618
        do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
619
    NS_ENSURE_SUCCESS(rv, rv);
620

621
622
623
    // Get the an auth prompter for our window so that the parenting
    // of the dialogs works as it should when using tabs.
    nsIPrompt* prompt;
624
    rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
625
    NS_ENSURE_SUCCESS(rv, rv);
626

627
628
629
    *aSink = prompt;
    return NS_OK;
  } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
630
             aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
631
632
633
    return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink))
               ? NS_OK
               : NS_NOINTERFACE;
634
  } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
635
636
637
638
639
    RefPtr<ChildSHistory> shistory = GetSessionHistory();
    if (shistory) {
      // XXX(nika): Stop exposing nsISHistory through GetInterface.
      nsCOMPtr<nsISHistory> legacy = shistory->LegacySHistory();
      legacy.forget(aSink);
640
      return NS_OK;
641
    }
642
643
644
645
646
    return NS_NOINTERFACE;
  } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
    nsresult rv = EnsureFind();
    if (NS_FAILED(rv)) {
      return rv;
647
    }
648

649
650
651
652
    *aSink = mFind;
    NS_ADDREF((nsISupports*)*aSink);
    return NS_OK;
  } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
653
654
    if (PresShell* presShell = GetPresShell()) {
      return presShell->QueryInterface(aIID, aSink);
655
656
657
658
659
660
661
    }
  } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
    nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
    if (NS_SUCCEEDED(rv) && treeOwner) {
      return treeOwner->QueryInterface(aIID, aSink);
    }
662
  } else if (aIID.Equals(NS_GET_IID(nsIBrowserChild))) {
663
    *aSink = GetBrowserChild().take();
664
    return *aSink ? NS_OK : NS_ERROR_FAILURE;
665
666
667
  } else {
    return nsDocLoader::GetInterface(aIID, aSink);
  }
668

669
670
  NS_IF_ADDREF(((nsISupports*)*aSink));
  return *aSink ? NS_OK : NS_NOINTERFACE;
671
672
}

673
674
675
676
677
678
679
680
681
682
NS_IMETHODIMP
nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) {
  // Note: this gets called fairly early (before a pageload actually starts).
  // We could probably defer this even longer.
  nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild();
  static_cast<BrowserChild*>(browserChild.get())
      ->SetCancelContentJSEpoch(aEpoch);
  return NS_OK;
}

683
NS_IMETHODIMP
684
nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
685
  MOZ_ASSERT(aLoadState, "Must have a valid load state!");
686
687
688
  MOZ_ASSERT(
      (aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,
      "Should not have these flags set");
689

690
691
  if (!aLoadState->TriggeringPrincipal()) {
#ifndef ANDROID
692
    MOZ_ASSERT(false, "LoadURI must have a triggering principal");
693
694
695
696
#endif
    if (mUseStrictSecurityChecks) {
      return NS_ERROR_FAILURE;
    }
697
698
  }

699
700
701
702
703
704
705
  bool oldIsNavigating = mIsNavigating;
  auto cleanupIsNavigating =
      MakeScopeExit([&]() { mIsNavigating = oldIsNavigating; });
  if (aSetNavigating) {
    mIsNavigating = true;
  }

706
707
708
709
710
711
712
713
  PopupBlocker::PopupControlState popupState;
  if (aLoadState->LoadFlags() & LOAD_FLAGS_ALLOW_POPUPS) {
    popupState = PopupBlocker::openAllowed;
  } else {
    popupState = PopupBlocker::openOverridden;
  }
  AutoPopupStatePusher statePusher(popupState);

714
715
716
717
718
719
720
721
722
723
  if (aLoadState->GetOriginalURIString().isSome()) {
    // Save URI string in case it's needed later when
    // sending to search engine service in EndPageLoad()
    mOriginalUriString = *aLoadState->GetOriginalURIString();
  }

  if (aLoadState->GetCancelContentJSEpoch().isSome()) {
    SetCancelContentJSEpoch(*aLoadState->GetCancelContentJSEpoch());
  }

724
725
726
727
728
729
730
  // Note: we allow loads to get through here even if mFiredUnloadEvent is
  // true; that case will get handled in LoadInternal or LoadHistoryEntry,
  // so we pass false as the second parameter to IsNavigationAllowed.
  // However, we don't allow the page to change location *in the middle of*
  // firing beforeunload, so we do need to check if *beforeunload* is currently
  // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
  if (!IsNavigationAllowed(true, false)) {
731
    return NS_OK;  // JS may not handle returning of an error code
732
  }
733

734
  if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
735
      mItemType == typeContent && !NS_IsAboutBlank(aLoadState->URI())) {
736
    StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
737
  }
738

739
740
741
742
  // LoadType used to be set to a default value here, if no LoadInfo/LoadState
  // object was passed in. That functionality has been removed as of bug
  // 1492648. LoadType should now be set up by the caller at the time they
  // create their nsDocShellLoadState object to pass into LoadURI.
743

744
745
746
747
  MOZ_LOG(
      gDocShellLeakLog, LogLevel::Debug,
      ("nsDocShell[%p]: loading %s with flags 0x%08x", this,
       aLoadState->URI()->GetSpecOrDefault().get(), aLoadState->LoadFlags()));
748
749
750
751
752
753
754
755
756
757

  if (!aLoadState->SHEntry() &&
      !LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
                           LOAD_FLAGS_REPLACE_HISTORY)) {
    // This is possibly a subframe, so handle it accordingly.
    //
    // If history exists, it will be loaded into the aLoadState object, and the
    // LoadType will be changed.
    MaybeHandleSubframeHistory(aLoadState);
  }
758

759
760
761
  if (aLoadState->SHEntry()) {
#ifdef DEBUG
    MOZ_LOG(gDocShellLog, LogLevel::Debug,
762
            ("nsDocShell[%p]: loading from session history", this));
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
#endif

    return LoadHistoryEntry(aLoadState->SHEntry(), aLoadState->LoadType());
  }

  // On history navigation via Back/Forward buttons, don't execute
  // automatic JavaScript redirection such as |location.href = ...| or
  // |window.open()|
  //
  // LOAD_NORMAL:        window.open(...) etc.
  // LOAD_STOP_CONTENT:  location.href = ..., location.assign(...)
  if ((aLoadState->LoadType() == LOAD_NORMAL ||
       aLoadState->LoadType() == LOAD_STOP_CONTENT) &&
      ShouldBlockLoadingForBackButton()) {
    return NS_OK;
  }

  // Set up the inheriting principal in LoadState.
781
782
  nsresult rv =
      aLoadState->SetupInheritingPrincipal(mItemType, mOriginAttributes);
783
784
785
786
787
  NS_ENSURE_SUCCESS(rv, rv);

  rv = aLoadState->SetupTriggeringPrincipal(mOriginAttributes);
  NS_ENSURE_SUCCESS(rv, rv);

788
  aLoadState->CalculateLoadURIFlags();
789
790
791
792
793
794
795
796

  MOZ_ASSERT(aLoadState->TypeHint().IsVoid(),
             "Typehint should be null when calling InternalLoad from LoadURI");
  MOZ_ASSERT(aLoadState->FileName().IsVoid(),
             "FileName should be null when calling InternalLoad from LoadURI");
  MOZ_ASSERT(aLoadState->SHEntry() == nullptr,
             "SHEntry should be null when calling InternalLoad from LoadURI");

797
798
799
  return InternalLoad(aLoadState,
                      nullptr,   // no nsIDocShell
                      nullptr);  // no nsIRequest
800
801
802
}

void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) {
803
  // First, verify if this is a subframe.
804
  nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
805
  GetInProcessSameTypeParent(getter_AddRefs(parentAsItem));
806
  nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
807
808
809
810
811
812
813
814
815
816
817
818
819
820

  if (!parentDS || parentDS == static_cast<nsIDocShell*>(this)) {
    // This is the root docshell. If we got here while
    // executing an onLoad Handler,this load will not go
    // into session history.
    bool inOnLoadHandler = false;
    GetIsExecutingOnLoadHandler(&inOnLoadHandler);
    if (inOnLoadHandler) {
      aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
    }
    return;
  }

  /* OK. It is a subframe. Checkout the parent's loadtype. If the parent was
821
822
   * loaded through a history mechanism, then get the SH entry for the child
   * from the parent. This is done to restore frameset navigation while going
823
824
825
   * back/forward. If the parent was loaded through any other loadType, set the
   * child's loadType too accordingly, so that session history does not get
   * confused.
826
   */
827

828
  // Get the parent's load type
829
  uint32_t parentLoadType;
830
  parentDS->GetLoadType(&parentLoadType);
831

832
833
834
835
836
  // Get the ShEntry for the child from the parent
  nsCOMPtr<nsISHEntry> currentSH;
  bool oshe = false;
  parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
  bool dynamicallyAddedChild = mDynamicallyCreated;
837

838
839
840
  if (!dynamicallyAddedChild && !oshe && currentSH) {
    // Only use the old SHEntry, if we're sure enough that
    // it wasn't originally for some other frame.
841
    nsCOMPtr<nsISHEntry> shEntry;
842
843
844
845
846
    currentSH->GetChildSHEntryIfHasNoDynamicallyAddedChild(
        mChildOffset, getter_AddRefs(shEntry));
    if (shEntry) {
      aLoadState->SetSHEntry(shEntry);
    }
847
  }
848

849
850
851
852
853
854
855
856
857
858
  // Make some decisions on the child frame's loadType based on the
  // parent's loadType, if the subframe hasn't loaded anything into it.
  //
  // In some cases privileged scripts may try to get the DOMWindow
  // reference of this docshell before the loading starts, causing the
  // initial about:blank content viewer being created and mCurrentURI being
  // set. To handle this case we check if mCurrentURI is about:blank and
  // currentSHEntry is null.
  nsCOMPtr<nsISHEntry> currentChildEntry;
  GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);
859
860

  if (mCurrentURI && (!NS_IsAboutBlank(mCurrentURI) || currentChildEntry)) {
861
862
863
864
    // This is a pre-existing subframe. If
    // 1. The load of this frame was not originally initiated by session
    //    history directly (i.e. (!shEntry) condition succeeded, but it can
    //    still be a history load on parent which causes this frame being
865
    //    loaded), which we checked with the above assert, and
866
867
868
869
870
871
872
873
    // 2. mCurrentURI is not null, nor the initial about:blank,
    // it is possible that a parent's onLoadHandler or even self's
    // onLoadHandler is loading a new page in this child. Check parent's and
    // self's busy flag and if it is set, we don't want this onLoadHandler
    // load to get in to session history.
    BusyFlags parentBusy = parentDS->GetBusyFlags();
    BusyFlags selfBusy = GetBusyFlags();

874
    if (parentBusy & BUSY_FLAGS_BUSY || selfBusy & BUSY_FLAGS_BUSY) {
875
876
      aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
      aLoadState->SetSHEntry(nullptr);
877
    }
878
    return;
879
880
  }

881
882
  // This is a newly created frame. Check for exception cases first.
  // By default the subframe will inherit the parent's loadType.
883
884
885
  if (aLoadState->SHEntry() &&
      (parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK ||
       parentLoadType == LOAD_NORMAL_EXTERNAL)) {
886
887
888
889
890
891
    // The parent was loaded normally. In this case, this *brand new*
    // child really shouldn't have a SHEntry. If it does, it could be
    // because the parent is replacing an existing frame with a new frame,
    // in the onLoadHandler. We don't want this url to get into session
    // history. Clear off shEntry, and set load type to
    // LOAD_BYPASS_HISTORY.
892
    bool inOnLoadHandler = false;
893
    parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
894
    if (inOnLoadHandler) {
895
896
897
898
899
900
901
902
903
904
905
906
907
      aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
      aLoadState->SetSHEntry(nullptr);
    }
  } else if (parentLoadType == LOAD_REFRESH) {
    // Clear shEntry. For refresh loads, we have to load
    // what comes through the pipe, not what's in history.
    aLoadState->SetSHEntry(nullptr);
  } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
             (aLoadState->SHEntry() &&
              ((parentLoadType & LOAD_CMD_HISTORY) ||
               (parentLoadType == LOAD_RELOAD_NORMAL) ||
               (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
               (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
908
909
               (parentLoadType ==
                LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
    // If the parent url, bypassed history or was loaded from
    // history, pass on the parent's loadType to the new child
    // frame too, so that the child frame will also
    // avoid getting into history.
    aLoadState->SetLoadType(parentLoadType);
  } else if (parentLoadType == LOAD_ERROR_PAGE) {
    // If the parent document is an error page, we don't
    // want to update global/session history. However,
    // this child frame is not an error page.
    aLoadState->SetLoadType(LOAD_BYPASS_HISTORY);
  } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
             (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
             (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
    // the new frame should inherit the parent's load type so that it also
    // bypasses the cache and/or proxy
    aLoadState->SetLoadType(parentLoadType);
926
  }
927
928
}

929
/*
930
931
932
 * Reset state to a new content model within the current document and the
 * document viewer. Called by the document before initiating an out of band
 * document.write().
933
934
 */
NS_IMETHODIMP
935
nsDocShell::PrepareForNewContentModel() {
936
  mEODForCurrentDocument = false;
937
938
939
  return NS_OK;
}

940
NS_IMETHODIMP
941
nsDocShell::FirePageHideNotification(bool aIsUnload) {
942
943
944
945
  FirePageHideNotificationInternal(aIsUnload, false);
  return NS_OK;
}

946
947
void nsDocShell::FirePageHideNotificationInternal(
    bool aIsUnload, bool aSkipCheckingDynEntries) {
948
949
950
  if (mContentViewer && !mFiredUnloadEvent) {
    // Keep an explicit reference since calling PageHide could release
    // mContentViewer
951
    nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer);
952
    mFiredUnloadEvent = true;
953

954
955
956
    if (mTiming) {
      mTiming->NotifyUnloadEventStart();
    }
957

958
    contentViewer->PageHide(aIsUnload);
959

960
961
962
    if (mTiming) {
      mTiming->NotifyUnloadEventEnd();
    }
963

964
    AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
965
966
967
968
969
    uint32_t n = mChildList.Length();
    kids.SetCapacity(n);
    for (uint32_t i = 0; i < n; i++) {
      kids.AppendElement(do_QueryInterface(ChildAt(i)));
    }
970

971
972
    n = kids.Length();
    for (uint32_t i = 0;