Bug 1351146 - P2 - Update test case and usage of nsIRedirectHistoryEntry interface
MozReview-Commit-ID: s61VV5CLx8
--- 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);