Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  nsGlobalWindowOuter.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */


#include "mozilla/Assertions.h"
#include "mozilla/ScopeExit.h"
#include "nsGlobalWindowOuter.h"
#include "nsGlobalWindowInner.h"

#include <algorithm>

#include "mozilla/MemoryReporting.h"

// Local Includes
#include "Navigator.h"
#include "nsContentSecurityManager.h"
#include "nsGlobalWindowOuter.h"
#include "nsScreen.h"
#include "nsHistory.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorageManager.h"
#include "nsISecureBrowserUI.h"
#include "nsIWebProgressListener.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/Result.h"
#include "mozilla/dom/AutoPrintEventDispatcher.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/MaybeCrossOriginObject.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/ProxyHandlerUtils.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/StorageNotifierService.h"
#include "mozilla/dom/StorageUtils.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowFeatures.h"  // WindowFeatures
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "nsBaseCommandController.h"
#include "nsError.h"
#include "nsICookieService.h"
#include "nsISizeOfEventTarget.h"
#include "nsDOMJSUtils.h"
#include "nsArrayUtils.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIPermissionManager.h"
#include "nsIScriptContext.h"
#include "nsWindowMemoryReporter.h"
#include "nsWindowSizes.h"
#include "nsWindowWatcher.h"
#include "WindowNamedPropertiesHandler.h"
#include "nsFrameSelection.h"
#include "nsNetUtil.h"
#include "nsVariant.h"
#include "nsPrintfCString.h"
#include "mozilla/intl/LocaleService.h"
#include "WindowDestroyedEvent.h"
#include "nsDocShellLoadState.h"
#include "mozilla/dom/WindowGlobalChild.h"

// Helper Classes
#include "nsJSUtils.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/CallAndConstruct.h"    // JS::Call
#include "js/friend/StackLimits.h"  // js::AutoCheckRecursionLimit
#include "js/friend/WindowProxy.h"  // js::IsWindowProxy, js::SetWindowProxy
#include "js/PropertyAndElement.h"  // JS_DefineObject, JS_GetProperty
#include "js/PropertySpec.h"
#include "js/RealmIterators.h"
#include "js/Wrapper.h"
#include "nsLayoutUtils.h"
#include "nsReadableUtils.h"
#include "nsJSEnvironment.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#include "mozilla/Likely.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Unused.h"

// Other Classes
#include "mozilla/dom/BarProps.h"
#include "nsLayoutStatics.h"
#include "nsCCUncollectableMarker.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsJSPrincipals.h"
#include "mozilla/Attributes.h"
#include "mozilla/Components.h"
#include "mozilla/Debug.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_full_screen_api.h"
#include "mozilla/StaticPrefs_print.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/ThrottledEventQueue.h"
#include "AudioChannelService.h"
#include "nsAboutProtocolUtils.h"
#include "nsCharTraits.h"  // NS_IS_HIGH/LOW_SURROGATE
#include "PostMessageEvent.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/net/CookieJarSettings.h"

// Interfaces Needed
#include "nsIFrame.h"
#include "nsCanvasFrame.h"
#include "nsIWidget.h"
#include "nsIWidgetListener.h"
#include "nsIBaseWindow.h"
#include "nsIDeviceSensors.h"
#include "nsIContent.h"
#include "nsIDocShell.h"
#include "mozilla/dom/Document.h"
#include "Crypto.h"
#include "nsDOMString.h"
#include "nsThreadUtils.h"
#include "nsILoadContext.h"
#include "nsView.h"
#include "nsViewManager.h"
#include "nsIPrompt.h"
#include "nsIPromptService.h"
#include "nsIPromptFactory.h"
#include "nsIWritablePropertyBag2.h"
#include "nsIWebNavigation.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebBrowserFind.h"  // For window.find()
#include "nsComputedDOMStyle.h"
#include "nsDOMCID.h"
#include "nsDOMWindowUtils.h"
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsIDocumentViewer.h"
#include "nsIScriptError.h"
#include "nsISHistory.h"
#include "nsIControllers.h"
#include "nsGlobalWindowCommands.h"
#include "nsQueryObject.h"
#include "nsContentUtils.h"
#include "nsCSSProps.h"
#include "nsIURIFixup.h"
#include "nsIURIMutator.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/ScrollContainerFrame.h"
#include "nsIObserverService.h"
#include "nsFocusManager.h"
#include "nsIAppWindow.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/CustomEvent.h"
#include "nsIScreenManager.h"
#include "nsIClassifiedChannel.h"
#include "nsIXULRuntime.h"
#include "xpcprivate.h"

#ifdef NS_PRINTING
#  include "nsIPrintSettings.h"
#  include "nsIPrintSettingsService.h"
#  include "nsIWebBrowserPrint.h"
#endif

#include "nsWindowRoot.h"
#include "nsNetCID.h"
#include "nsIArray.h"

#include "nsIDOMXULCommandDispatcher.h"

#include "mozilla/GlobalKeyListener.h"

#include "nsIDragService.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Selection.h"
#include "nsFrameLoader.h"
#include "nsFrameLoaderOwner.h"
#include "nsXPCOMCID.h"
#include "mozilla/Logging.h"
#include "mozilla/ProfilerMarkers.h"
#include "prenv.h"

#include "mozilla/dom/IDBFactory.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/Promise.h"

#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadManager.h"

#include "gfxVR.h"
#include "VRShMem.h"
#include "FxRWindowManager.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/VRDisplayEvent.h"
#include "mozilla/dom/VRDisplayEventBinding.h"
#include "mozilla/dom/VREventObserver.h"

#include "nsRefreshDriver.h"

#include "mozilla/extensions/WebExtensionPolicy.h"

#include "mozilla/BasePrincipal.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/Location.h"
#include "nsHTMLDocument.h"
#include "nsWrapperCacheInlines.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "prrng.h"
#include "nsSandboxFlags.h"
#include "nsXULControllers.h"
#include "mozilla/dom/AudioContext.h"
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/HashChangeEvent.h"
#include "mozilla/dom/IntlUtils.h"
#include "mozilla/dom/PopStateEvent.h"
#include "mozilla/dom/PopupBlockedEvent.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/WindowBinding.h"
#include "nsIBrowserChild.h"
#include "mozilla/dom/MediaQueryList.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapBinding.h"
#include "mozilla/dom/ServiceWorkerRegistration.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#include "mozilla/dom/Worklet.h"
#include "AccessCheck.h"

#ifdef MOZ_WEBSPEECH
#  include "mozilla/dom/SpeechSynthesis.h"
#endif

#ifdef ANDROID
#  include <android/log.h>
#endif

#ifdef XP_WIN
#  include <process.h>
#  define getpid _getpid
#else
#  include <unistd.h>  // for getpid()
#endif

