Bug 1351146 - P1 - Add more information to redirect chains draft
authorThomas Nguyen <tnguyen@mozilla.com>
Mon, 24 Apr 2017 15:59:48 +0800
changeset 574022 02a526a82abe5f82256165a2839ea7cfe9ffb92f
parent 572425 4a6a71f4aa22e4dc3961884ce505ce34bdd799a2
child 574023 e1a0901b3fa79fff356f5c1e40cd93eb68daa5b0
child 574030 437b9b6e59150f1964a9139612d44961ca4004cc
push id57563
push userbmo:tnguyen@mozilla.com
push dateMon, 08 May 2017 09:02:56 +0000
bugs1351146
milestone55.0a1
Bug 1351146 - P1 - Add more information to redirect chains In order to provide more details context of how client arrived at the unsafe page, particularly in redirect case, we may have to add more information to redirect chains including: - referrer (if any) - remote address. - URL We may want to use an idl interface instead of nsIPrincipal to store these information MozReview-Commit-ID: 3Uh4r06w60C
ipc/glue/BackgroundUtils.cpp
ipc/glue/BackgroundUtils.h
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/moz.build
netwerk/base/nsILoadInfo.idl
netwerk/base/nsIRedirectHistoryEntry.idl
netwerk/base/nsNetUtil.cpp
netwerk/base/nsRedirectHistoryEntry.cpp
netwerk/base/nsRedirectHistoryEntry.h
netwerk/ipc/NeckoChannelParams.ipdlh
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -5,27 +5,29 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BackgroundUtils.h"
 
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChannelParams.h"
 #include "ExpandedPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "mozilla/LoadInfo.h"
 #include "ContentPrincipal.h"
 #include "NullPrincipal.h"
 #include "nsContentUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "mozilla/nsRedirectHistoryEntry.h"
 
 namespace mozilla {
 namespace net {
 class OptionalLoadInfoArgs;
 }
 
 using mozilla::BasePrincipal;
 using namespace mozilla::net;
@@ -253,16 +255,56 @@ IsPincipalInfoPrivate(const PrincipalInf
   if (aPrincipalInfo.type() != ipc::PrincipalInfo::TContentPrincipalInfo) {
     return false;
   }
 
   const ContentPrincipalInfo& info = aPrincipalInfo.get_ContentPrincipalInfo();
   return !!info.attrs().mPrivateBrowsingId;
 }
 
+already_AddRefed<nsIRedirectHistoryEntry>
+RHEntryInfoToRHEntry(const RedirectHistoryEntryInfo& aRHEntryInfo)
+{
+  nsresult rv;
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(aRHEntryInfo.principalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aRHEntryInfo.referrerUri());
+
+  nsCOMPtr<nsIRedirectHistoryEntry> entry =
+    new nsRedirectHistoryEntry(principal, referrerUri, aRHEntryInfo.remoteAddress());
+
+  return entry.forget();
+}
+
+nsresult
+RHEntryToRHEntryInfo(nsIRedirectHistoryEntry* aRHEntry,
+                     RedirectHistoryEntryInfo* aRHEntryInfo)
+{
+  MOZ_ASSERT(aRHEntry);
+  MOZ_ASSERT(aRHEntryInfo);
+
+  nsresult rv;
+  aRHEntry->GetRemoteAddress(aRHEntryInfo->remoteAddress());
+
+  nsCOMPtr<nsIURI> referrerUri;
+  rv = aRHEntry->GetReferrerURI(getter_AddRefs(referrerUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  SerializeURI(referrerUri, aRHEntryInfo->referrerUri());
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = aRHEntry->GetPrincipal(getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return PrincipalToPrincipalInfo(principal, &aRHEntryInfo->principalInfo());
+}
+
 nsresult
 LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
                        OptionalLoadInfoArgs* aOptionalLoadInfoArgs)
 {
   if (!aLoadInfo) {
     // if there is no loadInfo, then there is nothing to serialize
     *aOptionalLoadInfoArgs = void_t();
     return NS_OK;
@@ -299,25 +341,29 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
         getter_AddRefs(sandboxedLoadingPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = PrincipalToPrincipalInfo(sandboxedLoadingPrincipal,
                                   &sandboxedLoadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
     sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
   }
 
-  nsTArray<PrincipalInfo> redirectChainIncludingInternalRedirects;
-  for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChainIncludingInternalRedirects()) {
-    rv = PrincipalToPrincipalInfo(principal, redirectChainIncludingInternalRedirects.AppendElement());
+  nsTArray<RedirectHistoryEntryInfo> redirectChainIncludingInternalRedirects;
+  for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry :
+       aLoadInfo->RedirectChainIncludingInternalRedirects()) {
+    RedirectHistoryEntryInfo* entry = redirectChainIncludingInternalRedirects.AppendElement();
+    rv = RHEntryToRHEntryInfo(redirectEntry, entry);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsTArray<PrincipalInfo> redirectChain;
-  for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChain()) {
-    rv = PrincipalToPrincipalInfo(principal, redirectChain.AppendElement());
+  nsTArray<RedirectHistoryEntryInfo> redirectChain;
+  for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry :
+       aLoadInfo->RedirectChain()) {
+    RedirectHistoryEntryInfo* entry = redirectChain.AppendElement();
+    rv = RHEntryToRHEntryInfo(redirectEntry, entry);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aOptionalLoadInfoArgs =
     LoadInfoArgs(
       loadingPrincipalInfo,
       triggeringPrincipalInfo,
       principalToInheritInfo,
@@ -380,30 +426,31 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
 
   nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal;
   if (loadInfoArgs.sandboxedLoadingPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
     sandboxedLoadingPrincipal =
       PrincipalInfoToPrincipal(loadInfoArgs.sandboxedLoadingPrincipalInfo(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsTArray<nsCOMPtr<nsIPrincipal>> redirectChainIncludingInternalRedirects;
-  for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChainIncludingInternalRedirects()) {
-    nsCOMPtr<nsIPrincipal> redirectedPrincipal =
-      PrincipalInfoToPrincipal(principalInfo, &rv);
+  RedirectHistoryArray redirectChainIncludingInternalRedirects;
+  for (const RedirectHistoryEntryInfo& entryInfo :
+      loadInfoArgs.redirectChainIncludingInternalRedirects()) {
+    nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry =
+      RHEntryInfoToRHEntry(entryInfo);
     NS_ENSURE_SUCCESS(rv, rv);
-    redirectChainIncludingInternalRedirects.AppendElement(redirectedPrincipal.forget());
+    redirectChainIncludingInternalRedirects.AppendElement(redirectHistoryEntry.forget());
   }
 
-  nsTArray<nsCOMPtr<nsIPrincipal>> redirectChain;
-  for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChain()) {
-    nsCOMPtr<nsIPrincipal> redirectedPrincipal =
-      PrincipalInfoToPrincipal(principalInfo, &rv);
+  RedirectHistoryArray redirectChain;
+  for (const RedirectHistoryEntryInfo& entryInfo : loadInfoArgs.redirectChain()) {
+    nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry =
+      RHEntryInfoToRHEntry(entryInfo);
     NS_ENSURE_SUCCESS(rv, rv);
-    redirectChain.AppendElement(redirectedPrincipal.forget());
+    redirectChain.AppendElement(redirectHistoryEntry.forget());
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(loadingPrincipal,
                           triggeringPrincipal,
                           principalToInherit,
                           sandboxedLoadingPrincipal,
                           loadInfoArgs.securityFlags(),
--- a/ipc/glue/BackgroundUtils.h
+++ b/ipc/glue/BackgroundUtils.h
@@ -10,16 +10,17 @@
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 
 class nsILoadInfo;
 class nsIPrincipal;
+class nsIRedirectHistoryEntry;
 
 namespace IPC {
 
 namespace detail {
 template<class ParamType>
 struct OriginAttributesParamTraits
 {
   typedef ParamType paramType;
@@ -44,16 +45,17 @@ template<>
 struct ParamTraits<mozilla::OriginAttributes>
   : public detail::OriginAttributesParamTraits<mozilla::OriginAttributes> {};
 
 } // namespace IPC
 
 namespace mozilla {
 namespace net {
 class OptionalLoadInfoArgs;
+class RedirectHistoryEntryInfo;
 } // namespace net
 
 using namespace mozilla::net;
 
 namespace ipc {
 
 class PrincipalInfo;
 
@@ -78,16 +80,31 @@ PrincipalToPrincipalInfo(nsIPrincipal* a
 /**
  * Return true if this PrincipalInfo is a content principal and it has
  * a privateBrowsing id in its OriginAttributes
  */
 bool
 IsPincipalInfoPrivate(const PrincipalInfo& aPrincipalInfo);
 
 /**
+ * Convert an RedirectHistoryEntryInfo to a nsIRedirectHistoryEntry.
+ */
+
+already_AddRefed<nsIRedirectHistoryEntry>
+RHEntryInfoToRHEntry(const RedirectHistoryEntryInfo& aRHEntryInfo);
+
+/**
+ * Convert an nsIRedirectHistoryEntry to a RedirectHistoryEntryInfo.
+ */
+
+nsresult
+RHEntryToRHEntryInfo(nsIRedirectHistoryEntry* aRHEntry,
+                     RedirectHistoryEntryInfo* aRHEntryInfo);
+
+/**
  * Convert a LoadInfo to LoadInfoArgs struct.
  */
 nsresult
 LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
                        OptionalLoadInfoArgs* outOptionalLoadInfoArgs);
 
 /**
  * Convert LoadInfoArgs to a LoadInfo.
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -17,16 +17,17 @@
 #include "nsIFrameLoader.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISupportsImpl.h"
 #include "nsISupportsUtils.h"
 #include "nsContentUtils.h"
 #include "nsDocShell.h"
 #include "nsGlobalWindow.h"
 #include "NullPrincipal.h"
+#include "nsRedirectHistoryEntry.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace net {
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
@@ -310,18 +311,18 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    uint64_t aInnerWindowID,
                    uint64_t aOuterWindowID,
                    uint64_t aParentOuterWindowID,
                    uint64_t aFrameOuterWindowID,
                    bool aEnforceSecurity,
                    bool aInitialSecurityCheckDone,
                    bool aIsThirdPartyContext,
                    const OriginAttributes& aOriginAttributes,
-                   nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
-                   nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChain,
+                   RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
+                   RedirectHistoryArray& aRedirectChain,
                    const nsTArray<nsCString>& aCorsUnsafeHeaders,
                    bool aForcePreflight,
                    bool aIsPreflight,
                    bool aForceHSTSPriming,
                    bool aMixedContentWouldBlock)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mPrincipalToInherit(aPrincipalToInherit)
@@ -790,53 +791,76 @@ LoadInfo::SetInitialSecurityCheckDone(bo
 NS_IMETHODIMP
 LoadInfo::GetInitialSecurityCheckDone(bool* aResult)
 {
   *aResult = mInitialSecurityCheckDone;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-LoadInfo::AppendRedirectedPrincipal(nsIPrincipal* aPrincipal, bool aIsInternalRedirect)
+LoadInfo::AppendRedirectHistoryEntry(nsIRedirectHistoryEntry* aEntry,
+                                     bool aIsInternalRedirect)
 {
-  NS_ENSURE_ARG(aPrincipal);
+  NS_ENSURE_ARG(aEntry);
   MOZ_ASSERT(NS_IsMainThread());
 
-  mRedirectChainIncludingInternalRedirects.AppendElement(aPrincipal);
+  mRedirectChainIncludingInternalRedirects.AppendElement(aEntry);
   if (!aIsInternalRedirect) {
-    mRedirectChain.AppendElement(aPrincipal);
+    mRedirectChain.AppendElement(aEntry);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::GetRedirects(JSContext* aCx, JS::MutableHandle<JS::Value> aRedirects,
+                       const RedirectHistoryArray& aArray)
+{
+  JS::Rooted<JSObject*> redirects(aCx, JS_NewArrayObject(aCx, aArray.Length()));
+  NS_ENSURE_TRUE(redirects, NS_ERROR_OUT_OF_MEMORY);
+
+  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+  NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsIXPConnect> xpc = mozilla::services::GetXPConnect();
+
+  for (size_t idx = 0; idx < aArray.Length(); idx++) {
+    JS::RootedObject jsobj(aCx);
+    nsresult rv = xpc->WrapNative(aCx, global, aArray[idx],
+                                  NS_GET_IID(nsIRedirectHistoryEntry),
+                                  jsobj.address());
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_STATE(jsobj);
+
+    bool rc = JS_DefineElement(aCx, redirects, idx, jsobj, JSPROP_ENUMERATE);
+    NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED);
+  }
+
+  aRedirects.setObject(*redirects);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 LoadInfo::GetRedirectChainIncludingInternalRedirects(JSContext* aCx, JS::MutableHandle<JS::Value> aChain)
 {
-  if (!ToJSValue(aCx, mRedirectChainIncludingInternalRedirects, aChain)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
+  return GetRedirects(aCx, aChain, mRedirectChainIncludingInternalRedirects);
 }
 
-const nsTArray<nsCOMPtr<nsIPrincipal>>&
+const RedirectHistoryArray&
 LoadInfo::RedirectChainIncludingInternalRedirects()
 {
   return mRedirectChainIncludingInternalRedirects;
 }
 
 NS_IMETHODIMP
 LoadInfo::GetRedirectChain(JSContext* aCx, JS::MutableHandle<JS::Value> aChain)
 {
-  if (!ToJSValue(aCx, mRedirectChain, aChain)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
+  return GetRedirects(aCx, aChain, mRedirectChain);
 }
 
-const nsTArray<nsCOMPtr<nsIPrincipal>>&
+const RedirectHistoryArray&
 LoadInfo::RedirectChain()
 {
   return mRedirectChain;
 }
 
 void
 LoadInfo::SetCorsPreflightInfo(const nsTArray<nsCString>& aHeaders,
                                bool aForcePreflight)
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -33,16 +33,18 @@ namespace ipc {
 // we have to forward declare that function so we can use it as a friend.
 nsresult
 LoadInfoArgsToLoadInfo(const mozilla::net::OptionalLoadInfoArgs& aLoadInfoArgs,
                        nsILoadInfo** outLoadInfo);
 } // namespace ipc
 
 namespace net {
 
+typedef nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>> RedirectHistoryArray;
+
 /**
  * Class that provides an nsILoadInfo implementation.
  */
 class LoadInfo final : public nsILoadInfo
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSILOADINFO
@@ -94,25 +96,28 @@ private:
            uint64_t aInnerWindowID,
            uint64_t aOuterWindowID,
            uint64_t aParentOuterWindowID,
            uint64_t aFrameOuterWindowID,
            bool aEnforceSecurity,
            bool aInitialSecurityCheckDone,
            bool aIsThirdPartyRequest,
            const OriginAttributes& aOriginAttributes,
-           nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
-           nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChain,
+           RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
+           RedirectHistoryArray& aRedirectChain,
            const nsTArray<nsCString>& aUnsafeHeaders,
            bool aForcePreflight,
            bool aIsPreflight,
            bool aForceHSTSPriming,
            bool aMixedContentWouldBlock);
   LoadInfo(const LoadInfo& rhs);
 
+  NS_IMETHOD GetRedirects(JSContext* aCx, JS::MutableHandle<JS::Value> aRedirects,
+                          const RedirectHistoryArray& aArra);
+
   friend nsresult
   mozilla::ipc::LoadInfoArgsToLoadInfo(
     const mozilla::net::OptionalLoadInfoArgs& aLoadInfoArgs,
     nsILoadInfo** outLoadInfo);
 
   ~LoadInfo();
 
   void ComputeIsThirdPartyContext(nsPIDOMWindowOuter* aOuterWindow);
@@ -139,18 +144,18 @@ private:
   uint64_t                         mInnerWindowID;
   uint64_t                         mOuterWindowID;
   uint64_t                         mParentOuterWindowID;
   uint64_t                         mFrameOuterWindowID;
   bool                             mEnforceSecurity;
   bool                             mInitialSecurityCheckDone;
   bool                             mIsThirdPartyContext;
   OriginAttributes                 mOriginAttributes;
-  nsTArray<nsCOMPtr<nsIPrincipal>> mRedirectChainIncludingInternalRedirects;
-  nsTArray<nsCOMPtr<nsIPrincipal>> mRedirectChain;
+  RedirectHistoryArray             mRedirectChainIncludingInternalRedirects;
+  RedirectHistoryArray             mRedirectChain;
   nsTArray<nsCString>              mCorsUnsafeHeaders;
   bool                             mForcePreflight;
   bool                             mIsPreflight;
 
   bool                             mForceHSTSPriming : 1;
   bool                             mMixedContentWouldBlock : 1;
 };
 
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -82,16 +82,17 @@ XPIDL_SOURCES += [
     'nsIProtocolProxyFilter.idl',
     'nsIProtocolProxyService.idl',
     'nsIProtocolProxyService2.idl',
     'nsIProxiedChannel.idl',
     'nsIProxiedProtocolHandler.idl',
     'nsIProxyInfo.idl',
     'nsIRandomGenerator.idl',
     'nsIRedirectChannelRegistrar.idl',
+    'nsIRedirectHistoryEntry.idl',
     'nsIRedirectResultListener.idl',
     'nsIRequest.idl',
     'nsIRequestContext.idl',
     'nsIRequestObserver.idl',
     'nsIRequestObserverProxy.idl',
     'nsIResumableChannel.idl',
     'nsISecCheckWrapChannel.idl',
     'nsISecureBrowserUI.idl',
@@ -162,16 +163,17 @@ EXPORTS += [
     'nsURLParsers.h',
     'SimpleChannel.h',
 ]
 
 EXPORTS.mozilla += [
     'LoadContextInfo.h',
     'LoadInfo.h',
     'LoadTainting.h',
+    'nsRedirectHistoryEntry.h',
 ]
 
 EXPORTS.mozilla.net += [
     'CaptivePortalService.h',
     'ChannelDiverterChild.h',
     'ChannelDiverterParent.h',
     'Dashboard.h',
     'DashboardTypes.h',
@@ -213,16 +215,17 @@ UNIFIED_SOURCES += [
     'nsMediaFragmentURIParser.cpp',
     'nsMIMEInputStream.cpp',
     'nsNetAddr.cpp',
     'nsNetUtil.cpp',
     'nsPACMan.cpp',
     'nsPreloadedStream.cpp',
     'nsProtocolProxyService.cpp',
     'nsProxyInfo.cpp',
+    'nsRedirectHistoryEntry.cpp',
     'nsRequestObserverProxy.cpp',
     'nsSecCheckWrapChannel.cpp',
     'nsSerializationHelper.cpp',
     'nsServerSocket.cpp',
     'nsSimpleNestedURI.cpp',
     'nsSimpleStreamListener.cpp',
     'nsSimpleURI.cpp',
     'nsSocketTransport2.cpp',
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -5,26 +5,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIContentPolicy.idl"
 
 interface nsIDOMDocument;
 interface nsINode;
 interface nsIPrincipal;
-
+interface nsIRedirectHistoryEntry;
 %{C++
 #include "nsTArray.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/LoadTainting.h"
 
 class nsCString;
 %}
 
-[ref] native const_nsIPrincipalArray(const nsTArray<nsCOMPtr<nsIPrincipal>>);
+[ref] native nsIRedirectHistoryEntryArray(const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>);
 native OriginAttributes(mozilla::OriginAttributes);
 [ref] native const_OriginAttributesRef(const mozilla::OriginAttributes);
 [ref] native StringArrayRef(const nsTArray<nsCString>);
 
 typedef unsigned long nsSecurityFlags;
 
 /**
  * The LoadInfo object contains information about a network load, why it
@@ -580,58 +580,60 @@ interface nsILoadInfo : nsISupports
    * Please note, once the flag is set to true it must remain true
    * throughout the lifetime of the channel. Trying to set it
    * to anything else than true will be discarded.
    *
    */
   [infallible] attribute boolean initialSecurityCheckDone;
 
   /**
-   * Whenever a channel gets redirected, append the principal of the
-   * channel [before the channels got redirected] to the loadinfo,
-   * so that at every point this array lets us reason about all the
-   * redirects this channel went through.
-   * @param aPrincipal, the channelURIPrincipal before the channel
+   * Whenever a channel gets redirected, append the redirect history entry of
+   * the channel which contains principal referrer and remote address [before
+   * the channels got redirected] to the loadinfo, so that at every point this
+   * array provides us information about all the redirects this channel went
+   * through.
+   * @param entry, the nsIRedirectHistoryEntry before the channel
    *         got redirected.
    * @param aIsInternalRedirect should be true if the channel is going
    *        through an internal redirect, otherwise false.
    */
-  void appendRedirectedPrincipal(in nsIPrincipal principal,
-                                 in boolean isInternalRedirect);
+  void appendRedirectHistoryEntry(in nsIRedirectHistoryEntry entry,
+                                  in boolean isInternalRedirect);
 
   /**
-   * An array of nsIPrincipals which stores redirects associated with this
-   * channel. This array is filled whether or not the channel has ever been
-   * opened. The last element of the array is associated with the most recent
-   * redirect. Please note, that this array *includes* internal redirects.
+   * An array of nsIRedirectHistoryEntry which stores redirects associated
+   * with this channel. This array is filled whether or not the channel has
+   * ever been opened. The last element of the array is associated with the
+   * most recent redirect. Please note, that this array *includes* internal
+   * redirects.
    */
   [implicit_jscontext]
   readonly attribute jsval redirectChainIncludingInternalRedirects;
 
   /**
    * A C++-friendly version of redirectChain.
    * Please note that this array has the same lifetime as the
    * loadInfo object - use with caution!
    */
   [noscript, notxpcom, nostdcall, binaryname(RedirectChainIncludingInternalRedirects)]
-  const_nsIPrincipalArray binaryRedirectChainIncludingInternalRedirects();
+  nsIRedirectHistoryEntryArray binaryRedirectChainIncludingInternalRedirects();
 
   /**
    * Same as RedirectChain but does *not* include internal redirects.
    */
   [implicit_jscontext]
   readonly attribute jsval redirectChain;
 
   /**
    * A C++-friendly version of redirectChain.
    * Please note that this array has the same lifetime as the
    * loadInfo object - use with caution!
    */
   [noscript, notxpcom, nostdcall, binaryname(RedirectChain)]
-  const_nsIPrincipalArray binaryRedirectChain();
+  nsIRedirectHistoryEntryArray binaryRedirectChain();
 
   /**
    * Sets the list of unsafe headers according to CORS spec, as well as
    * potentially forces a preflight.
    * Note that you do not need to set the Content-Type header. That will be
    * automatically detected as needed.
    *
    * Only call this function when using the SEC_REQUIRE_CORS_DATA_INHERITS mode.
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsIRedirectHistoryEntry.idl
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIPrincipal;
+interface nsIURI;
+
+/**
+ * This nsIRedirectHistoryEntry defines an interface for specifying channel
+ * redirect information
+ */
+
+[scriptable, uuid(133b2905-0eba-411c-a8bb-f59787142aa2)]
+interface nsIRedirectHistoryEntry : nsISupports
+{
+  /**
+   * The principal of this redirect entry
+   */
+  readonly attribute nsIPrincipal principal;
+
+  /**
+   * The referring URI of this redirect entry.  This may be null.
+   */
+  readonly attribute nsIURI referrerURI;
+
+  /**
+   * The remote address of this redirect entry.
+   */
+  readonly attribute ACString remoteAddress;
+
+};
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -64,16 +64,17 @@
 #include "plstr.h"
 #include "nsINestedURI.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/net/HttpBaseChannel.h"
 #include "nsIScriptError.h"
 #include "nsISiteSecurityService.h"
 #include "nsHttpHandler.h"
 #include "nsNSSComponent.h"
+#include "nsIRedirectHistoryEntry.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #include "nsThreadUtils.h" // for NS_IsMainThread
 #endif
 
 #include <limits>
 
@@ -1615,17 +1616,23 @@ NS_HasBeenCrossOrigin(nsIChannel* aChann
   uint32_t mode = loadInfo->GetSecurityMode();
   bool dataInherits =
     mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS ||
     mode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS ||
     mode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
 
   bool aboutBlankInherits = dataInherits && loadInfo->GetAboutBlankInherits();
 
-  for (nsIPrincipal* principal : loadInfo->RedirectChain()) {
+  for (nsIRedirectHistoryEntry* redirectHistoryEntry : loadInfo->RedirectChain()) {
+    nsCOMPtr<nsIPrincipal> principal;
+    redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
+    if (!principal) {
+      return true;
+    }
+
     nsCOMPtr<nsIURI> uri;
     principal->GetURI(getter_AddRefs(uri));
     if (!uri) {
       return true;
     }
 
     if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
       continue;
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsRedirectHistoryEntry.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsRedirectHistoryEntry.h"
+#include "nsCOMPtr.h"
+#include "nsIURI.h"
+#include "nsIPrincipal.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(nsRedirectHistoryEntry, nsIRedirectHistoryEntry)
+
+nsRedirectHistoryEntry::nsRedirectHistoryEntry(nsIPrincipal* aPrincipal,
+                                               nsIURI* aReferrer,
+                                               const nsACString& aRemoteAddress)
+  : mPrincipal(aPrincipal)
+  , mReferrer(aReferrer)
+  , mRemoteAddress(aRemoteAddress)
+{
+}
+
+nsRedirectHistoryEntry::~nsRedirectHistoryEntry()
+{
+}
+
+NS_IMETHODIMP
+nsRedirectHistoryEntry::GetRemoteAddress(nsACString &result)
+{
+  result = mRemoteAddress;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsRedirectHistoryEntry::GetReferrerURI(nsIURI** referrer)
+{
+  NS_IF_ADDREF(*referrer = mReferrer);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsRedirectHistoryEntry::GetPrincipal(nsIPrincipal** principal)
+{
+  NS_IF_ADDREF(*principal = mPrincipal);
+  return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsRedirectHistoryEntry.h
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsRedirectHistoryEntry_h__
+#define nsRedirectHistoryEntry_h__
+
+#include "nsIRedirectHistoryEntry.h"
+
+class nsIURI;
+class nsIPrincipal;
+
+namespace mozilla {
+namespace net {
+
+class nsRedirectHistoryEntry final : public nsIRedirectHistoryEntry
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIREDIRECTHISTORYENTRY
+
+  nsRedirectHistoryEntry(nsIPrincipal* aPrincipal, nsIURI* aReferrer,
+                         const nsACString& aRemoteAddress);
+
+private:
+  ~nsRedirectHistoryEntry();
+
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIURI> mReferrer;
+  nsCString mRemoteAddress;
+
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // nsRedirectHistoryEntry_h__
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -23,44 +23,51 @@ using class mozilla::TimeStamp from "moz
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
 // LoadInfo IPDL structs
 //-----------------------------------------------------------------------------
 
+struct RedirectHistoryEntryInfo
+{
+  PrincipalInfo       principalInfo;
+  OptionalURIParams   referrerUri;
+  nsCString           remoteAddress;
+};
+
 struct LoadInfoArgs
 {
-  OptionalPrincipalInfo requestingPrincipalInfo;
-  PrincipalInfo         triggeringPrincipalInfo;
-  OptionalPrincipalInfo principalToInheritInfo;
-  OptionalPrincipalInfo sandboxedLoadingPrincipalInfo;
-  uint32_t              securityFlags;
-  uint32_t              contentPolicyType;
-  uint32_t              tainting;
-  bool                  upgradeInsecureRequests;
-  bool                  verifySignedContent;
-  bool                  enforceSRI;
-  bool                  forceInheritPrincipalDropped;
-  uint64_t              innerWindowID;
-  uint64_t              outerWindowID;
-  uint64_t              parentOuterWindowID;
-  uint64_t              frameOuterWindowID;
-  bool                  enforceSecurity;
-  bool                  initialSecurityCheckDone;
-  bool                  isInThirdPartyContext;
-  OriginAttributes      originAttributes;
-  PrincipalInfo[]       redirectChainIncludingInternalRedirects;
-  PrincipalInfo[]       redirectChain;
-  nsCString[]           corsUnsafeHeaders;
-  bool                  forcePreflight;
-  bool                  isPreflight;
-  bool                  forceHSTSPriming;
-  bool                  mixedContentWouldBlock;
+  OptionalPrincipalInfo       requestingPrincipalInfo;
+  PrincipalInfo               triggeringPrincipalInfo;
+  OptionalPrincipalInfo       principalToInheritInfo;
+  OptionalPrincipalInfo       sandboxedLoadingPrincipalInfo;
+  uint32_t                    securityFlags;
+  uint32_t                    contentPolicyType;
+  uint32_t                    tainting;
+  bool                        upgradeInsecureRequests;
+  bool                        verifySignedContent;
+  bool                        enforceSRI;
+  bool                        forceInheritPrincipalDropped;
+  uint64_t                    innerWindowID;
+  uint64_t                    outerWindowID;
+  uint64_t                    parentOuterWindowID;
+  uint64_t                    frameOuterWindowID;
+  bool                        enforceSecurity;
+  bool                        initialSecurityCheckDone;
+  bool                        isInThirdPartyContext;
+  OriginAttributes            originAttributes;
+  RedirectHistoryEntryInfo[]  redirectChainIncludingInternalRedirects;
+  RedirectHistoryEntryInfo[]  redirectChain;
+  nsCString[]                 corsUnsafeHeaders;
+  bool                        forcePreflight;
+  bool                        isPreflight;
+  bool                        forceHSTSPriming;
+  bool                        mixedContentWouldBlock;
 };
 
 /**
  * Not every channel necessarily has a loadInfo attached.
  */
 union OptionalLoadInfoArgs
 {
   void_t;