Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /**
7 * Implementation of moz-anno: URLs for accessing favicons. The urls are sent
8 * to the favicon service. If the favicon service doesn't have the
9 * data, a stream containing the default favicon will be returned.
10 *
11 * The reference to annotations ("moz-anno") is a leftover from previous
12 * iterations of this component. As of now the moz-anno protocol is independent
13 * of annotations.
14 */
16 #include "nsAnnoProtocolHandler.h"
17 #include "nsFaviconService.h"
18 #include "nsIChannel.h"
19 #include "nsIInputStreamChannel.h"
20 #include "nsILoadGroup.h"
21 #include "nsIStandardURL.h"
22 #include "nsIStringStream.h"
23 #include "nsISupportsUtils.h"
24 #include "nsIURI.h"
25 #include "nsNetUtil.h"
26 #include "nsServiceManagerUtils.h"
27 #include "nsStringStream.h"
28 #include "mozilla/storage.h"
29 #include "nsIPipe.h"
30 #include "Helpers.h"
32 using namespace mozilla;
33 using namespace mozilla::places;
35 ////////////////////////////////////////////////////////////////////////////////
36 //// Global Functions
38 /**
39 * Creates a channel to obtain the default favicon.
40 */
41 static
42 nsresult
43 GetDefaultIcon(nsIChannel **aChannel)
44 {
45 nsCOMPtr<nsIURI> defaultIconURI;
46 nsresult rv = NS_NewURI(getter_AddRefs(defaultIconURI),
47 NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
48 NS_ENSURE_SUCCESS(rv, rv);
49 return NS_NewChannel(aChannel, defaultIconURI);
50 }
52 ////////////////////////////////////////////////////////////////////////////////
53 //// faviconAsyncLoader
55 namespace {
57 /**
58 * An instance of this class is passed to the favicon service as the callback
59 * for getting favicon data from the database. We'll get this data back in
60 * HandleResult, and on HandleCompletion, we'll close our output stream which
61 * will close the original channel for the favicon request.
62 *
63 * However, if an error occurs at any point, we do not set mReturnDefaultIcon to
64 * false, so we will open up another channel to get the default favicon, and
65 * pass that along to our output stream in HandleCompletion. If anything
66 * happens at that point, the world must be against us, so we return nothing.
67 */
68 class faviconAsyncLoader : public AsyncStatementCallback
69 , public nsIRequestObserver
70 {
71 public:
72 NS_DECL_ISUPPORTS_INHERITED
74 faviconAsyncLoader(nsIChannel *aChannel, nsIOutputStream *aOutputStream) :
75 mChannel(aChannel)
76 , mOutputStream(aOutputStream)
77 , mReturnDefaultIcon(true)
78 {
79 NS_ASSERTION(aChannel,
80 "Not providing a channel will result in crashes!");
81 NS_ASSERTION(aOutputStream,
82 "Not providing an output stream will result in crashes!");
83 }
85 //////////////////////////////////////////////////////////////////////////////
86 //// mozIStorageStatementCallback
88 NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet)
89 {
90 // We will only get one row back in total, so we do not need to loop.
91 nsCOMPtr<mozIStorageRow> row;
92 nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
93 NS_ENSURE_SUCCESS(rv, rv);
95 // We do not allow favicons without a MIME type, so we'll return the default
96 // icon.
97 nsAutoCString mimeType;
98 (void)row->GetUTF8String(1, mimeType);
99 NS_ENSURE_FALSE(mimeType.IsEmpty(), NS_OK);
101 // Set our mimeType now that we know it.
102 rv = mChannel->SetContentType(mimeType);
103 NS_ENSURE_SUCCESS(rv, rv);
105 // Obtain the binary blob that contains our favicon data.
106 uint8_t *favicon;
107 uint32_t size = 0;
108 rv = row->GetBlob(0, &size, &favicon);
109 NS_ENSURE_SUCCESS(rv, rv);
111 uint32_t totalWritten = 0;
112 do {
113 uint32_t bytesWritten;
114 rv = mOutputStream->Write(
115 &(reinterpret_cast<const char *>(favicon)[totalWritten]),
116 size - totalWritten,
117 &bytesWritten
118 );
119 if (NS_FAILED(rv) || !bytesWritten)
120 break;
121 totalWritten += bytesWritten;
122 } while (size != totalWritten);
123 NS_ASSERTION(NS_FAILED(rv) || size == totalWritten,
124 "Failed to write all of our data out to the stream!");
126 // Free our favicon array.
127 NS_Free(favicon);
129 // Handle an error to write if it occurred, but only after we've freed our
130 // favicon.
131 NS_ENSURE_SUCCESS(rv, rv);
133 // At this point, we should have written out all of our data to our stream.
134 // HandleCompletion will close the output stream, so we are done here.
135 mReturnDefaultIcon = false;
136 return NS_OK;
137 }
139 NS_IMETHOD HandleCompletion(uint16_t aReason)
140 {
141 if (!mReturnDefaultIcon)
142 return mOutputStream->Close();
144 // We need to return our default icon, so we'll open up a new channel to get
145 // that data, and push it to our output stream. If at any point we get an
146 // error, we can't do anything, so we'll just close our output stream.
147 nsCOMPtr<nsIStreamListener> listener;
148 nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(listener),
149 mOutputStream, this);
150 NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
152 nsCOMPtr<nsIChannel> newChannel;
153 rv = GetDefaultIcon(getter_AddRefs(newChannel));
154 NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
156 rv = newChannel->AsyncOpen(listener, nullptr);
157 NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
159 return NS_OK;
160 }
162 //////////////////////////////////////////////////////////////////////////////
163 //// nsIRequestObserver
165 NS_IMETHOD OnStartRequest(nsIRequest *, nsISupports *)
166 {
167 return NS_OK;
168 }
170 NS_IMETHOD OnStopRequest(nsIRequest *, nsISupports *, nsresult aStatusCode)
171 {
172 // We always need to close our output stream, regardless of the status code.
173 (void)mOutputStream->Close();
175 // But, we'll warn about it not being successful if it wasn't.
176 NS_WARN_IF_FALSE(NS_SUCCEEDED(aStatusCode),
177 "Got an error when trying to load our default favicon!");
179 return NS_OK;
180 }
182 private:
183 nsCOMPtr<nsIChannel> mChannel;
184 nsCOMPtr<nsIOutputStream> mOutputStream;
185 bool mReturnDefaultIcon;
186 };
188 NS_IMPL_ISUPPORTS_INHERITED(
189 faviconAsyncLoader,
190 AsyncStatementCallback,
191 nsIRequestObserver
192 )
194 } // anonymous namespace
196 ////////////////////////////////////////////////////////////////////////////////
197 //// nsAnnoProtocolHandler
199 NS_IMPL_ISUPPORTS(nsAnnoProtocolHandler, nsIProtocolHandler)
201 // nsAnnoProtocolHandler::GetScheme
203 NS_IMETHODIMP
204 nsAnnoProtocolHandler::GetScheme(nsACString& aScheme)
205 {
206 aScheme.AssignLiteral("moz-anno");
207 return NS_OK;
208 }
211 // nsAnnoProtocolHandler::GetDefaultPort
212 //
213 // There is no default port for annotation URLs
215 NS_IMETHODIMP
216 nsAnnoProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
217 {
218 *aDefaultPort = -1;
219 return NS_OK;
220 }
223 // nsAnnoProtocolHandler::GetProtocolFlags
225 NS_IMETHODIMP
226 nsAnnoProtocolHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
227 {
228 *aProtocolFlags = (URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
229 URI_IS_LOCAL_RESOURCE);
230 return NS_OK;
231 }
234 // nsAnnoProtocolHandler::NewURI
236 NS_IMETHODIMP
237 nsAnnoProtocolHandler::NewURI(const nsACString& aSpec,
238 const char *aOriginCharset,
239 nsIURI *aBaseURI, nsIURI **_retval)
240 {
241 nsCOMPtr <nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID);
242 if (!uri)
243 return NS_ERROR_OUT_OF_MEMORY;
244 nsresult rv = uri->SetSpec(aSpec);
245 NS_ENSURE_SUCCESS(rv, rv);
247 *_retval = nullptr;
248 uri.swap(*_retval);
249 return NS_OK;
250 }
253 // nsAnnoProtocolHandler::NewChannel
254 //
256 NS_IMETHODIMP
257 nsAnnoProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
258 {
259 NS_ENSURE_ARG_POINTER(aURI);
261 // annotation info
262 nsCOMPtr<nsIURI> annoURI;
263 nsAutoCString annoName;
264 nsresult rv = ParseAnnoURI(aURI, getter_AddRefs(annoURI), annoName);
265 NS_ENSURE_SUCCESS(rv, rv);
267 // Only favicon annotation are supported.
268 if (!annoName.EqualsLiteral(FAVICON_ANNOTATION_NAME))
269 return NS_ERROR_INVALID_ARG;
271 return NewFaviconChannel(aURI, annoURI, _retval);
272 }
275 // nsAnnoProtocolHandler::AllowPort
276 //
277 // Don't override any bans on bad ports.
279 NS_IMETHODIMP
280 nsAnnoProtocolHandler::AllowPort(int32_t port, const char *scheme,
281 bool *_retval)
282 {
283 *_retval = false;
284 return NS_OK;
285 }
288 // nsAnnoProtocolHandler::ParseAnnoURI
289 //
290 // Splits an annotation URL into its URI and name parts
292 nsresult
293 nsAnnoProtocolHandler::ParseAnnoURI(nsIURI* aURI,
294 nsIURI** aResultURI, nsCString& aName)
295 {
296 nsresult rv;
297 nsAutoCString path;
298 rv = aURI->GetPath(path);
299 NS_ENSURE_SUCCESS(rv, rv);
301 int32_t firstColon = path.FindChar(':');
302 if (firstColon <= 0)
303 return NS_ERROR_MALFORMED_URI;
305 rv = NS_NewURI(aResultURI, Substring(path, firstColon + 1));
306 NS_ENSURE_SUCCESS(rv, rv);
308 aName = Substring(path, 0, firstColon);
309 return NS_OK;
310 }
312 nsresult
313 nsAnnoProtocolHandler::NewFaviconChannel(nsIURI *aURI, nsIURI *aAnnotationURI,
314 nsIChannel **_channel)
315 {
316 // Create our pipe. This will give us our input stream and output stream
317 // that will be written to when we get data from the database.
318 nsCOMPtr<nsIInputStream> inputStream;
319 nsCOMPtr<nsIOutputStream> outputStream;
320 nsresult rv = NS_NewPipe(getter_AddRefs(inputStream),
321 getter_AddRefs(outputStream),
322 MAX_FAVICON_SIZE, MAX_FAVICON_SIZE, true,
323 true);
324 NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
326 // Create our channel. We'll call SetContentType with the right type when
327 // we know what it actually is.
328 nsCOMPtr<nsIChannel> channel;
329 rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inputStream,
330 EmptyCString());
331 NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
333 // Now we go ahead and get our data asynchronously for the favicon.
334 nsCOMPtr<mozIStorageStatementCallback> callback =
335 new faviconAsyncLoader(channel, outputStream);
336 NS_ENSURE_TRUE(callback, GetDefaultIcon(_channel));
337 nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
338 NS_ENSURE_TRUE(faviconService, GetDefaultIcon(_channel));
340 rv = faviconService->GetFaviconDataAsync(aAnnotationURI, callback);
341 NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
343 channel.forget(_channel);
344 return NS_OK;
345 }