Bug 1351146 - P2 - Update test case and usage of nsIRedirectHistoryEntry interface draft
authorThomas Nguyen <tnguyen@mozilla.com>
Mon, 24 Apr 2017 16:08:22 +0800
changeset 574030 437b9b6e59150f1964a9139612d44961ca4004cc
parent 574022 02a526a82abe5f82256165a2839ea7cfe9ffb92f
child 627466 9b1db7824b280b77d3da2894c6d084eb7e862ef0
push id57568
push userbmo:tnguyen@mozilla.com
push dateMon, 08 May 2017 09:20:13 +0000
bugs1351146
milestone55.0a1
Bug 1351146 - P2 - Update test case and usage of nsIRedirectHistoryEntry interface MozReview-Commit-ID: s61VV5CLx8
netwerk/base/nsBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/test/mochitests/file_loadinfo_redirectchain.sjs
netwerk/test/mochitests/test_loadinfo_redirectchain.html
netwerk/test/unit/test_redirect_history.js
toolkit/components/downloads/ApplicationReputation.cpp
toolkit/components/downloads/test/unit/test_app_rep.js
uriloader/exthandler/nsExternalHelperAppService.cpp
--- a/netwerk/base/nsBaseChannel.cpp
+++ b/netwerk/base/nsBaseChannel.cpp
@@ -18,16 +18,17 @@
 #include "nsIStreamConverterService.h"
 #include "nsChannelClassifier.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsProxyRelease.h"
 #include "nsXULAppAPI.h"
 #include "nsContentSecurityManager.h"
 #include "LoadInfo.h"
 #include "nsServiceManagerUtils.h"
+#include "nsRedirectHistoryEntry.h"
 
 // This class is used to suspend a request across a function scope.
 class ScopedRequestSuspender {
 public:
   explicit ScopedRequestSuspender(nsIRequest *request)
     : mRequest(request) {
     if (mRequest && NS_FAILED(mRequest->Suspend())) {
       NS_WARNING("Couldn't suspend pump");
@@ -92,17 +93,23 @@ nsBaseChannel::Redirect(nsIChannel *newC
       static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->CloneWithNewSecFlags(secFlags);
 
     nsCOMPtr<nsIPrincipal> uriPrincipal;
     nsIScriptSecurityManager *sm = nsContentUtils::GetSecurityManager();
     sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal));
     bool isInternalRedirect =
       (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
                         nsIChannelEventSink::REDIRECT_STS_UPGRADE));
-    newLoadInfo->AppendRedirectedPrincipal(uriPrincipal, isInternalRedirect);
+
+    // nsBaseChannel hst no thing to do with HttpBaseChannel, we would not care
+    // about referrer and remote address in this case
+    nsCOMPtr<nsIRedirectHistoryEntry> entry =
+      new nsRedirectHistoryEntry(uriPrincipal, nullptr, EmptyCString());
+
+    newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
     newChannel->SetLoadInfo(newLoadInfo);
   }
   else {
     // the newChannel was created with a dummy loadInfo, we should clear
     // it in case the original channel does not have a loadInfo
     newChannel->SetLoadInfo(nullptr);
   }
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -58,16 +58,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIMIMEInputStream.h"
 #include "nsIXULRuntime.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIThrottlingService.h"
+#include "nsRedirectHistoryEntry.h"
 
 #include <algorithm>
 #include "HttpBaseChannel.h"
 
 namespace mozilla {
 namespace net {
 
 static
@@ -3178,17 +3179,22 @@ HttpBaseChannel::SetupReplacementChannel
       attrs = docShellAttrs;
       attrs.SetFirstPartyDomain(true, newURI);
       newLoadInfo->SetOriginAttributes(attrs);
     }
 
     bool isInternalRedirect =
       (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
                         nsIChannelEventSink::REDIRECT_STS_UPGRADE));
-    newLoadInfo->AppendRedirectedPrincipal(GetURIPrincipal(), isInternalRedirect);
+    nsCString remoteAddress;
+    Unused << GetRemoteAddress(remoteAddress);
+    nsCOMPtr<nsIRedirectHistoryEntry> entry =
+      new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress);
+
+    newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
     newChannel->SetLoadInfo(newLoadInfo);
   }
   else {
     // the newChannel was created with a dummy loadInfo, we should clear
     // it in case the original channel does not have a loadInfo
     newChannel->SetLoadInfo(nullptr);
   }
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1463,20 +1463,25 @@ class Redirect1Event : public ChannelEve
 };
 
 mozilla::ipc::IPCResult
 HttpChannelChild::RecvRedirect1Begin(const uint32_t& registrarId,
                                      const URIParams& newUri,
                                      const uint32_t& redirectFlags,
                                      const nsHttpResponseHead& responseHead,
                                      const nsCString& securityInfoSerialization,
-                                     const uint64_t& channelId)
+                                     const uint64_t& channelId,
+                                     const NetAddr& oldPeerAddr)
 {
   // TODO: handle security info
   LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this));
