toolkit/components/places/nsAnnoProtocolHandler.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

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

mercurial