using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::BasePrincipal;
using mozilla::OriginAttributes;
using mozilla::TimeStamp;
using mozilla::layout::RemotePrintJobChild;

static inline nsGlobalWindowInner* GetCurrentInnerWindowInternal(
    const nsGlobalWindowOuter* aOuter) {
  return nsGlobalWindowInner::Cast(aOuter->GetCurrentInnerWindow());
}

#define FORWARD_TO_INNER(method, args, err_rval)           \
  PR_BEGIN_MACRO                                           \
  if (!mInnerWindow) {                                     \
    NS_WARNING("No inner window available!");              \
    return err_rval;                                       \
  }                                                        \
  return GetCurrentInnerWindowInternal(this)->method args; \
  PR_END_MACRO

#define FORWARD_TO_INNER_VOID(method, args)         \
  PR_BEGIN_MACRO                                    \
  if (!mInnerWindow) {                              \
    NS_WARNING("No inner window available!");       \
    return;                                         \
  }                                                 \
  GetCurrentInnerWindowInternal(this)->method args; \
  return;                                           \
  PR_END_MACRO

// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
// inner doesn't already exists.
#define FORWARD_TO_INNER_CREATE(method, args, err_rval)    \
  PR_BEGIN_MACRO                                           \
  if (!mInnerWindow) {                                     \
    if (mIsClosed) {                                       \
      return err_rval;                                     \
    }                                                      \
    nsCOMPtr<Document> kungFuDeathGrip = GetDoc();         \
    ::mozilla::Unused << kungFuDeathGrip;                  \
    if (!mInnerWindow) {                                   \
      return err_rval;                                     \
    }                                                      \
  }                                                        \
  return GetCurrentInnerWindowInternal(this)->method args; \
  PR_END_MACRO

static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
extern LazyLogModule gPageCacheLog;

#ifdef DEBUG
static LazyLogModule gDocShellAndDOMWindowLeakLogging(
    "DocShellAndDOMWindowLeak");
#endif

nsGlobalWindowOuter::OuterWindowByIdTable*
    nsGlobalWindowOuter::sOuterWindowsById = nullptr;

/* static */
nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
    nsPIDOMWindowInner* aInner) {
  if (!aInner) {
    return nullptr;
  }

  nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
  if (!outer || outer->GetCurrentInnerWindow() != aInner) {
    return nullptr;
  }

  return outer;
}

//*****************************************************************************
// nsOuterWindowProxy: Outer Window Proxy
//*****************************************************************************

// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
//
// We store the nsGlobalWindowOuter* in our first slot.
//
// We store our holder weakmap in the second slot.
const JSClass OuterWindowProxyClass = PROXY_CLASS_DEF(
    "Proxy", JSCLASS_HAS_RESERVED_SLOTS(2)); /* additional class flags */

static const size_t OUTER_WINDOW_SLOT = 0;
static const size_t HOLDER_WEAKMAP_SLOT = 1;

class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
  using Base = MaybeCrossOriginObject<js::Wrapper>;

 public:
  constexpr nsOuterWindowProxy() : Base(0) {}

  bool finalizeInBackground(const JS::Value& priv) const override {
    return false;
  }

  // Standard internal methods
  /**
   * Implementation of [[GetOwnProperty]] as defined at
   * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   */

  bool getOwnPropertyDescriptor(
      JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;

  /*
   * Implementation of the same-origin case of
   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty>.
   */

  bool definePropertySameOrigin(JSContext* cx, JS::Handle<JSObject*> proxy,
                                JS::Handle<jsid> id,
                                JS::Handle<JS::PropertyDescriptor> desc,
                                JS::ObjectOpResult& result) const override;

  /**
   * Implementation of [[OwnPropertyKeys]] as defined at
   *
   * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   */

  bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
                       JS::MutableHandleVector<jsid> props) const override;
  /**
   * Implementation of [[Delete]] as defined at
   * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   */

  bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
               JS::ObjectOpResult& result) const override;

  /**
   * Implementaton of hook for superclass getPrototype() method.
   */

  JSObject* getSameOriginPrototype(JSContext* cx) const override;

  /**
   * Implementation of [[HasProperty]] internal method as defined at
   * https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   *
   * Note that the HTML spec does not define an override for this internal
   * method, so we just want the "normal object" behavior.  We have to override
   * it, because js::Wrapper also overrides, with "not normal" behavior.
   */

  bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
           bool* bp) const override;

  /**
   * Implementation of [[Get]] internal method as defined at
   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get>.
   *
   * "proxy" is the WindowProxy object involved.  It may or may not be
   * same-compartment with "cx".
   *
   * "receiver" is the receiver ("this") for the get.  It will be
   * same-compartment with "cx".
   *
   * "vp" is the return value.  It will be same-compartment with "cx".
   */

  bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
           JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
           JS::MutableHandle<JS::Value> vp) const override;

  /**
   * Implementation of [[Set]] internal method as defined at
   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set>.
   *
   * "proxy" is the WindowProxy object involved.  It may or may not be
   * same-compartment with "cx".
   *
   * "v" is the value being set.  It will be same-compartment with "cx".
   *
   * "receiver" is the receiver ("this") for the set.  It will be
   * same-compartment with "cx".
   */

  bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
           JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
           JS::ObjectOpResult& result) const override;

  // SpiderMonkey extensions
  /**
   * Implementation of SpiderMonkey extension which just checks whether this
   * object has the property.  Basically Object.getOwnPropertyDescriptor(obj,
   * prop) !== undefined. but does not require reifying the descriptor.
   *
   * We have to override this because js::Wrapper overrides it, but we want
   * different behavior from js::Wrapper.
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   */

  bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
              bool* bp) const override;

  /**
   * Implementation of SpiderMonkey extension which is used as a fast path for
   * enumerating.
   *
   * We have to override this because js::Wrapper overrides it, but we want
   * different behavior from js::Wrapper.
   *
   * "proxy" is the WindowProxy object involved.  It may not be same-compartment
   * with cx.
   */

  bool getOwnEnumerablePropertyKeys(
      JSContext* cx, JS::Handle<JSObject*> proxy,
      JS::MutableHandleVector<jsid> props) const override;

  /**
   * Hook used by SpiderMonkey to implement Object.prototype.toString.
   */

  const char* className(JSContext* cx,
                        JS::Handle<JSObject*> wrapper) const override;

  void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
  size_t objectMoved(JSObject* proxy, JSObject* old) const override;

  bool isCallable(JSObject* obj) const override { return false; }
  bool isConstructor(JSObject* obj) const override { return false; }

  static const nsOuterWindowProxy singleton;

  static nsGlobalWindowOuter* GetOuterWindow(JSObject* proxy) {
    nsGlobalWindowOuter* outerWindow =
        nsGlobalWindowOuter::FromSupports(static_cast<nsISupports*>(
            js::GetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT).toPrivate()));
    return outerWindow;
  }

 protected:
  // False return value means we threw an exception.  True return value
  // but false "found" means we didn't have a subframe at that index.
  bool GetSubframeWindow(JSContext* cx, JS::Handle<JSObject*> proxy,
                         JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
                         bool& found) const;

  // Returns a non-null window only if id is an index and we have a
  // window at that index.
  Nullable<WindowProxyHolder> GetSubframeWindow(JSContext* cx,
                                                JS::Handle<JSObject*> proxy,
                                                JS::Handle<jsid> id) const;

  bool AppendIndexedPropertyNames(JSObject* proxy,
                                  JS::MutableHandleVector<jsid> props) const;

  using MaybeCrossOriginObjectMixins::EnsureHolder;
  bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
                    JS::MutableHandle<JSObject*> holder) const override;

  // Helper method for creating a special "print" method that allows printing
  // our PDF-viewer documents even if you're not same-origin with them.
  //
  // aProxy must be our nsOuterWindowProxy.  It will not be same-compartment
  // with aCx, since we only use this on the different-origin codepath!
  //
  // Can return true without filling in aDesc, which corresponds to not exposing
  // a "print" method.
  static bool MaybeGetPDFJSPrintMethod(
      JSContext* cx, JS::Handle<JSObject*> proxy,
      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);

  // The actual "print" method we use for the PDFJS case.
  static bool PDFJSPrintMethod(JSContext* cx, unsigned argc, JS::Value* vp);

  // Helper method to get the pre-PDF-viewer-messing-with-it principal from an
  // inner window.  Will return null if this is not a PDF-viewer inner or if the
  // principal could not be found for some reason.
  static already_AddRefed<nsIPrincipal> GetNoPDFJSPrincipal(
      nsGlobalWindowInner* inner);
};