+  // We set peer address of child to the old peer,
+  // Then it will be updated to new peer in OnStartRequest
+  mPeerAddr = oldPeerAddr;
+
   mEventQ->RunOrEnqueue(new Redirect1Event(this, registrarId, newUri,
                                            redirectFlags, responseHead,
                                            securityInfoSerialization,
                                            channelId));
   return IPC_OK();
 }
 
 nsresult
@@ -1769,17 +1774,22 @@ void
 HttpChannelChild::CleanupRedirectingChannel(nsresult rv)
 {
   // Redirecting to new channel: shut this down and init new channel
   if (mLoadGroup)
     mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
 
   if (NS_SUCCEEDED(rv)) {
     if (mLoadInfo) {
-      mLoadInfo->AppendRedirectedPrincipal(GetURIPrincipal(), false);
+      nsCString remoteAddress;
+      Unused << GetRemoteAddress(remoteAddress);
+      nsCOMPtr<nsIRedirectHistoryEntry> entry =
+        new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress);
+
+      mLoadInfo->AppendRedirectHistoryEntry(entry, false);
     }
   }
   else {
     NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
   }
 
   // Release ref to new channel.
   mRedirectChannelChild = nullptr;
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -142,17 +142,18 @@ protected:
   mozilla::ipc::IPCResult RecvOnProgress(const int64_t& progress, const int64_t& progressMax) override;
   mozilla::ipc::IPCResult RecvOnStatus(const nsresult& status) override;
   mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override;
   mozilla::ipc::IPCResult RecvRedirect1Begin(const uint32_t& registrarId,
                                              const URIParams& newURI,
                                              const uint32_t& redirectFlags,
                                              const nsHttpResponseHead& responseHead,
                                              const nsCString& securityInfoSerialization,
-                                             const uint64_t& channelId) override;
+                                             const uint64_t& channelId,
+                                             const NetAddr& oldPeerAddr) override;
   mozilla::ipc::IPCResult RecvRedirect3Complete() override;
   mozilla::ipc::IPCResult RecvAssociateApplicationCache(const nsCString& groupID,
                                                         const nsCString& clientID) override;
   mozilla::ipc::IPCResult RecvFlushedForDiversion() override;
   mozilla::ipc::IPCResult RecvDivertMessages() override;
   mozilla::ipc::IPCResult RecvDeleteSelf() override;
   mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1472,17 +1472,18 @@ HttpChannelParent::StartRedirect(uint32_
 
   nsHttpResponseHead *responseHead = mChannel->GetResponseHead();
   bool result = false;
   if (!mIPCClosed) {
     result = SendRedirect1Begin(registrarId, uriParams, redirectFlags,
                                 responseHead ? *responseHead
                                              : nsHttpResponseHead(),
                                 secInfoSerialization,
-                                channelId);
+                                channelId,
+                                mChannel->GetPeerAddr());
   }
   if (!result) {
     // Bug 621446 investigation
     mSentRedirect1BeginFailed = true;
     return NS_BINDING_ABORTED;
   }
 
   // Bug 621446 investigation
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -131,17 +131,18 @@ child:
 
   // Called to initiate content channel redirect, starts talking to sinks
   // on the content process and reports result via Redirect2Verify above
   async Redirect1Begin(uint32_t           registrarId,
                        URIParams          newUri,
                        uint32_t           redirectFlags,
                        nsHttpResponseHead responseHead,
                        nsCString          securityInfoSerialization,
-                       uint64_t           channelId);
+                       uint64_t           channelId,
+                       NetAddr            oldPeerAddr);
 
   // Called if redirect successful so that child can complete setup.
   async Redirect3Complete();
 
   // Associate the child with an application ids
   async AssociateApplicationCache(nsCString groupID,
                                   nsCString clientID);
 
--- a/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs
+++ b/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs
@@ -16,20 +16,20 @@ function createIframeContent(aQuery) {
     var myXHR = new XMLHttpRequest();
     myXHR.open("GET", "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?` + aQuery + `");
     myXHR.onload = function() {
     var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;
     var redirectChain = loadinfo.redirectChain;
     var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;
     var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };
     for (var i = 0; i < redirectChain.length; i++) {
-      resultOBJ.redirectChain.push(redirectChain[i].URI.spec);
+      resultOBJ.redirectChain.push(redirectChain[i].principal.URI.spec);
     }
     for (var i = 0; i < redirectChainIncludingInternalRedirects.length; i++) {
-      resultOBJ.redirectChainIncludingInternalRedirects.push(redirectChainIncludingInternalRedirects[i].URI.spec);
+      resultOBJ.redirectChainIncludingInternalRedirects.push(redirectChainIncludingInternalRedirects[i].principal.URI.spec);
     }
     var loadinfoJSON = JSON.stringify(resultOBJ);
     window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");
   }
   myXHR.onerror = function() {
     var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };
     var loadinfoJSON = JSON.stringify(resultOBJ);
     window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");
--- a/netwerk/test/mochitests/test_loadinfo_redirectchain.html
+++ b/netwerk/test/mochitests/test_loadinfo_redirectchain.html
@@ -76,37 +76,49 @@ function checkLoadInfoWithTwoRedirects()
   var myXHR = new XMLHttpRequest();
   myXHR.open("GET", "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-2");
 
   const EXPECTED_REDIRECT_CHAIN = [
     "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-2",
     "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-1"
   ];
 
+  // Referrer header will not change when redirect
+  const EXPECTED_REFERRER =
+    "http://mochi.test:8888/tests/netwerk/test/mochitests/test_loadinfo_redirectchain.html";
+  const isAndroid = !!navigator.userAgent.includes("Android");
+  const EXPECTED_REMOTE_IP = isAndroid ? "10.0.2.2" : "127.0.0.1";
+
   myXHR.onload = function() {
     is(myXHR.responseText, "checking redirectchain", "sanity check to make sure redirects succeeded");
 
     var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;
     var redirectChain = loadinfo.redirectChain;
     var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;
 
     is(redirectChain.length,
        EXPECTED_REDIRECT_CHAIN.length,
        "two redirects, chain should have length 2");
     is(redirectChainIncludingInternalRedirects.length,
        EXPECTED_REDIRECT_CHAIN.length,
        "two redirect, chainInternal should have length 2");
 
     for (var i = 0; i < redirectChain.length; i++) {
-      is(redirectChain[i].URI.spec,
+      is(redirectChain[i].principal.URI.spec,
         EXPECTED_REDIRECT_CHAIN[i],
          "redirectChain at index [" + i + "] should match");
-      is(redirectChainIncludingInternalRedirects[i].URI.spec,
+      is(redirectChainIncludingInternalRedirects[i].principal.URI.spec,
          EXPECTED_REDIRECT_CHAIN[i],
          "redirectChainIncludingInternalRedirects at index [" + i + "] should match");
+      is(redirectChain[i].referrerURI.spec,
+         EXPECTED_REFERRER,
+         "referrer should match");
+      is(redirectChain[i].remoteAddress,
+         EXPECTED_REMOTE_IP,
+         "remote address should match");
     }
 
     // move on to the next test
     checkLoadInfoWithInternalRedirects();
   }
   myXHR.onerror = function() {
     ok(false, "xhr problem within checkLoadInfoWithTwoRedirects()");
   }
--- a/netwerk/test/unit/test_redirect_history.js
+++ b/netwerk/test/unit/test_redirect_history.js
@@ -25,18 +25,20 @@ function contentHandler(request, respons
 function finish_test(request, buffer)
 {
   do_check_eq(buffer, responseBody);
   let chan = request.QueryInterface(Ci.nsIChannel);
   let redirectChain = chan.loadInfo.redirectChain;
 
   do_check_eq(numRedirects - 1, redirectChain.length);
   for (let i = 0; i < numRedirects - 1; ++i) {
-    let principal = redirectChain[i];
+    let principal = redirectChain[i].principal;
     do_check_eq(URL + redirects[i], principal.URI.spec);
+    do_check_eq(redirectChain[i].referrerURI.spec, "http://test.com/");
+    do_check_eq(redirectChain[i].remoteAddress, "127.0.0.1");
   }
   httpServer.stop(do_test_finished);
 }
 
 function redirectHandler(index, request, response) {
   response.setStatusLine(request.httpVersion, 301, "Moved");
   let path = redirects[index + 1];
   response.setHeader("Location", URL + path, false);
@@ -54,11 +56,14 @@ function run_test()
       // The last one doesn't redirect
       httpServer.registerPathHandler(redirects[numRedirects - 1],
                                      contentHandler);
     }
   }
   httpServer.start(-1);
 
   var chan = make_channel(URL + redirects[0]);
+  var uri = NetUtil.newURI("http://test.com");
+  httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
+  httpChan.referrer = uri;
   chan.asyncOpen2(new ChannelListener(finish_test, null));
   do_test_pending();
 }
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -50,16 +50,17 @@
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 #include "nsIContentPolicy.h"
 #include "nsILoadInfo.h"
 #include "nsContentUtils.h"
 #include "nsWeakReference.h"
 #include "nsCharSeparatedTokenizer.h"
+#include "nsIRedirectHistoryEntry.h"
 
 using namespace mozilla::downloads;
 using mozilla::ArrayLength;
 using mozilla::BasePrincipal;
 using mozilla::OriginAttributes;
 using mozilla::Preferences;
 using mozilla::TimeStamp;
 using mozilla::Telemetry::Accumulate;
@@ -1023,17 +1024,21 @@ PendingLookup::AddRedirects(nsIArray* aR
   rv = iter->HasMoreElements(&hasMoreRedirects);
   NS_ENSURE_SUCCESS(rv, rv);
 
   while (hasMoreRedirects) {
     nsCOMPtr<nsISupports> supports;
     rv = iter->GetNext(getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(supports, &rv);
+    nsCOMPtr<nsIRedirectHistoryEntry> redirectEntry = do_QueryInterface(supports, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIPrincipal> principal;
+    rv = redirectEntry->GetPrincipal(getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIURI> uri;
     rv = principal->GetURI(getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Add the spec to our list of local lookups. The most recent redirect is
     // the last element.
--- a/toolkit/components/downloads/test/unit/test_app_rep.js
+++ b/toolkit/components/downloads/test/unit/test_app_rep.js
@@ -325,19 +325,35 @@ add_test(function test_redirect_on_block
                              "http://localhost:4444/download");
   let counts = get_telemetry_counts();
   let listCounts = counts.listCounts;
   listCounts[BLOCK_LIST]++;
   listCounts[ALLOW_LIST]++;
   let secman = Services.scriptSecurityManager;
   let badRedirects = Cc["@mozilla.org/array;1"]
                        .createInstance(Ci.nsIMutableArray);
-  badRedirects.appendElement(secman.createCodebasePrincipal(exampleURI, {}));
-  badRedirects.appendElement(secman.createCodebasePrincipal(blocklistedURI, {}));
-  badRedirects.appendElement(secman.createCodebasePrincipal(whitelistedURI, {}));
+
+  let redirect1 = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIRedirectHistoryEntry]),
+    principal: secman.createCodebasePrincipal(exampleURI, {}),
+  };
+  badRedirects.appendElement(redirect1);
+
+  let redirect2 = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIRedirectHistoryEntry]),
+    principal: secman.createCodebasePrincipal(blocklistedURI, {}),
+  };
+  badRedirects.appendElement(redirect2);
+
+  let redirect3 = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIRedirectHistoryEntry]),
+    principal: secman.createCodebasePrincipal(whitelistedURI, {}),
+  };
+  badRedirects.appendElement(redirect3);
+
   gAppRep.queryReputation({
     sourceURI: whitelistedURI,
     referrerURI: exampleURI,
     redirects: badRedirects,
     fileSize: 12,
   }, function onComplete(aShouldBlock, aStatus) {
     do_check_eq(Cr.NS_OK, aStatus);
     do_check_true(aShouldBlock);
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -36,16 +36,17 @@
 #include "nsITransfer.h"
 #include "nsReadableUtils.h"
 #include "nsIRequest.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsThreadUtils.h"
 #include "nsAutoPtr.h"
 #include "nsIMutableArray.h"
+#include "nsIRedirectHistoryEntry.h"
 
 // used to access our datastore of user-configured helper applications
 #include "nsIHandlerService.h"
 #include "nsIMIMEInfo.h"
 #include "nsIRefreshURI.h" // XXX needed to redirect according to Refresh: URI
 #include "nsIDocumentLoader.h" // XXX needed to get orig. channel and assoc. refresh uri
 #include "nsIHelperAppLauncherDialog.h"
 #include "nsIContentDispatchChooser.h"
@@ -2048,18 +2049,18 @@ nsExternalAppHandler::OnSaveComplete(nsI
       nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
       if (loadInfo) {
         nsresult rv = NS_OK;
         nsCOMPtr<nsIMutableArray> redirectChain =
           do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
         NS_ENSURE_SUCCESS(rv, rv);
         LOG(("nsExternalAppHandler: Got %" PRIuSIZE " redirects\n",
              loadInfo->RedirectChain().Length()));
-        for (nsIPrincipal* principal : loadInfo->RedirectChain()) {
-          redirectChain->AppendElement(principal, false);
+        for (nsIRedirectHistoryEntry* entry : loadInfo->RedirectChain()) {
+          redirectChain->AppendElement(entry, false);
         }
         mRedirects = redirectChain;
       }
     }
 
     if (NS_FAILED(aStatus)) {
       nsAutoString path;
       mTempFile->GetPath(path);