1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsChannelClassifier.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,206 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsChannelClassifier.h" 1.9 + 1.10 +#include "nsNetUtil.h" 1.11 +#include "nsIChannel.h" 1.12 +#include "nsIProtocolHandler.h" 1.13 +#include "nsICachingChannel.h" 1.14 +#include "nsICacheEntryDescriptor.h" 1.15 +#include "prlog.h" 1.16 +#include "nsIScriptSecurityManager.h" 1.17 + 1.18 +#if defined(PR_LOGGING) 1.19 +// 1.20 +// NSPR_LOG_MODULES=nsChannelClassifier:5 1.21 +// 1.22 +static PRLogModuleInfo *gChannelClassifierLog; 1.23 +#endif 1.24 +#undef LOG 1.25 +#define LOG(args) PR_LOG(gChannelClassifierLog, PR_LOG_DEBUG, args) 1.26 + 1.27 +NS_IMPL_ISUPPORTS(nsChannelClassifier, 1.28 + nsIURIClassifierCallback) 1.29 + 1.30 +nsChannelClassifier::nsChannelClassifier() 1.31 +{ 1.32 +#if defined(PR_LOGGING) 1.33 + if (!gChannelClassifierLog) 1.34 + gChannelClassifierLog = PR_NewLogModule("nsChannelClassifier"); 1.35 +#endif 1.36 +} 1.37 + 1.38 +nsresult 1.39 +nsChannelClassifier::Start(nsIChannel *aChannel) 1.40 +{ 1.41 + // Don't bother to run the classifier on a load that has already failed. 1.42 + // (this might happen after a redirect) 1.43 + nsresult status; 1.44 + aChannel->GetStatus(&status); 1.45 + if (NS_FAILED(status)) 1.46 + return NS_OK; 1.47 + 1.48 + // Don't bother to run the classifier on a cached load that was 1.49 + // previously classified. 1.50 + if (HasBeenClassified(aChannel)) { 1.51 + return NS_OK; 1.52 + } 1.53 + 1.54 + nsCOMPtr<nsIURI> uri; 1.55 + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); 1.56 + NS_ENSURE_SUCCESS(rv, rv); 1.57 + 1.58 + // Don't bother checking certain types of URIs. 1.59 + bool hasFlags; 1.60 + rv = NS_URIChainHasFlags(uri, 1.61 + nsIProtocolHandler::URI_DANGEROUS_TO_LOAD, 1.62 + &hasFlags); 1.63 + NS_ENSURE_SUCCESS(rv, rv); 1.64 + if (hasFlags) return NS_OK; 1.65 + 1.66 + rv = NS_URIChainHasFlags(uri, 1.67 + nsIProtocolHandler::URI_IS_LOCAL_FILE, 1.68 + &hasFlags); 1.69 + NS_ENSURE_SUCCESS(rv, rv); 1.70 + if (hasFlags) return NS_OK; 1.71 + 1.72 + rv = NS_URIChainHasFlags(uri, 1.73 + nsIProtocolHandler::URI_IS_UI_RESOURCE, 1.74 + &hasFlags); 1.75 + NS_ENSURE_SUCCESS(rv, rv); 1.76 + if (hasFlags) return NS_OK; 1.77 + 1.78 + rv = NS_URIChainHasFlags(uri, 1.79 + nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, 1.80 + &hasFlags); 1.81 + NS_ENSURE_SUCCESS(rv, rv); 1.82 + if (hasFlags) return NS_OK; 1.83 + 1.84 + nsCOMPtr<nsIURIClassifier> uriClassifier = 1.85 + do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv); 1.86 + if (rv == NS_ERROR_FACTORY_NOT_REGISTERED || 1.87 + rv == NS_ERROR_NOT_AVAILABLE) { 1.88 + // no URI classifier, ignore this failure. 1.89 + return NS_OK; 1.90 + } 1.91 + NS_ENSURE_SUCCESS(rv, rv); 1.92 + 1.93 + nsCOMPtr<nsIScriptSecurityManager> securityManager = 1.94 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 1.95 + NS_ENSURE_SUCCESS(rv, rv); 1.96 + 1.97 + nsCOMPtr<nsIPrincipal> principal; 1.98 + rv = securityManager->GetChannelPrincipal(aChannel, 1.99 + getter_AddRefs(principal)); 1.100 + NS_ENSURE_SUCCESS(rv, rv); 1.101 + 1.102 + bool expectCallback; 1.103 + rv = uriClassifier->Classify(principal, this, &expectCallback); 1.104 + if (NS_FAILED(rv)) return rv; 1.105 + 1.106 + if (expectCallback) { 1.107 + // Suspend the channel, it will be resumed when we get the classifier 1.108 + // callback. 1.109 + rv = aChannel->Suspend(); 1.110 + if (NS_FAILED(rv)) { 1.111 + // Some channels (including nsJSChannel) fail on Suspend. This 1.112 + // shouldn't be fatal, but will prevent malware from being 1.113 + // blocked on these channels. 1.114 + return NS_OK; 1.115 + } 1.116 + 1.117 + mSuspendedChannel = aChannel; 1.118 +#ifdef DEBUG 1.119 + LOG(("nsChannelClassifier[%p]: suspended channel %p", 1.120 + this, mSuspendedChannel.get())); 1.121 +#endif 1.122 + } 1.123 + 1.124 + return NS_OK; 1.125 +} 1.126 + 1.127 +// Note in the cache entry that this URL was classified, so that future 1.128 +// cached loads don't need to be checked. 1.129 +void 1.130 +nsChannelClassifier::MarkEntryClassified(nsresult status) 1.131 +{ 1.132 + nsCOMPtr<nsICachingChannel> cachingChannel = 1.133 + do_QueryInterface(mSuspendedChannel); 1.134 + if (!cachingChannel) { 1.135 + return; 1.136 + } 1.137 + 1.138 + nsCOMPtr<nsISupports> cacheToken; 1.139 + cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); 1.140 + if (!cacheToken) { 1.141 + return; 1.142 + } 1.143 + 1.144 + nsCOMPtr<nsICacheEntryDescriptor> cacheEntry = 1.145 + do_QueryInterface(cacheToken); 1.146 + if (!cacheEntry) { 1.147 + return; 1.148 + } 1.149 + 1.150 + cacheEntry->SetMetaDataElement("necko:classified", 1.151 + NS_SUCCEEDED(status) ? "1" : nullptr); 1.152 +} 1.153 + 1.154 +bool 1.155 +nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel) 1.156 +{ 1.157 + nsCOMPtr<nsICachingChannel> cachingChannel = 1.158 + do_QueryInterface(aChannel); 1.159 + if (!cachingChannel) { 1.160 + return false; 1.161 + } 1.162 + 1.163 + // Only check the tag if we are loading from the cache without 1.164 + // validation. 1.165 + bool fromCache; 1.166 + if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) { 1.167 + return false; 1.168 + } 1.169 + 1.170 + nsCOMPtr<nsISupports> cacheToken; 1.171 + cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); 1.172 + if (!cacheToken) { 1.173 + return false; 1.174 + } 1.175 + 1.176 + nsCOMPtr<nsICacheEntryDescriptor> cacheEntry = 1.177 + do_QueryInterface(cacheToken); 1.178 + if (!cacheEntry) { 1.179 + return false; 1.180 + } 1.181 + 1.182 + nsXPIDLCString tag; 1.183 + cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag)); 1.184 + return tag.EqualsLiteral("1"); 1.185 +} 1.186 + 1.187 +NS_IMETHODIMP 1.188 +nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode) 1.189 +{ 1.190 + if (mSuspendedChannel) { 1.191 + MarkEntryClassified(aErrorCode); 1.192 + 1.193 + if (NS_FAILED(aErrorCode)) { 1.194 +#ifdef DEBUG 1.195 + LOG(("nsChannelClassifier[%p]: cancelling channel %p with error " 1.196 + "code: %x", this, mSuspendedChannel.get(), aErrorCode)); 1.197 +#endif 1.198 + mSuspendedChannel->Cancel(aErrorCode); 1.199 + } 1.200 +#ifdef DEBUG 1.201 + LOG(("nsChannelClassifier[%p]: resuming channel %p from " 1.202 + "OnClassifyComplete", this, mSuspendedChannel.get())); 1.203 +#endif 1.204 + mSuspendedChannel->Resume(); 1.205 + mSuspendedChannel = nullptr; 1.206 + } 1.207 + 1.208 + return NS_OK; 1.209 +}