Bug 1185256 - Save originURI to the history. r=bz ba=lizzard, a=lizzard
authorDragana Damjanovic <dd.mozilla@gmail.com>
Wed, 30 Sep 2015 08:54:39 +0200
changeset 296693 8b8a66145292
parent 296692 5ffeff840220
child 296694 23d25d9a94d7
push id5293
push usercbook@mozilla.com
push date2015-11-11 10:29 +0000
treeherdermozilla-beta@d8c7509ddad0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, lizzard
bugs1185256
milestone43.0
Bug 1185256 - Save originURI to the history. r=bz ba=lizzard, a=lizzard
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/nsISHEntry.idl
docshell/shistory/nsSHEntry.cpp
docshell/shistory/nsSHEntry.h
docshell/shistory/nsSHistory.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1261,16 +1261,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;
@@ -1287,16 +1288,17 @@ 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));
+    aLoadInfo->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);
@@ -1541,16 +1543,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
     flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
   }
 
   if (isSrcdoc) {
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
   return InternalLoad(aURI,
+                      originalURI,
                       referrer,
                       referrerPolicy,
                       owner,
                       flags,
                       target.get(),
                       nullptr,      // No type hint
                       NullString(), // No forced download
                       postStream,
@@ -5206,17 +5209,17 @@ 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,
+  return InternalLoad(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)
@@ -5256,27 +5259,37 @@ 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();
       }
-    }
+      nsCOMPtr<nsIChannel> chan = doc->GetChannel();
+      if (chan) {
+        nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
+        if (httpChan) {
+          httpChan->GetOriginalURI(getter_AddRefs(originalURI));
+        }
+      } 
+    }
+
     rv = InternalLoad(mCurrentURI,
+                      originalURI,
                       mReferrerURI,
                       mReferrerPolicy,
                       principal,
                       flags,
                       nullptr,         // No window target
                       NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
                       NullString(),    // No forced download
                       nullptr,         // No post data
@@ -9299,27 +9312,28 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
     favSvc->GetFaviconURLForPage(aOldURI, callback);
   }
 #endif
 }
 
 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)
@@ -9331,17 +9345,18 @@ public:
     if (aTypeHint) {
       mTypeHint = aTypeHint;
     }
   }
 
   NS_IMETHOD
   Run()
   {
-    return mDocShell->InternalLoad(mURI, mReferrer,
+    return mDocShell->InternalLoad(mURI, mOriginalURI,
+                                   mReferrer,
                                    mReferrerPolicy,
                                    mOwner, mFlags,
                                    nullptr, mTypeHint.get(),
                                    NullString(), mPostData, mHeadersData,
                                    mLoadType, mSHEntry, mFirstParty,
                                    mSrcdoc, mSourceDocShell, mBaseURI,
                                    nullptr, nullptr);
   }
@@ -9349,16 +9364,17 @@ public:
 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;
@@ -9402,16 +9418,17 @@ nsDocShell::CreatePrincipalFromReferrer(
     BasePrincipal::CreateCodebasePrincipal(aReferrer, attrs);
   prin.forget(aResult);
 
   return *aResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsDocShell::InternalLoad(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,
@@ -9663,16 +9680,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     }
 
     //
     // 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,
+                                        aOriginalURI,
                                         aReferrer,
                                         aReferrerPolicy,
                                         owner,
                                         aFlags,
                                         nullptr,         // No window target
                                         aTypeHint,
                                         NullString(),    // No forced download
                                         aPostData,
@@ -9744,17 +9762,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
@@ -10225,17 +10243,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);
@@ -10299,16 +10317,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,
@@ -10533,17 +10552,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()) {
@@ -11509,16 +11533,17 @@ 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);
+    newSHEntry->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
@@ -11692,16 +11717,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<nsICacheInfoChannel> cacheChannel;
   if (aChannel) {
@@ -11719,16 +11745,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;
@@ -11751,16 +11778,18 @@ nsDocShell::AddToSessionHistory(nsIURI* 
                 EmptyString(),     // Title
                 inputStream,       // Post data stream
                 nullptr,           // LayoutHistory state
                 cacheKey,          // CacheKey
                 mContentTypeHint,  // Content-type
                 owner,             // Channel or provided owner
                 mHistoryID,
                 mDynamicallyCreated);
+
+  entry->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;
@@ -11851,25 +11880,28 @@ 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);
+  NS_ENSURE_SUCCESS(aEntry->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);
@@ -11940,16 +11972,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
     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,
