From eba206c16ffc7477c6fbd2a511f9a20f8c6f1d97 Mon Sep 17 00:00:00 2001 From: "dcamp%mozilla.com" Date: Tue, 29 Jan 2008 23:49:20 +0000 Subject: [PATCH] Bug 413938: Add an nsIWebNavigation flag to let clients bypass malware/phishing detection. r=bz, sr=biesi, a1.9=damons git-svn-id: svn://10.0.0.236/trunk@244412 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/docshell/base/nsDocShell.cpp | 103 ++++++++++++++++---- mozilla/docshell/base/nsDocShell.h | 9 +- mozilla/docshell/base/nsDocShellLoadTypes.h | 3 +- mozilla/docshell/base/nsIDocShell.idl | 2 + mozilla/docshell/base/nsIWebNavigation.idl | 6 ++ 5 files changed, 102 insertions(+), 21 deletions(-) diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index d3d33f382f9..41c0dac79dd 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -149,6 +149,7 @@ #include "nsIDOMDocument.h" #include "nsICachingChannel.h" #include "nsICacheVisitor.h" +#include "nsICacheEntryDescriptor.h" #include "nsIMultiPartChannel.h" #include "nsIWyciwygChannel.h" @@ -883,6 +884,9 @@ nsDocShell::LoadURI(nsIURI * aURI, if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; + if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) + flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; + rv = InternalLoad(aURI, referrer, owner, @@ -951,7 +955,8 @@ nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI, uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader), NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, PR_FALSE), + NS_ERROR_FAILURE); return NS_OK; } @@ -7051,7 +7056,8 @@ nsDocShell::InternalLoad(nsIURI * aURI, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), owner, aTypeHint, aPostData, aHeadersData, aFirstParty, aDocShell, getter_AddRefs(req), - (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0); + (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0, + (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0); if (req && aRequest) NS_ADDREF(*aRequest = req); @@ -7121,7 +7127,8 @@ nsDocShell::DoURILoad(nsIURI * aURI, PRBool aFirstParty, nsIDocShell ** aDocShell, nsIRequest ** aRequest, - PRBool aIsNewWindowTarget) + PRBool aIsNewWindowTarget, + PRBool aBypassClassifier) { nsresult rv; nsCOMPtr uriLoader; @@ -7311,7 +7318,7 @@ nsDocShell::DoURILoad(nsIURI * aURI, } } - rv = DoChannelLoad(channel, uriLoader); + rv = DoChannelLoad(channel, uriLoader, aBypassClassifier); // // If the channel load failed, we failed and nsIWebProgress just ain't @@ -7404,7 +7411,8 @@ nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData, } nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel, - nsIURILoader * aURILoader) + nsIURILoader * aURILoader, + PRBool aBypassClassifier) { nsresult rv; // Mark the channel as being a document URI and allow content sniffing... @@ -7467,10 +7475,12 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel, this); NS_ENSURE_SUCCESS(rv, rv); - rv = CheckClassifier(aChannel); - if (NS_FAILED(rv)) { - aChannel->Cancel(rv); - return rv; + if (!aBypassClassifier) { + rv = CheckClassifier(aChannel); + if (NS_FAILED(rv)) { + aChannel->Cancel(rv); + return rv; + } } return NS_OK; @@ -9305,15 +9315,10 @@ nsClassifierCallback::Run() if (NS_FAILED(status)) return NS_OK; - // Don't bother to run the classifier on a load that's coming from the - // cache and doesn't need validaton. - nsCOMPtr cachingChannel = do_QueryInterface(channel); - if (cachingChannel) { - PRBool fromCache; - if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && - fromCache) { - return NS_OK; - } + // Don't bother to run the classifier on a cached load that was + // previously classified. + if (HasBeenClassified()) { + return NS_OK; } nsCOMPtr uri; @@ -9370,10 +9375,72 @@ nsClassifierCallback::Run() return NS_OK; } +// Note in the cache entry that this URL was classified, so that future +// cached loads don't need to be checked. +void +nsClassifierCallback::MarkEntryClassified(nsresult status) +{ + nsCOMPtr cachingChannel = + do_QueryInterface(mSuspendedChannel); + if (!cachingChannel) { + return; + } + + nsCOMPtr cacheToken; + cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); + if (!cacheToken) { + return; + } + + nsCOMPtr cacheEntry = + do_QueryInterface(cacheToken); + if (!cacheEntry) { + return; + } + + cacheEntry->SetMetaDataElement("docshell:classified", + NS_SUCCEEDED(status) ? "1" : nsnull); +} + +PRBool +nsClassifierCallback::HasBeenClassified() +{ + nsCOMPtr cachingChannel = + do_QueryInterface(mSuspendedChannel); + if (!cachingChannel) { + return PR_FALSE; + } + + // Only check the tag if we are loading from the cache without + // validation. + PRBool fromCache; + if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) { + return PR_FALSE; + } + + nsCOMPtr cacheToken; + cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); + if (!cacheToken) { + return PR_FALSE; + } + + nsCOMPtr cacheEntry = + do_QueryInterface(cacheToken); + if (!cacheEntry) { + return PR_FALSE; + } + + nsXPIDLCString tag; + cacheEntry->GetMetaDataElement("docshell:classified", getter_Copies(tag)); + return tag.EqualsLiteral("1"); +} + NS_IMETHODIMP nsClassifierCallback::OnClassifyComplete(nsresult aErrorCode) { if (mSuspendedChannel) { + MarkEntryClassified(aErrorCode); + if (NS_FAILED(aErrorCode)) { #ifdef DEBUG PR_LOG(gDocShellLog, PR_LOG_DEBUG, diff --git a/mozilla/docshell/base/nsDocShell.h b/mozilla/docshell/base/nsDocShell.h index 6b1a58941da..f6f07098cae 100644 --- a/mozilla/docshell/base/nsDocShell.h +++ b/mozilla/docshell/base/nsDocShell.h @@ -160,6 +160,9 @@ public: private: nsCOMPtr mChannel; nsCOMPtr mSuspendedChannel; + + void MarkEntryClassified(nsresult status); + PRBool HasBeenClassified(); }; //***************************************************************************** @@ -275,11 +278,13 @@ protected: PRBool firstParty, nsIDocShell ** aDocShell, nsIRequest ** aRequest, - PRBool aIsNewWindowTarget); + PRBool aIsNewWindowTarget, + PRBool aBypassClassifier); NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData, nsIChannel * aChannel); virtual nsresult DoChannelLoad(nsIChannel * aChannel, - nsIURILoader * aURILoader); + nsIURILoader * aURILoader, + PRBool aBypassClassifier); // Check the channel load against the URI classifier service (if it // exists). The channel will be suspended until the classification is diff --git a/mozilla/docshell/base/nsDocShellLoadTypes.h b/mozilla/docshell/base/nsDocShellLoadTypes.h index 173daf7a05a..0ee66b6e5b0 100644 --- a/mozilla/docshell/base/nsDocShellLoadTypes.h +++ b/mozilla/docshell/base/nsDocShellLoadTypes.h @@ -60,7 +60,8 @@ * be passed to MAKE_LOAD_TYPE. */ #define EXTRA_LOAD_FLAGS (LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | \ - LOAD_FLAGS_FIRST_LOAD) + LOAD_FLAGS_FIRST_LOAD | \ + LOAD_FLAGS_BYPASS_CLASSIFIER) /* load types are legal combinations of load commands and flags * diff --git a/mozilla/docshell/base/nsIDocShell.idl b/mozilla/docshell/base/nsIDocShell.idl index b6d8205b681..36f31898648 100644 --- a/mozilla/docshell/base/nsIDocShell.idl +++ b/mozilla/docshell/base/nsIDocShell.idl @@ -126,6 +126,8 @@ interface nsIDocShell : nsISupports // @see nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD const long INTERNAL_LOAD_FLAGS_FIRST_LOAD = 0x8; + const long INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER = 0x10; + /** * Loads the given URI. This method is identical to loadURI(...) except * that its parameter list is broken out instead of being packaged inside diff --git a/mozilla/docshell/base/nsIWebNavigation.idl b/mozilla/docshell/base/nsIWebNavigation.idl index a9dff965933..b00316c1572 100644 --- a/mozilla/docshell/base/nsIWebNavigation.idl +++ b/mozilla/docshell/base/nsIWebNavigation.idl @@ -197,6 +197,12 @@ interface nsIWebNavigation : nsISupports */ const unsigned long LOAD_FLAGS_ALLOW_POPUPS = 0x8000; + /** + * This flag specifies that the URI classifier should not be checked for + * this load. + */ + const unsigned long LOAD_FLAGS_BYPASS_CLASSIFIER = 0x10000; + /** * 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