const char* nsOuterWindowProxy::className(JSContext* cx,
                                          JS::Handle<JSObject*> proxy) const {
  MOZ_ASSERT(js::IsProxy(proxy));

  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    return "Object";
  }

  return "Window";
}

void nsOuterWindowProxy::finalize(JS::GCContext* gcx, JSObject* proxy) const {
  nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
  if (outerWindow) {
    outerWindow->ClearWrapper(proxy);
    BrowsingContext* bc = outerWindow->GetBrowsingContext();
    if (bc) {
      bc->ClearWindowProxy();
    }

    // Ideally we would use OnFinalize here, but it's possible that
    // EnsureScriptEnvironment will later be called on the window, and we don't
    // want to create a new script object in that case. Therefore, we need to
    // write a non-null value that will reliably crash when dereferenced.
    outerWindow->PoisonOuterWindowProxy(proxy);
  }
}

bool nsOuterWindowProxy::getOwnPropertyDescriptor(
    JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const {
  // First check for indexed access.  This is
  // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
  // step 2, mostly.
  JS::Rooted<JS::Value> subframe(cx);
  bool found;
  if (!GetSubframeWindow(cx, proxy, id, &subframe, found)) {
    return false;
  }
  if (found) {
    // Step 2.4.

    desc.set(Some(JS::PropertyDescriptor::Data(
        subframe, {
                      JS::PropertyAttribute::Configurable,
                      JS::PropertyAttribute::Enumerable,
                  })));
    return true;
  }

  bool isSameOrigin = IsPlatformObjectSameOrigin(cx, proxy);

  // If we did not find a subframe, we could still have an indexed property
  // access.  In that case we should throw a SecurityError in the cross-origin
  // case.
  if (!isSameOrigin && IsArrayIndex(GetArrayIndexFromId(id))) {
    // Step 2.5.2.
    return ReportCrossOriginDenial(cx, id, "access"_ns);
  }

  // Step 2.5.1 is handled via the forwarding to js::Wrapper; it saves us an
  // IsArrayIndex(GetArrayIndexFromId(id)) here.  We'll never have a property on
  // the Window whose name is an index, because our defineProperty doesn't pass
  // those on to the Window.

  // Step 3.
  if (isSameOrigin) {
    if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
      Window_Binding::CountMaybeMissingProperty(proxy, id);
    }

    // Fall through to js::Wrapper.
    {  // Scope for JSAutoRealm while we are dealing with js::Wrapper.
      // When forwarding to js::Wrapper, we should just enter the Realm of proxy
      // for now.  That's what js::Wrapper expects, and since we're same-origin
      // anyway this is not changing any security behavior.
      JSAutoRealm ar(cx, proxy);
      JS_MarkCrossZoneId(cx, id);
      bool ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
      if (!ok) {
        return false;
      }

#if 0
      // See https://github.com/tc39/ecma262/issues/672 for more information.
      if (desc.isSome() &&
          !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
        (*desc).setConfigurable(true);
      }
#endif
    }

    // Now wrap our descriptor back into the Realm that asked for it.
    return JS_WrapPropertyDescriptor(cx, desc);
  }

  // Step 4.
  if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
    return false;
  }

  // Step 5
  if (desc.isSome()) {
    return true;
  }

  // Non-spec step for the PDF viewer's window.print().  This comes before we
  // check for named subframes, because in the same-origin case print() would
  // shadow those.
  if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) {
    if (!MaybeGetPDFJSPrintMethod(cx, proxy, desc)) {
      return false;
    }

    if (desc.isSome()) {
      return true;
    }
  }

  // Step 6 -- check for named subframes.
  if (id.isString()) {
    nsAutoJSString name;
    if (!name.init(cx, id.toString())) {
      return false;
    }
    nsGlobalWindowOuter* win = GetOuterWindow(proxy);
    if (RefPtr<BrowsingContext> childDOMWin = win->GetChildWindow(name)) {
      JS::Rooted<JS::Value> childValue(cx);
      if (!ToJSValue(cx, WindowProxyHolder(childDOMWin), &childValue)) {
        return false;
      }
      desc.set(Some(JS::PropertyDescriptor::Data(
          childValue, {JS::PropertyAttribute::Configurable})));
      return true;
    }
  }

  // And step 7.
  return CrossOriginPropertyFallback(cx, proxy, id, desc);
}

