toolkit/components/places/nsFaviconService.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.

     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  * This is the favicon service, which stores favicons for web pages with your
     8  * history as you browse. It is also used to save the favicons for bookmarks.
     9  *
    10  * DANGER: The history query system makes assumptions about the favicon storage
    11  * so that icons can be quickly generated for history/bookmark result sets. If
    12  * you change the database layout at all, you will have to update both services.
    13  */
    15 #include "nsFaviconService.h"
    17 #include "nsNavHistory.h"
    18 #include "nsPlacesMacros.h"
    19 #include "Helpers.h"
    20 #include "AsyncFaviconHelpers.h"
    22 #include "nsNetUtil.h"
    23 #include "nsReadableUtils.h"
    24 #include "nsStreamUtils.h"
    25 #include "nsStringStream.h"
    26 #include "plbase64.h"
    27 #include "nsIClassInfoImpl.h"
    28 #include "mozilla/ArrayUtils.h"
    29 #include "mozilla/Preferences.h"
    31 // For large favicons optimization.
    32 #include "imgITools.h"
    33 #include "imgIContainer.h"
    35 // Default value for mOptimizedIconDimension
    36 #define OPTIMIZED_FAVICON_DIMENSION 16
    38 #define MAX_FAVICON_CACHE_SIZE 256
    39 #define FAVICON_CACHE_REDUCE_COUNT 64
    41 #define MAX_UNASSOCIATED_FAVICONS 64
    43 // When replaceFaviconData is called, we store the icons in an in-memory cache
    44 // instead of in storage. Icons in the cache are expired according to this
    45 // interval.
    46 #define UNASSOCIATED_ICON_EXPIRY_INTERVAL 60000
    48 // The MIME type of the default favicon and favicons created by
    49 // OptimizeFaviconImage.
    50 #define DEFAULT_MIME_TYPE "image/png"
    52 using namespace mozilla;
    53 using namespace mozilla::places;
    55 /**
    56  * Used to notify a topic to system observers on async execute completion.
    57  * Will throw on error.
    58  */
    59 class ExpireFaviconsStatementCallbackNotifier : public AsyncStatementCallback
    60 {
    61 public:
    62   ExpireFaviconsStatementCallbackNotifier();
    63   NS_IMETHOD HandleCompletion(uint16_t aReason);
    64 };
    67 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsFaviconService, gFaviconService)
    69 NS_IMPL_CLASSINFO(nsFaviconService, nullptr, 0, NS_FAVICONSERVICE_CID)
    70 NS_IMPL_ISUPPORTS_CI(
    71   nsFaviconService
    72 , nsIFaviconService
    73 , mozIAsyncFavicons
    74 , nsITimerCallback
    75 )
    77 nsFaviconService::nsFaviconService()
    78   : mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
    79   , mFailedFaviconSerial(0)
    80   , mFailedFavicons(MAX_FAVICON_CACHE_SIZE)
    81   , mUnassociatedIcons(MAX_UNASSOCIATED_FAVICONS)
    82 {
    83   NS_ASSERTION(!gFaviconService,
    84                "Attempting to create two instances of the service!");
    85   gFaviconService = this;
    86 }
    89 nsFaviconService::~nsFaviconService()
    90 {
    91   NS_ASSERTION(gFaviconService == this,
    92                "Deleting a non-singleton instance of the service");
    93   if (gFaviconService == this)
    94     gFaviconService = nullptr;
    95 }
    98 nsresult
    99 nsFaviconService::Init()
   100 {
   101   mDB = Database::GetDatabase();
   102   NS_ENSURE_STATE(mDB);
   104   mOptimizedIconDimension = Preferences::GetInt(
   105     "places.favicons.optimizeToDimension", OPTIMIZED_FAVICON_DIMENSION
   106   );
   108   mExpireUnassociatedIconsTimer = do_CreateInstance("@mozilla.org/timer;1");
   109   NS_ENSURE_STATE(mExpireUnassociatedIconsTimer);
   111   return NS_OK;
   112 }
   114 NS_IMETHODIMP
   115 nsFaviconService::ExpireAllFavicons()
   116 {
   117   nsCOMPtr<mozIStorageAsyncStatement> unlinkIconsStmt = mDB->GetAsyncStatement(
   118     "UPDATE moz_places "
   119     "SET favicon_id = NULL "
   120     "WHERE favicon_id NOT NULL"
   121   );
   122   NS_ENSURE_STATE(unlinkIconsStmt);
   123   nsCOMPtr<mozIStorageAsyncStatement> removeIconsStmt = mDB->GetAsyncStatement(
   124     "DELETE FROM moz_favicons WHERE id NOT IN ("
   125       "SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
   126     ")"
   127   );
   128   NS_ENSURE_STATE(removeIconsStmt);
   130   mozIStorageBaseStatement* stmts[] = {
   131     unlinkIconsStmt.get()
   132   , removeIconsStmt.get()
   133   };
   134   nsCOMPtr<mozIStoragePendingStatement> ps;
   135   nsRefPtr<ExpireFaviconsStatementCallbackNotifier> callback =
   136     new ExpireFaviconsStatementCallbackNotifier();
   137   nsresult rv = mDB->MainConn()->ExecuteAsync(
   138     stmts, ArrayLength(stmts), callback, getter_AddRefs(ps)
   139   );
   140   NS_ENSURE_SUCCESS(rv, rv);
   142   return NS_OK;
   143 }
   145 ////////////////////////////////////////////////////////////////////////////////
   146 //// nsITimerCallback
   148 static PLDHashOperator
   149 ExpireNonrecentUnassociatedIconsEnumerator(
   150   UnassociatedIconHashKey* aIconKey,
   151   void* aNow)
   152 {
   153   PRTime now = *(reinterpret_cast<PRTime*>(aNow));
   154   if (now - aIconKey->created >= UNASSOCIATED_ICON_EXPIRY_INTERVAL) {
   155     return PL_DHASH_REMOVE;
   156   }
   157   return PL_DHASH_NEXT;
   158 }
   160 NS_IMETHODIMP
   161 nsFaviconService::Notify(nsITimer* timer)
   162 {
   163   if (timer != mExpireUnassociatedIconsTimer.get()) {
   164     return NS_ERROR_INVALID_ARG;
   165   }
   167   PRTime now = PR_Now();
   168   mUnassociatedIcons.EnumerateEntries(
   169     ExpireNonrecentUnassociatedIconsEnumerator, &now);
   170   // Re-init the expiry timer if the cache isn't empty.
   171   if (mUnassociatedIcons.Count() > 0) {
   172     mExpireUnassociatedIconsTimer->InitWithCallback(
   173       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
   174   }
   176   return NS_OK;
   177 }
   179 ////////////////////////////////////////////////////////////////////////////////
   180 //// nsIFaviconService
   182 NS_IMETHODIMP
   183 nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
   184 {
   185   NS_ENSURE_ARG_POINTER(_retval);
   187   // not found, use default
   188   if (!mDefaultIcon) {
   189     nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
   190                             NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
   191     NS_ENSURE_SUCCESS(rv, rv);
   192   }
   193   return mDefaultIcon->Clone(_retval);
   194 }
   196 void
   197 nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
   198                                            nsIURI* aFaviconURI,
   199                                            const nsACString& aGUID)
   200 {
   201   nsAutoCString faviconSpec;
   202   nsNavHistory* history = nsNavHistory::GetHistoryService();
   203   if (history && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
   204     history->SendPageChangedNotification(aPageURI,
   205                                          nsINavHistoryObserver::ATTRIBUTE_FAVICON,
   206                                          NS_ConvertUTF8toUTF16(faviconSpec),
   207                                          aGUID);
   208   }
   209 }
   211 NS_IMETHODIMP
   212 nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI,
   213                                             nsIURI* aFaviconURI,
   214                                             bool aForceReload,
   215                                             uint32_t aFaviconLoadType,
   216                                             nsIFaviconDataCallback* aCallback)
   217 {
   218   NS_ENSURE_ARG(aPageURI);
   219   NS_ENSURE_ARG(aFaviconURI);
   221   // If a favicon is in the failed cache, only load it during a forced reload.
   222   bool previouslyFailed;
   223   nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed);
   224   NS_ENSURE_SUCCESS(rv, rv);
   225   if (previouslyFailed) {
   226     if (aForceReload)
   227       RemoveFailedFavicon(aFaviconURI);
   228     else
   229       return NS_OK;
   230   }
   232   // Check if the icon already exists and fetch it from the network, if needed.
   233   // Finally associate the icon to the requested page if not yet associated.
   234   rv = AsyncFetchAndSetIconForPage::start(
   235     aFaviconURI, aPageURI, aForceReload ? FETCH_ALWAYS : FETCH_IF_MISSING,
   236     aFaviconLoadType, aCallback
   237   );
   238   NS_ENSURE_SUCCESS(rv, rv);
   240   // DB will be updated and observers notified when data has finished loading.
   241   return NS_OK;
   242 }
   244 NS_IMETHODIMP
   245 nsFaviconService::ReplaceFaviconData(nsIURI* aFaviconURI,
   246                                     const uint8_t* aData,
   247                                     uint32_t aDataLen,
   248                                     const nsACString& aMimeType,
   249                                     PRTime aExpiration)
   250 {
   251   NS_ENSURE_ARG(aFaviconURI);
   252   NS_ENSURE_ARG(aData);
   253   NS_ENSURE_TRUE(aDataLen > 0, NS_ERROR_INVALID_ARG);
   254   NS_ENSURE_TRUE(aMimeType.Length() > 0, NS_ERROR_INVALID_ARG);
   255   if (aExpiration == 0) {
   256     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
   257   }
   259   UnassociatedIconHashKey* iconKey = mUnassociatedIcons.PutEntry(aFaviconURI);
   260   if (!iconKey) {
   261     return NS_ERROR_OUT_OF_MEMORY;
   262   }
   264   iconKey->created = PR_Now();
   266   // If the cache contains unassociated icons, an expiry timer should already exist, otherwise
   267   // there may be a timer left hanging around, so make sure we fire a new one.
   268   int32_t unassociatedCount = mUnassociatedIcons.Count();
   269   if (unassociatedCount == 1) {
   270     mExpireUnassociatedIconsTimer->Cancel();
   271     mExpireUnassociatedIconsTimer->InitWithCallback(
   272       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
   273   }
   275   IconData* iconData = &(iconKey->iconData);
   276   iconData->expiration = aExpiration;
   277   iconData->status = ICON_STATUS_CACHED;
   278   iconData->fetchMode = FETCH_NEVER;
   279   nsresult rv = aFaviconURI->GetSpec(iconData->spec);
   280   NS_ENSURE_SUCCESS(rv, rv);
   282   // If the page provided a large image for the favicon (eg, a highres image
   283   // or a multiresolution .ico file), we don't want to store more data than
   284   // needed.
   285   if (aDataLen > MAX_ICON_FILESIZE(mOptimizedIconDimension)) {
   286     rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, iconData->data, iconData->mimeType);
   287     NS_ENSURE_SUCCESS(rv, rv);
   289     if (iconData->data.Length() > MAX_FAVICON_SIZE) {
   290       // We cannot optimize this favicon size and we are over the maximum size
   291       // allowed, so we will not save data to the db to avoid bloating it.
   292       mUnassociatedIcons.RemoveEntry(aFaviconURI);
   293       return NS_ERROR_FAILURE;
   294     }
   295   } else {
   296     iconData->mimeType.Assign(aMimeType);
   297     iconData->data.Assign(TO_CHARBUFFER(aData), aDataLen);
   298   }
   300   // If the database contains an icon at the given url, we will update the
   301   // database immediately so that the associated pages are kept in sync.
   302   // Otherwise, do nothing and let the icon be picked up from the memory hash.
   303   rv = AsyncReplaceFaviconData::start(iconData);
   304   NS_ENSURE_SUCCESS(rv, rv);
   306   return NS_OK;
   307 }
   309 NS_IMETHODIMP
   310 nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI,
   311                                                const nsAString& aDataURL,
   312                                                PRTime aExpiration)
   313 {
   314   NS_ENSURE_ARG(aFaviconURI);
   315   NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG);
   316   if (aExpiration == 0) {
   317     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
   318   }
   320   nsCOMPtr<nsIURI> dataURI;
   321   nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL);
   322   NS_ENSURE_SUCCESS(rv, rv);
   324   // Use the data: protocol handler to convert the data.
   325   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   326   NS_ENSURE_SUCCESS(rv, rv);
   327   nsCOMPtr<nsIProtocolHandler> protocolHandler;
   328   rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler));
   329   NS_ENSURE_SUCCESS(rv, rv);
   331   nsCOMPtr<nsIChannel> channel;
   332   rv = protocolHandler->NewChannel(dataURI, getter_AddRefs(channel));
   333   NS_ENSURE_SUCCESS(rv, rv);
   335   // Blocking stream is OK for data URIs.
   336   nsCOMPtr<nsIInputStream> stream;
   337   rv = channel->Open(getter_AddRefs(stream));
   338   NS_ENSURE_SUCCESS(rv, rv);
   340   uint64_t available64;
   341   rv = stream->Available(&available64);
   342   NS_ENSURE_SUCCESS(rv, rv);
   343   if (available64 == 0 || available64 > UINT32_MAX / sizeof(uint8_t))
   344     return NS_ERROR_FILE_TOO_BIG;
   345   uint32_t available = (uint32_t)available64;
   347   // Read all the decoded data.
   348   uint8_t* buffer = static_cast<uint8_t*>
   349                                (nsMemory::Alloc(sizeof(uint8_t) * available));
   350   if (!buffer)
   351     return NS_ERROR_OUT_OF_MEMORY;
   352   uint32_t numRead;
   353   rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead);
   354   if (NS_FAILED(rv) || numRead != available) {
   355     nsMemory::Free(buffer);
   356     return rv;
   357   }
   359   nsAutoCString mimeType;
   360   rv = channel->GetContentType(mimeType);
   361   if (NS_FAILED(rv)) {
   362     nsMemory::Free(buffer);
   363     return rv;
   364   }
   366   // ReplaceFaviconData can now do the dirty work.
   367   rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration);
   368   nsMemory::Free(buffer);
   369   NS_ENSURE_SUCCESS(rv, rv);
   371   return NS_OK;
   372 }
   374 NS_IMETHODIMP
   375 nsFaviconService::GetFaviconURLForPage(nsIURI *aPageURI,
   376                                        nsIFaviconDataCallback* aCallback)
   377 {
   378   NS_ENSURE_ARG(aPageURI);
   379   NS_ENSURE_ARG(aCallback);
   381   nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, aCallback);
   382   NS_ENSURE_SUCCESS(rv, rv);
   383   return NS_OK;
   384 }
   386 NS_IMETHODIMP
   387 nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
   388                                         nsIFaviconDataCallback* aCallback)
   389 {
   390   NS_ENSURE_ARG(aPageURI);
   391   NS_ENSURE_ARG(aCallback);
   393   nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, aCallback);
   394   NS_ENSURE_SUCCESS(rv, rv);
   395   return NS_OK;
   396 }
   398 nsresult
   399 nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
   400                                         nsIURI** aOutputURI)
   401 {
   402   NS_ENSURE_ARG(aFaviconURI);
   403   NS_ENSURE_ARG_POINTER(aOutputURI);
   405   nsAutoCString spec;
   406   if (aFaviconURI) {
   407     nsresult rv = aFaviconURI->GetSpec(spec);
   408     NS_ENSURE_SUCCESS(rv, rv);
   409   }
   410   return GetFaviconLinkForIconString(spec, aOutputURI);
   411 }
   414 static PLDHashOperator
   415 ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
   416                              uint32_t& aData,
   417                              void* userArg)
   418 {
   419   uint32_t* threshold = reinterpret_cast<uint32_t*>(userArg);
   420   if (aData < *threshold)
   421     return PL_DHASH_REMOVE;
   422   return PL_DHASH_NEXT;
   423 }
   426 NS_IMETHODIMP
   427 nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
   428 {
   429   NS_ENSURE_ARG(aFaviconURI);
   431   nsAutoCString spec;
   432   nsresult rv = aFaviconURI->GetSpec(spec);
   433   NS_ENSURE_SUCCESS(rv, rv);
   435   mFailedFavicons.Put(spec, mFailedFaviconSerial);
   436   mFailedFaviconSerial ++;
   438   if (mFailedFavicons.Count() > MAX_FAVICON_CACHE_SIZE) {
   439     // need to expire some entries, delete the FAVICON_CACHE_REDUCE_COUNT number
   440     // of items that are the oldest
   441     uint32_t threshold = mFailedFaviconSerial -
   442                          MAX_FAVICON_CACHE_SIZE + FAVICON_CACHE_REDUCE_COUNT;
   443     mFailedFavicons.Enumerate(ExpireFailedFaviconsCallback, &threshold);
   444   }
   445   return NS_OK;
   446 }
   449 NS_IMETHODIMP
   450 nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
   451 {
   452   NS_ENSURE_ARG(aFaviconURI);
   454   nsAutoCString spec;
   455   nsresult rv = aFaviconURI->GetSpec(spec);
   456   NS_ENSURE_SUCCESS(rv, rv);
   458   // we silently do nothing and succeed if the icon is not in the cache
   459   mFailedFavicons.Remove(spec);
   460   return NS_OK;
   461 }
   464 NS_IMETHODIMP
   465 nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, bool* _retval)
   466 {
   467   NS_ENSURE_ARG(aFaviconURI);
   468   nsAutoCString spec;
   469   nsresult rv = aFaviconURI->GetSpec(spec);
   470   NS_ENSURE_SUCCESS(rv, rv);
   472   uint32_t serial;
   473   *_retval = mFailedFavicons.Get(spec, &serial);
   474   return NS_OK;
   475 }
   478 // nsFaviconService::GetFaviconLinkForIconString
   479 //
   480 //    This computes a favicon URL with string input and using the cached
   481 //    default one to minimize parsing.
   483 nsresult
   484 nsFaviconService::GetFaviconLinkForIconString(const nsCString& aSpec,
   485                                               nsIURI** aOutput)
   486 {
   487   if (aSpec.IsEmpty()) {
   488     // default icon for empty strings
   489     if (! mDefaultIcon) {
   490       nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
   491                               NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
   492       NS_ENSURE_SUCCESS(rv, rv);
   493     }
   494     return mDefaultIcon->Clone(aOutput);
   495   }
   497   if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
   498     // pass through for chrome URLs, since they can be referenced without
   499     // this service
   500     return NS_NewURI(aOutput, aSpec);
   501   }
   503   nsAutoCString annoUri;
   504   annoUri.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
   505   annoUri += aSpec;
   506   return NS_NewURI(aOutput, annoUri);
   507 }
   510 // nsFaviconService::GetFaviconSpecForIconString
   511 //
   512 //    This computes a favicon spec for when you don't want a URI object (as in
   513 //    the tree view implementation), sparing all parsing and normalization.
   514 void
   515 nsFaviconService::GetFaviconSpecForIconString(const nsCString& aSpec,
   516                                               nsACString& aOutput)
   517 {
   518   if (aSpec.IsEmpty()) {
   519     aOutput.AssignLiteral(FAVICON_DEFAULT_URL);
   520   } else if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
   521     aOutput = aSpec;
   522   } else {
   523     aOutput.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
   524     aOutput += aSpec;
   525   }
   526 }
   529 // nsFaviconService::OptimizeFaviconImage
   530 //
   531 // Given a blob of data (a image file already read into a buffer), optimize
   532 // its size by recompressing it as a 16x16 PNG.
   533 nsresult
   534 nsFaviconService::OptimizeFaviconImage(const uint8_t* aData, uint32_t aDataLen,
   535                                        const nsACString& aMimeType,
   536                                        nsACString& aNewData,
   537                                        nsACString& aNewMimeType)
   538 {
   539   nsresult rv;
   541   nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
   543   nsCOMPtr<nsIInputStream> stream;
   544   rv = NS_NewByteInputStream(getter_AddRefs(stream),
   545                 reinterpret_cast<const char*>(aData), aDataLen,
   546                 NS_ASSIGNMENT_DEPEND);
   547   NS_ENSURE_SUCCESS(rv, rv);
   549   // decode image
   550   nsCOMPtr<imgIContainer> container;
   551   rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container));
   552   NS_ENSURE_SUCCESS(rv, rv);
   554   aNewMimeType.AssignLiteral(DEFAULT_MIME_TYPE);
   556   // scale and recompress
   557   nsCOMPtr<nsIInputStream> iconStream;
   558   rv = imgtool->EncodeScaledImage(container, aNewMimeType,
   559                                   mOptimizedIconDimension,
   560                                   mOptimizedIconDimension,
   561                                   EmptyString(),
   562                                   getter_AddRefs(iconStream));
   563   NS_ENSURE_SUCCESS(rv, rv);
   565   // Read the stream into a new buffer.
   566   rv = NS_ConsumeStream(iconStream, UINT32_MAX, aNewData);
   567   NS_ENSURE_SUCCESS(rv, rv);
   569   return NS_OK;
   570 }
   572 nsresult
   573 nsFaviconService::GetFaviconDataAsync(nsIURI* aFaviconURI,
   574                                       mozIStorageStatementCallback *aCallback)
   575 {
   576   NS_ASSERTION(aCallback, "Doesn't make sense to call this without a callback");
   577   nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
   578     "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
   579   );
   580   NS_ENSURE_STATE(stmt);
   582   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
   583   NS_ENSURE_SUCCESS(rv, rv);
   585   nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
   586   return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
   587 }
   589 ////////////////////////////////////////////////////////////////////////////////
   590 //// ExpireFaviconsStatementCallbackNotifier
   592 ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier()
   593 {
   594 }
   597 NS_IMETHODIMP
   598 ExpireFaviconsStatementCallbackNotifier::HandleCompletion(uint16_t aReason)
   599 {
   600   // We should dispatch only if expiration has been successful.
   601   if (aReason != mozIStorageStatementCallback::REASON_FINISHED)
   602     return NS_OK;
   604   nsCOMPtr<nsIObserverService> observerService =
   605     mozilla::services::GetObserverService();
   606   if (observerService) {
   607     (void)observerService->NotifyObservers(nullptr,
   608                                            NS_PLACES_FAVICONS_EXPIRED_TOPIC_ID,
   609                                            nullptr);
   610   }
   612   return NS_OK;
   613 }

mercurial