Bug 1496251 - Convert nsDocShell::InternalLoad to using nsDocShellLoadState r=bzbarsky,nika
authorKyle Machulis <kyle@nonpolynomial.com>
Wed, 19 Dec 2018 21:01:13 +0000
changeset 451399 73ecece00c9c7261bbe72ebbb7f4232bf2cd2ec9
parent 451398 eab2b1be4f3fc1eca0120080975365e1f72056eb
child 451400 78e2f7ce4040fb85c336f29613bb5b946d3d33ec
push id35237
push userrmaries@mozilla.com
push dateThu, 20 Dec 2018 04:52:39 +0000
treeherdermozilla-central@1260c07d4b17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, nika
bugs1496251, 1475331
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1496251 - Convert nsDocShell::InternalLoad to using nsDocShellLoadState r=bzbarsky,nika Move InternalLoad from 24 arguments to 3, using nsDocShellLoadState objects. Move all internal argument references to using calls to accessors/mutators on nsDocShellLoadState. Comments from old interface function definition have been spread to relevant places in code. Internal load flags in nsDocShellLoadState are also consolidated to the LoadFlags member, as they were usually passed as that member before nsDocShellLoadState existed. This begins the work to simplify load flags further in a later patch (See Bug 1475331). Depends on D13487 Differential Revision: https://phabricator.services.mozilla.com/D13488
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadState.cpp
docshell/base/nsDocShellLoadState.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -325,17 +325,17 @@ nsDocShell::nsDocShell(BrowsingContext* 
       mPreviousEntryIndex(-1),
       mLoadedEntryIndex(-1),
       mChildOffset(0),
       mSandboxFlags(0),
       mBusyFlags(BUSY_FLAGS_NONE),
       mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
       mLoadType(0),
       mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
-      mReferrerPolicy(0),
+      mReferrerPolicy((uint32_t)mozilla::net::ReferrerPolicy::RP_Unset),
       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),