bool nsOuterWindowProxy::definePropertySameOrigin(
    JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) const {
  if (IsArrayIndex(GetArrayIndexFromId(id))) {
    // Spec says to Reject whether this is a supported index or not,
    // since we have no indexed setter or indexed creator.  It is up
    // to the caller to decide whether to throw a TypeError.
    return result.failCantDefineWindowElement();
  }

  JS::ObjectOpResult ourResult;
  bool ok = js::Wrapper::defineProperty(cx, proxy, id, desc, ourResult);
  if (!ok) {
    return false;
  }

  if (!ourResult.ok()) {
    // It's possible that this failed because the page got the existing
    // descriptor (which we force to claim to be configurable) and then tried to
    // redefine the property with the descriptor it got but a different value.
    // We want to allow this case to succeed, so check for it and if we're in
    // that case try again but now with an attempt to define a non-configurable
    // property.
    if (!desc.hasConfigurable() || !desc.configurable()) {
      // The incoming descriptor was not explicitly marked "configurable: true",
      // so it failed for some other reason.  Just propagate that reason out.
      result = ourResult;
      return true;
    }

    JS::Rooted<Maybe<JS::PropertyDescriptor>> existingDesc(cx);
    ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &existingDesc);
    if (!ok) {
      return false;
    }
    if (existingDesc.isNothing() || existingDesc->configurable()) {
      // We have no existing property, or its descriptor is already configurable
      // (on the Window itself, where things really can be non-configurable).
      // So we failed for some other reason, which we should propagate out.
      result = ourResult;
      return true;
    }

    JS::Rooted<JS::PropertyDescriptor> updatedDesc(cx, desc);
    updatedDesc.setConfigurable(false);

    JS::ObjectOpResult ourNewResult;
    ok = js::Wrapper::defineProperty(cx, proxy, id, updatedDesc, ourNewResult);
    if (!ok) {
      return false;
    }

    if (!ourNewResult.ok()) {
      // Twiddling the configurable flag didn't help.  Just return this failure
      // out to the caller.
      result = ourNewResult;
      return true;
    }
  }

#if 0
  // See https://github.com/tc39/ecma262/issues/672 for more information.
  if (desc.hasConfigurable() && !desc.configurable() &&
      !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
    // Give callers a way to detect that they failed to "really" define a
    // non-configurable property.
    result.failCantDefineWindowNonConfigurable();
    return true;
  }
#endif

  result.succeed();
  return true;
}

bool nsOuterWindowProxy::ownPropertyKeys(
    JSContext* cx, JS::Handle<JSObject*> proxy,
    JS::MutableHandleVector<jsid> props) const {
  // Just our indexed stuff followed by our "normal" own property names.
  if (!AppendIndexedPropertyNames(proxy, props)) {
    return false;
  }

  if (IsPlatformObjectSameOrigin(cx, proxy)) {
    // When forwarding to js::Wrapper, we should just enter the Realm of proxy
    // for now.  That's what js::Wrapper expects, and since we're same-origin
    // anyway this is not changing any security behavior.
    JS::RootedVector<jsid> innerProps(cx);
    {  // Scope for JSAutoRealm so we can mark the ids once we exit it
      JSAutoRealm ar(cx, proxy);
      if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
        return false;
      }
    }
    for (auto& id : innerProps) {
      JS_MarkCrossZoneId(cx, id);
    }
    return js::AppendUnique(cx, props, innerProps);
  }

  // In the cross-origin case we purposefully exclude subframe names from the
  // list of property names we report here.
  JS::Rooted<JSObject*> holder(cx);
  if (!EnsureHolder(cx, proxy, &holder)) {
    return false;
  }

  JS::RootedVector<jsid> crossOriginProps(cx);
  if (!js::GetPropertyKeys(cx, holder,
                           JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
                           &crossOriginProps) ||
      !js::AppendUnique(cx, props, crossOriginProps)) {
    return false;
  }

  // Add the "print" property if needed.
  nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
  nsGlobalWindowInner* inner =
      nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
  if (inner) {
    nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
    if (targetPrincipal &&
        nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
      JS::RootedVector<jsid> printProp(cx);
      if (!printProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) ||
          !js::AppendUnique(cx, props, printProp)) {
        return false;
      }
    }
  }

  return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
}

bool nsOuterWindowProxy::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                                 JS::Handle<jsid> id,
                                 JS::ObjectOpResult& result) const {
  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    return ReportCrossOriginDenial(cx, id, "delete"_ns);
  }

  if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
    // Fail (which means throw if strict, else return false).
    return result.failCantDeleteWindowElement();
  }

  if (IsArrayIndex(GetArrayIndexFromId(id))) {
    // Indexed, but not supported.  Spec says return true.
    return result.succeed();
  }

  // We're same-origin, so it should be safe to enter the Realm of "proxy".
  // Let's do that, just in case, to avoid cross-compartment issues in our
  // js::Wrapper caller..
  JSAutoRealm ar(cx, proxy);
  JS_MarkCrossZoneId(cx, id);
  return js::Wrapper::delete_(cx, proxy, id, result);
}

JSObject* nsOuterWindowProxy::getSameOriginPrototype(JSContext* cx) const {
  return Window_Binding::GetProtoObjectHandle(cx);
}

bool nsOuterWindowProxy::has(JSContext* cx, JS::Handle<JSObject*> proxy,
                             JS::Handle<jsid> id, bool* bp) const {
  // We could just directly forward this method to js::BaseProxyHandler, but
  // that involves reifying the actual property descriptor, which might be more
  // work than we have to do for has() on the Window.

  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    // In the cross-origin case we only have own properties.  Just call hasOwn
    // directly.
    return hasOwn(cx, proxy, id, bp);
  }

  if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
    *bp = true;
    return true;
  }

  // Just to be safe in terms of compartment asserts, enter the Realm of
  // "proxy".  We're same-origin with it, so this should be safe.
  JSAutoRealm ar(cx, proxy);
  JS_MarkCrossZoneId(cx, id);
  return js::Wrapper::has(cx, proxy, id, bp);
}

bool nsOuterWindowProxy::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
                                JS::Handle<jsid> id, bool* bp) const {
  // We could just directly forward this method to js::BaseProxyHandler, but
  // that involves reifying the actual property descriptor, which might be more
  // work than we have to do for hasOwn() on the Window.

  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    // Avoiding reifying the property descriptor here would require duplicating
    // a bunch of "is this property exposed cross-origin" logic, which is
    // probably not worth it.  Just forward this along to the base
    // implementation.
    //
    // It's very important to not forward this to js::Wrapper, because that will
    // not do the right security and cross-origin checks and will pass through
    // the call to the Window.
    //
    // The BaseProxyHandler code is OK with this happening without entering the
    // compartment of "proxy".
    return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
  }

  if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
    *bp = true;
    return true;
  }

  // Just to be safe in terms of compartment asserts, enter the Realm of
  // "proxy".  We're same-origin with it, so this should be safe.
  JSAutoRealm ar(cx, proxy);
  JS_MarkCrossZoneId(cx, id);
  return js::Wrapper::hasOwn(cx, proxy, id, bp);
}

