block document loads for URIs tagged as malware by the url-classifier service. b=384941, r=bzbarsky, r=tony, sr=biesi, ui-r=johnath, a=bzbarsky

git-svn-id: svn://10.0.0.236/trunk@233523 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dcamp%mozilla.com
2007-08-31 23:18:48 +00:00
parent 1a2a6df23f
commit 1a066ed8a8
14 changed files with 470 additions and 21 deletions

View File

@@ -58,6 +58,7 @@
#include "nsIDocumentViewer.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsCURILoader.h"
#include "nsURILoader.h"
#include "nsDocShellCID.h"
#include "nsLayoutCID.h"
#include "nsDOMCID.h"
@@ -105,6 +106,7 @@
#include "nsIViewManager.h"
#include "nsIScrollableView.h"
#include "nsIScriptChannel.h"
#include "nsIURIClassifier.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@@ -2840,6 +2842,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
PRUint32 formatStrCount = 0;
nsresult rv = NS_OK;
nsAutoString messageStr;
nsCAutoString cssClass;
// Turn the error code into a human readable error message.
if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
@@ -2980,6 +2983,15 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
// Bad Content Encoding.
error.AssignLiteral("contentEncodingError");
break;
case NS_ERROR_MALWARE_URI:
nsCAutoString host;
aURI->GetHost(host);
CopyUTF8toUTF16(host, formatStrs[0]);
formatStrCount = 1;
error.AssignLiteral("malwareBlocked");
cssClass.AssignLiteral("blacklist");
break;
}
}
@@ -3021,7 +3033,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
if (mUseErrorPages && aURI && aFailedChannel) {
// Display an error page
LoadErrorPage(aURI, aURL, error.get(), messageStr.get(),
aFailedChannel);
cssClass.get(), aFailedChannel);
}
else
{
@@ -3046,6 +3058,7 @@ NS_IMETHODIMP
nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
const PRUnichar *aErrorType,
const PRUnichar *aDescription,
const char *aCSSClass,
nsIChannel* aFailedChannel)
{
#if defined(PR_LOGGING) && defined(DEBUG)
@@ -3110,12 +3123,17 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
char *escapedCharset = nsEscape(charset.get(), url_Path);
char *escapedError = nsEscape(NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
char *escapedDescription = nsEscape(NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
char *escapedCSSClass = nsEscape(aCSSClass, url_Path);
nsCString errorPageUrl("about:neterror?e=");
errorPageUrl.AppendASCII(escapedError);
errorPageUrl.AppendLiteral("&u=");
errorPageUrl.AppendASCII(escapedUrl);
if (escapedCSSClass && escapedCSSClass[0]) {
errorPageUrl.AppendASCII("&s=");
errorPageUrl.AppendASCII(escapedCSSClass);
}
errorPageUrl.AppendLiteral("&c=");
errorPageUrl.AppendASCII(escapedCharset);
errorPageUrl.AppendLiteral("&d=");
@@ -3125,6 +3143,7 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
nsMemory::Free(escapedError);
nsMemory::Free(escapedUrl);
nsMemory::Free(escapedCharset);
nsMemory::Free(escapedCSSClass);
nsCOMPtr<nsIURI> errorPageURI;
nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
@@ -3222,6 +3241,11 @@ nsDocShell::Stop(PRUint32 aStopFlags)
mRefreshURIList = nsnull;
}
if (mClassifier) {
mClassifier->Cancel();
mClassifier = nsnull;
}
// XXXbz We could also pass |this| to nsIURILoader::Stop. That will
// just call Stop() on us as an nsIDocumentLoader... We need fewer
// redundant apis!
@@ -4831,6 +4855,17 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
if (!(aStateFlags & STATE_IS_DOCUMENT))
return; // not a toplevel document
// If this load is being checked by the URI classifier, we need to
// query the classifier again for the new URI.
if (mClassifier) {
mClassifier->SetChannel(aNewChannel);
// we call the nsClassifierCallback:Run() from the main loop to
// give the channel a chance to AsyncOpen() the channel before
// we suspend it.
NS_DispatchToCurrentThread(mClassifier);
}
nsCOMPtr<nsIGlobalHistory3> history3(do_QueryInterface(mGlobalHistory));
nsresult result = NS_ERROR_NOT_IMPLEMENTED;
if (history3) {
@@ -4880,6 +4915,10 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
// during this load handler.
//
nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
// We're done with the URI classifier for this channel
mClassifier = nsnull;
//
// Notify the ContentViewer that the Document has finished loading...
//
@@ -7244,8 +7283,34 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
rv = aURILoader->OpenURI(aChannel,
(mLoadType == LOAD_LINK),
this);
return rv;
NS_ENSURE_SUCCESS(rv, rv);
rv = CheckClassifier(aChannel);
if (NS_FAILED(rv)) {
aChannel->Cancel(rv);
return rv;
}
return NS_OK;
}
nsresult
nsDocShell::CheckClassifier(nsIChannel *aChannel)
{
nsRefPtr<nsClassifierCallback> classifier = new nsClassifierCallback();
if (!classifier) return NS_ERROR_OUT_OF_MEMORY;
classifier->SetChannel(aChannel);
nsresult rv = classifier->Run();
if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
// no URI classifier, ignore this
return NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
mClassifier = classifier;
return NS_OK;
}
NS_IMETHODIMP
@@ -8992,4 +9057,126 @@ nsDocShell::IsAboutBlank(nsIURI* aURI)
aURI->GetSpec(str);
return str.EqualsLiteral("about:blank");
}
//*****************************************************************************
// nsClassifierCallback
//*****************************************************************************
NS_IMPL_THREADSAFE_ISUPPORTS2(nsClassifierCallback,
nsIURIClassifierCallback,
nsIRunnable)
NS_IMETHODIMP
nsClassifierCallback::Run()
{
if (!mChannel) {
return NS_OK;
}
NS_ASSERTION(!mSuspendedChannel,
"nsClassifierCallback::Run() called while a "
"channel is still suspended.");
nsCOMPtr<nsIChannel> channel;
channel.swap(mChannel);
// Don't bother to run the classifier on a load that has already failed.
// (this might happen after a redirect)
PRUint32 status;
channel->GetStatus(&status);
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<nsICachingChannel> cachingChannel = do_QueryInterface(channel);
if (cachingChannel) {
PRBool fromCache;
if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) &&
fromCache) {
return NS_OK;
}
}
nsCOMPtr<nsIURI> uri;
nsresult rv = channel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
// Don't bother checking certain types of URIs.
PRBool hasFlags;
rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) return NS_OK;
rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) return NS_OK;
rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) return NS_OK;
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
PRBool expectCallback;
rv = uriClassifier->Classify(uri, this, &expectCallback);
if (NS_FAILED(rv)) return rv;
if (expectCallback) {
// Suspend the channel, it will be resumed when we get the classifier
// callback.
rv = channel->Suspend();
NS_ENSURE_SUCCESS(rv, rv);
mSuspendedChannel = channel;
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsClassifierCallback[%p]: suspended channel %p",
this, mSuspendedChannel.get()));
}
return NS_OK;
}
NS_IMETHODIMP
nsClassifierCallback::OnClassifyComplete(nsresult aErrorCode)
{
if (mSuspendedChannel) {
if (NS_FAILED(aErrorCode)) {
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsClassifierCallback[%p]: cancelling channel %p with error code: %d",
this, mSuspendedChannel.get(), aErrorCode));
mSuspendedChannel->Cancel(aErrorCode);
}
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsClassifierCallback[%p]: resuming channel %p from OnClassifyComplete",
this, mSuspendedChannel.get()));
mSuspendedChannel->Resume();
mSuspendedChannel = nsnull;
}
return NS_OK;
}
void
nsClassifierCallback::Cancel()
{
if (mSuspendedChannel) {
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
("nsClassifierCallback[%p]: resuming channel %p from Cancel()",
this, mSuspendedChannel.get()));
mSuspendedChannel->Resume();
mSuspendedChannel = nsnull;
}
if (mChannel) {
mChannel = nsnull;
}
}