netwerk/base/src/nsChannelClassifier.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "nsChannelClassifier.h"
michael@0 6
michael@0 7 #include "nsNetUtil.h"
michael@0 8 #include "nsIChannel.h"
michael@0 9 #include "nsIProtocolHandler.h"
michael@0 10 #include "nsICachingChannel.h"
michael@0 11 #include "nsICacheEntryDescriptor.h"
michael@0 12 #include "prlog.h"
michael@0 13 #include "nsIScriptSecurityManager.h"
michael@0 14
michael@0 15 #if defined(PR_LOGGING)
michael@0 16 //
michael@0 17 // NSPR_LOG_MODULES=nsChannelClassifier:5
michael@0 18 //
michael@0 19 static PRLogModuleInfo *gChannelClassifierLog;
michael@0 20 #endif
michael@0 21 #undef LOG
michael@0 22 #define LOG(args) PR_LOG(gChannelClassifierLog, PR_LOG_DEBUG, args)
michael@0 23
michael@0 24 NS_IMPL_ISUPPORTS(nsChannelClassifier,
michael@0 25 nsIURIClassifierCallback)
michael@0 26
michael@0 27 nsChannelClassifier::nsChannelClassifier()
michael@0 28 {
michael@0 29 #if defined(PR_LOGGING)
michael@0 30 if (!gChannelClassifierLog)
michael@0 31 gChannelClassifierLog = PR_NewLogModule("nsChannelClassifier");
michael@0 32 #endif
michael@0 33 }
michael@0 34
michael@0 35 nsresult
michael@0 36 nsChannelClassifier::Start(nsIChannel *aChannel)
michael@0 37 {
michael@0 38 // Don't bother to run the classifier on a load that has already failed.
michael@0 39 // (this might happen after a redirect)
michael@0 40 nsresult status;
michael@0 41 aChannel->GetStatus(&status);
michael@0 42 if (NS_FAILED(status))
michael@0 43 return NS_OK;
michael@0 44
michael@0 45 // Don't bother to run the classifier on a cached load that was
michael@0 46 // previously classified.
michael@0 47 if (HasBeenClassified(aChannel)) {
michael@0 48 return NS_OK;
michael@0 49 }
michael@0 50
michael@0 51 nsCOMPtr<nsIURI> uri;
michael@0 52 nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
michael@0 53 NS_ENSURE_SUCCESS(rv, rv);
michael@0 54
michael@0 55 // Don't bother checking certain types of URIs.
michael@0 56 bool hasFlags;
michael@0 57 rv = NS_URIChainHasFlags(uri,
michael@0 58 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
michael@0 59 &hasFlags);
michael@0 60 NS_ENSURE_SUCCESS(rv, rv);
michael@0 61 if (hasFlags) return NS_OK;
michael@0 62
michael@0 63 rv = NS_URIChainHasFlags(uri,
michael@0 64 nsIProtocolHandler::URI_IS_LOCAL_FILE,
michael@0 65 &hasFlags);
michael@0 66 NS_ENSURE_SUCCESS(rv, rv);
michael@0 67 if (hasFlags) return NS_OK;
michael@0 68
michael@0 69 rv = NS_URIChainHasFlags(uri,
michael@0 70 nsIProtocolHandler::URI_IS_UI_RESOURCE,
michael@0 71 &hasFlags);
michael@0 72 NS_ENSURE_SUCCESS(rv, rv);
michael@0 73 if (hasFlags) return NS_OK;
michael@0 74
michael@0 75 rv = NS_URIChainHasFlags(uri,
michael@0 76 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
michael@0 77 &hasFlags);
michael@0 78 NS_ENSURE_SUCCESS(rv, rv);
michael@0 79 if (hasFlags) return NS_OK;
michael@0 80
michael@0 81 nsCOMPtr<nsIURIClassifier> uriClassifier =
michael@0 82 do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
michael@0 83 if (rv == NS_ERROR_FACTORY_NOT_REGISTERED ||
michael@0 84 rv == NS_ERROR_NOT_AVAILABLE) {
michael@0 85 // no URI classifier, ignore this failure.
michael@0 86 return NS_OK;
michael@0 87 }
michael@0 88 NS_ENSURE_SUCCESS(rv, rv);
michael@0 89
michael@0 90 nsCOMPtr<nsIScriptSecurityManager> securityManager =
michael@0 91 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 92 NS_ENSURE_SUCCESS(rv, rv);
michael@0 93
michael@0 94 nsCOMPtr<nsIPrincipal> principal;
michael@0 95 rv = securityManager->GetChannelPrincipal(aChannel,
michael@0 96 getter_AddRefs(principal));
michael@0 97 NS_ENSURE_SUCCESS(rv, rv);
michael@0 98
michael@0 99 bool expectCallback;
michael@0 100 rv = uriClassifier->Classify(principal, this, &expectCallback);
michael@0 101 if (NS_FAILED(rv)) return rv;
michael@0 102
michael@0 103 if (expectCallback) {
michael@0 104 // Suspend the channel, it will be resumed when we get the classifier
michael@0 105 // callback.
michael@0 106 rv = aChannel->Suspend();
michael@0 107 if (NS_FAILED(rv)) {
michael@0 108 // Some channels (including nsJSChannel) fail on Suspend. This
michael@0 109 // shouldn't be fatal, but will prevent malware from being
michael@0 110 // blocked on these channels.
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113
michael@0 114 mSuspendedChannel = aChannel;
michael@0 115 #ifdef DEBUG
michael@0 116 LOG(("nsChannelClassifier[%p]: suspended channel %p",
michael@0 117 this, mSuspendedChannel.get()));
michael@0 118 #endif
michael@0 119 }
michael@0 120
michael@0 121 return NS_OK;
michael@0 122 }
michael@0 123
michael@0 124 // Note in the cache entry that this URL was classified, so that future
michael@0 125 // cached loads don't need to be checked.
michael@0 126 void
michael@0 127 nsChannelClassifier::MarkEntryClassified(nsresult status)
michael@0 128 {
michael@0 129 nsCOMPtr<nsICachingChannel> cachingChannel =
michael@0 130 do_QueryInterface(mSuspendedChannel);
michael@0 131 if (!cachingChannel) {
michael@0 132 return;
michael@0 133 }
michael@0 134
michael@0 135 nsCOMPtr<nsISupports> cacheToken;
michael@0 136 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
michael@0 137 if (!cacheToken) {
michael@0 138 return;
michael@0 139 }
michael@0 140
michael@0 141 nsCOMPtr<nsICacheEntryDescriptor> cacheEntry =
michael@0 142 do_QueryInterface(cacheToken);
michael@0 143 if (!cacheEntry) {
michael@0 144 return;
michael@0 145 }
michael@0 146
michael@0 147 cacheEntry->SetMetaDataElement("necko:classified",
michael@0 148 NS_SUCCEEDED(status) ? "1" : nullptr);
michael@0 149 }
michael@0 150
michael@0 151 bool
michael@0 152 nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel)
michael@0 153 {
michael@0 154 nsCOMPtr<nsICachingChannel> cachingChannel =
michael@0 155 do_QueryInterface(aChannel);
michael@0 156 if (!cachingChannel) {
michael@0 157 return false;
michael@0 158 }
michael@0 159
michael@0 160 // Only check the tag if we are loading from the cache without
michael@0 161 // validation.
michael@0 162 bool fromCache;
michael@0 163 if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) {
michael@0 164 return false;
michael@0 165 }
michael@0 166
michael@0 167 nsCOMPtr<nsISupports> cacheToken;
michael@0 168 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
michael@0 169 if (!cacheToken) {
michael@0 170 return false;
michael@0 171 }
michael@0 172
michael@0 173 nsCOMPtr<nsICacheEntryDescriptor> cacheEntry =
michael@0 174 do_QueryInterface(cacheToken);
michael@0 175 if (!cacheEntry) {
michael@0 176 return false;
michael@0 177 }
michael@0 178
michael@0 179 nsXPIDLCString tag;
michael@0 180 cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag));
michael@0 181 return tag.EqualsLiteral("1");
michael@0 182 }
michael@0 183
michael@0 184 NS_IMETHODIMP
michael@0 185 nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
michael@0 186 {
michael@0 187 if (mSuspendedChannel) {
michael@0 188 MarkEntryClassified(aErrorCode);
michael@0 189
michael@0 190 if (NS_FAILED(aErrorCode)) {
michael@0 191 #ifdef DEBUG
michael@0 192 LOG(("nsChannelClassifier[%p]: cancelling channel %p with error "
michael@0 193 "code: %x", this, mSuspendedChannel.get(), aErrorCode));
michael@0 194 #endif
michael@0 195 mSuspendedChannel->Cancel(aErrorCode);
michael@0 196 }
michael@0 197 #ifdef DEBUG
michael@0 198 LOG(("nsChannelClassifier[%p]: resuming channel %p from "
michael@0 199 "OnClassifyComplete", this, mSuspendedChannel.get()));
michael@0 200 #endif
michael@0 201 mSuspendedChannel->Resume();
michael@0 202 mSuspendedChannel = nullptr;
michael@0 203 }
michael@0 204
michael@0 205 return NS_OK;
michael@0 206 }

mercurial