netwerk/base/src/nsChannelClassifier.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial