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"
8 #include "nsIChannel.h"
9 #include "nsIProtocolHandler.h"
10 #include "nsICachingChannel.h"
11 #include "nsICacheEntryDescriptor.h"
13 #include "nsIScriptSecurityManager.h"
15 #if defined(PR_LOGGING)
17 // NSPR_LOG_MODULES=nsChannelClassifier:5
19 static PRLogModuleInfo
*gChannelClassifierLog
;
21 #define LOG(args) PR_LOG(gChannelClassifierLog, PR_LOG_DEBUG, args)
23 NS_IMPL_ISUPPORTS1(nsChannelClassifier
,
24 nsIURIClassifierCallback
)
26 nsChannelClassifier::nsChannelClassifier()
28 #if defined(PR_LOGGING)
29 if (!gChannelClassifierLog
)
30 gChannelClassifierLog
= PR_NewLogModule("nsChannelClassifier");
35 nsChannelClassifier::Start(nsIChannel
*aChannel
)
37 // Don't bother to run the classifier on a load that has already failed.
38 // (this might happen after a redirect)
40 aChannel
->GetStatus(&status
);
41 if (NS_FAILED(status
))
44 // Don't bother to run the classifier on a cached load that was
45 // previously classified.
46 if (HasBeenClassified(aChannel
)) {
51 nsresult rv
= aChannel
->GetURI(getter_AddRefs(uri
));
52 NS_ENSURE_SUCCESS(rv
, rv
);
54 // Don't bother checking certain types of URIs.
56 rv
= NS_URIChainHasFlags(uri
,
57 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD
,
59 NS_ENSURE_SUCCESS(rv
, rv
);
60 if (hasFlags
) return NS_OK
;
62 rv
= NS_URIChainHasFlags(uri
,
63 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
65 NS_ENSURE_SUCCESS(rv
, rv
);
66 if (hasFlags
) return NS_OK
;
68 rv
= NS_URIChainHasFlags(uri
,
69 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
71 NS_ENSURE_SUCCESS(rv
, rv
);
72 if (hasFlags
) return NS_OK
;
74 rv
= NS_URIChainHasFlags(uri
,
75 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE
,
77 NS_ENSURE_SUCCESS(rv
, rv
);
78 if (hasFlags
) return NS_OK
;
80 nsCOMPtr
<nsIURIClassifier
> uriClassifier
=
81 do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID
, &rv
);
82 if (rv
== NS_ERROR_FACTORY_NOT_REGISTERED
||
83 rv
== NS_ERROR_NOT_AVAILABLE
) {
84 // no URI classifier, ignore this failure.
87 NS_ENSURE_SUCCESS(rv
, rv
);
89 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
90 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
91 NS_ENSURE_SUCCESS(rv
, rv
);
93 nsCOMPtr
<nsIPrincipal
> principal
;
94 rv
= securityManager
->GetChannelPrincipal(aChannel
,
95 getter_AddRefs(principal
));
96 NS_ENSURE_SUCCESS(rv
, rv
);
99 rv
= uriClassifier
->Classify(principal
, this, &expectCallback
);
100 if (NS_FAILED(rv
)) return rv
;
102 if (expectCallback
) {
103 // Suspend the channel, it will be resumed when we get the classifier
105 rv
= aChannel
->Suspend();
107 // Some channels (including nsJSChannel) fail on Suspend. This
108 // shouldn't be fatal, but will prevent malware from being
109 // blocked on these channels.
113 mSuspendedChannel
= aChannel
;
115 LOG(("nsChannelClassifier[%p]: suspended channel %p",
116 this, mSuspendedChannel
.get()));
123 // Note in the cache entry that this URL was classified, so that future
124 // cached loads don't need to be checked.
126 nsChannelClassifier::MarkEntryClassified(nsresult status
)
128 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
129 do_QueryInterface(mSuspendedChannel
);
130 if (!cachingChannel
) {
134 nsCOMPtr
<nsISupports
> cacheToken
;
135 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
140 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
141 do_QueryInterface(cacheToken
);
146 cacheEntry
->SetMetaDataElement("necko:classified",
147 NS_SUCCEEDED(status
) ? "1" : nullptr);
151 nsChannelClassifier::HasBeenClassified(nsIChannel
*aChannel
)
153 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
154 do_QueryInterface(aChannel
);
155 if (!cachingChannel
) {
159 // Only check the tag if we are loading from the cache without
162 if (NS_FAILED(cachingChannel
->IsFromCache(&fromCache
)) || !fromCache
) {
166 nsCOMPtr
<nsISupports
> cacheToken
;
167 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
172 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
173 do_QueryInterface(cacheToken
);
179 cacheEntry
->GetMetaDataElement("necko:classified", getter_Copies(tag
));
180 return tag
.EqualsLiteral("1");
184 nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode
)
186 if (mSuspendedChannel
) {
187 MarkEntryClassified(aErrorCode
);
189 if (NS_FAILED(aErrorCode
)) {
191 LOG(("nsChannelClassifier[%p]: cancelling channel %p with error "
192 "code: %x", this, mSuspendedChannel
.get(), aErrorCode
));
194 mSuspendedChannel
->Cancel(aErrorCode
);
197 LOG(("nsChannelClassifier[%p]: resuming channel %p from "
198 "OnClassifyComplete", this, mSuspendedChannel
.get()));
200 mSuspendedChannel
->Resume();
201 mSuspendedChannel
= nullptr;