bool nsOuterWindowProxy::get(JSContext* cx, JS::Handle<JSObject*> proxy,
                             JS::Handle<JS::Value> receiver,
                             JS::Handle<jsid> id,
                             JS::MutableHandle<JS::Value> vp) const {
  if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
      xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
    vp.set(JS::ObjectValue(*proxy));
    return MaybeWrapValue(cx, vp);
  }

  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    return CrossOriginGet(cx, proxy, receiver, id, vp);
  }

  bool found;
  if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
    return false;
  }

  if (found) {
    return true;
  }

  if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
    Window_Binding::CountMaybeMissingProperty(proxy, id);
  }

  {  // Scope for JSAutoRealm
    // Enter "proxy"'s Realm.  We're in the same-origin case, so this should be
    // safe.
    JSAutoRealm ar(cx, proxy);

    JS_MarkCrossZoneId(cx, id);

    JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
    if (!MaybeWrapValue(cx, &wrappedReceiver)) {
      return false;
    }

    // Fall through to js::Wrapper.
    if (!js::Wrapper::get(cx, proxy, wrappedReceiver, id, vp)) {
      return false;
    }
  }

  // Make sure our return value is in the caller compartment.
  return MaybeWrapValue(cx, vp);
}

bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
                             JS::Handle<jsid> id, JS::Handle<JS::Value> v,
                             JS::Handle<JS::Value> receiver,
                             JS::ObjectOpResult& result) const {
  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    return CrossOriginSet(cx, proxy, id, v, receiver, result);
  }

  if (IsArrayIndex(GetArrayIndexFromId(id))) {
    // Reject the set.  It's up to the caller to decide whether to throw a
    // TypeError.  If the caller is strict mode JS code, it'll throw.
    return result.failReadOnly();
  }

  // Do the rest in the Realm of "proxy", since we're in the same-origin case.
  JSAutoRealm ar(cx, proxy);
  JS::Rooted<JS::Value> wrappedArg(cx, v);
  if (!MaybeWrapValue(cx, &wrappedArg)) {
    return false;
  }
  JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
  if (!MaybeWrapValue(cx, &wrappedReceiver)) {
    return false;
  }

  JS_MarkCrossZoneId(cx, id);

  return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
}

bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
    JSContext* cx, JS::Handle<JSObject*> proxy,
    JS::MutableHandleVector<jsid> props) const {
  // We could just stop overring getOwnEnumerablePropertyKeys and let our
  // superclasses deal (by falling back on the BaseProxyHandler implementation
  // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
  // only return the enumerable ones.  But maybe there's value in having
  // somewhat faster for-in iteration on Window objects...

  // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
  // own property names.
  if (!AppendIndexedPropertyNames(proxy, props)) {
    return false;
  }

  if (!IsPlatformObjectSameOrigin(cx, proxy)) {
    // All the cross-origin properties other than the indexed props are
    // non-enumerable, so we're done here.
    return true;
  }

  // When forwarding to js::Wrapper, we should just enter the Realm of proxy
  // for now.  That's what js::Wrapper expects, and since we're same-origin
  // anyway this is not changing any security behavior.
  JS::RootedVector<jsid> innerProps(cx);
  {  // Scope for JSAutoRealm so we can mark the ids once we exit it.
    JSAutoRealm ar(cx, proxy);
    if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
      return false;
    }
  }

  for (auto& id : innerProps) {
    JS_MarkCrossZoneId(cx, id);
  }

  return js::AppendUnique(cx, props, innerProps);
}

bool nsOuterWindowProxy::GetSubframeWindow(JSContext* cx,
                                           JS::Handle<JSObject*> proxy,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JS::Value> vp,
                                           bool& found) const {
  Nullable<WindowProxyHolder> frame = GetSubframeWindow(cx, proxy, id);
  if (frame.IsNull()) {
    found = false;
    return true;
  }

  found = true;
  return WrapObject(cx, frame.Value(), vp);
}

Nullable<WindowProxyHolder> nsOuterWindowProxy::GetSubframeWindow(
    JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const {
  uint32_t index = GetArrayIndexFromId(id);
  if (!IsArrayIndex(index)) {
    return nullptr;
  }

  nsGlobalWindowOuter* win = GetOuterWindow(proxy);
  return win->IndexedGetterOuter(index);
}

bool nsOuterWindowProxy::AppendIndexedPropertyNames(
    JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
  uint32_t length = GetOuterWindow(proxy)->Length();
  MOZ_ASSERT(int32_t(length) >= 0);
  if (!props.reserve(props.length() + length)) {
    return false;
  }
  for (int32_t i = 0; i < int32_t(length); ++i) {
    if (!props.append(JS::PropertyKey::Int(i))) {
      return false;
    }
  }

  return true;
}

bool nsOuterWindowProxy::EnsureHolder(
    JSContext* cx, JS::Handle<JSObject*> proxy,
    JS::MutableHandle<JSObject*> holder) const {
  return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
                      Window_Binding::sCrossOriginProperties, holder);
}

size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {
  nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
  if (outerWindow) {
    outerWindow->UpdateWrapper(obj, old);
    BrowsingContext* bc = outerWindow->GetBrowsingContext();
    if (bc) {
      bc->UpdateWindowProxy(obj, old);
    }
  }
  return 0;
}

enum { PDFJS_SLOT_CALLEE = 0 };

// static
bool nsOuterWindowProxy::MaybeGetPDFJSPrintMethod(
    JSContext* cx, JS::Handle<JSObject*> proxy,
    JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) {
  MOZ_ASSERT(proxy);
  MOZ_ASSERT(!desc.isSome());

  nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
  nsGlobalWindowInner* inner =
      nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
  if (!inner) {
    // No print method to expose.
    return true;
  }

  nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
  if (!targetPrincipal) {
    // Nothing special to be done.
    return true;
  }

  if (!nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
    // Not our origin's PDF document.
    return true;
  }

  // Get the function we plan to actually call.
  JS::Rooted<JSObject*> innerObj(cx, inner->GetGlobalJSObject());
  if (!innerObj) {
    // Really should not happen, but ok, let's just return.
    return true;
  }

  JS::Rooted<JS::Value> targetFunc(cx);
  {
    JSAutoRealm ar(cx, innerObj);
    if (!JS_GetProperty(cx, innerObj, "print", &targetFunc)) {
      return false;
    }
  }

  if (!targetFunc.isObject()) {
    // Who knows what's going on.  Just return.
    return true;
  }

  // The Realm of cx is the realm our caller is in and the realm we
  // should create our function in.  Note that we can't use the
  // standard XPConnect function forwarder machinery because our
  // "this" is cross-origin, so we have to do thus by hand.

  // Make sure targetFunc is wrapped into the right compartment.
  if (!MaybeWrapValue(cx, &targetFunc)) {
    return false;
  }

  JSFunction* fun =
      js::NewFunctionWithReserved(cx, PDFJSPrintMethod, 0, 0, "print");
  if (!fun) {
    return false;
  }

  JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
  js::SetFunctionNativeReserved(funObj, PDFJS_SLOT_CALLEE, targetFunc);

  // { value: <print>, writable: true, enumerable: true, configurable: true }
  // because that's what it would have been in the same-origin case without
  // the PDF viewer messing with things.
  desc.set(Some(JS::PropertyDescriptor::Data(
      JS::ObjectValue(*funObj),
      {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
       JS::PropertyAttribute::Writable})));
  return true;
}

