Bug 1451307 - Part 1 - Consider iframes when comparing loading URIs in nsChannelClassifier::SetBlockedContent. r=mayhemer,francois
MozReview-Commit-ID: 17edGCCTEmo
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -797,16 +797,35 @@ nsChannelClassifier::SameLoadingURI(nsID
return false;
}
bool equals = false;
nsresult rv = docURI->EqualsExceptRef(channelLoadingURI, &equals);
return NS_SUCCEEDED(rv) && equals;
}
// static
+nsPIDOMWindowOuter*
+nsChannelClassifier::GetWindowForChannel(nsIChannel *aChannel)
+{
+ nsCOMPtr<nsILoadContext> ctx;
+ NS_QueryNotificationCallbacks(aChannel, ctx);
+ if (!ctx) {
+ return nullptr;
+ }
+
+ nsCOMPtr<mozIDOMWindowProxy> window;
+ ctx->GetAssociatedWindow(getter_AddRefs(window));
+ if (!window) {
+ return nullptr;
+ }
+
+ return nsPIDOMWindowOuter::From(window);
+}
+
+// static
nsresult
nsChannelClassifier::SetBlockedContent(nsIChannel *channel,
nsresult aErrorCode,
const nsACString& aList,
const nsACString& aProvider,
const nsACString& aFullHash)
{
NS_ENSURE_ARG(!aList.IsEmpty());
@@ -824,51 +843,69 @@ nsChannelClassifier::SetBlockedContent(n
nsresult rv;
nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (classifiedChannel) {
classifiedChannel->SetMatchedInfo(aList, aProvider, aFullHash);
}
- nsCOMPtr<mozIDOMWindowProxy> win;
- nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
- do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- rv = thirdPartyUtil->GetTopWindowForChannel(channel, getter_AddRefs(win));
- NS_ENSURE_SUCCESS(rv, NS_OK);
- auto* pwin = nsPIDOMWindowOuter::From(win);
- nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
- if (!docShell) {
- return NS_OK;
- }
- nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_OK);
-
// This event might come after the user has navigated to another page.
// To prevent showing the TrackingProtection UI on the wrong page, we need to
// check that the loading URI for the channel is the same as the URI currently
- // loaded in the document.
- if (!SameLoadingURI(doc, channel)) {
+ // loaded in the document that is associated with the channel (which may be
+ // different than the top-level document, so we avoid ignoring all iframes).
+ nsCOMPtr<nsPIDOMWindowOuter> win = GetWindowForChannel(channel);
+ if (!win) {
+ return NS_OK;
+ }
+ nsCOMPtr<nsIDocument> frameDoc = win->GetExtantDoc();
+
+ // If the blocked request is the document load request to an iframe that
+ // contains a tracking page, the window associated with the channel belongs
+ // to that iframe, not its loading parent. In this case we actually want to
+ // compare load URIs with the parent frame, so we step up one level.
+ bool isDocumentLoad = false;
+ Unused << NS_WARN_IF(NS_FAILED(channel->GetIsDocument(&isDocumentLoad)));
+ if (isDocumentLoad || !frameDoc) {
+ win = win->GetParent();
+ if (NS_WARN_IF(!win)) {
+ return NS_OK;
+ }
+ frameDoc = win->GetExtantDoc();
+ }
+
+ if (!frameDoc || !SameLoadingURI(frameDoc, channel)) {
+ return NS_OK;
+ }
+
+ // Get the root docshell for updating the security UI.
+ nsCOMPtr<nsPIDOMWindowOuter> topWin = win->GetScriptableTop();
+ nsCOMPtr<nsIDocShell> topDocShell = topWin->GetDocShell();
+ if (!topDocShell) {
return NS_OK;
}
// Notify nsIWebProgressListeners of this security event.
// Can be used to change the UI state.
- nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
+ nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(topDocShell, &rv);
NS_ENSURE_SUCCESS(rv, NS_OK);
uint32_t state = 0;
nsCOMPtr<nsISecureBrowserUI> securityUI;
- docShell->GetSecurityUI(getter_AddRefs(securityUI));
+ topDocShell->GetSecurityUI(getter_AddRefs(securityUI));
if (!securityUI) {
return NS_OK;
}
securityUI->GetState(&state);
if (aErrorCode == NS_ERROR_TRACKING_URI) {
- doc->SetHasTrackingContentBlocked(true);
+ nsCOMPtr<nsIDocument> topLevelDoc = topDocShell->GetDocument();
+ if (!topLevelDoc) {
+ return NS_OK;
+ }
+ topLevelDoc->SetHasTrackingContentBlocked(true);
state |= nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
} else {
state |= nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
}
eventSink->OnSecurityChange(channel, state);
// Log a warning to the web console.
@@ -879,17 +916,17 @@ nsChannelClassifier::SetBlockedContent(n
const char* message = (aErrorCode == NS_ERROR_TRACKING_URI) ?
"TrackingUriBlocked" : "UnsafeUriBlocked";
nsCString category = (aErrorCode == NS_ERROR_TRACKING_URI) ?
NS_LITERAL_CSTRING("Tracking Protection") :
NS_LITERAL_CSTRING("Safe Browsing");
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
category,
- doc,
+ frameDoc,
nsContentUtils::eNECKO_PROPERTIES,
message,
params, ArrayLength(params));
return NS_OK;
}
namespace {
--- a/netwerk/base/nsChannelClassifier.h
+++ b/netwerk/base/nsChannelClassifier.h
@@ -75,16 +75,18 @@ private:
// Helper function so that we ensure we call ContinueBeginConnect once
// Start is called. Returns NS_OK if and only if we will get a callback
// from the classifier service.
nsresult StartInternal();
// Helper function to check a URI against the hostname whitelist
bool IsHostnameWhitelisted(nsIURI *aUri, const nsACString &aWhitelisted);
// Checks that the channel was loaded by the URI currently loaded in aDoc
static bool SameLoadingURI(nsIDocument *aDoc, nsIChannel *aChannel);
+ // Helper function to get the (not necessarily top-level) window from a channel.
+ static nsPIDOMWindowOuter* GetWindowForChannel(nsIChannel *aChannel);
// Note this function will be also used to decide whether or not to enable
// channel annotation. When |aAnnotationsOnly| is true, this function
// is called by ShouldEnableTrackingAnnotation(). Otherwise, this is called
// by ShouldEnableTrackingProtection().
nsresult ShouldEnableTrackingProtectionInternal(nsIChannel *aChannel,
bool aAnnotationsOnly,
bool *result);