+                    originalURI,
                     referrerURI,
                     referrerPolicy,
                     owner,
                     flags,
                     nullptr,            // No window target
                     contentType.get(),  // Type hint
                     NullString(),       // No forced file download
                     postData,           // Post data stream
@@ -13398,16 +13431,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
   // 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
+                             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
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -324,17 +324,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
@@ -46,16 +46,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
@@ -27,16 +27,17 @@ public:
   NS_DECL_ISUPPORTS
   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
@@ -41,17 +41,17 @@ interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(e534b6ee-c35d-4ee2-acce-1bcd08a91230)]
+[scriptable, builtinclass, uuid(df834cfd-5073-4053-96e4-4e5a4e508696)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -118,16 +118,19 @@ interface nsIDocShell : nsIDocShellTreeI
   // NB: 0x80 is available.
 
   /**
    * 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.
@@ -144,16 +147,17 @@ interface nsIDocShell : nsIDocShellTreeI
    *                          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 internalLoad(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,
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -14,22 +14,27 @@
 interface nsIURI;
 interface nsIInputStream;
 interface nsISHEntry;
 interface nsIDocShell;
 
 typedef long nsDocShellInfoLoadType;
 typedef unsigned long nsDocShellInfoReferrerPolicy;
 
-[scriptable, uuid(c63e9d64-490d-48bf-8013-b5d8ee4dbc25)]
+[scriptable, uuid(9d3bc466-5efe-414d-ae8b-3830b45877bb)]
 interface nsIDocShellLoadInfo : nsISupports
 {
     /** This is the referrer for the load. */
     attribute nsIURI referrer;
 
+    /**
+     * The originalURI to be passed to nsIDocShell.internalLoad. May be null.
+     */ 
+    attribute nsIURI originalURI;
+
     /** The owner of the load, that is, the entity responsible for 
      *  causing the load to occur. This should be a nsIPrincipal typically.
      */
     attribute nsISupports owner;
 
     /** If this attribute is true and no owner is specified, copy
      *  the owner from the referring document.
      */
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -25,27 +25,34 @@ interface nsIBFCacheEntry;
 #include "nsRect.h"
 class nsDocShellEditorData;
 class nsSHEntryShared;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 [ptr] native nsSHEntryShared(nsSHEntryShared);
 
-[scriptable, uuid(d5fbeb10-f373-4677-b69a-2694aa706cac)]
+[scriptable, uuid(e45ab6ef-3485-449c-b91c-0846b2bf6faf)]
 interface nsISHEntry : nsISupports
 {
     /**
      * A readonly property that returns the URI
      * of the current entry. The object returned is
      * of type nsIURI
      */
     readonly attribute nsIURI URI;
 
     /**
+     * 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 readonly property that returns the title
      * of the current entry.  The object returned
      * is a encoded string
      */
     readonly attribute wstring title;
 
     /**
      * A readonly property that returns a boolean
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -33,16 +33,17 @@ nsSHEntry::nsSHEntry()
   , mURIWasModified(false)
   , mIsSrcdocEntry(false)
 {
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
   : mShared(aOther.mShared)
   , mURI(aOther.mURI)
+  , mOriginalURI(aOther.mOriginalURI)
   , mReferrerURI(aOther.mReferrerURI)
   , mReferrerPolicy(aOther.mReferrerPolicy)
   , mTitle(aOther.mTitle)
   , mPostData(aOther.mPostData)
   , mLoadType(0)         // XXX why not copy?
   , mID(aOther.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
@@ -113,16 +114,31 @@ nsSHEntry::GetURI(nsIURI** aURI)
 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
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -44,16 +44,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/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -1766,16 +1766,20 @@ nsSHistory::InitiateLoad(nsISHEntry* aFr
    * 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;
+  aFrameEntry->GetOriginalURI(getter_AddRefs(originalURI));
+  loadInfo->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);
 
 }