// static
bool nsOuterWindowProxy::PDFJSPrintMethod(JSContext* cx, unsigned argc,
                                          JS::Value* vp) {
  JS::CallArgs args = CallArgsFromVp(argc, vp);

  JS::Rooted<JSObject*> realCallee(
      cx, &js::GetFunctionNativeReserved(&args.callee(), PDFJS_SLOT_CALLEE)
               .toObject());
  // Unchecked unwrap, because we want to extract the thing we really had
  // before.
  realCallee = js::UncheckedUnwrap(realCallee);

  JS::Rooted<JS::Value> thisv(cx, args.thisv());
  if (thisv.isNullOrUndefined()) {
    // Replace it with the global of our stashed callee, simulating the
    // global-assuming behavior of DOM methods.
    JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(realCallee));
    if (!MaybeWrapObject(cx, &global)) {
      return false;
    }
    thisv.setObject(*global);
  } else if (!thisv.isObject()) {
    return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
  }

  // We want to do an UncheckedUnwrap here, because we're going to directly
  // examine the principal of the inner window, if we have an inner window.
  JS::Rooted<JSObject*> unwrappedObj(cx,
                                     js::UncheckedUnwrap(&thisv.toObject()));
  nsGlobalWindowInner* inner = nullptr;
  {
    // Do the unwrap in the Realm of the object we're looking at.
    JSAutoRealm ar(cx, unwrappedObj);
    UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &unwrappedObj, inner, cx);
  }
  if (!inner) {
    return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
  }

  nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal(cx);
  if (!callerPrincipal->SubsumesConsideringDomain(inner->GetPrincipal())) {
    // Check whether it's a PDF viewer from our origin.
    nsCOMPtr<nsIPrincipal> pdfPrincipal = GetNoPDFJSPrincipal(inner);
    if (!pdfPrincipal || !callerPrincipal->Equals(pdfPrincipal)) {
      // Security error.
      return ThrowInvalidThis(cx, args, true, prototypes::id::Window);
    }
  }

  // Go ahead and enter the Realm of our real callee to call it.  We'll pass it
  // our "thisv", just in case someone grabs a "print" method off one PDF
  // document and .call()s it on another one.
  {
    JSAutoRealm ar(cx, realCallee);
    if (!MaybeWrapValue(cx, &thisv)) {
      return false;
    }

    // Don't bother passing through the args; they will get ignored anyway.

    if (!JS::Call(cx, thisv, realCallee, JS::HandleValueArray::empty(),
                  args.rval())) {
      return false;
    }
  }

  // Wrap the return value (not that there should be any!) into the right
  // compartment.
  return MaybeWrapValue(cx, args.rval());
}

// static
already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
    nsGlobalWindowInner* inner) {
  if (!nsContentUtils::IsPDFJS(inner->GetPrincipal())) {
    return nullptr;
  }

  if (Document* doc = inner->GetExtantDoc()) {
    if (nsCOMPtr<nsIPropertyBag2> propBag =
            do_QueryInterface(doc->GetChannel())) {
      nsCOMPtr<nsIPrincipal> principal(
          do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
      return principal.forget();
    }
  }
  return nullptr;
}

const nsOuterWindowProxy nsOuterWindowProxy::singleton;

class nsChromeOuterWindowProxy : public nsOuterWindowProxy {
 public:
  constexpr nsChromeOuterWindowProxy() = default;

  const char* className(JSContext* cx,
                        JS::Handle<JSObject*> wrapper) const override;

  static const nsChromeOuterWindowProxy singleton;
};

const char* nsChromeOuterWindowProxy::className(
    JSContext* cx, JS::Handle<JSObject*> proxy) const {
  MOZ_ASSERT(js::IsProxy(proxy));

  return "ChromeWindow";
}

const nsChromeOuterWindowProxy nsChromeOuterWindowProxy::singleton;

static JSObject* NewOuterWindowProxy(JSContext* cx,
                                     JS::Handle<JSObject*> global,
                                     bool isChrome) {
  MOZ_ASSERT(JS_IsGlobalObject(global));

  JSAutoRealm ar(cx, global);

  js::WrapperOptions options;
  options.setClass(&OuterWindowProxyClass);
  JSObject* obj =
      js::Wrapper::New(cx, global,
                       isChrome ? &nsChromeOuterWindowProxy::singleton
                                : &nsOuterWindowProxy::singleton,
                       options);
  MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
  return obj;
}

//*****************************************************************************
//***    nsGlobalWindowOuter: Object Management
//*****************************************************************************

nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
    : nsPIDOMWindowOuter(aWindowID),
      mFullscreenHasChangedDuringProcessing(false),
      mForceFullScreenInWidget(false),
      mIsClosed(false),
      mInClose(false),
      mHavePendingClose(false),
      mBlockScriptedClosingFlag(false),
      mWasOffline(false),
      mCreatingInnerWindow(false),
      mIsChrome(false),
      mAllowScriptsToClose(false),
      mTopLevelOuterContentWindow(false),
      mDelayedPrintUntilAfterLoad(false),
      mDelayedCloseForPrinting(false),
      mShouldDelayPrintUntilAfterLoad(false),
#ifdef DEBUG
      mSerial(0),
      mSetOpenerWindowCalled(false),
#endif
      mCleanedUp(false),
      mCanSkipCCGeneration(0),
      mAutoActivateVRDisplayID(0) {
  AssertIsOnMainThread();
  SetIsOnMainThread();
  nsLayoutStatics::AddRef();

  // Initialize the PRCList (this).
  PR_INIT_CLIST(this);

  // |this| is an outer window. Outer windows start out frozen and
  // remain frozen until they get an inner window.
  MOZ_ASSERT(IsFrozen());

  // We could have failed the first time through trying
  // to create the entropy collector, so we should
  // try to get one until we succeed.

#ifdef DEBUG
  mSerial = nsContentUtils::InnerOrOuterWindowCreated();

  MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
          ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
           nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
           static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
           nullptr));
