Bug 1185256 - Save originURI to the history. r=bz ba=ritu
authorDragana Damjanovic <dd.mozilla@gmail.com>
Wed, 02 Mar 2016 15:50:26 -0800
changeset 260971 532544c91db7f13c39be1b7b7c4461cd03126e9c
parent 260970 f4220254d5bd0851a439467da39ba431e0ce2804
child 260972 b3b151a6e08730e81227102fc2827fc9fd041ecf
push id294
push userkwierso@gmail.com
push dateWed, 02 Mar 2016 23:55:05 +0000
treeherdermozilla-esr38@dd4b90de8fd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1185256
milestone38.6.0
Bug 1185256 - Save originURI to the history. r=bz ba=ritu MozReview-Commit-ID: Lvh9C84RQUc
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadInfo.cpp
docshell/base/nsDocShellLoadInfo.h
docshell/base/nsIDocShell.idl
docshell/base/nsIDocShellLoadInfo.idl
docshell/shistory/public/nsISHEntry.idl
docshell/shistory/src/nsSHEntry.cpp
docshell/shistory/src/nsSHEntry.h
docshell/shistory/src/nsSHistory.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1020,16 +1020,17 @@ nsDocShell::DestroyChildren()
 //*****************************************************************************
 // nsDocShell::nsISupports
 //*****************************************************************************
 
 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
 
 NS_INTERFACE_MAP_BEGIN(nsDocShell)
+  NS_INTERFACE_MAP_ENTRY(nsIDocShell_ESR38_2)
   NS_INTERFACE_MAP_ENTRY(nsIDocShell_ESR38)
   NS_INTERFACE_MAP_ENTRY(nsIDocShell)
   NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
   NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   NS_INTERFACE_MAP_ENTRY(nsIScrollable)
   NS_INTERFACE_MAP_ENTRY(nsITextScroll)
   NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
@@ -1372,16 +1373,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
     return NS_OK; // JS may not handle returning of an error code
   }
 
   if (DoAppRedirectIfNeeded(aURI, aLoadInfo, aFirstParty)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> referrer;
+  nsCOMPtr<nsIURI> originalURI;
   nsCOMPtr<nsIInputStream> postStream;
   nsCOMPtr<nsIInputStream> headersStream;
   nsCOMPtr<nsISupports> owner;
   bool inheritOwner = false;
   bool ownerIsExplicit = false;
   bool sendReferrer = true;
   uint32_t referrerPolicy = mozilla::net::RP_Default;
   bool isSrcdoc = false;
@@ -1398,16 +1400,20 @@ nsDocShell::LoadURI(nsIURI* aURI,
   if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
       mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
     StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
   }
 
   // Extract the info from the DocShellLoadInfo struct...
   if (aLoadInfo) {
     aLoadInfo->GetReferrer(getter_AddRefs(referrer));
+    nsCOMPtr<nsIDocShellLoadInfo_ESR38> liESR38 = do_QueryInterface(aLoadInfo);
+    if (liESR38) {
+      liESR38->GetOriginalURI(getter_AddRefs(originalURI));
+    }
 
     nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
     aLoadInfo->GetLoadType(&lt);
     // Get the appropriate loadType from nsIDocShellLoadInfo type
     loadType = ConvertDocShellLoadInfoToLoadType(lt);
 
     aLoadInfo->GetOwner(getter_AddRefs(owner));
     aLoadInfo->GetInheritOwner(&inheritOwner);
@@ -1652,34 +1658,35 @@ nsDocShell::LoadURI(nsIURI* aURI,
   if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
     flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
   }
 
   if (isSrcdoc) {
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
-  return InternalLoad(aURI,
-                      referrer,
-                      referrerPolicy,
-                      owner,
-                      flags,
-                      target.get(),
-                      nullptr,      // No type hint
-                      NullString(), // No forced download
-                      postStream,
-                      headersStream,
-                      loadType,
-                      nullptr, // No SHEntry
-                      aFirstParty,
-                      srcdoc,
-                      sourceDocShell,
-                      baseURI,
-                      nullptr,  // No nsIDocShell
-                      nullptr); // No nsIRequest
+  return InternalLoad2(aURI,
+                       originalURI,
+                       referrer,
+                       referrerPolicy,
+                       owner,
+                       flags,
+                       target.get(),
+                       nullptr,      // No type hint
+                       NullString(), // No forced download
+                       postStream,
+                       headersStream,
+                       loadType,
+                       nullptr, // No SHEntry
+                       aFirstParty,
+                       srcdoc,
+                       sourceDocShell,
+                       baseURI,
+                       nullptr,  // No nsIDocShell
+                       nullptr); // No nsIRequest
 }
 
 NS_IMETHODIMP
 nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
                        const nsACString& aContentType,
                        const nsACString& aContentCharset,
                        nsIDocShellLoadInfo* aLoadInfo)
 {
@@ -5398,21 +5405,21 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
   // end of the URL, so append it last.
   errorPageUrl.AppendLiteral("&d=");
   errorPageUrl.AppendASCII(escapedDescription.get());
 
   nsCOMPtr<nsIURI> errorPageURI;
   rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return InternalLoad(errorPageURI, nullptr, mozilla::net::RP_Default,
-                      nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr,
-                      nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
-                      nullptr, true, NullString(), this, nullptr, nullptr,
-                      nullptr);
+  return InternalLoad2(errorPageURI, nullptr, nullptr, mozilla::net::RP_Default,
+                       nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr,
+                       nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
+                       nullptr, true, NullString(), this, nullptr, nullptr,
+                       nullptr);
 }
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags)
 {
   if (!IsNavigationAllowed()) {
     return NS_OK; // JS may not handle returning of an error code
   }
@@ -5448,44 +5455,54 @@ nsDocShell::Reload(uint32_t aReloadFlags
     nsCOMPtr<nsIDocument> doc(GetDocument());
 
     // Do not inherit owner from document
     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
     nsAutoString srcdoc;
     nsIPrincipal* principal = nullptr;
     nsAutoString contentTypeHint;
     nsCOMPtr<nsIURI> baseURI;
+    nsCOMPtr<nsIURI> originalURI;
     if (doc) {
       principal = doc->NodePrincipal();
       doc->GetContentType(contentTypeHint);
 
       if (doc->IsSrcdocDocument()) {
         doc->GetSrcdocData(srcdoc);
         flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
         baseURI = doc->GetBaseURI();
       }
-    }
-    rv = InternalLoad(mCurrentURI,
-                      mReferrerURI,
-                      mReferrerPolicy,
-                      principal,
-                      flags,
-                      nullptr,         // No window target
-                      NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
-                      NullString(),    // 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
+      nsCOMPtr<nsIChannel> chan = doc->GetChannel();
+      if (chan) {
+        nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
+        if (httpChan) {
+          httpChan->GetOriginalURI(getter_AddRefs(originalURI));
+        }
+      } 
+    }
+
+    rv = InternalLoad2(mCurrentURI,
+                       originalURI,
+                       mReferrerURI,
+                       mReferrerPolicy,
+                       principal,
+                       flags,
+                       nullptr,         // No window target
+                       NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
+                       NullString(),    // 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
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::Stop(uint32_t aStopFlags)
 {
@@ -9463,27 +9480,28 @@ CopyFavicon(nsIURI* aOldURI, nsIURI* aNe
 #endif
 }
 
 } // anonymous namespace
 
 class InternalLoadEvent : public nsRunnable
 {
 public:
-  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI,
+  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, nsIURI* aOriginalURI,
                     nsIURI* aReferrer, uint32_t aReferrerPolicy,
                     nsISupports* aOwner, uint32_t aFlags,
                     const char* aTypeHint, nsIInputStream* aPostData,
                     nsIInputStream* aHeadersData, uint32_t aLoadType,
                     nsISHEntry* aSHEntry, bool aFirstParty,
                     const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
                     nsIURI* aBaseURI)
     : mSrcdoc(aSrcdoc)
     , mDocShell(aDocShell)
     , mURI(aURI)
+    , mOriginalURI(aOriginalURI)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
     , mOwner(aOwner)
     , mPostData(aPostData)
     , mHeadersData(aHeadersData)
     , mSHEntry(aSHEntry)
     , mFlags(aFlags)
     , mLoadType(aLoadType)
@@ -9494,34 +9512,36 @@ public:
     // Make sure to keep null things null as needed
     if (aTypeHint) {
       mTypeHint = aTypeHint;
     }
   }
 
   NS_IMETHOD Run()
   {
-    return mDocShell->InternalLoad(mURI, mReferrer,
-                                   mReferrerPolicy,
-                                   mOwner, mFlags,
-                                   nullptr, mTypeHint.get(),
-                                   NullString(), mPostData, mHeadersData,
-                                   mLoadType, mSHEntry, mFirstParty,
-                                   mSrcdoc, mSourceDocShell, mBaseURI,
-                                   nullptr, nullptr);
+    return mDocShell->InternalLoad2(mURI, mOriginalURI,
+                                    mReferrer,
+                                    mReferrerPolicy,
+                                    mOwner, mFlags,
+                                    nullptr, mTypeHint.get(),
+                                    NullString(), mPostData, mHeadersData,
+                                    mLoadType, mSHEntry, mFirstParty,
+                                    mSrcdoc, mSourceDocShell, mBaseURI,
+                                    nullptr, nullptr);
   }
 
 private:
   // Use IDL strings so .get() returns null by default
   nsXPIDLString mWindowTarget;
   nsXPIDLCString mTypeHint;
   nsString mSrcdoc;
 
   nsRefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mReferrer;
   uint32_t mReferrerPolicy;
   nsCOMPtr<nsISupports> mOwner;
   nsCOMPtr<nsIInputStream> mPostData;
   nsCOMPtr<nsIInputStream> mHeadersData;
   nsCOMPtr<nsISHEntry> mSHEntry;
   uint32_t mFlags;
   uint32_t mLoadType;
@@ -9584,16 +9604,43 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                          nsISHEntry* aSHEntry,
                          bool aFirstParty,
                          const nsAString& aSrcdoc,
                          nsIDocShell* aSourceDocShell,
                          nsIURI* aBaseURI,
                          nsIDocShell** aDocShell,
                          nsIRequest** aRequest)
 {
+  return InternalLoad2(aURI, nullptr, aReferrer, aReferrerPolicy, aOwner,
+                       aFlags, aWindowTarget, aTypeHint, aFileName, aPostData,
+                       aHeadersData, aLoadType, aSHEntry, aFirstParty, aSrcdoc,
+                       aSourceDocShell, aBaseURI, aDocShell, aRequest);
+}
+
+NS_IMETHODIMP
+nsDocShell::InternalLoad2(nsIURI* aURI,
+                          nsIURI* aOriginalURI,
+                          nsIURI* aReferrer,
+                          uint32_t aReferrerPolicy,
+                          nsISupports* aOwner,
+                          uint32_t aFlags,
+                          const char16_t* aWindowTarget,
+                          const char* 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 rv = NS_OK;
   mOriginalUriString.Truncate();
 
 #ifdef PR_LOGGING
   if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
     nsAutoCString spec;
     if (aURI) {
       aURI->GetSpec(spec);
@@ -9831,34 +9878,58 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       targetDocShell = do_QueryInterface(webNav);
     }
 
     //
     // Transfer the load to the target DocShell...  Pass nullptr as the
     // window target name from to prevent recursive retargeting!
     //
     if (NS_SUCCEEDED(rv) && targetDocShell) {
-      rv = targetDocShell->InternalLoad(aURI,
-                                        aReferrer,
-                                        aReferrerPolicy,
-                                        owner,
-                                        aFlags,
-                                        nullptr,         // No window target
-                                        aTypeHint,
-                                        NullString(),    // No forced download
-                                        aPostData,
-                                        aHeadersData,
-                                        aLoadType,
-                                        aSHEntry,
-                                        aFirstParty,
-                                        aSrcdoc,
-                                        aSourceDocShell,
-                                        aBaseURI,
-                                        aDocShell,
-                                        aRequest);
+      nsCOMPtr<nsIDocShell_ESR38_2> dsESR38 = do_QueryInterface(targetDocShell);
+      if (dsESR38) {
+        rv = dsESR38->InternalLoad2(aURI,
+                                    aOriginalURI,
+                                    aReferrer,
+                                    aReferrerPolicy,
+                                    owner,
+                                    aFlags,
+                                    nullptr,         // No window target
+                                    aTypeHint,
+                                    NullString(),    // No forced download
+                                    aPostData,
+                                    aHeadersData,
+                                    aLoadType,
+                                    aSHEntry,
+                                    aFirstParty,
+                                    aSrcdoc,
+                                    aSourceDocShell,
+                                    aBaseURI,
+                                    aDocShell,
+                                    aRequest);
+      } else {
+        rv = targetDocShell->InternalLoad(aURI,
+                                          aReferrer,
+                                          aReferrerPolicy,
+                                          owner,
+                                          aFlags,
+                                          nullptr,         // No window target
+                                          aTypeHint,
+                                          NullString(),    // No forced download
+                                          aPostData,
+                                          aHeadersData,
+                                          aLoadType,
+                                          aSHEntry,
+                                          aFirstParty,
+                                          aSrcdoc,
+                                          aSourceDocShell,
+                                          aBaseURI,
+                                          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
@@ -9913,17 +9984,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // 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)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       }
 
       // Do this asynchronously
       nsCOMPtr<nsIRunnable> ev =
-        new InternalLoadEvent(this, aURI, aReferrer,
+        new InternalLoadEvent(this, aURI, aOriginalURI, aReferrer,
                               aReferrerPolicy, aOwner, aFlags,
                               aTypeHint, aPostData, aHeadersData,
                               aLoadType, aSHEntry, aFirstParty, aSrcdoc,
                               aSourceDocShell, aBaseURI);
       return NS_DispatchToCurrentThread(ev);
     }
 
     // Just ignore this load attempt
@@ -10371,17 +10442,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   }
 
   net::PredictorLearn(aURI, nullptr,
                       nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, this);
   net::PredictorPredict(aURI, nullptr,
                         nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
 
   nsCOMPtr<nsIRequest> req;
-  rv = DoURILoad(aURI, aReferrer,
+  rv = DoURILoad(aURI, aOriginalURI, aReferrer,
                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                  aReferrerPolicy,
                  owner, 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);
@@ -10445,16 +10516,17 @@ nsDocShell::GetInheritedPrincipal(bool a
     return docPrincipal;
   }
 
   return nullptr;
 }
 
 nsresult
 nsDocShell::DoURILoad(nsIURI* aURI,
+                      nsIURI* aOriginalURI,
                       nsIURI* aReferrerURI,
                       bool aSendReferrer,
                       uint32_t aReferrerPolicy,
                       nsISupports* aOwner,
                       const char* aTypeHint,
                       const nsAString& aFileName,
                       nsIInputStream* aPostData,
                       nsIInputStream* aHeadersData,
@@ -10652,17 +10724,22 @@ nsDocShell::DoURILoad(nsIURI* aURI,
   }
 
   // Make sure to give the caller a channel if we managed to create one
   // This is important for correct error page/session history interaction
   if (aRequest) {
     NS_ADDREF(*aRequest = channel);
   }
 
-  channel->SetOriginalURI(aURI);
+  if (aOriginalURI) {
+    channel->SetOriginalURI(aOriginalURI);
+  } else {
+    channel->SetOriginalURI(aURI);
+  }
+
   if (aTypeHint && *aTypeHint) {
     channel->SetContentType(nsDependentCString(aTypeHint));
     mContentTypeHint = aTypeHint;
   } else {
     mContentTypeHint.Truncate();
   }
 
   if (!aFileName.IsVoid()) {
@@ -11624,16 +11701,20 @@ nsDocShell::AddState(JS::Handle<JS::Valu
 
     // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
     // we'll just set mOSHE here.
     mOSHE = newSHEntry;
 
   } else {
     newSHEntry = mOSHE;
     newSHEntry->SetURI(newURI);
+    nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(newSHEntry);
+    if (entryESR38) {
+      entryESR38->SetOriginalURI(newURI);
+    }
   }
 
   // Step 4: Modify new/original session history entry and clear its POST
   // data, if there is any.
   newSHEntry->SetStateData(scContainer);
   newSHEntry->SetPostData(nullptr);
 
   // If this push/replaceState changed the document's current URI and the new
@@ -11816,16 +11897,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
 
     if (!entry) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Get the post data & referrer
   nsCOMPtr<nsIInputStream> inputStream;
+  nsCOMPtr<nsIURI> originalURI;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy = mozilla::net::RP_Default;
   nsCOMPtr<nsISupports> cacheKey;
   nsCOMPtr<nsISupports> owner = aOwner;
   bool expired = false;
   bool discardLayoutState = false;
   nsCOMPtr<nsICachingChannel> cacheChannel;
   if (aChannel) {
@@ -11843,16 +11925,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
     if (!httpChannel) {
       GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
     }
     if (httpChannel) {
       nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
       if (uploadChannel) {
         uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
       }
+      httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
       httpChannel->GetReferrer(getter_AddRefs(referrerURI));
       httpChannel->GetReferrerPolicy(&referrerPolicy);
 
       discardLayoutState = ShouldDiscardLayoutState(httpChannel);
     }
     aChannel->GetOwner(getter_AddRefs(owner));
     if (!owner) {
       nsCOMPtr<nsILoadInfo> loadInfo;
@@ -11875,16 +11958,21 @@ nsDocShell::AddToSessionHistory(nsIURI* 
                 EmptyString(),     // Title
                 inputStream,       // Post data stream
                 nullptr,           // LayoutHistory state
                 cacheKey,          // CacheKey
                 mContentTypeHint,  // Content-type
                 owner,             // Channel or provided owner
                 mHistoryID,
                 mDynamicallyCreated);
+
+  nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(entry);
+  if (entryESR38) {
+    entryESR38->SetOriginalURI(originalURI);
+  }
   entry->SetReferrerURI(referrerURI);
   entry->SetReferrerPolicy(referrerPolicy);
   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
   if (inStrmChan) {
     bool isSrcdocChannel;
     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
     if (isSrcdocChannel) {
       nsAutoString srcdoc;
@@ -11976,25 +12064,32 @@ nsDocShell::AddToSessionHistory(nsIURI* 
 nsresult
 nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
 {
   if (!IsNavigationAllowed()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> uri;
+  nsCOMPtr<nsIURI> originalURI;
   nsCOMPtr<nsIInputStream> postData;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy;
   nsAutoCString contentType;
   nsCOMPtr<nsISupports> owner;
 
   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
 
   NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsISHEntry_ESR38> entryESR38 = do_QueryInterface(aEntry);
+  if (entryESR38) {
+    NS_ENSURE_SUCCESS(entryESR38->GetOriginalURI(getter_AddRefs(originalURI)),
+                      NS_ERROR_FAILURE);
+  }
   NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)), NS_ERROR_FAILURE);
@@ -12064,34 +12159,35 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
   } else {
     srcdoc = NullString();
   }
 
   // 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.
-  rv = InternalLoad(uri,
-                    referrerURI,
-                    referrerPolicy,
-                    owner,
-                    flags,
-                    nullptr,            // No window target
-                    contentType.get(),  // Type hint
-                    NullString(),       // 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,
-                    nullptr,            // No nsIDocShell
-                    nullptr);           // No nsIRequest
+  rv = InternalLoad2(uri,
+                     originalURI,
+                     referrerURI,
+                     referrerPolicy,
+                     owner,
+                     flags,
+                     nullptr,            // No window target
+                     contentType.get(),  // Type hint
+                     NullString(),       // 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,
+                     nullptr,            // No nsIDocShell
+                     nullptr);           // No nsIRequest
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetShouldSaveLayoutState(bool* aShould)
 {
   *aShould = false;
   if (mOSHE) {
@@ -13527,35 +13623,36 @@ nsDocShell::OnLinkClickSync(nsIContent* 
   // with it under InternalLoad; we do _not_ want to change the URI
   // our caller passed in.
   nsCOMPtr<nsIURI> clonedURI;
   aURI->Clone(getter_AddRefs(clonedURI));
   if (!clonedURI) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  nsresult rv = InternalLoad(clonedURI,                 // New URI
-                             referer,                   // Referer URI
-                             refererPolicy,             // Referer policy
-                             aContent->NodePrincipal(), // Owner is our node's
-                                                        // principal
-                             flags,
-                             target.get(),              // Window target
-                             NS_LossyConvertUTF16toASCII(typeHint).get(),
-                             aFileName,                 // Download as file
-                             aPostDataStream,           // Post data stream
-                             aHeadersDataStream,        // Headers stream
-                             LOAD_LINK,                 // Load type
-                             nullptr,                   // No SHEntry
-                             true,                      // first party site
-                             NullString(),              // No srcdoc
-                             this,                      // We are the source
-                             nullptr,                   // baseURI not needed
-                             aDocShell,                 // DocShell out-param
-                             aRequest);                 // Request out-param
+  nsresult rv = InternalLoad2(clonedURI,                 // New URI
+                              nullptr,                   // Original URI
+                              referer,                   // Referer URI
+                              refererPolicy,             // Referer policy
+                              aContent->NodePrincipal(), // Owner is our node's
+                                                         // principal
+                              flags,
+                              target.get(),              // Window target
+                              NS_LossyConvertUTF16toASCII(typeHint).get(),
+                              aFileName,                 // Download as file
+                              aPostDataStream,           // Post data stream
+                              aHeadersDataStream,        // Headers stream
+                              LOAD_LINK,                 // Load type
+                              nullptr,                   // No SHEntry
+                              true,                      // first party site
+                              NullString(),              // No srcdoc
+                              this,                      // We are the source
+                              nullptr,                   // baseURI not needed
+                              aDocShell,                 // DocShell out-param
+                              aRequest);                 // Request out-param
   if (NS_SUCCEEDED(rv)) {
     DispatchPings(aContent, aURI, referer, refererPolicy);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::OnOverLink(nsIContent* aContent,
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -132,17 +132,17 @@ enum eCharsetReloadState
 };
 
 //*****************************************************************************
 //***    nsDocShell
 //*****************************************************************************
 
 class nsDocShell final
   : public nsDocLoader
-  , public nsIDocShell_ESR38
+  , public nsIDocShell_ESR38_2
   , public nsIWebNavigation
   , public nsIBaseWindow
   , public nsIScrollable
   , public nsITextScroll
   , public nsIDocCharset
   , public nsIContentViewerContainer
   , public nsIRefreshURI
   , public nsIWebProgressListener
@@ -164,16 +164,17 @@ public:
   nsDocShell();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   virtual nsresult Init() override;
 
   NS_DECL_ISUPPORTS_INHERITED
 
+  NS_DECL_NSIDOCSHELL_ESR38_2
   NS_DECL_NSIDOCSHELL_ESR38
   NS_DECL_NSIDOCSHELL
   NS_DECL_NSIDOCSHELLTREEITEM
   NS_DECL_NSIWEBNAVIGATION
   NS_DECL_NSIBASEWINDOW
   NS_DECL_NSISCROLLABLE
   NS_DECL_NSITEXTSCROLL
   NS_DECL_NSIDOCCHARSET
@@ -312,17 +313,20 @@ protected:
   // at the parent.
   nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument);
 
   // Actually open a channel and perform a URI load.  Note: whatever owner is
   // passed to this function will be set on the channel.  Callers who wish to
   // not have an owner on the channel should just pass null.
   // If aSrcdoc is not void, the load will be considered as a srcdoc load,
   // and the contents of aSrcdoc will be loaded instead of aURI.
+  // aOriginalURI will be set as the originalURI on the channel that does the
+  // load. If aOriginalURI is null, aURI will be set as the originalURI.
   nsresult DoURILoad(nsIURI* aURI,
+                     nsIURI* aOriginalURI,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
                      nsISupports* aOwner,
                      const char* aTypeHint,
                      const nsAString& aFileName,
                      nsIInputStream* aPostData,
                      nsIInputStream* aHeadersData,
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -34,16 +34,17 @@ nsDocShellLoadInfo::~nsDocShellLoadInfo(
 // nsDocShellLoadInfo::nsISupports
 //*****************************************************************************
 
 NS_IMPL_ADDREF(nsDocShellLoadInfo)
 NS_IMPL_RELEASE(nsDocShellLoadInfo)
 
 NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo)
+  NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo_ESR38)
   NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo)
 NS_INTERFACE_MAP_END
 
 //*****************************************************************************
 // nsDocShellLoadInfo::nsIDocShellLoadInfo
 //*****************************************************************************
 
 NS_IMETHODIMP
@@ -59,16 +60,33 @@ nsDocShellLoadInfo::GetReferrer(nsIURI**
 NS_IMETHODIMP
 nsDocShellLoadInfo::SetReferrer(nsIURI* aReferrer)
 {
   mReferrer = aReferrer;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShellLoadInfo::GetOriginalURI(nsIURI** aOriginalURI)
+{
+  NS_ENSURE_ARG_POINTER(aOriginalURI);
+
+  *aOriginalURI = mOriginalURI;
+  NS_IF_ADDREF(*aOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShellLoadInfo::SetOriginalURI(nsIURI* aOriginalURI)
+{
+  mOriginalURI = aOriginalURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShellLoadInfo::GetOwner(nsISupports** aOwner)
 {
   NS_ENSURE_ARG_POINTER(aOwner);
 
   *aOwner = mOwner;
   NS_IF_ADDREF(*aOwner);
   return NS_OK;
 }
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -14,29 +14,31 @@
 // Interfaces Needed
 #include "nsIDocShellLoadInfo.h"
 
 class nsIInputStream;
 class nsISHEntry;
 class nsIURI;
 class nsIDocShell;
 
-class nsDocShellLoadInfo : public nsIDocShellLoadInfo
+class nsDocShellLoadInfo : public nsIDocShellLoadInfo_ESR38
 {
 public:
   nsDocShellLoadInfo();
 
   NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOCSHELLLOADINFO_ESR38
   NS_DECL_NSIDOCSHELLLOADINFO
 
 protected:
   virtual ~nsDocShellLoadInfo();
 
 protected:
   nsCOMPtr<nsIURI> mReferrer;
+  nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsISupports> mOwner;
   bool mInheritOwner;
   bool mOwnerIsExplicit;
   bool mSendReferrer;
   nsDocShellInfoReferrerPolicy mReferrerPolicy;
   nsDocShellInfoLoadType mLoadType;
   nsCOMPtr<nsISHEntry> mSHEntry;
   nsString mTarget;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1059,8 +1059,66 @@ interface nsIDocShell : nsIDocShellTreeI
 interface nsIDocShell_ESR38 : nsIDocShell
 {
   /**
    * True if new child docshells should allow content retargeting.
    * Setting allowContentRetargeting also overwrites this value.
    */
   [infallible] attribute boolean allowContentRetargetingOnChildren;
 };
+
+[scriptable, builtinclass, uuid(607604b6-8fe0-4d2c-8a6c-44f5f31a6e02)]
+interface nsIDocShell_ESR38_2 : nsIDocShell_ESR38
+{
+  /**
+   * Loads the given URI.  This method is identical to 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 aReferrer       - Referring URI
+   * @param aReferrerPolicy - Referrer policy
+   * @param aOwner          - Owner (security principal) 
+   * @param aInheritOwner   - Flag indicating whether the owner of the current
+   *                          document should be inherited if aOwner is null.
+   * @param aStopActiveDoc  - Flag indicating whether loading the current
+   *                          document should be stopped.
+   * @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.
+   */
+  [noscript]void internalLoad2(in nsIURI aURI,
+                               in nsIURI aOriginalURI,
+                               in nsIURI aReferrer,
+                               in unsigned long aReferrerPolicy,
+                               in nsISupports aOwner,
+                               in uint32_t aFlags,
+                               in wstring aWindowTarget,
+                               in string aTypeHint,
+                               in AString aFileName,
+                               in nsIInputStream aPostDataStream,
+                               in nsIInputStream aHeadersStream,
+                               in unsigned long aLoadFlags,
+                               in nsISHEntry aSHEntry,
+                               in boolean firstParty,
+                               in AString aSrcdoc,
+                               in nsIDocShell aSourceDocShell,
+                               in nsIURI aBaseURI,
+                               out nsIDocShell aDocShell,
+                               out nsIRequest aRequest);
+};
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -106,8 +106,17 @@ interface nsIDocShellLoadInfo : nsISuppo
     attribute nsIDocShell sourceDocShell;
 
     /**
      * 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.
      */
     attribute nsIURI baseURI;
 };
+
+[scriptable, uuid(9d3bc466-5efe-414d-ae8b-3830b45877bb)]
+interface nsIDocShellLoadInfo_ESR38 : nsIDocShellLoadInfo
+{
+    /**
+     * The originalURI to be passed to nsIDocShell.internalLoad. May be null.
+     */
+    attribute nsIURI originalURI;
+};
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -319,8 +319,18 @@ interface nsISHEntryInternal : nsISuppor
 #define NS_SHENTRY_CID \
 {0xbfd1a791, 0xad9f, 0x11d3, {0xbd, 0xc7, 0x0, 0x50, 0x4, 0xa, 0x9b, 0x44}}
 
 #define NS_SHENTRY_CONTRACTID \
     "@mozilla.org/browser/session-history-entry;1"
 
 %}
 
+[scriptable, uuid(e45ab6ef-3485-449c-b91c-0846b2bf6faf)]
+interface nsISHEntry_ESR38 : nsISHEntry
+{
+    /**
+     * A readonly property that returns the original URI of the current entry.
+     * If an entry is the result of a redirect this attribute holds original
+     * URI. The object returned is of type nsIURI
+     */
+    attribute nsIURI originalURI;
+};
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -38,16 +38,17 @@ nsSHEntry::nsSHEntry()
   , mIsSrcdocEntry(false)
 {
   mShared = new nsSHEntryShared();
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry &other)
   : mShared(other.mShared)
   , mURI(other.mURI)
+  , mOriginalURI(other.mOriginalURI)
   , mReferrerURI(other.mReferrerURI)
   , mReferrerPolicy(other.mReferrerPolicy)
   , mTitle(other.mTitle)
   , mPostData(other.mPostData)
   , mLoadType(0)         // XXX why not copy?
   , mID(other.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
@@ -74,17 +75,17 @@ nsSHEntry::~nsSHEntry()
   // Null out the mParent pointers on all our kids.
   mChildren.EnumerateForwards(ClearParentPtr, nullptr);
 }
 
 //*****************************************************************************
 //    nsSHEntry: nsISupports
 //*****************************************************************************
 
-NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal)
+NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry_ESR38, nsISHEntry, nsISHEntryInternal)
 
 //*****************************************************************************
 //    nsSHEntry: nsISHEntry
 //*****************************************************************************
 
 NS_IMETHODIMP nsSHEntry::SetScrollPosition(int32_t x, int32_t y)
 {
   mScrollPositionX = x;
@@ -119,16 +120,29 @@ NS_IMETHODIMP nsSHEntry::GetURI(nsIURI**
 }
 
 NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI)
 {
   mURI = aURI;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI)
+{
+  *aOriginalURI = mOriginalURI;
+  NS_IF_ADDREF(*aOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI)
+{
+  mOriginalURI = aOriginalURI;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI)
 {
   *aReferrerURI = mReferrerURI;
   NS_IF_ADDREF(*aReferrerURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -17,25 +17,26 @@
 // Interfaces needed
 #include "nsISHEntry.h"
 #include "nsISHContainer.h"
 
 class nsSHEntryShared;
 class nsIInputStream;
 class nsIURI;
 
-class nsSHEntry final : public nsISHEntry,
+class nsSHEntry final : public nsISHEntry_ESR38,
                             public nsISHContainer,
                             public nsISHEntryInternal
 {
 public: 
   nsSHEntry();
   nsSHEntry(const nsSHEntry &other);
 
   NS_DECL_ISUPPORTS
+  NS_DECL_NSISHENTRY_ESR38
   NS_DECL_NSISHENTRY
   NS_DECL_NSISHENTRYINTERNAL
   NS_DECL_NSISHCONTAINER
 
   void DropPresentationState();
 
   static nsresult Startup();
   static void Shutdown();
@@ -44,16 +45,17 @@ private:
   ~nsSHEntry();
 
   // We share the state in here with other SHEntries which correspond to the
   // same document.
   nsRefPtr<nsSHEntryShared> mShared;
 
   // See nsSHEntry.idl for comments on these members.
   nsCOMPtr<nsIURI>         mURI;
+  nsCOMPtr<nsIURI>         mOriginalURI;
   nsCOMPtr<nsIURI>         mReferrerURI;
   uint32_t                 mReferrerPolicy;
   nsString                 mTitle;
   nsCOMPtr<nsIInputStream> mPostData;
   uint32_t                 mLoadType;
   uint32_t                 mID;
   int32_t                  mScrollPositionX;
   int32_t                  mScrollPositionY;
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -1779,16 +1779,26 @@ nsSHistory::InitiateLoad(nsISHEntry * aF
    * so that proper loadType is maintained through out a frameset
    */
   aFrameEntry->SetLoadType(aLoadType);    
   aFrameDS->CreateLoadInfo (getter_AddRefs(loadInfo));
 
   loadInfo->SetLoadType(aLoadType);
   loadInfo->SetSHEntry(aFrameEntry);
 
+  nsCOMPtr<nsIURI> originalURI;
+  nsCOMPtr<nsISHEntry_ESR38> feESR38 = do_QueryInterface(aFrameEntry);
+  if (feESR38) {
+    feESR38->GetOriginalURI(getter_AddRefs(originalURI));
+  }
+  nsCOMPtr<nsIDocShellLoadInfo_ESR38> liESR38 = do_QueryInterface(loadInfo);
+  if (liESR38) {
+    liESR38->SetOriginalURI(originalURI);
+  }
+
   nsCOMPtr<nsIURI> nextURI;
   aFrameEntry->GetURI(getter_AddRefs(nextURI));
   // Time   to initiate a document load
   return aFrameDS->LoadURI(nextURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, false);
 
 }