Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / netwerk / base / src / nsChannelClassifier.cpp
blobc41238b4ca8a9a5c9fc8cea13c28f090c103ef7c
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
12 * License.
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.
21 * Contributor(s):
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"
46 #include "prlog.h"
48 #if defined(PR_LOGGING)
50 // NSPR_LOG_MODULES=nsChannelClassifier:5
52 static PRLogModuleInfo *gChannelClassifierLog;
53 #endif
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");
64 #endif
67 nsresult
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)
72 PRUint32 status;
73 aChannel->GetStatus(&status);
74 if (NS_FAILED(status))
75 return NS_OK;
77 // Don't bother to run the classifier on a cached load that was
78 // previously classified.
79 if (HasBeenClassified(aChannel)) {
80 return NS_OK;
83 nsCOMPtr<nsIURI> uri;
84 nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
85 NS_ENSURE_SUCCESS(rv, rv);
87 // Don't bother checking certain types of URIs.
88 PRBool hasFlags;
89 rv = NS_URIChainHasFlags(uri,
90 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
91 &hasFlags);
92 NS_ENSURE_SUCCESS(rv, rv);
93 if (hasFlags) return NS_OK;
95 rv = NS_URIChainHasFlags(uri,
96 nsIProtocolHandler::URI_IS_LOCAL_FILE,
97 &hasFlags);
98 NS_ENSURE_SUCCESS(rv, rv);
99 if (hasFlags) return NS_OK;
101 rv = NS_URIChainHasFlags(uri,
102 nsIProtocolHandler::URI_IS_UI_RESOURCE,
103 &hasFlags);
104 NS_ENSURE_SUCCESS(rv, rv);
105 if (hasFlags) return NS_OK;
107 rv = NS_URIChainHasFlags(uri,
108 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
109 &hasFlags);
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.
118 return NS_OK;
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
128 // callback.
129 rv = aChannel->Suspend();
130 if (NS_FAILED(rv)) {
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.
134 return NS_OK;
137 mSuspendedChannel = aChannel;
138 #ifdef DEBUG
139 LOG(("nsChannelClassifier[%p]: suspended channel %p",
140 this, mSuspendedChannel.get()));
141 #endif
144 return NS_OK;
147 // Note in the cache entry that this URL was classified, so that future
148 // cached loads don't need to be checked.
149 void
150 nsChannelClassifier::MarkEntryClassified(nsresult status)
152 nsCOMPtr<nsICachingChannel> cachingChannel =
153 do_QueryInterface(mSuspendedChannel);
154 if (!cachingChannel) {
155 return;
158 nsCOMPtr<nsISupports> cacheToken;
159 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
160 if (!cacheToken) {
161 return;
164 nsCOMPtr<nsICacheEntryDescriptor> cacheEntry =
165 do_QueryInterface(cacheToken);
166 if (!cacheEntry) {
167 return;
170 cacheEntry->SetMetaDataElement("necko:classified",
171 NS_SUCCEEDED(status) ? "1" : nsnull);
174 PRBool
175 nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel)
177 nsCOMPtr<nsICachingChannel> cachingChannel =
178 do_QueryInterface(aChannel);
179 if (!cachingChannel) {
180 return PR_FALSE;
183 // Only check the tag if we are loading from the cache without
184 // validation.
185 PRBool fromCache;
186 if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) {
187 return PR_FALSE;
190 nsCOMPtr<nsISupports> cacheToken;
191 cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
192 if (!cacheToken) {
193 return PR_FALSE;
196 nsCOMPtr<nsICacheEntryDescriptor> cacheEntry =
197 do_QueryInterface(cacheToken);
198 if (!cacheEntry) {
199 return PR_FALSE;
202 nsXPIDLCString tag;
203 cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag));
204 return tag.EqualsLiteral("1");
207 NS_IMETHODIMP
208 nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
210 if (mSuspendedChannel) {
211 MarkEntryClassified(aErrorCode);
213 if (NS_FAILED(aErrorCode)) {
214 #ifdef DEBUG
215 LOG(("nsChannelClassifier[%p]: cancelling channel %p with error "
216 "code: %x", this, mSuspendedChannel.get(), aErrorCode));
217 #endif
218 mSuspendedChannel->Cancel(aErrorCode);
220 #ifdef DEBUG
221 LOG(("nsChannelClassifier[%p]: resuming channel %p from "
222 "OnClassifyComplete", this, mSuspendedChannel.get()));
223 #endif
224 mSuspendedChannel->Resume();
225 mSuspendedChannel = nsnull;
228 return NS_OK;