#endif

  MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,
          ("DOMWINDOW %p created outer=nullptr"this));

  // Add ourselves to the outer windows list.
  MOZ_ASSERT(sOuterWindowsById, "Outer Windows hash table must be created!");

  // |this| is an outer window, add to the outer windows list.
  MOZ_ASSERT(!sOuterWindowsById->Contains(mWindowID),
             "This window shouldn't be in the hash table yet!");
  // We seem to see crashes in release builds because of null
  // |sOuterWindowsById|.
  if (sOuterWindowsById) {
    sOuterWindowsById->InsertOrUpdate(mWindowID, this);
  }
}

#ifdef DEBUG

/* static */
void nsGlobalWindowOuter::AssertIsOnMainThread() {
  MOZ_ASSERT(NS_IsMainThread());
}

#endif  // DEBUG

/* static */
void nsGlobalWindowOuter::Init() {
  AssertIsOnMainThread();

  NS_ASSERTION(gDOMLeakPRLogOuter,
               "gDOMLeakPRLogOuter should have been initialized!");

  sOuterWindowsById = new OuterWindowByIdTable();
}

nsGlobalWindowOuter::~nsGlobalWindowOuter() {
  AssertIsOnMainThread();

  if (sOuterWindowsById) {
    sOuterWindowsById->Remove(mWindowID);
  }

  nsContentUtils::InnerOrOuterWindowDestroyed();

#ifdef DEBUG
  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);
      }
    }

    MOZ_LOG(
        gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
        ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
         "%s]\n",
         nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
         static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
         nullptr, url.get()));
  }
#endif

  MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,
          ("DOMWINDOW %p destroyed"this));

  JSObject* proxy = GetWrapperMaybeDead();
  if (proxy) {
    if (mBrowsingContext && mBrowsingContext->GetUnbarrieredWindowProxy()) {
      nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
          mBrowsingContext->GetUnbarrieredWindowProxy());
      // Check that the current WindowProxy object corresponds to this
      // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
      // we've replaced it with a cross-process WindowProxy.
      if (outer == this) {
        mBrowsingContext->ClearWindowProxy();
      }
    }
    js::SetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT,
                             JS::PrivateValue(nullptr));
  }

  // An outer window is destroyed with inner windows still possibly
  // alive, iterate through the inner windows and null out their
  // back pointer to this outer, and pull them out of the list of
  // inner windows.
  //
  // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
  // and our inner windows (nsGlobalWindowInners). This means that we need to
  // use PRCList*. We can then compare that PRCList* to `this` to see if its an
  // inner or outer window.
  PRCList* w;
  while ((w = PR_LIST_HEAD(this)) != this) {
    PR_REMOVE_AND_INIT_LINK(w);
  }

  DropOuterWindowDocs();

  // Outer windows are always supposed to call CleanUp before letting themselves
  // be destroyed.
  MOZ_ASSERT(mCleanedUp);

  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
  if (ac) ac->RemoveWindowAsListener(this);

  nsLayoutStatics::Release();
}

// static
void nsGlobalWindowOuter::ShutDown() {
  AssertIsOnMainThread();

  delete sOuterWindowsById;
  sOuterWindowsById = nullptr;
}

void nsGlobalWindowOuter::DropOuterWindowDocs() {
  MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
  mDoc = nullptr;
  mSuspendedDocs.Clear();
}

void nsGlobalWindowOuter::CleanUp() {
  // Guarantee idempotence.
  if (mCleanedUp) return;
  mCleanedUp = true;

  StartDying();

  mWindowUtils = nullptr;

  ClearControllers();

  mContext = nullptr;             // Forces Release
  mChromeEventHandler = nullptr;  // Forces Release
  mParentTarget = nullptr;
  mMessageManager = nullptr;

  mArguments = nullptr;
}

void nsGlobalWindowOuter::ClearControllers() {
  if (mControllers) {
    uint32_t count;
    mControllers->GetControllerCount(&count);

    while (count--) {
      nsCOMPtr<nsIController> controller;
      mControllers->GetControllerAt(count, getter_AddRefs(controller));

      nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
      if (context) context->SetCommandContext(nullptr);
    }

    mControllers = nullptr;
  }
}

//*****************************************************************************
// nsGlobalWindowOuter::nsISupports
//*****************************************************************************

// QueryInterface implementation for nsGlobalWindowOuter
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
  NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
  NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
  NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)
  NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowOuter)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowOuter)

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)
  if (tmp->IsBlackForCC(false)) {
    if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
      return true;
    }
    tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
    if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
      elm->MarkForCC();
    }
    return true;
  }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)
  return tmp->IsBlackForCC(true);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)
  return tmp->IsBlackForCC(false);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END

NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)
  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    char name[512];
    nsAutoCString uri;
    if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
    }
    SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64 " outer %s",
                   tmp->mWindowID, uri.get());
    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
  } else {
    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())
  }

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDocs)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)

  // Traverse stuff from nsPIDOMWindow
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)

  tmp->TraverseObjectsInGlobal(cb);

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
  if (sOuterWindowsById) {
    sOuterWindowsById->Remove(tmp->mWindowID);
  }

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDocs)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)

  // Unlink stuff from nsPIDOMWindow
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
  if (tmp->mBrowsingContext) {
    if (tmp->mBrowsingContext->GetUnbarrieredWindowProxy()) {
      nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
          tmp->mBrowsingContext->GetUnbarrieredWindowProxy());
      // Check that the current WindowProxy object corresponds to this
      // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
      // we've replaced it with a cross-process WindowProxy.
      if (outer == tmp) {
        tmp->mBrowsingContext->ClearWindowProxy();
      }
    }
    tmp->mBrowsingContext = nullptr;
  }

  tmp->UnlinkObjectsInGlobal();

  if (tmp->IsChromeWindow()) {
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)
  }

  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END

bool nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded) {
  if (!nsCCUncollectableMarker::sGeneration) {
    return false;
  }

  // Unlike most wrappers, the outer window wrapper is not a wrapper for
  // the outer window. Instead, the outer window wrapper holds the inner
  // window binding object, which in turn holds the nsGlobalWindowInner, which
  // has a strong reference to the nsGlobalWindowOuter. We're using the
  // mInnerWindow pointer as a flag for that whole chain.
  return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
          (mInnerWindow && HasKnownLiveWrapper())) &&
         (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
}

//*****************************************************************************
// nsGlobalWindowOuter::nsIScriptGlobalObject
//*****************************************************************************

bool nsGlobalWindowOuter::ShouldResistFingerprinting(RFPTarget aTarget) const {
  if (mDoc) {
    return mDoc->ShouldResistFingerprinting(aTarget);
  }
  return nsContentUtils::ShouldResistFingerprinting(
      "If we do not have a document then we do not have any context"
      "to make an informed RFP choice, so we fall back to the global pref",
      aTarget);
}

OriginTrials nsGlobalWindowOuter::Trials() const {
  return mInnerWindow ? nsGlobalWindowInner::Cast(mInnerWindow)->Trials()
                      : OriginTrials();
}