@@ -733,41 +733,28 @@ nsDocShell::LoadURI(nsDocShellLoadState*
   // Set up the inheriting principal in LoadState.
   nsresult rv =
       aLoadState->SetupInheritingPrincipal(mItemType, mOriginAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aLoadState->SetupTriggeringPrincipal(mOriginAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  aLoadState->CalculateDocShellInternalLoadFlags();
-
-  mozilla::Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
-  aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
+  aLoadState->CalculateLoadURIFlags();
 
   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");
 
-  return InternalLoad(
-      aLoadState->URI(), aLoadState->OriginalURI(), resultPrincipalURI,
-      aLoadState->KeepResultPrincipalURIIfSet(), aLoadState->LoadReplace(),
-      aLoadState->GetIsFromProcessingFrameAttributes(), aLoadState->Referrer(),
-      aLoadState->ReferrerPolicy(), aLoadState->TriggeringPrincipal(),
-      aLoadState->PrincipalToInherit(), aLoadState->DocShellInternalLoadFlags(),
-      aLoadState->Target(), aLoadState->TypeHint(), aLoadState->FileName(),
-      aLoadState->PostDataStream(), aLoadState->HeadersStream(),
-      aLoadState->LoadType(), aLoadState->SHEntry(), aLoadState->FirstParty(),
-      aLoadState->SrcdocData(), aLoadState->SourceDocShell(),
-      aLoadState->BaseURI(),
-      nullptr,   // no nsIDocShell
-      nullptr);  // no nsIRequest
+  return InternalLoad(aLoadState,
+                      nullptr,   // no nsIDocShell
+                      nullptr);  // no nsIRequest
 }
 
 void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) {
   // First, verify if this is a subframe.
   nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
   GetSameTypeParent(getter_AddRefs(parentAsItem));
   nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
 
@@ -4582,22 +4569,24 @@ nsresult nsDocShell::LoadErrorPage(nsIUR
 
   if (mLSHE) {
     // Abandon mLSHE's BFCache entry and create a new one.  This way, if
     // we go back or forward to another SHEntry with the same doc
     // identifier, the error page won't persist.
     mLSHE->AbandonBFCacheEntry();
   }
 
-  return InternalLoad(aErrorURI, nullptr, Nothing(), false, false, false,
-                      nullptr, RP_Unset, nsContentUtils::GetSystemPrincipal(),
-                      nullptr, INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
-                      VoidCString(), VoidString(), nullptr, nullptr,
-                      LOAD_ERROR_PAGE, nullptr, true, VoidString(), this,
-                      nullptr, nullptr, nullptr);
+  RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
+  loadState->SetURI(aErrorURI);
+  loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
+  loadState->SetLoadType(LOAD_ERROR_PAGE);
+  loadState->SetFirstParty(true);
+  loadState->SetSourceDocShell(this);
+
+  return InternalLoad(loadState, nullptr, nullptr);
 }
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags) {
   if (!IsNavigationAllowed()) {
     return NS_OK;  // JS may not handle returning of an error code
   }
   nsresult rv;
@@ -4677,34 +4666,34 @@ nsDocShell::Reload(uint32_t aReloadFlags
     // the call.
     nsCOMPtr<nsIURI> currentURI = mCurrentURI;
     nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
     uint32_t referrerPolicy = mReferrerPolicy;
 
     // Reload always rewrites result principal URI.
     Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
     emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
-    rv = InternalLoad(currentURI, originalURI, emplacedResultPrincipalURI,
-                      false, loadReplace,
-                      false,  // IsFromProcessingFrameAttributes
-                      referrerURI, referrerPolicy, triggeringPrincipal,
-                      triggeringPrincipal, flags,
-                      EmptyString(),  // No window target
-                      NS_LossyConvertUTF16toASCII(contentTypeHint),
-                      VoidString(),  // No forced download
-                      nullptr,       // No post data
-                      nullptr,       // No headers data
-                      loadType,      // Load type
-                      nullptr,       // No SHEntry
-                      true,
-                      srcdoc,  // srcdoc argument for iframe
-                      this,    // For reloads we are the source
-                      baseURI,
-                      nullptr,   // No nsIDocShell
-                      nullptr);  // No nsIRequest
+
+    RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
+    loadState->SetURI(currentURI);
+    loadState->SetOriginalURI(originalURI);
+    loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
+    loadState->SetLoadReplace(loadReplace);
+    loadState->SetReferrer(referrerURI);
+    loadState->SetReferrerPolicy((mozilla::net::ReferrerPolicy)referrerPolicy);
+    loadState->SetTriggeringPrincipal(triggeringPrincipal);
+    loadState->SetPrincipalToInherit(triggeringPrincipal);
+    loadState->SetLoadFlags(flags);
+    loadState->SetTypeHint(NS_ConvertUTF16toUTF8(contentTypeHint));
+    loadState->SetLoadType(loadType);
+    loadState->SetFirstParty(true);
+    loadState->SetSrcdocData(srcdoc);
+    loadState->SetSourceDocShell(this);
+    loadState->SetBaseURI(baseURI);
+    rv = InternalLoad(loadState, nullptr, nullptr);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::Stop(uint32_t aStopFlags) {
   // Revoke any pending event related to content viewer restoration
@@ -8610,178 +8599,127 @@ void nsDocShell::CopyFavicon(nsIURI* aOl
                              : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
                          nullptr);
   }
 #endif
 }
 
 class InternalLoadEvent : public Runnable {
  public:
-  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, nsIURI* aOriginalURI,
-                    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
-                    bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
-                    bool aIsFromProcessingFrameAttributes, nsIURI* aReferrer,
-                    uint32_t aReferrerPolicy,
-                    nsIPrincipal* aTriggeringPrincipal,
-                    nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
-                    const nsACString& aTypeHint, nsIInputStream* aPostData,
-                    nsIInputStream* aHeadersData, uint32_t aLoadType,
-                    nsISHEntry* aSHEntry, bool aFirstParty,
-                    const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
-                    nsIURI* aBaseURI)
+  InternalLoadEvent(nsDocShell* aDocShell, nsDocShellLoadState* aLoadState)
       : mozilla::Runnable("InternalLoadEvent"),
-        mTypeHint(aTypeHint),
-        mSrcdoc(aSrcdoc),
         mDocShell(aDocShell),
-        mURI(aURI),
-        mOriginalURI(aOriginalURI),
-        mResultPrincipalURI(aResultPrincipalURI),
-        mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet),
-        mLoadReplace(aLoadReplace),
-        mIsFromProcessingFrameAttributes(aIsFromProcessingFrameAttributes),
-        mReferrer(aReferrer),
-        mReferrerPolicy(aReferrerPolicy),
-        mTriggeringPrincipal(aTriggeringPrincipal),
-        mPrincipalToInherit(aPrincipalToInherit),
-        mPostData(aPostData),
-        mHeadersData(aHeadersData),
-        mSHEntry(aSHEntry),
-        mFlags(aFlags),
-        mLoadType(aLoadType),
-        mFirstParty(aFirstParty),
-        mSourceDocShell(aSourceDocShell),
-        mBaseURI(aBaseURI) {}
+        mLoadState(aLoadState) {
+    // For events, both target and filename should be the version of "null" they
+    // expect. By the time the event is fired, both window targeting and file
+    // downloading have been handled, so we should never have an internal load
+    // event that retargets or had a download.
+    mLoadState->SetTarget(EmptyString());
+    mLoadState->SetFileName(VoidString());
+  }
 
   NS_IMETHOD
   Run() override {
 #ifndef ANDROID
-    MOZ_ASSERT(mTriggeringPrincipal,
+    MOZ_ASSERT(mLoadState->TriggeringPrincipal(),
                "InternalLoadEvent: Should always have a principal here");
 #endif
-    return mDocShell->InternalLoad(
-        mURI, mOriginalURI, mResultPrincipalURI, mKeepResultPrincipalURIIfSet,
-        mLoadReplace, mIsFromProcessingFrameAttributes, mReferrer,
-        mReferrerPolicy, mTriggeringPrincipal, mPrincipalToInherit, mFlags,
-        EmptyString(), mTypeHint, VoidString(), mPostData, mHeadersData,
-        mLoadType, mSHEntry, mFirstParty, mSrcdoc, mSourceDocShell, mBaseURI,
-        nullptr, nullptr);
+    return mDocShell->InternalLoad(mLoadState, nullptr, nullptr);
   }
 
  private:
-  nsCString mTypeHint;
-  nsString mSrcdoc;
-
   RefPtr<nsDocShell> mDocShell;
-  nsCOMPtr<nsIURI> mURI;
-  nsCOMPtr<nsIURI> mOriginalURI;
-  Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
-  bool mKeepResultPrincipalURIIfSet;
-  bool mLoadReplace;
-  bool mIsFromProcessingFrameAttributes;
-  nsCOMPtr<nsIURI> mReferrer;
-  uint32_t mReferrerPolicy;
-  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
-  nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
-  nsCOMPtr<nsIInputStream> mPostData;
-  nsCOMPtr<nsIInputStream> mHeadersData;
-  nsCOMPtr<nsISHEntry> mSHEntry;
-  uint32_t mFlags;
-  uint32_t mLoadType;
-  bool mFirstParty;
-  nsCOMPtr<nsIDocShell> mSourceDocShell;
-  nsCOMPtr<nsIURI> mBaseURI;
+  RefPtr<nsDocShellLoadState> mLoadState;
 };
 
 /**
  * Returns true if we started an asynchronous load (i.e., from the network), but
  * the document we're loading there hasn't yet become this docshell's active
  * document.
  *
  * When JustStartedNetworkLoad is true, you should be careful about modifying
  * mLoadType and mLSHE.  These are both set when the asynchronous load first
  * starts, and the load expects that, when it eventually runs InternalLoad,
  * mLoadType and mLSHE will have their original values.
  */
 bool nsDocShell::JustStartedNetworkLoad() {
   return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
 }
 
-nsresult nsDocShell::InternalLoad(
-    nsIURI* aURI, nsIURI* aOriginalURI,
-    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
-    bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
-    bool aIsFromProcessingFrameAttributes, nsIURI* aReferrer,
-    uint32_t aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
-    nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
-    const nsAString& aWindowTarget, const nsACString& aTypeHint,
-    const nsAString& aFileName, nsIInputStream* aPostData,
-    nsIInputStream* aHeadersData, uint32_t aLoadType, nsISHEntry* aSHEntry,
-    bool aFirstParty, const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
-    nsIURI* aBaseURI, nsIDocShell** aDocShell, nsIRequest** aRequest) {
-  MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
-  if (mUseStrictSecurityChecks && !aTriggeringPrincipal) {
+nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
+                                  nsIDocShell** aDocShell,
+                                  nsIRequest** aRequest) {
+  MOZ_ASSERT(aLoadState, "need a load state!");
+  MOZ_ASSERT(aLoadState->TriggeringPrincipal(),
+             "need a valid TriggeringPrincipal");
+
+  if (mUseStrictSecurityChecks && !aLoadState->TriggeringPrincipal()) {
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = NS_OK;
   mOriginalUriString.Truncate();
 
-  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
-          ("DOCSHELL %p InternalLoad %s\n", this,
-           aURI ? aURI->GetSpecOrDefault().get() : ""));
+  MOZ_LOG(
+      gDocShellLeakLog, LogLevel::Debug,
+      ("DOCSHELL %p InternalLoad %s\n", this,
+       aLoadState->URI() ? aLoadState->URI()->GetSpecOrDefault().get() : ""));
+
   // Initialize aDocShell/aRequest
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
     *aRequest = nullptr;
   }
 
-  if (!aURI) {
+  if (!aLoadState->URI()) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
+  NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG);
 
   NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
 
   rv = EnsureScriptEnvironment();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // wyciwyg urls can only be loaded through history. Any normal load of
   // wyciwyg through docshell is  illegal. Disallow such loads.
-  if (aLoadType & LOAD_CMD_NORMAL) {
+  if (aLoadState->LoadType() & LOAD_CMD_NORMAL) {
     bool isWyciwyg = false;
-    rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
+    rv = aLoadState->URI()->SchemeIs("wyciwyg", &isWyciwyg);
     if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   bool isJavaScript = false;
-  if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) {
+  if (NS_FAILED(aLoadState->URI()->SchemeIs("javascript", &isJavaScript))) {
     isJavaScript = false;
   }
 
   bool isTargetTopLevelDocShell = false;
   nsCOMPtr<nsIDocShell> targetDocShell;
-  if (!aWindowTarget.IsEmpty()) {
+  if (!aLoadState->Target().IsEmpty()) {
     // Locate the target DocShell.
     nsCOMPtr<nsIDocShellTreeItem> targetItem;
     // Only _self, _parent, and _top are supported in noopener case.  But we
     // have to be careful to not apply that to the noreferrer case.  See bug
     // 1358469.
-    bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
-                            (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
-    if (allowNamedTarget || aWindowTarget.LowerCaseEqualsLiteral("_self") ||
-        aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
-        aWindowTarget.LowerCaseEqualsLiteral("_top")) {
-      rv = FindItemWithName(aWindowTarget, nullptr, this, false,
+    bool allowNamedTarget =
+        !aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
+        aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
+    if (allowNamedTarget ||
+        aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
+        aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
+        aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
+      rv = FindItemWithName(aLoadState->Target(), nullptr, this, false,
                             getter_AddRefs(targetItem));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     targetDocShell = do_QueryInterface(targetItem);
     if (targetDocShell) {
       // If the targetDocShell and the rootDocShell are the same, then the
       // targetDocShell is the top level document and hence we should
@@ -8805,17 +8743,17 @@ nsresult nsDocShell::InternalLoad(
       //
       // For example, when target="_blank"
       isTargetTopLevelDocShell = true;
     }
   }
 
   // The contentType will be INTERNAL_(I)FRAME if:
   // 1. This docshell is for iframe.
-  // 2. AND aWindowTarget is not a new window, nor a top-level window.
+  // 2. AND aLoadState->Target() is not a new window, nor a top-level window.
   //
   // This variable will be used when we call NS_CheckContentLoadPolicy, and
   // later when we call DoURILoad.
   uint32_t contentType;
   if (IsFrame() && !isTargetTopLevelDocShell) {
     nsCOMPtr<Element> requestingElement =
         mScriptGlobal->AsOuter()->GetFrameElementInternal();
     if (requestingElement) {
@@ -8828,21 +8766,21 @@ nsresult nsDocShell::InternalLoad(
       contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
     }
   } else {
     contentType = nsIContentPolicy::TYPE_DOCUMENT;
     isTargetTopLevelDocShell = true;
   }
 
   // If there's no targetDocShell, that means we are about to create a new
-  // window (or aWindowTarget is empty). Perform a content policy check before
-  // creating the window. Please note for all other docshell loads
-  // content policy checks are performed within the contentSecurityManager
-  // when the channel is about to be openend.
-  if (!targetDocShell && !aWindowTarget.IsEmpty()) {
+  // window (or aLoadState->Target() is empty). Perform a content policy check
+  // before creating the window. Please note for all other docshell loads
+  // content policy checks are performed within the contentSecurityManager when
+  // the channel is about to be openend.
+  if (!targetDocShell && !aLoadState->Target().IsEmpty()) {
     MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
                "opening a new window requires type to be TYPE_DOCUMENT");
 
     nsISupports* requestingContext = nullptr;
     if (XRE_IsContentProcess()) {
       // In e10s the child process doesn't have access to the element that
       // contains the browsing context (because that element is in the chrome
       // process). So we just pass mScriptGlobal.
@@ -8854,209 +8792,196 @@ nsresult nsDocShell::InternalLoad(
       nsCOMPtr<Element> requestingElement =
           mScriptGlobal->AsOuter()->GetFrameElementInternal();
       requestingContext = requestingElement;
     }
 
     // Ideally we should use the same loadinfo as within DoURILoad which
     // should match this one when both are applicable.
     nsCOMPtr<nsPIDOMWindowOuter> loadingWindow = mScriptGlobal->AsOuter();
-    nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
-        new LoadInfo(loadingWindow, aTriggeringPrincipal, requestingContext,
-                     nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK);
+    nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new LoadInfo(
+        loadingWindow, aLoadState->TriggeringPrincipal(), requestingContext,
+        nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK);
 
     // Since Content Policy checks are performed within docShell as well as
     // the ContentSecurityManager we need a reliable way to let certain
     // nsIContentPolicy consumers ignore duplicate calls.
     secCheckLoadInfo->SetSkipContentPolicyCheckForWebRequest(true);
 
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(aURI, secCheckLoadInfo,
+    rv = NS_CheckContentLoadPolicy(aLoadState->URI(), secCheckLoadInfo,
                                    EmptyCString(),  // mime guess
                                    &shouldLoad);
 
     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
       if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
         return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
       }
 
       return NS_ERROR_CONTENT_BLOCKED;
     }
   }
 
-  nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
-  //
-  // Get a principal from the current document if necessary.  Note that we
-  // only do this for URIs that inherit a security context and local file
-  // URIs; in particular we do NOT do this for about:blank.  This way, random
-  // about:blank loads that have no principal (which basically means they were
-  // done by someone from chrome manually messing with our nsIWebNavigation
-  // or by C++ setting document.location) don't get a funky principal.  If
-  // callers want something interesting to happen with the about:blank
-  // principal in this case, they should pass aPrincipalToInherit in.
-  //
-  {
-    bool inherits;
-    // One more twist: Don't inherit the principal for external loads.
-    if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
-        (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
-        NS_SUCCEEDED(
-            nsContentUtils::URIInheritsSecurityContext(aURI, &inherits)) &&
-        inherits) {
-      principalToInherit = GetInheritedPrincipal(true);
-    }
-  }
-
   nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
 
   const bool isDocumentAuxSandboxed =
       doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
 
-  if (aURI && mLoadURIDelegate && aLoadType != LOAD_ERROR_PAGE &&
+  if (aLoadState->URI() && mLoadURIDelegate &&
+      aLoadState->LoadType() != LOAD_ERROR_PAGE &&
       (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
     // Dispatch only load requests for the current or a new window to the
     // delegate, e.g., to allow for GeckoView apps to handle the load event
     // outside of Gecko.
-    const int where = (aWindowTarget.IsEmpty() || targetDocShell)
+    const int where = (aLoadState->Target().IsEmpty() || targetDocShell)
                           ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
                           : nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 
     if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW &&
         isDocumentAuxSandboxed) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
 
     bool loadURIHandled = false;
-    rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
-                                   &loadURIHandled);
+    rv = mLoadURIDelegate->LoadURI(
+        aLoadState->URI(), where, aLoadState->LoadFlags(),
+        aLoadState->TriggeringPrincipal(), &loadURIHandled);
     if (NS_SUCCEEDED(rv) && loadURIHandled) {
       // The request has been handled, nothing to do here.
       return NS_OK;
     }
   }
 
   //
   // Resolve the window target before going any further...
   // If the load has been targeted to another DocShell, then transfer the
   // load to it...
   //
-  if (!aWindowTarget.IsEmpty()) {
+  if (!aLoadState->Target().IsEmpty()) {
     // We've already done our owner-inheriting.  Mask out that bit, so we
     // don't try inheriting an owner from the target window if we came up
     // with a null owner above.
-    aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
+    aLoadState->UnsetLoadFlag(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
 
     bool isNewWindow = false;
     if (!targetDocShell) {
       // If the docshell's document is sandboxed, only open a new window
       // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
       // (i.e. if allow-popups is specified)
       NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
       if (isDocumentAuxSandboxed) {
         return NS_ERROR_DOM_INVALID_ACCESS_ERR;
       }
 
       nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
       NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
 
       nsCOMPtr<nsPIDOMWindowOuter> newWin;
       nsAutoCString spec;
-      if (aURI) {
-        aURI->GetSpec(spec);
+      if (aLoadState->URI()) {
+        aLoadState->URI()->GetSpec(spec);
       }
       // If we are a noopener load, we just hand the whole thing over to our
       // window.
-      if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
-        // Various asserts that we know to hold because NO_OPENER loads can
-        // only happen for links.
-        MOZ_ASSERT(!aLoadReplace);
-        MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
-        MOZ_ASSERT((aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
+      if (aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER)) {
+        // Various asserts that we know to hold because NO_OPENER loads can only
+        // happen for links.
+        MOZ_ASSERT(!aLoadState->LoadReplace());
+        MOZ_ASSERT(aLoadState->PrincipalToInherit() ==
+                   aLoadState->TriggeringPrincipal());
+        MOZ_ASSERT((aLoadState->LoadFlags() &
+                    ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
                        INTERNAL_LOAD_FLAGS_NO_OPENER ||
-                   (aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
+                   (aLoadState->LoadFlags() &
+                    ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
                        (INTERNAL_LOAD_FLAGS_NO_OPENER |
                         INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
-        MOZ_ASSERT(!aPostData);
-        MOZ_ASSERT(!aHeadersData);
+        MOZ_ASSERT(!aLoadState->PostDataStream());
+        MOZ_ASSERT(!aLoadState->HeadersStream());
         // If OnLinkClickSync was invoked inside the onload handler, the load
         // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
         // LOAD_LINK.
-        MOZ_ASSERT(aLoadType == LOAD_LINK || aLoadType == LOAD_NORMAL_REPLACE);
-        MOZ_ASSERT(!aSHEntry);
-        MOZ_ASSERT(aFirstParty);  // Windowwatcher will assume this.
+        MOZ_ASSERT(aLoadState->LoadType() == LOAD_LINK ||
+                   aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
+        MOZ_ASSERT(!aLoadState->SHEntry());
+        MOZ_ASSERT(
+            aLoadState->FirstParty());  // Windowwatcher will assume this.
 
         RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
 
-        // Set up our loadinfo so it will do the load as much like we would
-        // have as possible.
-        loadState->SetReferrer(aReferrer);
+        // Set up our loadinfo so it will do the load as much like we would have
+        // as possible.
+        loadState->SetReferrer(aLoadState->Referrer());
         loadState->SetReferrerPolicy(
-            (mozilla::net::ReferrerPolicy)aReferrerPolicy);
-        loadState->SetSendReferrer(
-            !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
-        loadState->SetOriginalURI(aOriginalURI);
-        loadState->SetMaybeResultPrincipalURI(aResultPrincipalURI);
-        loadState->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet);
-        loadState->SetLoadReplace(aLoadReplace);
-        loadState->SetTriggeringPrincipal(aTriggeringPrincipal);
-        loadState->SetInheritPrincipal(aFlags &
-                                       INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
-        // Explicit principal because we do not want any guesses as to what
-        // the principal to inherit is: it should be aTriggeringPrincipal.
+            (mozilla::net::ReferrerPolicy)aLoadState->ReferrerPolicy());
+        loadState->SetSendReferrer(!(
+            aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)));
+        loadState->SetOriginalURI(aLoadState->OriginalURI());
+
+        Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
+        aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
+
+        loadState->SetMaybeResultPrincipalURI(resultPrincipalURI);
+        loadState->SetKeepResultPrincipalURIIfSet(
+            aLoadState->KeepResultPrincipalURIIfSet());
+        // LoadReplace will always be false due to asserts above, skip setting
+        // it.
+        loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
+        loadState->SetInheritPrincipal(
+            aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
+        // Explicit principal because we do not want any guesses as to what the
+        // principal to inherit is: it should be aTriggeringPrincipal.
         loadState->SetPrincipalIsExplicit(true);
         loadState->SetLoadType(LOAD_LINK);
         loadState->SetForceAllowDataURI(
-            aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
+            aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
 
         rv = win->Open(NS_ConvertUTF8toUTF16(spec),
-                       aWindowTarget,  // window name
-                       EmptyString(),  // Features
+                       aLoadState->Target(),  // window name
+                       EmptyString(),         // Features
                        loadState,
                        true,  // aForceNoOpener
                        getter_AddRefs(newWin));
         MOZ_ASSERT(!newWin);
         return rv;
       }
 
       rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
-                               aWindowTarget,  // window name
-                               EmptyString(),  // Features
+                               aLoadState->Target(),  // window name
+                               EmptyString(),         // Features
                                getter_AddRefs(newWin));
 
       // In some cases the Open call doesn't actually result in a new
       // window being opened.  We can detect these cases by examining the
       // document in |newWin|, if any.
       nsCOMPtr<nsPIDOMWindowOuter> piNewWin = newWin;
       if (piNewWin) {
         nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
         if (!newDoc || newDoc->IsInitialDocument()) {
           isNewWindow = true;
-          aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
+          aLoadState->SetLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
         }
       }
 
       nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
       targetDocShell = do_QueryInterface(webNav);
     }
 
     //
-    // Transfer the load to the target DocShell...  Pass nullptr as the
+    // Transfer the load to the target DocShell... Pass empty string as the
     // window target name from to prevent recursive retargeting!
     //
     if (NS_SUCCEEDED(rv) && targetDocShell) {
       nsDocShell* docShell = nsDocShell::Cast(targetDocShell);
-      rv = docShell->InternalLoad(
-          aURI, aOriginalURI, aResultPrincipalURI, aKeepResultPrincipalURIIfSet,
-          aLoadReplace, aIsFromProcessingFrameAttributes, aReferrer,
-          aReferrerPolicy, aTriggeringPrincipal, principalToInherit, aFlags,
-          EmptyString(),  // No window target
-          aTypeHint,
-          VoidString(),  // No forced download
-          aPostData, aHeadersData, aLoadType, aSHEntry, aFirstParty, aSrcdoc,
-          aSourceDocShell, aBaseURI, aDocShell, aRequest);
+      // No window target
+      aLoadState->SetTarget(EmptyString());
+      // No forced download
+      aLoadState->SetFileName(VoidString());
+      rv = docShell->InternalLoad(aLoadState, aDocShell, aRequest);
+
       if (rv == NS_ERROR_NO_CONTENT) {
         // XXXbz except we never reach this code!
         if (isNewWindow) {
           //
           // At this point, a new window has been created, but the
           // URI did not have any data associated with it...
           //
           // So, the best we can do, is to tear down the new window
@@ -9098,156 +9023,188 @@ nsresult nsDocShell::InternalLoad(
     }
 
     // Else we ran out of memory, or were a popup and got blocked,
     // or something.
 
     return rv;
   }
 
+  // If we are loading a URI that should inherit a security context (basically
+  // javascript: at this point), and the caller has said that principal
+  // inheritance is allowed, there are a few possible cases:
+  //
+  // 1) We are provided with the principal to inherit. In that case, we just use
+  //    it.
+  //
+  // 2) The load is coming from some other application. In this case we don't
+  //    want to inherit from whatever document we have loaded now, since the
+  //    load is unrelated to it.
+  //
+  // 3) It's a load from our application, but does not provide an explicit
+  //    principal to inherit. In that case, we want to inherit the principal of
+  //    our current document, or of our parent document (if any) if we don't
+  //    have a current document.
+  {
+    bool inherits;
+
+    if (aLoadState->LoadType() != LOAD_NORMAL_EXTERNAL &&
+        !aLoadState->PrincipalToInherit() &&
+        (aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL)) &&
+        NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(
+            aLoadState->URI(), &inherits)) &&
+        inherits) {
+      aLoadState->SetPrincipalToInherit(GetInheritedPrincipal(true));
+    }
+    // If principalToInherit is still null (e.g. if some of the conditions of
+    // were not satisfied), then no inheritance of any sort will happen: the
+    // load will just get a principal based on the URI being loaded.
+  }
+
   //
   // Load is being targetted at this docshell so return an error if the
   // docshell is in the process of being destroyed.
   //
   if (mIsBeingDestroyed) {
     return NS_ERROR_FAILURE;
   }
 
   NS_ENSURE_STATE(!HasUnloadedParent());
 
   rv = CheckLoadingPermissions();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (mFiredUnloadEvent) {
-    if (IsOKToLoadURI(aURI)) {
-      MOZ_ASSERT(aWindowTarget.IsEmpty(),
+    if (IsOKToLoadURI(aLoadState->URI())) {
+      MOZ_ASSERT(aLoadState->Target().IsEmpty(),
                  "Shouldn't have a window target here!");
 
       // If this is a replace load, make whatever load triggered
       // the unload event also a replace load, so we don't
       // create extra history entries.
-      if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
+      if (LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
+                              LOAD_FLAGS_REPLACE_HISTORY)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       }
 
       // Do this asynchronously
-      nsCOMPtr<nsIRunnable> ev = new InternalLoadEvent(
-          this, aURI, aOriginalURI, aResultPrincipalURI,
-          aKeepResultPrincipalURIIfSet, aLoadReplace,
-          aIsFromProcessingFrameAttributes, aReferrer, aReferrerPolicy,
-          aTriggeringPrincipal, principalToInherit, aFlags, aTypeHint,
-          aPostData, aHeadersData, aLoadType, aSHEntry, aFirstParty, aSrcdoc,
-          aSourceDocShell, aBaseURI);
+      nsCOMPtr<nsIRunnable> ev = new InternalLoadEvent(this, aLoadState);
       return DispatchToTabGroup(TaskCategory::Other, ev.forget());
     }
 
     // Just ignore this load attempt
     return NS_OK;
   }
 
   // If a source docshell has been passed, check to see if we are sandboxed
   // from it as the result of an iframe or CSP sandbox.
-  if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
+  if (aLoadState->SourceDocShell() &&
+      aLoadState->SourceDocShell()->IsSandboxedFrom(this)) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   // If this docshell is owned by a frameloader, make sure to cancel
   // possible frameloader initialization before loading a new page.
   nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
   if (parent) {
     nsCOMPtr<nsIDocument> doc = parent->GetDocument();
     if (doc) {
       doc->TryCancelFrameLoaderInitialization(this);
     }
   }
 
   bool loadFromExternal = false;
 
   // Before going any further vet loads initiated by external programs.
-  if (aLoadType == LOAD_NORMAL_EXTERNAL) {
+  if (aLoadState->LoadType() == LOAD_NORMAL_EXTERNAL) {
     loadFromExternal = true;
     // Disallow external chrome: loads targetted at content windows
     bool isChrome = false;
-    if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
+    if (NS_SUCCEEDED(aLoadState->URI()->SchemeIs("chrome", &isChrome)) &&
+        isChrome) {
       NS_WARNING("blocked external chrome: url -- use '--chrome' option");
       return NS_ERROR_FAILURE;
     }
 
     // clear the decks to prevent context bleed-through (bug 298255)
     rv = CreateAboutBlankContentViewer(nullptr, nullptr);
     if (NS_FAILED(rv)) {
       return NS_ERROR_FAILURE;
     }
 
     // reset loadType so we don't have to add lots of tests for
     // LOAD_NORMAL_EXTERNAL after this point
-    aLoadType = LOAD_NORMAL;
+    aLoadState->SetLoadType(LOAD_NORMAL);
   }
 
   mAllowKeywordFixup =
-      (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
   mURIResultedInDocument = false;  // reset the clock...
 
-  if (aLoadType == LOAD_NORMAL || aLoadType == LOAD_STOP_CONTENT ||
-      LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
-      aLoadType == LOAD_HISTORY || aLoadType == LOAD_LINK) {
+  if (aLoadState->LoadType() == LOAD_NORMAL ||
+      aLoadState->LoadType() == LOAD_STOP_CONTENT ||
+      LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(), LOAD_FLAGS_REPLACE_HISTORY) ||
+      aLoadState->LoadType() == LOAD_HISTORY ||
+      aLoadState->LoadType() == LOAD_LINK) {
     nsCOMPtr<nsIURI> currentURI = mCurrentURI;
 
     nsAutoCString curHash, newHash;
     bool curURIHasRef = false, newURIHasRef = false;
 
-    nsresult rvURINew = aURI->GetRef(newHash);
+    nsresult rvURINew = aLoadState->URI()->GetRef(newHash);
     if (NS_SUCCEEDED(rvURINew)) {
-      rvURINew = aURI->GetHasRef(&newURIHasRef);
+      rvURINew = aLoadState->URI()->GetHasRef(&newURIHasRef);
     }
 
     bool sameExceptHashes = false;
     if (currentURI && NS_SUCCEEDED(rvURINew)) {
       nsresult rvURIOld = currentURI->GetRef(curHash);
       if (NS_SUCCEEDED(rvURIOld)) {
         rvURIOld = currentURI->GetHasRef(&curURIHasRef);
       }
       if (NS_SUCCEEDED(rvURIOld)) {
-        if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
+        if (NS_FAILED(currentURI->EqualsExceptRef(aLoadState->URI(),
+                                                  &sameExceptHashes))) {
           sameExceptHashes = false;
         }
       }
     }
 
     if (!sameExceptHashes && sURIFixup && currentURI &&
         NS_SUCCEEDED(rvURINew)) {
-      // Maybe aURI came from the exposable form of currentURI?
+      // Maybe aLoadState->URI() came from the exposable form of currentURI?
       nsCOMPtr<nsIURI> currentExposableURI;
       rv = sURIFixup->CreateExposableURI(currentURI,
                                          getter_AddRefs(currentExposableURI));
       NS_ENSURE_SUCCESS(rv, rv);
       nsresult rvURIOld = currentExposableURI->GetRef(curHash);
       if (NS_SUCCEEDED(rvURIOld)) {
         rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef);
       }
       if (NS_SUCCEEDED(rvURIOld)) {
         if (NS_FAILED(currentExposableURI->EqualsExceptRef(
-                aURI, &sameExceptHashes))) {
+                aLoadState->URI(), &sameExceptHashes))) {
           sameExceptHashes = false;
         }
       }
     }
 
     bool historyNavBetweenSameDoc = false;
-    if (mOSHE && aSHEntry) {
+    if (mOSHE && aLoadState->SHEntry()) {
       // We're doing a history load.
 
-      mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
+      mOSHE->SharesDocumentWith(aLoadState->SHEntry(),
+                                &historyNavBetweenSameDoc);
 
 #ifdef DEBUG
       if (historyNavBetweenSameDoc) {
         nsCOMPtr<nsIInputStream> currentPostData = mOSHE->GetPostData();
-        NS_ASSERTION(currentPostData == aPostData,
+        NS_ASSERTION(currentPostData == aLoadState->PostDataStream(),
                      "Different POST data for entries for the same page?");
       }
 #endif
     }
 
     // A short-circuited load happens when we navigate between two SHEntries
     // for the same document.  We do a short-circuited load under two
     // circumstances.  Either
@@ -9258,119 +9215,122 @@ nsresult nsDocShell::InternalLoad(
     //  b) we're navigating to a new shentry whose URI differs from the
     //     current URI only in its hash, the new hash is non-empty, and
     //     we're not doing a POST.
     //
     // The restriction tha the SHEntries in (a) must be different ensures
     // that history.go(0) and the like trigger full refreshes, rather than
     // short-circuited loads.
     bool doShortCircuitedLoad =
-        (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
-        (!aSHEntry && !aPostData && sameExceptHashes && newURIHasRef);
+        (historyNavBetweenSameDoc && mOSHE != aLoadState->SHEntry()) ||
+        (!aLoadState->SHEntry() && !aLoadState->PostDataStream() &&
+         sameExceptHashes && newURIHasRef);
 
     if (doShortCircuitedLoad) {
       // Save the position of the scrollers.
       nscoord cx = 0, cy = 0;
       GetCurScrollPos(ScrollOrientation_X, &cx);
       GetCurScrollPos(ScrollOrientation_Y, &cy);
 
       // Reset mLoadType to its original value once we exit this block,
       // because this short-circuited load might have started after a
       // normal, network load, and we don't want to clobber its load type.
       // See bug 737307.
       AutoRestore<uint32_t> loadTypeResetter(mLoadType);
 
       // If a non-short-circuit load (i.e., a network load) is pending,
       // make this a replacement load, so that we don't add a SHEntry here
       // and the network load goes into the SHEntry it expects to.
-      if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
+      if (JustStartedNetworkLoad() &&
+          (aLoadState->LoadType() & LOAD_CMD_NORMAL)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       } else {
-        mLoadType = aLoadType;
+        mLoadType = aLoadState->LoadType();
       }
 
       mURIResultedInDocument = true;
 
       nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
 
-      /* we need to assign mLSHE to aSHEntry right here, so that on History
-       * loads, SetCurrentURI() called from OnNewURI() will send proper
-       * onLocationChange() notifications to the browser to update
-       * back/forward buttons.
-       */
-      SetHistoryEntry(&mLSHE, aSHEntry);
+      // we need to assign aLoadState->SHEntry() to mLSHE right here, so that on
+      // History loads, SetCurrentURI() called from OnNewURI() will send proper
+      // onLocationChange() notifications to the browser to update back/forward
+      // buttons.
+      SetHistoryEntry(&mLSHE, aLoadState->SHEntry());
 
       // Set the doc's URI according to the new history entry's URI.
       nsCOMPtr<nsIDocument> doc = GetDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
-      doc->SetDocumentURI(aURI);
+      doc->SetDocumentURI(aLoadState->URI());
 
       /* This is a anchor traversal with in the same page.
        * call OnNewURI() so that, this traversal will be
        * recorded in session and global history.
        */
       nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal,
           newURIPrincipalToInherit;
       if (mOSHE) {
         newURITriggeringPrincipal = mOSHE->GetTriggeringPrincipal();
         newURIPrincipalToInherit = mOSHE->GetPrincipalToInherit();
       } else {
-        newURITriggeringPrincipal = aTriggeringPrincipal;
+        newURITriggeringPrincipal = aLoadState->TriggeringPrincipal();
         newURIPrincipalToInherit = doc->NodePrincipal();
       }
       // Pass true for aCloneSHChildren, since we're not
       // changing documents here, so all of our subframes are
       // still relevant to the new session history entry.
       //
       // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
       // flag on firing onLocationChange(...).
       // Anyway, aCloneSHChildren param is simply reflecting
       // doShortCircuitedLoad in this scope.
-      OnNewURI(aURI, nullptr, newURITriggeringPrincipal,
+      OnNewURI(aLoadState->URI(), nullptr, newURITriggeringPrincipal,
                newURIPrincipalToInherit, mLoadType, true, true, true);
 
       nsCOMPtr<nsIInputStream> postData;
       uint32_t cacheKey = 0;
 
       bool scrollRestorationIsManual = false;
       if (mOSHE) {
         /* save current position of scroller(s) (bug 59774) */
         mOSHE->SetScrollPosition(cx, cy);
         scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
         // Get the postdata and page ident from the current page, if
         // the new load is being done via normal means.  Note that
         // "normal means" can be checked for just by checking for
         // LOAD_CMD_NORMAL, given the loadType and allowScroll check
         // above -- it filters out some LOAD_CMD_NORMAL cases that we
         // wouldn't want here.
-        if (aLoadType & LOAD_CMD_NORMAL) {
+        if (aLoadState->LoadType() & LOAD_CMD_NORMAL) {
           postData = mOSHE->GetPostData();
           cacheKey = mOSHE->GetCacheKey();
 
           // Link our new SHEntry to the old SHEntry's back/forward
           // cache data, since the two SHEntries correspond to the
           // same document.
           if (mLSHE) {
-            if (!aSHEntry) {
+            if (!aLoadState->SHEntry()) {
               // If we're not doing a history load, scroll restoration
               // should be inherited from the previous session history entry.
               mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
             }
             mLSHE->AdoptBFCacheEntry(mOSHE);
           }
         }
       }
 
       // If we're doing a history load, use its scroll restoration state.
-      if (aSHEntry) {
-        scrollRestorationIsManual = aSHEntry->GetScrollRestorationIsManual();
-      }
-
-      /* Assign mOSHE to mLSHE. This will either be a new entry created
-       * by OnNewURI() for normal loads or aSHEntry for history loads.
+      if (aLoadState->SHEntry()) {
+        scrollRestorationIsManual =
+            aLoadState->SHEntry()->GetScrollRestorationIsManual();
+      }
+
+      /* Assign mLSHE to mOSHE. This will either be a new entry created
+       * by OnNewURI() for normal loads or aLoadState->SHEntry() for history
+       * loads.
        */
       if (mLSHE) {
         SetHistoryEntry(&mOSHE, mLSHE);
         // Save the postData obtained from the previous page
         // in to the session history entry created for the
         // anchor page, so that any history load of the anchor
         // page will restore the appropriate postData.
         if (postData) {
@@ -9397,45 +9357,48 @@ nsresult nsDocShell::InternalLoad(
         mSessionHistory->LegacySHistory()->GetEntryAtIndex(
             index, getter_AddRefs(shEntry));
         NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
         shEntry->SetTitle(mTitle);
       }
 
       /* Set the title for the Global History entry for this anchor url.
        */
-      UpdateGlobalHistoryTitle(aURI);
+      UpdateGlobalHistoryTitle(aLoadState->URI());
 
       SetDocCurrentStateObj(mOSHE);
 
       // Inform the favicon service that the favicon for oldURI also
-      // applies to aURI.
-      CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
+      // applies to aLoadState->URI().
+      CopyFavicon(currentURI, aLoadState->URI(), doc->NodePrincipal(),
+                  UsePrivateBrowsing());
 
       RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal;
       RefPtr<nsGlobalWindowInner> win =
           scriptGlobal ? scriptGlobal->GetCurrentInnerWindowInternal()
                        : nullptr;
 
       // ScrollToAnchor doesn't necessarily cause us to scroll the window;
       // the function decides whether a scroll is appropriate based on the
       // arguments it receives.  But even if we don't end up scrolling,
       // ScrollToAnchor performs other important tasks, such as informing
       // the presShell that we have a new hash.  See bug 680257.
-      rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
+      rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash,
+                          aLoadState->LoadType());
       NS_ENSURE_SUCCESS(rv, rv);
 
       /* restore previous position of scroller(s), if we're moving
        * back in history (bug 59774)
        */
       nscoord bx = 0;
       nscoord by = 0;
       bool needsScrollPosUpdate = false;
       if (mOSHE &&
-          (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) &&
+          (aLoadState->LoadType() == LOAD_HISTORY ||
+           aLoadState->LoadType() == LOAD_RELOAD_NORMAL) &&
           !scrollRestorationIsManual) {
         needsScrollPosUpdate = true;
         mOSHE->GetScrollPosition(&bx, &by);
       }
 
       // Dispatch the popstate and hashchange events, as appropriate.
       //
       // The event dispatch below can cause us to re-enter script and
@@ -9452,17 +9415,17 @@ nsresult nsDocShell::InternalLoad(
 
         if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) {
           SetCurScrollPosEx(bx, by);
         }
 
         if (doHashchange) {
           // Note that currentURI hasn't changed because it's on the
           // stack, so we can just use it directly as the old URI.
-          win->DispatchAsyncHashchange(currentURI, aURI);
+          win->DispatchAsyncHashchange(currentURI, aLoadState->URI());
         }
       }
 
       return NS_OK;
     }
   }
 
   // mContentViewer->PermitUnload can destroy |this| docShell, which
@@ -9476,45 +9439,47 @@ nsresult nsDocShell::InternalLoad(
   // timing then, from OnStateChange.
 
   // XXXbz mTiming should know what channel it's for, so we don't
   // need this hackery.
   bool toBeReset = false;
   if (!isJavaScript) {
     toBeReset = MaybeInitTiming();
   }
-  bool timeBeforeUnload = aFileName.IsVoid();
-  if (mTiming && timeBeforeUnload) {
+  bool isNotDownload = aLoadState->FileName().IsVoid();
+  if (mTiming && isNotDownload) {
     mTiming->NotifyBeforeUnload();
   }
   // Check if the page doesn't want to be unloaded. The javascript:
   // protocol handler deals with this for javascript: URLs.
-  if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
+  if (!isJavaScript && isNotDownload && mContentViewer) {
     bool okToUnload;
     rv = mContentViewer->PermitUnload(&okToUnload);
 
     if (NS_SUCCEEDED(rv) && !okToUnload) {
       // The user chose not to unload the page, interrupt the
       // load.
       MaybeResetInitTiming(toBeReset);
       return NS_OK;
     }
   }
 
-  if (mTiming && timeBeforeUnload) {
+  if (mTiming && isNotDownload) {
     mTiming->NotifyUnloadAccepted(mCurrentURI);
   }
 
   // Check if the webbrowser chrome wants the load to proceed; this can be
   // used to cancel attempts to load URIs in the wrong process.
   nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
   if (browserChrome3) {
     bool shouldLoad;
-    rv = browserChrome3->ShouldLoadURI(this, aURI, aReferrer, !!aPostData,
-                                       aTriggeringPrincipal, &shouldLoad);
+    rv = browserChrome3->ShouldLoadURI(
+        this, aLoadState->URI(), aLoadState->Referrer(),
+        !!aLoadState->PostDataStream(), aLoadState->TriggeringPrincipal(),
+        &shouldLoad);
     if (NS_SUCCEEDED(rv) && !shouldLoad) {
       return NS_OK;
     }
   }
 
   // Whenever a top-level browsing context is navigated, the user agent MUST
   // lock the orientation of the document to the document's default
   // orientation. We don't explicitly check for a top-level browsing context
@@ -9533,142 +9498,151 @@ nsresult nsDocShell::InternalLoad(
   }
 
   // Check for saving the presentation here, before calling Stop().
   // This is necessary so that we can catch any pending requests.
   // Since the new request has not been created yet, we pass null for the
   // new request parameter.
   // Also pass nullptr for the document, since it doesn't affect the return
   // value for our purposes here.
-  bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
+  bool savePresentation =
+      CanSavePresentation(aLoadState->LoadType(), nullptr, nullptr);
 
   // Don't stop current network activity for javascript: URL's since
   // they might not result in any data, and thus nothing should be
   // stopped in those cases. In the case where they do result in
   // data, the javascript: URL channel takes care of stopping
   // current network activity.
-  if (!isJavaScript && aFileName.IsVoid()) {
+  if (!isJavaScript && isNotDownload) {
     // Stop any current network activity.
     // Also stop content if this is a zombie doc. otherwise
     // the onload will be delayed by other loads initiated in the
     // background by the first document that
     // didn't fully load before the next load was initiated.
     // If not a zombie, don't stop content until data
     // starts arriving from the new URI...
 
     if ((mContentViewer && mContentViewer->GetPreviousViewer()) ||
-        LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
+        LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(), LOAD_FLAGS_STOP_CONTENT)) {
       rv = Stop(nsIWebNavigation::STOP_ALL);
     } else {
       rv = Stop(nsIWebNavigation::STOP_NETWORK);
     }
 
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
-  mLoadType = aLoadType;
-
-  // mLSHE should be assigned to aSHEntry, only after Stop() has
+  mLoadType = aLoadState->LoadType();
+
+  // aLoadState->SHEntry() should be assigned to mLSHE, only after Stop() has
   // been called. But when loading an error page, do not clear the
   // mLSHE for the real page.
   if (mLoadType != LOAD_ERROR_PAGE) {
-    SetHistoryEntry(&mLSHE, aSHEntry);
-    if (aSHEntry) {
+    SetHistoryEntry(&mLSHE, aLoadState->SHEntry());
+    if (aLoadState->SHEntry()) {
       // We're making history navigation or a reload. Make sure our history ID
       // points to the same ID as SHEntry's docshell ID.
-      mHistoryID = aSHEntry->DocshellID();
+      mHistoryID = aLoadState->SHEntry()->DocshellID();
     }
   }
 
   mSavingOldViewer = savePresentation;
 
   // If we have a saved content viewer in history, restore and show it now.
-  if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
+  if (aLoadState->SHEntry() && (mLoadType & LOAD_CMD_HISTORY)) {
     // It's possible that the previous viewer of mContentViewer is the
-    // viewer that will end up in aSHEntry when it gets closed.  If that's
-    // the case, we need to go ahead and force it into its shentry so we
+    // viewer that will end up in aLoadState->SHEntry() when it gets closed.  If
+    // that's the case, we need to go ahead and force it into its shentry so we
     // can restore it.
     if (mContentViewer) {
       nsCOMPtr<nsIContentViewer> prevViewer =
           mContentViewer->GetPreviousViewer();
       if (prevViewer) {
 #ifdef DEBUG
         nsCOMPtr<nsIContentViewer> prevPrevViewer =
             prevViewer->GetPreviousViewer();
         NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
 #endif
         nsCOMPtr<nsISHEntry> viewerEntry;
         prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
-        if (viewerEntry == aSHEntry) {
+        if (viewerEntry == aLoadState->SHEntry()) {
           // Make sure this viewer ends up in the right place
           mContentViewer->SetPreviousViewer(nullptr);
           prevViewer->Destroy();
         }
       }
     }
     nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
     bool restoring;
-    rv = RestorePresentation(aSHEntry, &restoring);
+    rv = RestorePresentation(aLoadState->SHEntry(), &restoring);
     if (restoring) {
       return rv;
     }
 
     // We failed to restore the presentation, so clean up.
     // Both the old and new history entries could potentially be in
     // an inconsistent state.
     if (NS_FAILED(rv)) {
       if (oldEntry) {
         oldEntry->SyncPresentationState();
       }
 
-      aSHEntry->SyncPresentationState();
+      aLoadState->SHEntry()->SyncPresentationState();
     }
   }
 
   nsAutoString srcdoc;
-  if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) {
-    srcdoc = aSrcdoc;
+  if (aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC)) {
+    srcdoc = aLoadState->SrcdocData();
   } else {
     srcdoc = VoidString();
   }
 
   bool isTopLevelDoc = mItemType == typeContent &&
                        (isTargetTopLevelDocShell || GetIsMozBrowser());
 
   OriginAttributes attrs = GetOriginAttributes();
-  attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
-
-  PredictorLearn(aURI, nullptr, nsINetworkPredictor::LEARN_LOAD_TOPLEVEL,
-                 attrs);
-  PredictorPredict(aURI, nullptr, nsINetworkPredictor::PREDICT_LOAD, attrs,
-                   nullptr);
+  attrs.SetFirstPartyDomain(isTopLevelDoc, aLoadState->URI());
+
+  PredictorLearn(aLoadState->URI(), nullptr,
+                 nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
+  PredictorPredict(aLoadState->URI(), nullptr,
+                   nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
+
+  Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
+  aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
 
   nsCOMPtr<nsIRequest> req;
   rv = DoURILoad(
-      aURI, aOriginalURI, aResultPrincipalURI, aKeepResultPrincipalURIIfSet,
-      aLoadReplace, aIsFromProcessingFrameAttributes, loadFromExternal,
-      (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
-      (aFlags & INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC), aReferrer,
-      !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), aReferrerPolicy,
-      aTriggeringPrincipal, principalToInherit, aTypeHint, aFileName, aPostData,
-      aHeadersData, aFirstParty, aDocShell, getter_AddRefs(req),
-      (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
-      (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
-      (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0, srcdoc, aBaseURI,
-      contentType);
+      aLoadState->URI(), aLoadState->OriginalURI(), resultPrincipalURI,
+      aLoadState->KeepResultPrincipalURIIfSet(), aLoadState->LoadReplace(),
+      aLoadState->GetIsFromProcessingFrameAttributes(), loadFromExternal,
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC),
+      aLoadState->Referrer(),
+      !(aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)),
+      aLoadState->ReferrerPolicy(), aLoadState->TriggeringPrincipal(),
+      aLoadState->PrincipalToInherit(), aLoadState->TypeHint(),
+      aLoadState->FileName(), aLoadState->PostDataStream(),
+      aLoadState->HeadersStream(), aLoadState->FirstParty(), aDocShell,
+      getter_AddRefs(req),
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FIRST_LOAD),
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER),
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES), srcdoc,
+      aLoadState->BaseURI(), contentType);
   if (req && aRequest) {
     NS_ADDREF(*aRequest = req);
   }
 
   if (NS_FAILED(rv)) {
     nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
-    if (DisplayLoadError(rv, aURI, nullptr, chan) &&
-        (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
+    if (DisplayLoadError(rv, aLoadState->URI(), nullptr, chan) &&
+        aLoadState->HasLoadFlags(LOAD_FLAGS_ERROR_LOAD_CHANGES_RV)) {
       return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
     }
 
     // We won't report any error if this is an unknown protocol error. The
     // reason behind this is that it will allow enumeration of external
     // protocols if we report an error for each unknown protocol.
     if (NS_ERROR_UNKNOWN_PROTOCOL == rv) {
       return NS_OK;
@@ -11663,31 +11637,36 @@ nsresult nsDocShell::LoadHistoryEntry(ns
   }
 
   // Passing nullptr as aSourceDocShell gives the same behaviour as before
   // aSourceDocShell was introduced. According to spec we should be passing
   // the source browsing context that was used when the history entry was
   // first created. bug 947716 has been created to address this issue.
   Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
   emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
-  rv = InternalLoad(uri, originalURI, emplacedResultPrincipalURI, false,
-                    loadReplace,
-                    false,  // IsFromProcessingFrameAttributes
-                    referrerURI, referrerPolicy, triggeringPrincipal,
-                    principalToInherit, flags,
-                    EmptyString(),  // No window target
-                    contentType,    // Type hint
-                    VoidString(),   // No forced file download
-                    postData,       // Post data stream
-                    nullptr,        // No headers stream
-                    aLoadType,      // Load type
-                    aEntry,         // SHEntry
-                    true, srcdoc,
-                    nullptr,  // Source docshell, see comment above
-                    baseURI,
+
+  RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
+  loadState->SetURI(uri);
+  loadState->SetOriginalURI(originalURI);
+  loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
+  loadState->SetLoadReplace(loadReplace);
+  loadState->SetReferrer(referrerURI);
+  loadState->SetReferrerPolicy((mozilla::net::ReferrerPolicy)referrerPolicy);
+  loadState->SetTriggeringPrincipal(triggeringPrincipal);
+  loadState->SetPrincipalToInherit(principalToInherit);
+  loadState->SetLoadFlags(flags);
+  loadState->SetTypeHint(contentType);
+  loadState->SetPostDataStream(postData);
+  loadState->SetLoadType(aLoadType);
+  loadState->SetSHEntry(aEntry);
+  loadState->SetFirstParty(true);
+  loadState->SetSrcdocData(srcdoc);
+  loadState->SetBaseURI(baseURI);
+
+  rv = InternalLoad(loadState,
                     nullptr,   // No nsIDocShell
                     nullptr);  // No nsIRequest
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetShouldSaveLayoutState(bool* aShould) {
   *aShould = false;
@@ -12777,39 +12756,33 @@ nsDocShell::OnLinkClickSync(nsIContent* 
   bool inOnLoadHandler = false;
   GetIsExecutingOnLoadHandler(&inOnLoadHandler);
   uint32_t loadType = inOnLoadHandler ? LOAD_NORMAL_REPLACE : LOAD_LINK;
 
   if (aIsUserTriggered) {
     flags |= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED;
   }
 
-  nsresult rv =
-      InternalLoad(aURI,       // New URI
-                   nullptr,    // Original URI
-                   Nothing(),  // Let the protocol handler assign it
-                   false,
-                   false,          // LoadReplace
-                   false,          // IsFromProcessingFrameAttributes
-                   referer,        // Referer URI
-                   refererPolicy,  // Referer policy
-                   triggeringPrincipal, aContent->NodePrincipal(), flags,
-                   aTargetSpec,  // Window target
-                   NS_LossyConvertUTF16toASCII(typeHint),
-                   aFileName,           // Download as file
-                   aPostDataStream,     // Post data stream
-                   aHeadersDataStream,  // Headers stream
-                   loadType,            // Load type
-                   nullptr,             // No SHEntry
-                   true,                // first party site
-                   VoidString(),        // No srcdoc
-                   this,                // We are the source
-                   nullptr,             // baseURI not needed
-                   aDocShell,           // DocShell out-param
-                   aRequest);           // Request out-param
+  RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
+  loadState->SetURI(aURI);
+  loadState->SetReferrer(referer);
+  loadState->SetReferrerPolicy((mozilla::net::ReferrerPolicy)refererPolicy);
+  loadState->SetTriggeringPrincipal(triggeringPrincipal);
+  loadState->SetPrincipalToInherit(aContent->NodePrincipal());
+  loadState->SetLoadFlags(flags);
+  loadState->SetTarget(aTargetSpec);
+  loadState->SetTypeHint(NS_ConvertUTF16toUTF8(typeHint));
+  loadState->SetFileName(aFileName);
+  loadState->SetPostDataStream(aPostDataStream);
+  loadState->SetHeadersStream(aHeadersDataStream);
+  loadState->SetLoadType(loadType);
+  loadState->SetFirstParty(true);
+  loadState->SetSourceDocShell(this);
+  nsresult rv = InternalLoad(loadState, aDocShell, aRequest);
+
   if (NS_SUCCEEDED(rv)) {
     nsPingListener::DispatchPings(this, aContent, aURI, referer, refererPolicy);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::OnOverLink(nsIContent* aContent, nsIURI* aURI,
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -384,93 +384,22 @@ class nsDocShell final : public nsDocLoa
   bool IsForceReloading();
 
   /**
    * Native getter for a DocShell's BrowsingContext.
    */
   mozilla::dom::BrowsingContext* GetBrowsingContext() const;
 
   /**
-   * Loads the given URI. This method is identical to nsIDocShell::loadURI(...)
-   * except that its parameter list is broken out instead of being packaged
-   * inside of an nsIDocShellLoadInfo object...
-   *
-   * @param aURI                 - The URI to load.
-   * @param aOriginalURI         - The URI to set as the originalURI on the channel
-   *                               that does the load. If null, aURI will be set as
-   *                               the originalURI.
-   * @param aResultPrincipalURI  - The URI to be set to loadInfo.resultPrincipalURI
-   *                               When Nothing, there will be no change
-   *                               When Some, the principal URI will overwrite even
-   *                               with a null value.
-   * @param aKeepResultPrincipalURIIfSet - If a refresh is caused by
-   *                                       http-equiv="refresh" we want to set
-   *                                       aResultPrincipalURI, but we do not want
-   *                                       to overwrite the channel's
-   *                                       ResultPrincipalURI, if it has already
-   *                                       been set on the channel by a protocol
-   *                                       handler.
-   * @param aLoadReplace         - If set LOAD_REPLACE flag will be set on the
-   *                               channel. aOriginalURI is null, this argument is
-   *                               ignored.
-   * @param aIsFromProcessingFrameAttributes
-   *                             - If this is a load triggered by changing frame
-   *                               attributes.
-   * @param aReferrer            - Referring URI
-   * @param aReferrerPolicy      - Referrer policy
-   * @param aTriggeringPrincipal - A non-null principal that initiated that load.
-   *                               Please note that this is the principal that is
-   *                               used for security checks. If the argument aURI
-   *                               is provided by the web, then please do not pass
-   *                               a SystemPrincipal as the triggeringPrincipal.
-   * @param aPrincipalToInherit  - Principal to be inherited for that load. If this
-   *                               argument is null then principalToInherit is
-   *                               computed as follows:
-   *                               a) If INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL, and
-   *                                  aLoadType is not LOAD_NORMAL_EXTERNAL, and the
-   *                                  URI would normally inherit a principal, then
-   *                                  principalToInherit is set to the current
-   *                                  document's principal, or parent document if
-   *                                  there is not a current document.
-   *                               b) If principalToInherit is still null (e.g. if
-   *                                  some of the conditions of (a) were not satisfied),
-   *                                  then no inheritance of any sort will happen: the
-   *                                  load will just get a principal based on the URI
-   *                                  being loaded.
-   * @param aFlags               - Any of the load flags defined within above.
-   * @param aWindowTarget        - Window target for the load.
-   * @param aTypeHint            - A hint as to the content-type of the resulting
-   *                               data.  May be null or empty if no hint.
-   * @param aFileName            - Non-null when the link should be downloaded as
-   *                               the given filename.
-   * @param aPostDataStream      - Post data stream (if POSTing)
-   * @param aHeadersStream       - Stream containing "extra" request headers...
-   * @param aLoadFlags           - Flags to modify load behaviour. Flags are defined
-   *                               in nsIWebNavigation.
-   * @param aSHEntry             - Active Session History entry (if loading from SH)
-   * @param aSrcdoc                When INTERNAL_LOAD_FLAGS_IS_SRCDOC is set, the
-   *                               contents of this parameter will be loaded instead
-   *                               of aURI.
-   * @param aSourceDocShell      - The source browsing context for the navigation.
-   * @param aBaseURI             - The base URI to be used for the load.  Set in
-   *                               srcdoc loads as it cannot otherwise be inferred
-   *                               in certain situations such as view-source.
+   * Loads the given URI. See comments on nsDocShellLoadState members for more
+   * information on information used. aDocShell and aRequest come from
+   * onLinkClickSync, which is triggered during form submission.
    */
-  nsresult InternalLoad(
-      nsIURI* aURI, nsIURI* aOriginalURI,
-      mozilla::Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
-      bool aKeepResultPrincipalURIIfSet, bool aLoadReplace,
-      bool aIsFromProcessingFrameAttributes, nsIURI* aReferrer,
-      uint32_t aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
-      nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
-      const nsAString& aWindowTarget, const nsACString& aTypeHint,
-      const nsAString& aFileName, nsIInputStream* aPostData,
-      nsIInputStream* aHeadersData, uint32_t aLoadType, nsISHEntry* aSHEntry,
-      bool aFirstParty, const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
-      nsIURI* aBaseURI, nsIDocShell** aDocShell, nsIRequest** aRequest);
+  nsresult InternalLoad(nsDocShellLoadState* aLoadState,
+                        nsIDocShell** aDocShell, nsIRequest** aRequest);
 
  private:  // member functions
   friend class nsDSURIContentListener;
   friend class FramingChecker;
   friend class OnLinkClickEvent;
   friend class nsIDocShell;
 
   // It is necessary to allow adding a timeline marker wherever a docshell
--- a/docshell/base/nsDocShellLoadState.cpp
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -19,22 +19,22 @@ nsDocShellLoadState::nsDocShellLoadState
       mLoadReplace(false),
       mInheritPrincipal(false),
       mPrincipalIsExplicit(false),
       mForceAllowDataURI(false),
       mOriginalFrameSrc(false),
       mSendReferrer(true),
       mReferrerPolicy(mozilla::net::RP_Unset),
       mLoadType(LOAD_NORMAL),
-      mIsSrcdocLoad(false),
+      mTarget(),
+      mSrcdocData(VoidString()),
       mLoadFlags(0),
       mFirstParty(false),
       mTypeHint(VoidCString()),
       mFileName(VoidString()),
-      mDocShellInternalLoadFlags(0),
       mIsFromProcessingFrameAttributes(false) {}
 
 nsDocShellLoadState::~nsDocShellLoadState() {}
 
 nsIURI* nsDocShellLoadState::Referrer() const { return mReferrer; }
 
 void nsDocShellLoadState::SetReferrer(nsIURI* aReferrer) {
   mReferrer = aReferrer;
@@ -161,30 +161,29 @@ void nsDocShellLoadState::SetHeadersStre
 }
 
 bool nsDocShellLoadState::SendReferrer() const { return mSendReferrer; }
 
 void nsDocShellLoadState::SetSendReferrer(bool aSendReferrer) {
   mSendReferrer = aSendReferrer;
 }
 
-uint32_t nsDocShellLoadState::ReferrerPolicy() const { return mReferrerPolicy; }
+mozilla::net::ReferrerPolicy nsDocShellLoadState::ReferrerPolicy() const {
+  return mReferrerPolicy;
+}
 
 void nsDocShellLoadState::SetReferrerPolicy(
     mozilla::net::ReferrerPolicy aReferrerPolicy) {
   mReferrerPolicy = aReferrerPolicy;
 }
 
-bool nsDocShellLoadState::IsSrcdocLoad() const { return mIsSrcdocLoad; }
-
 const nsString& nsDocShellLoadState::SrcdocData() const { return mSrcdocData; }
 
 void nsDocShellLoadState::SetSrcdocData(const nsAString& aSrcdocData) {
   mSrcdocData = aSrcdocData;
-  mIsSrcdocLoad = true;
 }
 
 nsIDocShell* nsDocShellLoadState::SourceDocShell() const {
   return mSourceDocShell;
 }
 
 void nsDocShellLoadState::SetSourceDocShell(nsIDocShell* aSourceDocShell) {
   mSourceDocShell = aSourceDocShell;
@@ -214,16 +213,26 @@ void nsDocShellLoadState::SetMaybeResult
 }
 
 uint32_t nsDocShellLoadState::LoadFlags() const { return mLoadFlags; }
 
 void nsDocShellLoadState::SetLoadFlags(uint32_t aLoadFlags) {
   mLoadFlags = aLoadFlags;
 }
 
+void nsDocShellLoadState::SetLoadFlag(uint32_t aFlag) { mLoadFlags |= aFlag; }
+
+void nsDocShellLoadState::UnsetLoadFlag(uint32_t aFlag) {
+  mLoadFlags &= ~aFlag;
+}
+
+bool nsDocShellLoadState::HasLoadFlags(uint32_t aFlags) {
+  return (mLoadFlags & aFlags) == aFlags;
+}
+
 bool nsDocShellLoadState::FirstParty() const { return mFirstParty; }
 
 void nsDocShellLoadState::SetFirstParty(bool aFirstParty) {
   mFirstParty = aFirstParty;
 }
 
 const nsCString& nsDocShellLoadState::TypeHint() const { return mTypeHint; }
 
@@ -232,24 +241,16 @@ void nsDocShellLoadState::SetTypeHint(co
 }
 
 const nsString& nsDocShellLoadState::FileName() const { return mFileName; }
 
 void nsDocShellLoadState::SetFileName(const nsAString& aFileName) {
   mFileName = aFileName;
 }
 
-uint32_t nsDocShellLoadState::DocShellInternalLoadFlags() const {
-  return mDocShellInternalLoadFlags;
-}
-
-void nsDocShellLoadState::SetDocShellInternalLoadFlags(uint32_t aFlags) {
-  mDocShellInternalLoadFlags = aFlags;
-}
-
 nsresult nsDocShellLoadState::SetupInheritingPrincipal(
     uint32_t aItemType, const mozilla::OriginAttributes& aOriginAttributes) {
   // We need a principalToInherit.
   //
   // If principalIsExplicit is not set there are 4 possibilities:
   // (1) If the system principal or an expanded principal was passed
   //     in and we're a typeContent docshell, inherit the principal
   //     from the current document instead.
@@ -334,57 +335,50 @@ nsresult nsDocShellLoadState::SetupTrigg
       }
     } else {
       mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
     }
   }
   return NS_OK;
 }
 
-void nsDocShellLoadState::CalculateDocShellInternalLoadFlags() {
-  MOZ_ASSERT(mDocShellInternalLoadFlags == 0,
-             "Shouldn't have any load flags set at this point.");
+void nsDocShellLoadState::CalculateLoadURIFlags() {
+  uint32_t oldLoadFlags = mLoadFlags;
+  mLoadFlags = 0;
 
   if (mInheritPrincipal) {
     MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(mPrincipalToInherit),
                "Should not inherit SystemPrincipal");
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
   }
 
   if (!mSendReferrer) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
   }
 
-  if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+  if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
   }
 
-  if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
-    mDocShellInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
+  if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
   }
 
-  if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
+  if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
   }
 
-  if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
+  if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
   }
 
-  if (mIsSrcdocLoad) {
-    mDocShellInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+  if (!mSrcdocData.IsVoid()) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
   if (mForceAllowDataURI) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
   }
 
   if (mOriginalFrameSrc) {
-    mDocShellInternalLoadFlags |=
-        nsDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
   }
 }
--- a/docshell/base/nsDocShellLoadState.h
+++ b/docshell/base/nsDocShellLoadState.h
@@ -102,17 +102,17 @@ class nsDocShellLoadState final {
   nsIInputStream* HeadersStream() const;
 
   void SetHeadersStream(nsIInputStream* aHeadersStream);
 
   bool SendReferrer() const;
 
   void SetSendReferrer(bool aSendReferrer);
 
-  uint32_t ReferrerPolicy() const;
+  mozilla::net::ReferrerPolicy ReferrerPolicy() const;
 
   void SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy);
 
   bool IsSrcdocLoad() const;
 
   const nsString& SrcdocData() const;
 
   void SetSrcdocData(const nsAString& aSrcdocData);
@@ -133,32 +133,34 @@ class nsDocShellLoadState final {
 
   void SetMaybeResultPrincipalURI(
       mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI);
 
   uint32_t LoadFlags() const;
 
   void SetLoadFlags(uint32_t aFlags);
 
+  void SetLoadFlag(uint32_t aFlag);
+
+  void UnsetLoadFlag(uint32_t aFlag);
+
+  bool HasLoadFlags(uint32_t aFlag);
+
   bool FirstParty() const;
 
   void SetFirstParty(bool aFirstParty);
 
   const nsCString& TypeHint() const;
 
   void SetTypeHint(const nsCString& aTypeHint);
 
   const nsString& FileName() const;
 
   void SetFileName(const nsAString& aFileName);
 
-  uint32_t DocShellInternalLoadFlags() const;
-
-  void SetDocShellInternalLoadFlags(uint32_t aFlags);
-
   // Give the type of DocShell we're loading into (chrome/content/etc) and
   // origin attributes for the URI we're loading, figure out if we should
   // inherit our principal from the document the load was requested from, or
   // else if the principal should be set up later in the process (after loads).
   // See comments in function for more info on principal selection algorithm
   nsresult SetupInheritingPrincipal(
       uint32_t aItemType, const mozilla::OriginAttributes& aOriginAttributes);
 
@@ -173,66 +175,83 @@ class nsDocShellLoadState final {
   bool GetIsFromProcessingFrameAttributes() {
     return mIsFromProcessingFrameAttributes;
   }
 
   // When loading a document through nsDocShell::LoadURI(), a special set of
   // flags needs to be set based on other values in nsDocShellLoadState. This
   // function calculates those flags, before the LoadState is passed to
   // nsDocShell::InternalLoad.
-  void CalculateDocShellInternalLoadFlags();
+  void CalculateLoadURIFlags();
 
  protected:
   // Destructor can't be defaulted or inlined, as header doesn't have all type
   // includes it needs to do so.
   ~nsDocShellLoadState();
 
  protected:
   // This is the referrer for the load.
   nsCOMPtr<nsIURI> mReferrer;
 
   // The URI we are navigating to. Will not be null once set.
   nsCOMPtr<nsIURI> mURI;
 
-  // The originalURI to be passed to nsIDocShell.internalLoad. May be null.
+  // The URI to set as the originalURI on the channel that does the load. If
+  // null, aURI will be set as the originalURI.
   nsCOMPtr<nsIURI> mOriginalURI;
 
-  // Result principal URL from nsILoadInfo, may be null. Valid only if
-  // mResultPrincipalURIIsSome is true (has the same meaning as isSome() on
-  // mozilla::Maybe.)
+  // The URI to be set to loadInfo.resultPrincipalURI
+  // - When Nothing, there will be no change
+  // - When Some, the principal URI will overwrite even
+  //   with a null value.
+  //
+  // Valid only if mResultPrincipalURIIsSome is true (has the same meaning as
+  // isSome() on mozilla::Maybe.)
   nsCOMPtr<nsIURI> mResultPrincipalURI;
   bool mResultPrincipalURIIsSome;
 
   // The principal of the load, that is, the entity responsible for causing the
   // load to occur. In most cases the referrer and the triggeringPrincipal's URI
   // will be identical.
+  //
+  // Please note that this is the principal that is used for security checks. If
+  // the argument aURI is provided by the web, then please do not pass a
+  // SystemPrincipal as the triggeringPrincipal.
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
 
-  // if http-equiv="refresh" cause reload we do not want to replace
-  // ResultPrinicpalURI if it was already set.
+  // If a refresh is caused by http-equiv="refresh" we want to set
+  // aResultPrincipalURI, but we do not want to overwrite the channel's
+  // ResultPrincipalURI, if it has already been set on the channel by a protocol
+  // handler.
   bool mKeepResultPrincipalURIIfSet;
 
-  // loadReplace flag to be passed to nsIDocShell.internalLoad.
+  // If set LOAD_REPLACE flag will be set on the channel. If aOriginalURI is
+  // null, this argument is ignored.
   bool mLoadReplace;
 
   // If this attribute is true and no triggeringPrincipal is specified,
   // copy the principal from the referring document.
   bool mInheritPrincipal;
 
   // If this attribute is true only ever use the principal specified
   // by the triggeringPrincipal and inheritPrincipal attributes.
   // If there are security reasons for why this is unsafe, such
   // as trying to use a systemprincipal as the triggeringPrincipal
   // for a content docshell the load fails.
   bool mPrincipalIsExplicit;
 
   // Principal we're inheriting. If null, this means the principal should be
   // inherited from the current document. If set to NullPrincipal, the channel
-  // will fill in principal information later in the load. See internal function
-  // comments for more info.
+  // will fill in principal information later in the load. See internal comments
+  // of SetupInheritingPrincipal for more info.
+  //
+  // When passed to InternalLoad, If this argument is null then
+  // principalToInherit is computed differently. See nsDocShell::InternalLoad
+  // for more comments.
+
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
 
   // If this attribute is true, then a top-level navigation
   // to a data URI will be allowed.
   bool mForceAllowDataURI;
 
   // If this attribute is true, this load corresponds to a frame
   // element loading its original src (or srcdoc) attribute.
@@ -245,63 +264,54 @@ class nsDocShellLoadState final {
   // Referrer policy for the load. This attribute holds one of the values
   // (REFERRER_POLICY_*) defined in nsIHttpChannel.
   mozilla::net::ReferrerPolicy mReferrerPolicy;
 
   // Contains a load type as specified by the nsDocShellLoadTypes::load*
   // constants
   uint32_t mLoadType;
 
-  // SHEntry for this page
+  // Active Session History entry (if loading from SH)
   nsCOMPtr<nsISHEntry> mSHEntry;
 
   // Target for load, like _content, _blank etc.
   nsString mTarget;
 
-  // Post data
+  // Post data stream (if POSTing)
   nsCOMPtr<nsIInputStream> mPostDataStream;
 
   // Additional Headers
   nsCOMPtr<nsIInputStream> mHeadersStream;
 
-  // True if the docshell has been created to load an iframe where the srcdoc
-  // attribute has been set. Set when srcdocData is specified.
-  bool mIsSrcdocLoad;
-
   // When set, the load will be interpreted as a srcdoc load, where contents of
   // this string will be loaded instead of the URI. Setting srcdocData sets
   // isSrcdocLoad to true
   nsString mSrcdocData;
 
   // When set, this is the Source Browsing Context for the navigation.
   nsCOMPtr<nsIDocShell> mSourceDocShell;
 
   // Used for srcdoc loads to give view-source knowledge of the load's base URI
   // as this information isn't embedded in the load's URI.
   nsCOMPtr<nsIURI> mBaseURI;
 
-  // Set of Load Flags, taken from nsDocShellLoadTypes.h
+  // Set of Load Flags, taken from nsDocShellLoadTypes.h and nsIWebNavigation
   uint32_t mLoadFlags;
 
   // Is this a First Party Load?
   bool mFirstParty;
 
   // A hint as to the content-type of the resulting data. If no hint, IsVoid()
   // should return true.
   nsCString mTypeHint;
 
   // Non-void when the link should be downloaded as the given filename.
   // mFileName being non-void but empty means that no filename hint was
   // specified, but link should still trigger a download. If not a download,
   // mFileName.IsVoid() should return true.
   nsString mFileName;
 
-  // LoadFlags calculated in nsDocShell::LoadURI and passed to
-  // nsDocShell::InternalLoad, taken from the INTERNAL_LOAD consts in
-  // nsIDocShell.idl
-  uint32_t mDocShellInternalLoadFlags;
-
   // This will be true if this load is triggered by attribute changes.
   // See nsILoadInfo.isFromProcessingFrameAttributes
   bool mIsFromProcessingFrameAttributes;
 };
 
 #endif /* nsDocShellLoadState_h__ */