diff --git a/mozilla/browser/locales/en-US/chrome/overrides/appstrings.properties b/mozilla/browser/locales/en-US/chrome/overrides/appstrings.properties index eafb720c46b..357abe385ca 100644 --- a/mozilla/browser/locales/en-US/chrome/overrides/appstrings.properties +++ b/mozilla/browser/locales/en-US/chrome/overrides/appstrings.properties @@ -59,3 +59,4 @@ externalProtocolPrompt=An external application must be launched to handle %1$S: externalProtocolUnknown= externalProtocolChkMsg=Remember my choice for all links of this type. externalProtocolLaunchBtn=Launch application +malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences. diff --git a/mozilla/docshell/base/Makefile.in b/mozilla/docshell/base/Makefile.in index fd1074642ab..cbe158912a9 100644 --- a/mozilla/docshell/base/Makefile.in +++ b/mozilla/docshell/base/Makefile.in @@ -113,6 +113,7 @@ XPIDLSRCS = \ nsIURIFixup.idl \ nsIEditorDocShell.idl \ nsIWebPageDescriptor.idl \ + nsIURIClassifier.idl \ $(NULL) EXPORTS = nsDocShellLoadTypes.h diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index cb0d16d1ca1..68536f5fe15 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -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 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 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 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 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 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 cachingChannel = do_QueryInterface(channel); + if (cachingChannel) { + PRBool fromCache; + if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && + fromCache) { + return NS_OK; + } + } + + nsCOMPtr 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 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; + } +} diff --git a/mozilla/docshell/base/nsDocShell.h b/mozilla/docshell/base/nsDocShell.h index 2e3dcce912b..e44a8deb521 100644 --- a/mozilla/docshell/base/nsDocShell.h +++ b/mozilla/docshell/base/nsDocShell.h @@ -105,6 +105,7 @@ #include "nsIObserver.h" #include "nsDocShellLoadTypes.h" #include "nsPIDOMEventTarget.h" +#include "nsIURIClassifier.h" class nsIScrollableView; @@ -141,6 +142,26 @@ protected: virtual ~nsRefreshTimer(); }; +class nsClassifierCallback : public nsIURIClassifierCallback + , public nsIRunnable +{ +public: + nsClassifierCallback() {} + ~nsClassifierCallback() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIURICLASSIFIERCALLBACK + NS_DECL_NSIRUNNABLE + + void SetChannel(nsIChannel * aChannel) + { mChannel = aChannel; } + + void Cancel(); +private: + nsCOMPtr mChannel; + nsCOMPtr mSuspendedChannel; +}; + //***************************************************************************** //*** nsDocShell //***************************************************************************** @@ -260,6 +281,12 @@ protected: nsIChannel * aChannel); virtual nsresult DoChannelLoad(nsIChannel * aChannel, nsIURILoader * aURILoader); + + // Check the channel load against the URI classifier service (if it + // exists). The channel will be suspended until the classification is + // complete. + nsresult CheckClassifier(nsIChannel *aChannel); + NS_IMETHOD ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor, PRUint32 aLoadType, nscoord *cx, nscoord *cy); @@ -379,6 +406,7 @@ protected: NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, const PRUnichar *aPage, const PRUnichar *aDescription, + const char *aCSSClass, nsIChannel* aFailedChannel); PRBool IsNavigationAllowed(PRBool aDisplayPrintErrorDialog = PR_TRUE); PRBool IsPrintingOrPP(PRBool aDisplayErrorDialog = PR_TRUE); @@ -612,6 +640,9 @@ protected: // Secure browser UI object nsCOMPtr mSecurityUI; + // Suspends/resumes channels based on the URI classifier. + nsRefPtr mClassifier; + // WEAK REFERENCES BELOW HERE. // Note these are intentionally not addrefd. Doing so will create a cycle. // For that reasons don't use nsCOMPtr. diff --git a/mozilla/docshell/base/nsIURIClassifier.idl b/mozilla/docshell/base/nsIURIClassifier.idl new file mode 100644 index 00000000000..04c07bfc355 --- /dev/null +++ b/mozilla/docshell/base/nsIURIClassifier.idl @@ -0,0 +1,85 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dave Camp + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIURI; +interface nsIChannel; + +/** + * Callback function for nsIURIClassifier lookups. + */ +[scriptable, function, uuid(8face46e-0c96-470f-af40-0037dcd797bd)] +interface nsIURIClassifierCallback : nsISupports +{ + /** + * Called by the URI classifier service when it is done checking a URI. + * + * Clients are responsible for associating callback objects with classify() + * calls. + * + * @param aErrorCode + * The error code with which the channel should be cancelled, or + * NS_OK if the load should continue normally. + */ + void onClassifyComplete(in nsresult aErrorCode); +}; + +/** + * The URI classifier service checks a URI against lists of phishing + * and malware sites. + */ +[scriptable, uuid(2de5c563-1203-43dd-a212-f5d56d530b6f)] +interface nsIURIClassifier : nsISupports +{ + /** + * Classify a URI. + * + * @param aURI + * The URI that should be checked by the URI classifier. + * @param aCallback + * The URI classifier will call this callback when the URI has been + * classified. + * + * @return false if classification is not necessary. The + * callback will not be called. + * true if classification will be performed. The + * callback will be called. + */ + boolean classify(in nsIURI aURI, + in nsIURIClassifierCallback aCallback); +}; diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index 883b11b28b8..35c2eca14f3 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -85,6 +85,7 @@ #include "nsIDocShellTreeNode.h" #include "nsIDocShellTreeOwner.h" #include "nsCURILoader.h" +#include "nsURILoader.h" #include "nsIDOMWindowInternal.h" #include "nsEscape.h" #include "nsIPlatformCharset.h" @@ -124,6 +125,8 @@ #include "nsIScriptSecurityManager.h" #include "nsContentPolicyUtils.h" +#include "nsIURIClassifier.h" + #ifdef NS_DEBUG /** * Note: the log module is created during initialization which @@ -1191,6 +1194,7 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE || aStatus == NS_ERROR_NET_INTERRUPT || aStatus == NS_ERROR_NET_RESET || + aStatus == NS_ERROR_MALWARE_URI || NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { DisplayLoadError(aStatus, url, nsnull, channel); } diff --git a/mozilla/docshell/build/nsDocShellCID.h b/mozilla/docshell/build/nsDocShellCID.h index 48e4c87d71d..4dd040e0da7 100644 --- a/mozilla/docshell/build/nsDocShellCID.h +++ b/mozilla/docshell/build/nsDocShellCID.h @@ -49,6 +49,12 @@ #define NS_WEBNAVIGATION_INFO_CONTRACTID \ "@mozilla.org/webnavigation-info;1" +/** + * Contract ID for a service implementing nsIURIClassifier that identifies + * phishing and malware sites. + */ +#define NS_URICLASSIFIERSERVICE_CONTRACTID "@mozilla.org/uriclassifierservice" + /** * An observer service topic that can be listened to to catch creation * of content browsing areas (both toplevel ones and subframes). The diff --git a/mozilla/docshell/resources/content/netError.xhtml b/mozilla/docshell/resources/content/netError.xhtml index 5bce0393e2f..886410ebeb3 100644 --- a/mozilla/docshell/resources/content/netError.xhtml +++ b/mozilla/docshell/resources/content/netError.xhtml @@ -67,7 +67,7 @@ // or optionally, to specify an alternate CSS class to allow for // custom styling and favicon: // - // moz-neterror:page?c=classname&e=error&u=url&d=desc + // moz-neterror:page?e=error&u=url&s=classname&d=desc // Note that this file uses document.documentURI to get // the URL (with the format from above). This is because @@ -86,14 +86,13 @@ function getCSSClass() { var url = document.documentURI; - var classParam = url.search(/c\=/); - - // c is optional, if classParam == -1 just return nothing - if (classParam == -1) + var matches = url.match(/s\=([^&]+)\&/); + // s is optional, if no match just return nothing + if (!matches || matches.length < 2) return ""; - - var rest = url.search(/\&/); - return decodeURIComponent(url.slice(classParam + 2, rest)); + + // parenthetical match is the second entry + return decodeURIComponent(matches[1]); } function getDescription() diff --git a/mozilla/dom/locales/en-US/chrome/appstrings.properties b/mozilla/dom/locales/en-US/chrome/appstrings.properties index 673456cacf1..b31d45522e7 100644 --- a/mozilla/dom/locales/en-US/chrome/appstrings.properties +++ b/mozilla/dom/locales/en-US/chrome/appstrings.properties @@ -59,3 +59,4 @@ externalProtocolPrompt=An external application must be launched to handle %1$S: externalProtocolUnknown= externalProtocolChkMsg=Remember my choice for all links of this type. externalProtocolLaunchBtn=Launch application +malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences. diff --git a/mozilla/toolkit/components/build/nsToolkitCompsModule.cpp b/mozilla/toolkit/components/build/nsToolkitCompsModule.cpp index 869789eca0c..4da2431a38d 100644 --- a/mozilla/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/mozilla/toolkit/components/build/nsToolkitCompsModule.cpp @@ -58,6 +58,7 @@ #include "nsUrlClassifierDBService.h" #include "nsUrlClassifierStreamUpdater.h" #include "nsUrlClassifierUtils.h" +#include "nsDocShellCID.h" #endif #ifdef MOZ_FEEDS @@ -137,6 +138,10 @@ static const nsModuleComponentInfo components[] = NS_URLCLASSIFIERDBSERVICE_CID, NS_URLCLASSIFIERDBSERVICE_CONTRACTID, nsUrlClassifierDBServiceConstructor }, + { "Url Classifier DB Service", + NS_URLCLASSIFIERDBSERVICE_CID, + NS_URICLASSIFIERSERVICE_CONTRACTID, + nsUrlClassifierDBServiceConstructor }, { "Url Classifier Stream Updater", NS_URLCLASSIFIERSTREAMUPDATER_CID, NS_URLCLASSIFIERSTREAMUPDATER_CONTRACTID, diff --git a/mozilla/toolkit/components/url-classifier/src/Makefile.in b/mozilla/toolkit/components/url-classifier/src/Makefile.in index 8a8bb1f024d..c6303b6596d 100644 --- a/mozilla/toolkit/components/url-classifier/src/Makefile.in +++ b/mozilla/toolkit/components/url-classifier/src/Makefile.in @@ -12,9 +12,11 @@ LIBXUL_LIBRARY = 1 FORCE_STATIC_LIB = 1 -REQUIRES = necko \ +REQUIRES = docshell \ + necko \ storage \ string \ + uriloader \ xpcom \ $(ZLIB_REQUIRES) \ $(NULL) diff --git a/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp b/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp index ff189cfd400..4bc2318d28c 100644 --- a/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp +++ b/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp @@ -38,6 +38,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "mozIStorageService.h" #include "mozIStorageConnection.h" @@ -50,11 +51,15 @@ #include "nsICryptoHash.h" #include "nsIDirectoryService.h" #include "nsIObserverService.h" +#include "nsIPrefBranch.h" +#include "nsIPrefBranch2.h" +#include "nsIPrefService.h" #include "nsIProperties.h" #include "nsIProxyObjectManager.h" #include "nsToolkitCompsCID.h" #include "nsIUrlClassifierUtils.h" #include "nsUrlClassifierDBService.h" +#include "nsURILoader.h" #include "nsString.h" #include "nsTArray.h" #include "nsVoidArray.h" @@ -119,6 +124,10 @@ static const PRLogModuleInfo *gUrlClassifierDbServiceLog = nsnull; #define KEY_LENGTH 16 +// Prefs for implementing nsIURIClassifier to block page loads +#define CHECK_MALWARE_PREF "browser.safebrowsing.malware.enabled" +#define CHECK_MALWARE_DEFAULT PR_FALSE + // Singleton instance. static nsUrlClassifierDBService* sUrlClassifierDBService; @@ -2028,11 +2037,55 @@ nsUrlClassifierDBServiceWorker::MaybeCreateTables(mozIStorageConnection* connect return rv; } +// ------------------------------------------------------------------------- +// Helper class for nsIURIClassifier implementation, translates table names +// to nsIURIClassifier enums. + +class nsUrlClassifierClassifyCallback : public nsIUrlClassifierCallback +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIURLCLASSIFIERCALLBACK + + nsUrlClassifierClassifyCallback(nsIURIClassifierCallback *c) + : mCallback(c) + {} + +private: + nsCOMPtr mCallback; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierClassifyCallback, + nsIUrlClassifierCallback); + +NS_IMETHODIMP +nsUrlClassifierClassifyCallback::HandleEvent(const nsACString& tables) +{ + // XXX: we should probably have the wardens tell the service which table + // names match with which classification. For now the table names give + // enough information. + nsresult response = NS_OK; + + nsACString::const_iterator begin, end; + + tables.BeginReading(begin); + tables.EndReading(end); + if (FindInReadable(NS_LITERAL_CSTRING("-malware-"), begin, end)) { + response = NS_ERROR_MALWARE_URI; + } + + mCallback->OnClassifyComplete(response); + + return NS_OK; +} + + // ------------------------------------------------------------------------- // Proxy class implementation -NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierDBService, +NS_IMPL_THREADSAFE_ISUPPORTS3(nsUrlClassifierDBService, nsIUrlClassifierDBService, + nsIURIClassifier, nsIObserver) /* static */ nsUrlClassifierDBService* @@ -2058,6 +2111,7 @@ nsUrlClassifierDBService::GetInstance() nsUrlClassifierDBService::nsUrlClassifierDBService() + : mCheckMalware(CHECK_MALWARE_DEFAULT) { } @@ -2088,6 +2142,17 @@ nsUrlClassifierDBService::Init() do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); + // Should we check document loads for malware URIs? + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + + if (prefs) { + PRBool tmpbool; + rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); + mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; + + prefs->AddObserver(CHECK_MALWARE_PREF, this, PR_FALSE); + } + // Start the background thread. rv = NS_NewThread(&gDbBackgroundThread); if (NS_FAILED(rv)) @@ -2115,7 +2180,27 @@ nsUrlClassifierDBService::Init() return NS_OK; } -nsresult +NS_IMETHODIMP +nsUrlClassifierDBService::Classify(nsIURI *uri, + nsIURIClassifierCallback* c, + PRBool* result) +{ + NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED); + + if (!mCheckMalware) { + *result = PR_FALSE; + return NS_OK; + } + + nsRefPtr callback = + new nsUrlClassifierClassifyCallback(c); + if (!callback) return NS_ERROR_OUT_OF_MEMORY; + + *result = PR_TRUE; + return LookupURI(uri, callback, PR_TRUE); +} + +NS_IMETHODIMP nsUrlClassifierDBService::Lookup(const nsACString& spec, nsIUrlClassifierCallback* c, PRBool needsProxy) @@ -2132,11 +2217,21 @@ nsUrlClassifierDBService::Lookup(const nsACString& spec, return NS_ERROR_FAILURE; } + return LookupURI(uri, c, needsProxy); +} + +nsresult +nsUrlClassifierDBService::LookupURI(nsIURI* uri, + nsIUrlClassifierCallback* c, + PRBool needsProxy) +{ + NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED); + nsCAutoString key; // Canonicalize the url nsCOMPtr utilsService = do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID); - rv = utilsService->GetKeyForURI(uri, key); + nsresult rv = utilsService->GetKeyForURI(uri, key); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr proxyCallback; @@ -2278,11 +2373,21 @@ NS_IMETHODIMP nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { - NS_ASSERTION(strcmp(aTopic, "profile-before-change") == 0 || - strcmp(aTopic, "xpcom-shutdown-threads") == 0, - "Unexpected observer topic"); - - Shutdown(); + if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { + nsresult rv; + nsCOMPtr prefs(do_QueryInterface(aSubject, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) { + PRBool tmpbool; + rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); + mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; + } + } else if (!strcmp(aTopic, "profile-before-change") || + !strcmp(aTopic, "xpcom-shutdown-threads")) { + Shutdown(); + } else { + return NS_ERROR_UNEXPECTED; + } return NS_OK; } @@ -2296,6 +2401,11 @@ nsUrlClassifierDBService::Shutdown() if (!gDbBackgroundThread) return NS_OK; + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + prefs->RemoveObserver(CHECK_MALWARE_PREF, this); + } + nsresult rv; // First close the db connection. if (mWorker) { diff --git a/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.h b/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.h index 9c9ab05a6db..2c449aec05a 100644 --- a/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.h +++ b/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierDBService.h @@ -45,12 +45,14 @@ #include "nsID.h" #include "nsIObserver.h" #include "nsIUrlClassifierDBService.h" +#include "nsIURIClassifier.h" class nsUrlClassifierDBServiceWorker; // This is a proxy class that just creates a background thread and delagates // calls to the background thread. class nsUrlClassifierDBService : public nsIUrlClassifierDBService, + public nsIURIClassifier, public nsIObserver { public: @@ -69,12 +71,17 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIURLCLASSIFIERDBSERVICE + NS_DECL_NSIURICLASSIFIER NS_DECL_NSIOBSERVER private: // No subclassing ~nsUrlClassifierDBService(); + nsresult LookupURI(nsIURI* uri, + nsIUrlClassifierCallback* c, + PRBool needsProxy); + // Disallow copy constructor nsUrlClassifierDBService(nsUrlClassifierDBService&); @@ -85,6 +92,10 @@ private: nsresult Shutdown(); nsCOMPtr mWorker; + + // TRUE if the nsURIClassifier implementation should check for malware + // uris on document loads. + PRBool mCheckMalware; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsUrlClassifierDBService, NS_URLCLASSIFIERDBSERVICE_CID) diff --git a/mozilla/uriloader/base/nsURILoader.h b/mozilla/uriloader/base/nsURILoader.h index 3a8237ea57e..854d364d767 100644 --- a/mozilla/uriloader/base/nsURILoader.h +++ b/mozilla/uriloader/base/nsURILoader.h @@ -92,4 +92,10 @@ protected: friend class nsDocumentOpenInfo; }; +/** + * The load has been cancelled because it was found on a malware blacklist. + * XXX: this belongs in an nsDocShellErrors.h file of some sort. + */ +#define NS_ERROR_MALWARE_URI NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_URILOADER, 30) + #endif /* nsURILoader_h__ */