FontFaceSet* nsGlobalWindowOuter::GetFonts() {
  if (mDoc) {
    return mDoc->Fonts();
  }
  return nullptr;
}

nsresult nsGlobalWindowOuter::EnsureScriptEnvironment() {
  if (GetWrapperPreserveColor()) {
    return NS_OK;
  }

  NS_ENSURE_STATE(!mCleanedUp);

  NS_ASSERTION(!GetCurrentInnerWindowInternal(this),
               "No cached wrapper, but we have an inner window?");
  NS_ASSERTION(!mContext, "Will overwrite mContext!");

  // If this window is an [i]frame, don't bother GC'ing when the frame's context
  // is destroyed since a GC will happen when the frameset or host document is
  // destroyed anyway.
  mContext = new nsJSContext(mBrowsingContext->IsTop(), this);
  return NS_OK;
}

nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }

bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
  // We reuse the inner window when:
  // a. We are currently at our original document.
  // b. At least one of the following conditions are true:
  // -- The new document is the same as the old document. This means that we're
  //    getting called from document.open().
  // -- The new document has the same origin as what we have loaded right now.

  if (!mDoc || !aNewDocument) {
    return false;
  }

  if (!mDoc->IsInitialDocument()) {
    return false;
  }

#ifdef DEBUG
  {
    nsCOMPtr<nsIURI> uri;
    NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
    NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?");
  }
#endif

  // Great, we're the original document, check for one of the other
  // conditions.

  if (mDoc == aNewDocument) {
    return true;
  }

  if (aNewDocument->IsStaticDocument()) {
    return false;
  }

  if (BasePrincipal::Cast(mDoc->NodePrincipal())
          ->FastEqualsConsideringDomain(aNewDocument->NodePrincipal())) {
    // The origin is the same.
    return true;
  }

  return false;
}

void nsGlobalWindowOuter::SetInitialPrincipal(
    nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP,
    const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
  // We should never create windows with an expanded principal.
  // If we have a system principal, make sure we're not using it for a content
  // docshell.
  // NOTE: Please keep this logic in sync with
  // nsAppShellService::JustCreateTopWindow
  if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) ||
      (aNewWindowPrincipal->IsSystemPrincipal() &&
       GetBrowsingContext()->IsContent())) {
    aNewWindowPrincipal = nullptr;
  }

  // If there's an existing document, bail if it either:
  if (mDoc) {
    // (a) is not an initial about:blank document, or
    if (!mDoc->IsInitialDocument()) return;
    // (b) already has the correct principal.
    if (mDoc->NodePrincipal() == aNewWindowPrincipal) return;

#ifdef DEBUG
    // If we have a document loaded at this point, it had better be about:blank.
    // Otherwise, something is really weird. An about:blank page has a
    // NullPrincipal.
    bool isNullPrincipal;
    MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(
                   &isNullPrincipal)) &&
               isNullPrincipal);
#endif
  }

  // Use the subject (or system) principal as the storage principal too until
  // the new window finishes navigating and gets a real storage principal.
  nsDocShell::Cast(GetDocShell())
      ->CreateAboutBlankDocumentViewer(aNewWindowPrincipal, aNewWindowPrincipal,
                                       aCSP, nullptr,
                                       /* aIsInitialDocument */ true, aCOEP);

  if (mDoc) {
    MOZ_ASSERT(mDoc->IsInitialDocument(),
               "document should be initial document");
  }

  RefPtr<PresShell> presShell = GetDocShell()->GetPresShell();
  if (presShell && !presShell->DidInitialize()) {
    // Ensure that if someone plays with this document they will get
    // layout happening.
    presShell->Initialize();
  }
}

#define WINDOWSTATEHOLDER_IID \
  {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}

class WindowStateHolder final : public nsISupports {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
  NS_DECL_ISUPPORTS

  explicit WindowStateHolder(nsGlobalWindowInner* aWindow);

  nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }

  void DidRestoreWindow() {
    mInnerWindow = nullptr;
    mInnerWindowReflector = nullptr;
  }

 protected:
  ~WindowStateHolder();

  nsGlobalWindowInner* mInnerWindow;
  // We hold onto this to make sure the inner window doesn't go away. The outer
  // window ends up recalculating it anyway.
  JS::PersistentRooted<JSObject*> mInnerWindowReflector;
};

NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)

WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
    : mInnerWindow(aWindow),
      mInnerWindowReflector(RootingCx(), aWindow->GetWrapper()) {
  MOZ_ASSERT(aWindow, "null window");

  aWindow->Suspend();

  // When a global goes into the bfcache, we disable script.
  xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
}

WindowStateHolder::~WindowStateHolder() {
  if (mInnerWindow) {
    // This window was left in the bfcache and is now going away. We need to
    // free it up.
    // Note that FreeInnerObjects may already have been called on the
    // inner window if its outer has already had SetDocShell(null)
    // called.
    mInnerWindow->FreeInnerObjects();
  }
}

NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)

bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
                                                 SecureContextFlags aFlags) {
  nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
  if (principal->IsSystemPrincipal()) {
    return true;
  }

  // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
  // With some modifications to allow for aFlags.

  bool hadNonSecureContextCreator = false;

  if (WindowContext* parentWindow =
          GetBrowsingContext()->GetParentWindowContext()) {
    hadNonSecureContextCreator = !parentWindow->GetIsSecureContext();
  }

  if (hadNonSecureContextCreator) {
    return false;
  }

  if (nsContentUtils::HttpsStateIsModern(aDocument)) {
    return true;
  }

  if (principal->GetIsNullPrincipal()) {
    // If the NullPrincipal has a valid precursor URI we want to use it to
    // construct the principal otherwise we fall back to the original document
    // URI.
    nsCOMPtr<nsIPrincipal> precursorPrin = principal->GetPrecursorPrincipal();
    nsCOMPtr<nsIURI> uri = precursorPrin ? precursorPrin->GetURI() : nullptr;
    if (!uri) {
      uri = aDocument->GetOriginalURI();
    }
    // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
    // it doesn't actually matter what we use here, but reusing the document
    // principal's attributes is convenient.
    const OriginAttributes& attrs = principal->OriginAttributesRef();
    // CreateContentPrincipal correctly gets a useful principal for blob: and
    // other URI_INHERITS_SECURITY_CONTEXT URIs.
    principal = BasePrincipal::CreateContentPrincipal(uri, attrs);
    if (NS_WARN_IF(!principal)) {
      return false;
    }
  }

  return principal->GetIsOriginPotentiallyTrustworthy();
}

static bool InitializeLegacyNetscapeObject(JSContext* aCx,
--> --------------------

--> maximum size reached

--> --------------------

99%


¤ Dauer der Verarbeitung: 0.36 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge