netwerk/base/src/nsChannelClassifier.cpp

changeset 0
6474c204b198
     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 +}

mercurial