1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is mozilla.org code.
16 * The Initial Developer of the Original Code is
17 * Mozilla Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2007
19 * the Initial Developer. All Rights Reserved.
22 * Dave Camp <dcamp@mozilla.com>
23 * Michal Novotny <michal.novotny@gmail.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsChannelClassifier.h"
41 #include "nsNetUtil.h"
42 #include "nsIChannel.h"
43 #include "nsIProtocolHandler.h"
44 #include "nsICachingChannel.h"
45 #include "nsICacheEntryDescriptor.h"
48 #if defined(PR_LOGGING)
50 // NSPR_LOG_MODULES=nsChannelClassifier:5
52 static PRLogModuleInfo
*gChannelClassifierLog
;
54 #define LOG(args) PR_LOG(gChannelClassifierLog, PR_LOG_DEBUG, args)
56 NS_IMPL_ISUPPORTS1(nsChannelClassifier
,
57 nsIURIClassifierCallback
)
59 nsChannelClassifier::nsChannelClassifier()
61 #if defined(PR_LOGGING)
62 if (!gChannelClassifierLog
)
63 gChannelClassifierLog
= PR_NewLogModule("nsChannelClassifier");
68 nsChannelClassifier::Start(nsIChannel
*aChannel
)
70 // Don't bother to run the classifier on a load that has already failed.
71 // (this might happen after a redirect)
73 aChannel
->GetStatus(&status
);
74 if (NS_FAILED(status
))
77 // Don't bother to run the classifier on a cached load that was
78 // previously classified.
79 if (HasBeenClassified(aChannel
)) {
84 nsresult rv
= aChannel
->GetURI(getter_AddRefs(uri
));
85 NS_ENSURE_SUCCESS(rv
, rv
);
87 // Don't bother checking certain types of URIs.
89 rv
= NS_URIChainHasFlags(uri
,
90 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD
,
92 NS_ENSURE_SUCCESS(rv
, rv
);
93 if (hasFlags
) return NS_OK
;
95 rv
= NS_URIChainHasFlags(uri
,
96 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
98 NS_ENSURE_SUCCESS(rv
, rv
);
99 if (hasFlags
) return NS_OK
;
101 rv
= NS_URIChainHasFlags(uri
,
102 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
104 NS_ENSURE_SUCCESS(rv
, rv
);
105 if (hasFlags
) return NS_OK
;
107 rv
= NS_URIChainHasFlags(uri
,
108 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE
,
110 NS_ENSURE_SUCCESS(rv
, rv
);
111 if (hasFlags
) return NS_OK
;
113 nsCOMPtr
<nsIURIClassifier
> uriClassifier
=
114 do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID
, &rv
);
115 if (rv
== NS_ERROR_FACTORY_NOT_REGISTERED
||
116 rv
== NS_ERROR_NOT_AVAILABLE
) {
117 // no URI classifier, ignore this failure.
120 NS_ENSURE_SUCCESS(rv
, rv
);
122 PRBool expectCallback
;
123 rv
= uriClassifier
->Classify(uri
, this, &expectCallback
);
124 if (NS_FAILED(rv
)) return rv
;
126 if (expectCallback
) {
127 // Suspend the channel, it will be resumed when we get the classifier
129 rv
= aChannel
->Suspend();
131 // Some channels (including nsJSChannel) fail on Suspend. This
132 // shouldn't be fatal, but will prevent malware from being
133 // blocked on these channels.
137 mSuspendedChannel
= aChannel
;
139 LOG(("nsChannelClassifier[%p]: suspended channel %p",
140 this, mSuspendedChannel
.get()));
147 // Note in the cache entry that this URL was classified, so that future
148 // cached loads don't need to be checked.
150 nsChannelClassifier::MarkEntryClassified(nsresult status
)
152 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
153 do_QueryInterface(mSuspendedChannel
);
154 if (!cachingChannel
) {
158 nsCOMPtr
<nsISupports
> cacheToken
;
159 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
164 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
165 do_QueryInterface(cacheToken
);
170 cacheEntry
->SetMetaDataElement("necko:classified",
171 NS_SUCCEEDED(status
) ? "1" : nsnull
);
175 nsChannelClassifier::HasBeenClassified(nsIChannel
*aChannel
)
177 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
178 do_QueryInterface(aChannel
);
179 if (!cachingChannel
) {
183 // Only check the tag if we are loading from the cache without
186 if (NS_FAILED(cachingChannel
->IsFromCache(&fromCache
)) || !fromCache
) {
190 nsCOMPtr
<nsISupports
> cacheToken
;
191 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
196 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
197 do_QueryInterface(cacheToken
);
203 cacheEntry
->GetMetaDataElement("necko:classified", getter_Copies(tag
));
204 return tag
.EqualsLiteral("1");
208 nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode
)
210 if (mSuspendedChannel
) {
211 MarkEntryClassified(aErrorCode
);
213 if (NS_FAILED(aErrorCode
)) {
215 LOG(("nsChannelClassifier[%p]: cancelling channel %p with error "
216 "code: %x", this, mSuspendedChannel
.get(), aErrorCode
));
218 mSuspendedChannel
->Cancel(aErrorCode
);
221 LOG(("nsChannelClassifier[%p]: resuming channel %p from "
222 "OnClassifyComplete", this, mSuspendedChannel
.get()));
224 mSuspendedChannel
->Resume();
225 mSuspendedChannel
= nsnull
;