LCOV - code coverage report
Current view: top level - toolkit/components/places - nsFaviconService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 75 466 16.1 %
Date: 2017-07-14 16:53:18 Functions: 10 34 29.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /**
       8             :  * This is the favicon service, which stores favicons for web pages with your
       9             :  * history as you browse. It is also used to save the favicons for bookmarks.
      10             :  *
      11             :  * DANGER: The history query system makes assumptions about the favicon storage
      12             :  * so that icons can be quickly generated for history/bookmark result sets. If
      13             :  * you change the database layout at all, you will have to update both services.
      14             :  */
      15             : 
      16             : #include "nsFaviconService.h"
      17             : 
      18             : #include "nsNavHistory.h"
      19             : #include "nsPlacesMacros.h"
      20             : #include "Helpers.h"
      21             : 
      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/LoadInfo.h"
      30             : #include "mozilla/Preferences.h"
      31             : #include "nsILoadInfo.h"
      32             : #include "nsIContentPolicy.h"
      33             : #include "nsContentUtils.h"
      34             : #include "NullPrincipal.h"
      35             : #include "imgICache.h"
      36             : 
      37             : #define MAX_FAILED_FAVICONS 256
      38             : #define FAVICON_CACHE_REDUCE_COUNT 64
      39             : 
      40             : #define UNASSOCIATED_FAVICONS_LENGTH 32
      41             : 
      42             : // When replaceFaviconData is called, we store the icons in an in-memory cache
      43             : // instead of in storage. Icons in the cache are expired according to this
      44             : // interval.
      45             : #define UNASSOCIATED_ICON_EXPIRY_INTERVAL 60000
      46             : 
      47             : using namespace mozilla;
      48             : using namespace mozilla::places;
      49             : 
      50             : /**
      51             :  * Used to notify a topic to system observers on async execute completion.
      52             :  * Will throw on error.
      53             :  */
      54           0 : class ExpireFaviconsStatementCallbackNotifier : public AsyncStatementCallback
      55             : {
      56             : public:
      57             :   ExpireFaviconsStatementCallbackNotifier();
      58             :   NS_IMETHOD HandleCompletion(uint16_t aReason);
      59             : };
      60             : 
      61             : namespace {
      62             : 
      63             : /**
      64             :  * Extracts and filters native sizes from the given container, based on the
      65             :  * list of sizes we are supposed to retain.
      66             :  * All calculation is done considering square sizes and the largest side.
      67             :  * In case of multiple frames of the same size, only the first one is retained.
      68             :  */
      69             : nsresult
      70           0 : GetFramesInfoForContainer(imgIContainer* aContainer,
      71             :                            nsTArray<FrameData>& aFramesInfo) {
      72             :   // Don't extract frames from animated images.
      73             :   bool animated;
      74           0 :   nsresult rv = aContainer->GetAnimated(&animated);
      75           0 :   if (NS_FAILED(rv) || !animated) {
      76           0 :     nsTArray<nsIntSize> nativeSizes;
      77           0 :     rv = aContainer->GetNativeSizes(nativeSizes);
      78           0 :     if (NS_SUCCEEDED(rv) && nativeSizes.Length() > 1) {
      79           0 :       for (uint32_t i = 0; i < nativeSizes.Length(); ++i) {
      80           0 :         nsIntSize nativeSize = nativeSizes[i];
      81             :         // Only retain square frames.
      82           0 :         if (nativeSize.width != nativeSize.height) {
      83           0 :           continue;
      84             :         }
      85             :         // Check if it's one of the sizes we care about.
      86           0 :         auto end = std::end(sFaviconSizes);
      87           0 :         uint16_t* matchingSize = std::find(std::begin(sFaviconSizes), end,
      88           0 :                                           nativeSize.width);
      89           0 :         if (matchingSize != end) {
      90             :           // We must avoid duped sizes, an image could contain multiple frames of
      91             :           // the same size, but we can only store one. We could use an hashtable,
      92             :           // but considered the average low number of frames, we'll just do a
      93             :           // linear search.
      94           0 :           bool dupe = false;
      95           0 :           for (const auto& frameInfo : aFramesInfo) {
      96           0 :             if (frameInfo.width == *matchingSize) {
      97           0 :               dupe = true;
      98           0 :               break;
      99             :             }
     100             :           }
     101           0 :           if (!dupe) {
     102           0 :             aFramesInfo.AppendElement(FrameData(i, *matchingSize));
     103             :           }
     104             :         }
     105             :       }
     106             :     }
     107             :   }
     108             : 
     109           0 :   if (aFramesInfo.Length() == 0) {
     110             :     // Always have at least the default size.
     111             :     int32_t width;
     112           0 :     rv = aContainer->GetWidth(&width);
     113           0 :     NS_ENSURE_SUCCESS(rv, rv);
     114             :     int32_t height;
     115           0 :     rv = aContainer->GetHeight(&height);
     116           0 :     NS_ENSURE_SUCCESS(rv, rv);
     117             :     // For non-square images, pick the largest side.
     118           0 :     aFramesInfo.AppendElement(FrameData(0, std::max(width, height)));
     119             :   }
     120           0 :   return NS_OK;
     121             : }
     122             : 
     123             : } // namespace
     124             : 
     125           2 : PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsFaviconService, gFaviconService)
     126             : 
     127           3 : NS_IMPL_CLASSINFO(nsFaviconService, nullptr, 0, NS_FAVICONSERVICE_CID)
     128          76 : NS_IMPL_ISUPPORTS_CI(
     129             :   nsFaviconService
     130             : , nsIFaviconService
     131             : , mozIAsyncFavicons
     132             : , nsITimerCallback
     133             : )
     134             : 
     135           1 : nsFaviconService::nsFaviconService()
     136             :   : mFailedFaviconSerial(0)
     137             :   , mFailedFavicons(MAX_FAILED_FAVICONS / 2)
     138           1 :   , mUnassociatedIcons(UNASSOCIATED_FAVICONS_LENGTH)
     139             : {
     140           1 :   NS_ASSERTION(!gFaviconService,
     141             :                "Attempting to create two instances of the service!");
     142           1 :   gFaviconService = this;
     143           1 : }
     144             : 
     145             : 
     146           0 : nsFaviconService::~nsFaviconService()
     147             : {
     148           0 :   NS_ASSERTION(gFaviconService == this,
     149             :                "Deleting a non-singleton instance of the service");
     150           0 :   if (gFaviconService == this)
     151           0 :     gFaviconService = nullptr;
     152           0 : }
     153             : 
     154             : Atomic<int64_t> nsFaviconService::sLastInsertedIconId(0);
     155             : 
     156             : void // static
     157           0 : nsFaviconService::StoreLastInsertedId(const nsACString& aTable,
     158             :                                       const int64_t aLastInsertedId) {
     159           0 :   MOZ_ASSERT(aTable.EqualsLiteral("moz_icons"));
     160           0 :   sLastInsertedIconId = aLastInsertedId;
     161           0 : }
     162             : 
     163             : nsresult
     164           1 : nsFaviconService::Init()
     165             : {
     166           1 :   mDB = Database::GetDatabase();
     167           1 :   NS_ENSURE_STATE(mDB);
     168             : 
     169           1 :   mExpireUnassociatedIconsTimer = do_CreateInstance("@mozilla.org/timer;1");
     170           1 :   NS_ENSURE_STATE(mExpireUnassociatedIconsTimer);
     171             : 
     172             :   // Check if there are still icon payloads to be converted.
     173             :   bool shouldConvertPayloads =
     174           1 :     Preferences::GetBool(PREF_CONVERT_PAYLOADS, false);
     175           1 :   if (shouldConvertPayloads) {
     176           0 :     ConvertUnsupportedPayloads(mDB->MainConn());
     177             :   }
     178             : 
     179           1 :   return NS_OK;
     180             : }
     181             : 
     182             : NS_IMETHODIMP
     183           0 : nsFaviconService::ExpireAllFavicons()
     184             : {
     185           0 :   NS_ENSURE_STATE(mDB);
     186             : 
     187           0 :   nsCOMPtr<mozIStorageAsyncStatement> removePagesStmt = mDB->GetAsyncStatement(
     188             :     "DELETE FROM moz_pages_w_icons"
     189           0 :   );
     190           0 :   NS_ENSURE_STATE(removePagesStmt);
     191           0 :   nsCOMPtr<mozIStorageAsyncStatement> removeIconsStmt = mDB->GetAsyncStatement(
     192             :     "DELETE FROM moz_icons"
     193           0 :   );
     194           0 :   NS_ENSURE_STATE(removeIconsStmt);
     195           0 :   nsCOMPtr<mozIStorageAsyncStatement> unlinkIconsStmt = mDB->GetAsyncStatement(
     196             :     "DELETE FROM moz_icons_to_pages"
     197           0 :   );
     198           0 :   NS_ENSURE_STATE(unlinkIconsStmt);
     199             : 
     200             :   mozIStorageBaseStatement* stmts[] = {
     201           0 :     removePagesStmt.get()
     202           0 :   , removeIconsStmt.get()
     203           0 :   , unlinkIconsStmt.get()
     204           0 :   };
     205           0 :   nsCOMPtr<mozIStorageConnection> conn = mDB->MainConn();
     206           0 :   if (!conn) {
     207           0 :     return NS_ERROR_UNEXPECTED;
     208             :   }
     209           0 :   nsCOMPtr<mozIStoragePendingStatement> ps;
     210             :   RefPtr<ExpireFaviconsStatementCallbackNotifier> callback =
     211           0 :     new ExpireFaviconsStatementCallbackNotifier();
     212           0 :   return conn->ExecuteAsync(stmts, ArrayLength(stmts),
     213           0 :                                         callback, getter_AddRefs(ps));
     214             : }
     215             : 
     216             : ////////////////////////////////////////////////////////////////////////////////
     217             : //// nsITimerCallback
     218             : 
     219             : NS_IMETHODIMP
     220           0 : nsFaviconService::Notify(nsITimer* timer)
     221             : {
     222           0 :   if (timer != mExpireUnassociatedIconsTimer.get()) {
     223           0 :     return NS_ERROR_INVALID_ARG;
     224             :   }
     225             : 
     226           0 :   PRTime now = PR_Now();
     227           0 :   for (auto iter = mUnassociatedIcons.Iter(); !iter.Done(); iter.Next()) {
     228           0 :     UnassociatedIconHashKey* iconKey = iter.Get();
     229           0 :     if (now - iconKey->created >= UNASSOCIATED_ICON_EXPIRY_INTERVAL) {
     230           0 :       iter.Remove();
     231             :     }
     232             :   }
     233             : 
     234             :   // Re-init the expiry timer if the cache isn't empty.
     235           0 :   if (mUnassociatedIcons.Count() > 0) {
     236           0 :     mExpireUnassociatedIconsTimer->InitWithCallback(
     237           0 :       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
     238             :   }
     239             : 
     240           0 :   return NS_OK;
     241             : }
     242             : 
     243             : ////////////////////////////////////////////////////////////////////////////////
     244             : //// nsIFaviconService
     245             : 
     246             : NS_IMETHODIMP
     247           0 : nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
     248             : {
     249           0 :   NS_ENSURE_ARG_POINTER(_retval);
     250             : 
     251             :   // not found, use default
     252           0 :   if (!mDefaultIcon) {
     253           0 :     nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
     254           0 :                             NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
     255           0 :     NS_ENSURE_SUCCESS(rv, rv);
     256             :   }
     257           0 :   return mDefaultIcon->Clone(_retval);
     258             : }
     259             : 
     260             : NS_IMETHODIMP
     261           0 : nsFaviconService::GetDefaultFaviconMimeType(nsACString& _retval)
     262             : {
     263           0 :   _retval = NS_LITERAL_CSTRING(FAVICON_DEFAULT_MIMETYPE);
     264           0 :   return NS_OK;
     265             : }
     266             : 
     267             : void
     268           0 : nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
     269             :                                            nsIURI* aFaviconURI,
     270             :                                            const nsACString& aGUID)
     271             : {
     272           0 :   nsAutoCString faviconSpec;
     273           0 :   nsNavHistory* history = nsNavHistory::GetHistoryService();
     274           0 :   if (history && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
     275             :     // Invalide page-icon image cache, since the icon is about to change.
     276           0 :     nsCString spec;
     277           0 :     nsresult rv = aPageURI->GetSpec(spec);
     278           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
     279           0 :     if (NS_SUCCEEDED(rv)) {
     280           0 :       nsCString pageIconSpec("page-icon:");
     281           0 :       pageIconSpec.Append(spec);
     282           0 :       nsCOMPtr<nsIURI> pageIconURI;
     283           0 :       rv = NS_NewURI(getter_AddRefs(pageIconURI), pageIconSpec);
     284           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
     285           0 :       if (NS_SUCCEEDED(rv)) {
     286           0 :         nsCOMPtr<imgICache> imgCache;
     287           0 :         rv = GetImgTools()->GetImgCacheForDocument(nullptr, getter_AddRefs(imgCache));
     288           0 :         MOZ_ASSERT(NS_SUCCEEDED(rv));
     289           0 :         if (NS_SUCCEEDED(rv)) {
     290           0 :           Unused << imgCache->RemoveEntry(pageIconURI, nullptr);
     291             :         }
     292             :       }
     293             :     }
     294             : 
     295             :     history->SendPageChangedNotification(aPageURI,
     296             :                                          nsINavHistoryObserver::ATTRIBUTE_FAVICON,
     297           0 :                                          NS_ConvertUTF8toUTF16(faviconSpec),
     298           0 :                                          aGUID);
     299             :   }
     300           0 : }
     301             : 
     302             : NS_IMETHODIMP
     303           1 : nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI,
     304             :                                             nsIURI* aFaviconURI,
     305             :                                             bool aForceReload,
     306             :                                             uint32_t aFaviconLoadType,
     307             :                                             nsIFaviconDataCallback* aCallback,
     308             :                                             nsIPrincipal* aLoadingPrincipal,
     309             :                                             mozIPlacesPendingOperation **_canceler)
     310             : {
     311           1 :   MOZ_ASSERT(NS_IsMainThread());
     312           1 :   NS_ENSURE_ARG(aPageURI);
     313           1 :   NS_ENSURE_ARG(aFaviconURI);
     314           1 :   NS_ENSURE_ARG_POINTER(_canceler);
     315             : 
     316             :   // If a favicon is in the failed cache, only load it during a forced reload.
     317             :   bool previouslyFailed;
     318           1 :   nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed);
     319           1 :   NS_ENSURE_SUCCESS(rv, rv);
     320           1 :   if (previouslyFailed) {
     321           0 :     if (aForceReload) {
     322           0 :       RemoveFailedFavicon(aFaviconURI);
     323             :     }
     324             :     else {
     325           0 :       return NS_OK;
     326             :     }
     327             :   }
     328             : 
     329           2 :   nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadingPrincipal;
     330           1 :   MOZ_ASSERT(loadingPrincipal, "please provide aLoadingPrincipal for this favicon");
     331           1 :   if (!loadingPrincipal) {
     332             :     // Let's default to the nullPrincipal if no loadingPrincipal is provided.
     333             :     const char16_t* params[] = {
     334             :       u"nsFaviconService::setAndFetchFaviconForPage()",
     335             :       u"nsFaviconService::setAndFetchFaviconForPage(..., [optional aLoadingPrincipal])"
     336           0 :     };
     337           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     338           0 :                                     NS_LITERAL_CSTRING("Security by Default"),
     339             :                                     nullptr, // aDocument
     340             :                                     nsContentUtils::eNECKO_PROPERTIES,
     341             :                                     "APIDeprecationWarning",
     342           0 :                                     params, ArrayLength(params));
     343           0 :     loadingPrincipal = NullPrincipal::Create();
     344             :   }
     345           1 :   NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE);
     346             : 
     347           1 :   bool loadPrivate = aFaviconLoadType == nsIFaviconService::FAVICON_LOAD_PRIVATE;
     348             : 
     349             :   // Build page data.
     350           2 :   PageData page;
     351           1 :   rv = aPageURI->GetSpec(page.spec);
     352           1 :   NS_ENSURE_SUCCESS(rv, rv);
     353             :   // URIs can arguably lack a host.
     354           1 :   Unused << aPageURI->GetHost(page.host);
     355           1 :   if (StringBeginsWith(page.host, NS_LITERAL_CSTRING("www."))) {
     356           0 :     page.host.Cut(0, 4);
     357             :   }
     358             :   bool canAddToHistory;
     359           1 :   nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
     360           1 :   NS_ENSURE_TRUE(navHistory, NS_ERROR_OUT_OF_MEMORY);
     361           1 :   rv = navHistory->CanAddURI(aPageURI, &canAddToHistory);
     362           1 :   NS_ENSURE_SUCCESS(rv, rv);
     363           1 :   page.canAddToHistory = !!canAddToHistory && !loadPrivate;
     364             : 
     365             :   // Build icon data.
     366           2 :   IconData icon;
     367             :   // If we have an in-memory icon payload, it overwrites the actual request.
     368           1 :   UnassociatedIconHashKey* iconKey = mUnassociatedIcons.GetEntry(aFaviconURI);
     369           1 :   if (iconKey) {
     370           0 :     icon = iconKey->iconData;
     371           0 :     mUnassociatedIcons.RemoveEntry(iconKey);
     372             :   } else {
     373           1 :     icon.fetchMode = aForceReload ? FETCH_ALWAYS : FETCH_IF_MISSING;
     374           1 :     rv = aFaviconURI->GetSpec(icon.spec);
     375           1 :     NS_ENSURE_SUCCESS(rv, rv);
     376             :     // URIs can arguably lack a host.
     377           1 :     Unused << aFaviconURI->GetHost(icon.host);
     378           1 :     if (StringBeginsWith(icon.host, NS_LITERAL_CSTRING("www."))) {
     379           0 :       icon.host.Cut(0, 4);
     380             :     }
     381           2 :     nsAutoCString path;
     382           1 :     rv = aFaviconURI->GetPath(path);
     383           1 :     if (NS_SUCCEEDED(rv) && path.EqualsLiteral("/favicon.ico")) {
     384           1 :       icon.rootIcon = 1;
     385             :     }
     386             :   }
     387             : 
     388             :   // If the page url points to an image, the icon's url will be the same.
     389             :   // TODO (Bug 403651): store a resample of the image.  For now avoid that
     390             :   // for database size and UX concerns.
     391             :   // Don't store favicons for error pages too.
     392           2 :   if (icon.spec.Equals(page.spec) ||
     393           1 :       icon.spec.Equals(FAVICON_ERRORPAGE_URL)) {
     394           0 :     return NS_OK;
     395             :   }
     396             : 
     397             :   RefPtr<AsyncFetchAndSetIconForPage> event =
     398             :     new AsyncFetchAndSetIconForPage(icon, page, loadPrivate,
     399           2 :                                     aCallback, aLoadingPrincipal);
     400             : 
     401             :   // Get the target thread and start the work.
     402             :   // DB will be updated and observers notified when data has finished loading.
     403           2 :   RefPtr<Database> DB = Database::GetDatabase();
     404           1 :   NS_ENSURE_STATE(DB);
     405           1 :   DB->DispatchToAsyncThread(event);
     406             : 
     407             :   // Return this event to the caller to allow aborting an eventual fetch.
     408           1 :   event.forget(_canceler);
     409             : 
     410           1 :   return NS_OK;
     411             : }
     412             : 
     413             : NS_IMETHODIMP
     414           0 : nsFaviconService::ReplaceFaviconData(nsIURI* aFaviconURI,
     415             :                                     const uint8_t* aData,
     416             :                                     uint32_t aDataLen,
     417             :                                     const nsACString& aMimeType,
     418             :                                     PRTime aExpiration)
     419             : {
     420           0 :   MOZ_ASSERT(NS_IsMainThread());
     421           0 :   NS_ENSURE_ARG(aFaviconURI);
     422           0 :   NS_ENSURE_ARG(aData);
     423           0 :   NS_ENSURE_ARG(aDataLen > 0);
     424           0 :   NS_ENSURE_ARG(aMimeType.Length() > 0);
     425           0 :   NS_ENSURE_ARG(imgLoader::SupportImageWithMimeType(PromiseFlatCString(aMimeType).get(),
     426             :                                                      AcceptedMimeTypes::IMAGES_AND_DOCUMENTS));
     427             : 
     428           0 :   if (aExpiration == 0) {
     429           0 :     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
     430             :   }
     431             : 
     432           0 :   UnassociatedIconHashKey* iconKey = mUnassociatedIcons.PutEntry(aFaviconURI);
     433           0 :   if (!iconKey) {
     434           0 :     return NS_ERROR_OUT_OF_MEMORY;
     435             :   }
     436             : 
     437           0 :   iconKey->created = PR_Now();
     438             : 
     439             :   // If the cache contains unassociated icons, an expiry timer should already exist, otherwise
     440             :   // there may be a timer left hanging around, so make sure we fire a new one.
     441           0 :   int32_t unassociatedCount = mUnassociatedIcons.Count();
     442           0 :   if (unassociatedCount == 1) {
     443           0 :     mExpireUnassociatedIconsTimer->Cancel();
     444           0 :     mExpireUnassociatedIconsTimer->InitWithCallback(
     445           0 :       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
     446             :   }
     447             : 
     448           0 :   IconData* iconData = &(iconKey->iconData);
     449           0 :   iconData->expiration = aExpiration;
     450           0 :   iconData->status = ICON_STATUS_CACHED;
     451           0 :   iconData->fetchMode = FETCH_NEVER;
     452           0 :   nsresult rv = aFaviconURI->GetSpec(iconData->spec);
     453           0 :   NS_ENSURE_SUCCESS(rv, rv);
     454           0 :   nsAutoCString path;
     455           0 :   rv = aFaviconURI->GetPath(path);
     456           0 :   if (NS_SUCCEEDED(rv) && path.EqualsLiteral("/favicon.ico")) {
     457           0 :     iconData->rootIcon = 1;
     458             :   }
     459             :   // URIs can arguably lack a host.
     460           0 :   Unused << aFaviconURI->GetHost(iconData->host);
     461           0 :   if (StringBeginsWith(iconData->host, NS_LITERAL_CSTRING("www."))) {
     462           0 :     iconData->host.Cut(0, 4);
     463             :   }
     464             : 
     465           0 :   IconPayload payload;
     466           0 :   payload.mimeType = aMimeType;
     467           0 :   payload.data.Assign(TO_CHARBUFFER(aData), aDataLen);
     468           0 :   if (payload.mimeType.EqualsLiteral(SVG_MIME_TYPE)) {
     469           0 :     payload.width = UINT16_MAX;
     470             :   }
     471             :   // There may already be a previous payload, so ensure to only have one.
     472           0 :   iconData->payloads.Clear();
     473           0 :   iconData->payloads.AppendElement(payload);
     474             : 
     475           0 :   rv = OptimizeIconSizes(*iconData);
     476           0 :   NS_ENSURE_SUCCESS(rv, rv);
     477             : 
     478             :   // If there's not valid payload, don't store the icon into to the database.
     479           0 :   if ((*iconData).payloads.Length() == 0) {
     480             :     // We cannot optimize this favicon size and we are over the maximum size
     481             :     // allowed, so we will not save data to the db to avoid bloating it.
     482           0 :     mUnassociatedIcons.RemoveEntry(aFaviconURI);
     483           0 :     return NS_ERROR_FAILURE;
     484             :   }
     485             : 
     486             :   // If the database contains an icon at the given url, we will update the
     487             :   // database immediately so that the associated pages are kept in sync.
     488             :   // Otherwise, do nothing and let the icon be picked up from the memory hash.
     489           0 :   RefPtr<AsyncReplaceFaviconData> event = new AsyncReplaceFaviconData(*iconData);
     490           0 :   RefPtr<Database> DB = Database::GetDatabase();
     491           0 :   NS_ENSURE_STATE(DB);
     492           0 :   DB->DispatchToAsyncThread(event);
     493             : 
     494           0 :   return NS_OK;
     495             : }
     496             : 
     497             : NS_IMETHODIMP
     498           0 : nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI,
     499             :                                                const nsAString& aDataURL,
     500             :                                                PRTime aExpiration,
     501             :                                                nsIPrincipal* aLoadingPrincipal)
     502             : {
     503           0 :   NS_ENSURE_ARG(aFaviconURI);
     504           0 :   NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG);
     505           0 :   if (aExpiration == 0) {
     506           0 :     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
     507             :   }
     508             : 
     509           0 :   nsCOMPtr<nsIURI> dataURI;
     510           0 :   nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL);
     511           0 :   NS_ENSURE_SUCCESS(rv, rv);
     512             : 
     513             :   // Use the data: protocol handler to convert the data.
     514           0 :   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
     515           0 :   NS_ENSURE_SUCCESS(rv, rv);
     516           0 :   nsCOMPtr<nsIProtocolHandler> protocolHandler;
     517           0 :   rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler));
     518           0 :   NS_ENSURE_SUCCESS(rv, rv);
     519             : 
     520           0 :   nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadingPrincipal;
     521           0 :   MOZ_ASSERT(loadingPrincipal, "please provide aLoadingPrincipal for this favicon");
     522           0 :   if (!loadingPrincipal) {
     523             :     // Let's default to the nullPrincipal if no loadingPrincipal is provided.
     524             :     const char16_t* params[] = {
     525             :       u"nsFaviconService::ReplaceFaviconDataFromDataURL()",
     526             :       u"nsFaviconService::ReplaceFaviconDataFromDataURL(..., [optional aLoadingPrincipal])"
     527           0 :     };
     528           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     529           0 :                                     NS_LITERAL_CSTRING("Security by Default"),
     530             :                                     nullptr, // aDocument
     531             :                                     nsContentUtils::eNECKO_PROPERTIES,
     532             :                                     "APIDeprecationWarning",
     533           0 :                                     params, ArrayLength(params));
     534             : 
     535           0 :     loadingPrincipal = NullPrincipal::Create();
     536             :   }
     537           0 :   NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE);
     538             : 
     539             :   nsCOMPtr<nsILoadInfo> loadInfo =
     540             :     new mozilla::LoadInfo(loadingPrincipal,
     541             :                           nullptr, // aTriggeringPrincipal
     542             :                           nullptr, // aLoadingNode
     543             :                           nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
     544             :                           nsILoadInfo::SEC_ALLOW_CHROME |
     545             :                           nsILoadInfo::SEC_DISALLOW_SCRIPT,
     546           0 :                           nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON);
     547             : 
     548           0 :   nsCOMPtr<nsIChannel> channel;
     549           0 :   rv = protocolHandler->NewChannel2(dataURI, loadInfo, getter_AddRefs(channel));
     550           0 :   NS_ENSURE_SUCCESS(rv, rv);
     551             : 
     552             :   // Blocking stream is OK for data URIs.
     553           0 :   nsCOMPtr<nsIInputStream> stream;
     554           0 :   rv = channel->Open2(getter_AddRefs(stream));
     555           0 :   NS_ENSURE_SUCCESS(rv, rv);
     556             : 
     557             :   uint64_t available64;
     558           0 :   rv = stream->Available(&available64);
     559           0 :   NS_ENSURE_SUCCESS(rv, rv);
     560           0 :   if (available64 == 0 || available64 > UINT32_MAX / sizeof(uint8_t))
     561           0 :     return NS_ERROR_FILE_TOO_BIG;
     562           0 :   uint32_t available = (uint32_t)available64;
     563             : 
     564             :   // Read all the decoded data.
     565             :   uint8_t* buffer = static_cast<uint8_t*>
     566           0 :                                (moz_xmalloc(sizeof(uint8_t) * available));
     567           0 :   if (!buffer)
     568           0 :     return NS_ERROR_OUT_OF_MEMORY;
     569             :   uint32_t numRead;
     570           0 :   rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead);
     571           0 :   if (NS_FAILED(rv) || numRead != available) {
     572           0 :     free(buffer);
     573           0 :     return rv;
     574             :   }
     575             : 
     576           0 :   nsAutoCString mimeType;
     577           0 :   rv = channel->GetContentType(mimeType);
     578           0 :   if (NS_FAILED(rv)) {
     579           0 :     free(buffer);
     580           0 :     return rv;
     581             :   }
     582             : 
     583             :   // ReplaceFaviconData can now do the dirty work.
     584           0 :   rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration);
     585           0 :   free(buffer);
     586           0 :   NS_ENSURE_SUCCESS(rv, rv);
     587             : 
     588           0 :   return NS_OK;
     589             : }
     590             : 
     591             : NS_IMETHODIMP
     592           0 : nsFaviconService::GetFaviconURLForPage(nsIURI *aPageURI,
     593             :                                        nsIFaviconDataCallback* aCallback,
     594             :                                        uint16_t aPreferredWidth)
     595             : {
     596           0 :   MOZ_ASSERT(NS_IsMainThread());
     597           0 :   NS_ENSURE_ARG(aPageURI);
     598           0 :   NS_ENSURE_ARG(aCallback);
     599             : 
     600           0 :   nsAutoCString pageSpec;
     601           0 :   nsresult rv = aPageURI->GetSpec(pageSpec);
     602           0 :   NS_ENSURE_SUCCESS(rv, rv);
     603           0 :   nsAutoCString pageHost;
     604             :   // It's expected that some domains may not have a host.
     605           0 :   Unused << aPageURI->GetHost(pageHost);
     606             : 
     607             :   RefPtr<AsyncGetFaviconURLForPage> event =
     608           0 :     new AsyncGetFaviconURLForPage(pageSpec, pageHost, aPreferredWidth, aCallback);
     609             : 
     610           0 :   RefPtr<Database> DB = Database::GetDatabase();
     611           0 :   NS_ENSURE_STATE(DB);
     612           0 :   DB->DispatchToAsyncThread(event);
     613             : 
     614           0 :   return NS_OK;
     615             : }
     616             : 
     617             : NS_IMETHODIMP
     618           0 : nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
     619             :                                         nsIFaviconDataCallback* aCallback,
     620             :                                         uint16_t aPreferredWidth)
     621             : {
     622           0 :   MOZ_ASSERT(NS_IsMainThread());
     623           0 :   NS_ENSURE_ARG(aPageURI);
     624           0 :   NS_ENSURE_ARG(aCallback);
     625             : 
     626           0 :   nsAutoCString pageSpec;
     627           0 :   nsresult rv = aPageURI->GetSpec(pageSpec);
     628           0 :   NS_ENSURE_SUCCESS(rv, rv);
     629           0 :   nsAutoCString pageHost;
     630             :   // It's expected that some domains may not have a host.
     631           0 :   Unused << aPageURI->GetHost(pageHost);
     632             : 
     633             :   RefPtr<AsyncGetFaviconDataForPage> event =
     634           0 :     new AsyncGetFaviconDataForPage(pageSpec, pageHost, aPreferredWidth, aCallback);
     635           0 :   RefPtr<Database> DB = Database::GetDatabase();
     636           0 :   NS_ENSURE_STATE(DB);
     637           0 :   DB->DispatchToAsyncThread(event);
     638             : 
     639           0 :   return NS_OK;
     640             : }
     641             : 
     642             : NS_IMETHODIMP
     643           0 : nsFaviconService::CopyFavicons(nsIURI* aFromPageURI,
     644             :                                nsIURI* aToPageURI,
     645             :                                uint32_t aFaviconLoadType,
     646             :                                nsIFaviconDataCallback* aCallback)
     647             : {
     648           0 :   MOZ_ASSERT(NS_IsMainThread());
     649           0 :   NS_ENSURE_ARG(aFromPageURI);
     650           0 :   NS_ENSURE_ARG(aToPageURI);
     651           0 :   NS_ENSURE_TRUE(aFaviconLoadType >= nsIFaviconService::FAVICON_LOAD_PRIVATE &&
     652             :                  aFaviconLoadType <= nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
     653             :                  NS_ERROR_INVALID_ARG);
     654             : 
     655           0 :   PageData fromPage;
     656           0 :   nsresult rv = aFromPageURI->GetSpec(fromPage.spec);
     657           0 :   NS_ENSURE_SUCCESS(rv, rv);
     658           0 :   PageData toPage;
     659           0 :   rv = aToPageURI->GetSpec(toPage.spec);
     660           0 :   NS_ENSURE_SUCCESS(rv, rv);
     661             : 
     662             :   bool canAddToHistory;
     663           0 :   nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
     664           0 :   NS_ENSURE_TRUE(navHistory, NS_ERROR_OUT_OF_MEMORY);
     665           0 :   rv = navHistory->CanAddURI(aToPageURI, &canAddToHistory);
     666           0 :   NS_ENSURE_SUCCESS(rv, rv);
     667           0 :   toPage.canAddToHistory = !!canAddToHistory &&
     668             :                            aFaviconLoadType != nsIFaviconService::FAVICON_LOAD_PRIVATE;
     669             : 
     670           0 :   RefPtr<AsyncCopyFavicons> event = new AsyncCopyFavicons(fromPage, toPage, aCallback);
     671             : 
     672             :   // Get the target thread and start the work.
     673             :   // DB will be updated and observers notified when done.
     674           0 :   RefPtr<Database> DB = Database::GetDatabase();
     675           0 :   NS_ENSURE_STATE(DB);
     676           0 :   DB->DispatchToAsyncThread(event);
     677             : 
     678           0 :   return NS_OK;
     679             : }
     680             : 
     681             : nsresult
     682           0 : nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
     683             :                                         nsIURI** aOutputURI)
     684             : {
     685           0 :   NS_ENSURE_ARG(aFaviconURI);
     686           0 :   NS_ENSURE_ARG_POINTER(aOutputURI);
     687             : 
     688           0 :   nsAutoCString spec;
     689           0 :   if (aFaviconURI) {
     690           0 :     nsresult rv = aFaviconURI->GetSpec(spec);
     691           0 :     NS_ENSURE_SUCCESS(rv, rv);
     692             :   }
     693           0 :   return GetFaviconLinkForIconString(spec, aOutputURI);
     694             : }
     695             : 
     696             : 
     697             : NS_IMETHODIMP
     698           1 : nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
     699             : {
     700           1 :   NS_ENSURE_ARG(aFaviconURI);
     701             : 
     702           2 :   nsAutoCString spec;
     703           1 :   nsresult rv = aFaviconURI->GetSpec(spec);
     704           1 :   NS_ENSURE_SUCCESS(rv, rv);
     705             : 
     706           1 :   mFailedFavicons.Put(spec, mFailedFaviconSerial);
     707           1 :   mFailedFaviconSerial ++;
     708             : 
     709           1 :   if (mFailedFavicons.Count() > MAX_FAILED_FAVICONS) {
     710             :     // need to expire some entries, delete the FAVICON_CACHE_REDUCE_COUNT number
     711             :     // of items that are the oldest
     712           0 :     uint32_t threshold = mFailedFaviconSerial -
     713           0 :                          MAX_FAILED_FAVICONS + FAVICON_CACHE_REDUCE_COUNT;
     714           0 :     for (auto iter = mFailedFavicons.Iter(); !iter.Done(); iter.Next()) {
     715           0 :       if (iter.Data() < threshold) {
     716           0 :         iter.Remove();
     717             :       }
     718             :     }
     719             :   }
     720           1 :   return NS_OK;
     721             : }
     722             : 
     723             : 
     724             : NS_IMETHODIMP
     725           0 : nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
     726             : {
     727           0 :   NS_ENSURE_ARG(aFaviconURI);
     728             : 
     729           0 :   nsAutoCString spec;
     730           0 :   nsresult rv = aFaviconURI->GetSpec(spec);
     731           0 :   NS_ENSURE_SUCCESS(rv, rv);
     732             : 
     733             :   // we silently do nothing and succeed if the icon is not in the cache
     734           0 :   mFailedFavicons.Remove(spec);
     735           0 :   return NS_OK;
     736             : }
     737             : 
     738             : 
     739             : NS_IMETHODIMP
     740           2 : nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, bool* _retval)
     741             : {
     742           2 :   NS_ENSURE_ARG(aFaviconURI);
     743           4 :   nsAutoCString spec;
     744           2 :   nsresult rv = aFaviconURI->GetSpec(spec);
     745           2 :   NS_ENSURE_SUCCESS(rv, rv);
     746             : 
     747             :   uint32_t serial;
     748           2 :   *_retval = mFailedFavicons.Get(spec, &serial);
     749           2 :   return NS_OK;
     750             : }
     751             : 
     752             : 
     753             : // nsFaviconService::GetFaviconLinkForIconString
     754             : //
     755             : //    This computes a favicon URL with string input and using the cached
     756             : //    default one to minimize parsing.
     757             : 
     758             : nsresult
     759           0 : nsFaviconService::GetFaviconLinkForIconString(const nsCString& aSpec,
     760             :                                               nsIURI** aOutput)
     761             : {
     762           0 :   if (aSpec.IsEmpty()) {
     763           0 :     return GetDefaultFavicon(aOutput);
     764             :   }
     765             : 
     766           0 :   if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
     767             :     // pass through for chrome URLs, since they can be referenced without
     768             :     // this service
     769           0 :     return NS_NewURI(aOutput, aSpec);
     770             :   }
     771             : 
     772           0 :   nsAutoCString annoUri;
     773           0 :   annoUri.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
     774           0 :   annoUri += aSpec;
     775           0 :   return NS_NewURI(aOutput, annoUri);
     776             : }
     777             : 
     778             : /**
     779             :  * Checks the icon and evaluates if it needs to be optimized.
     780             :  *
     781             :  * @param aIcon
     782             :  *        The icon to be evaluated.
     783             :  */
     784             : nsresult
     785           0 : nsFaviconService::OptimizeIconSizes(IconData& aIcon)
     786             : {
     787             :   // TODO (bug 1346139): move optimization to the async thread.
     788           0 :   MOZ_ASSERT(NS_IsMainThread());
     789             :   // There should only be a single payload at this point, it may have to be
     790             :   // split though, if it's an ico file.
     791           0 :   MOZ_ASSERT(aIcon.payloads.Length() == 1);
     792             : 
     793             :   // Even if the page provides a large image for the favicon (eg, a highres
     794             :   // image or a multiresolution .ico file), don't try to store more data than
     795             :   // needed.
     796           0 :   IconPayload payload = aIcon.payloads[0];
     797           0 :   if (payload.mimeType.EqualsLiteral(SVG_MIME_TYPE)) {
     798             :     // Nothing to optimize, but check the payload size.
     799           0 :     if (payload.data.Length() >= nsIFaviconService::MAX_FAVICON_BUFFER_SIZE) {
     800           0 :       aIcon.payloads.Clear();
     801             :     }
     802           0 :     return NS_OK;
     803             :   }
     804             : 
     805             :   // Make space for the optimized payloads.
     806           0 :   aIcon.payloads.Clear();
     807             : 
     808           0 :   nsCOMPtr<nsIInputStream> stream;
     809           0 :   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
     810             :                                       payload.data.get(),
     811           0 :                                       payload.data.Length(),
     812           0 :                                       NS_ASSIGNMENT_DEPEND);
     813           0 :   NS_ENSURE_SUCCESS(rv, rv);
     814             : 
     815             :   // decode image
     816           0 :   nsCOMPtr<imgIContainer> container;
     817           0 :   rv = GetImgTools()->DecodeImageData(stream, payload.mimeType,
     818           0 :                                       getter_AddRefs(container));
     819           0 :   NS_ENSURE_SUCCESS(rv, rv);
     820             : 
     821             :   // For ICO files, we must evaluate each of the frames we care about.
     822           0 :   nsTArray<FrameData> framesInfo;
     823           0 :   rv = GetFramesInfoForContainer(container, framesInfo);
     824           0 :   NS_ENSURE_SUCCESS(rv, rv);
     825             : 
     826           0 :   for (const auto& frameInfo : framesInfo) {
     827           0 :     IconPayload newPayload;
     828           0 :     newPayload.mimeType = NS_LITERAL_CSTRING(PNG_MIME_TYPE);
     829           0 :     newPayload.width = frameInfo.width;
     830           0 :     for (uint16_t size : sFaviconSizes) {
     831             :       // The icon could be smaller than 16, that is our minimum.
     832             :       // Icons smaller than 16px are kept as-is.
     833           0 :       if (frameInfo.width >= 16) {
     834           0 :         if (size > frameInfo.width) {
     835           0 :           continue;
     836             :         }
     837           0 :         newPayload.width = size;
     838             :       }
     839             : 
     840             :       // If the original payload is png and the size is the same, rescale the
     841             :       // image only if it's larger than the maximum allowed.
     842           0 :       if (newPayload.mimeType.Equals(payload.mimeType) &&
     843           0 :           newPayload.width == frameInfo.width &&
     844           0 :           payload.data.Length() < nsIFaviconService::MAX_FAVICON_BUFFER_SIZE) {
     845           0 :         newPayload.data = payload.data;
     846             :       } else {
     847             :         // Otherwise, scale and recompress.
     848             :         // Since EncodeScaledImage uses SYNC_DECODE, it will pick the best frame.
     849           0 :         nsCOMPtr<nsIInputStream> iconStream;
     850           0 :         rv = GetImgTools()->EncodeScaledImage(container,
     851             :                                               newPayload.mimeType,
     852           0 :                                               newPayload.width,
     853           0 :                                               newPayload.width,
     854           0 :                                               EmptyString(),
     855           0 :                                               getter_AddRefs(iconStream));
     856           0 :         NS_ENSURE_SUCCESS(rv, rv);
     857             :         // Read the stream into the new buffer.
     858           0 :         rv = NS_ConsumeStream(iconStream, UINT32_MAX, newPayload.data);
     859           0 :         NS_ENSURE_SUCCESS(rv, rv);
     860             :       }
     861             : 
     862             :       // If the icon size is good, we are done, otherwise try the next size.
     863           0 :       if (newPayload.data.Length() < nsIFaviconService::MAX_FAVICON_BUFFER_SIZE) {
     864           0 :         break;
     865             :       }
     866             :     }
     867             : 
     868           0 :     MOZ_ASSERT(newPayload.data.Length() < nsIFaviconService::MAX_FAVICON_BUFFER_SIZE);
     869           0 :     if (newPayload.data.Length() < nsIFaviconService::MAX_FAVICON_BUFFER_SIZE) {
     870           0 :       aIcon.payloads.AppendElement(newPayload);
     871             :     }
     872             :   }
     873             : 
     874           0 :   return NS_OK;
     875             : }
     876             : 
     877             : nsresult
     878           0 : nsFaviconService::GetFaviconDataAsync(const nsCString& aFaviconURI,
     879             :                                       mozIStorageStatementCallback *aCallback)
     880             : {
     881           0 :   MOZ_ASSERT(aCallback, "Doesn't make sense to call this without a callback");
     882             : 
     883           0 :   nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
     884             :     "/*Do not warn (bug no: not worth adding an index */ "
     885             :     "SELECT data, width FROM moz_icons "
     886             :     "WHERE fixed_icon_url_hash = hash(fixup_url(:url)) AND icon_url = :url "
     887             :     "ORDER BY width DESC"
     888           0 :   );
     889           0 :   NS_ENSURE_STATE(stmt);
     890             : 
     891           0 :   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("url"), aFaviconURI);
     892           0 :   NS_ENSURE_SUCCESS(rv, rv);
     893             : 
     894           0 :   nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
     895           0 :   return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
     896             : }
     897             : 
     898             : void // static
     899           0 : nsFaviconService::ConvertUnsupportedPayloads(mozIStorageConnection* aDBConn)
     900             : {
     901           0 :   MOZ_ASSERT(NS_IsMainThread());
     902             :   // Ensure imgTools are initialized, so that the image decoders can be used
     903             :   // off the main thread.
     904           0 :   nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
     905             : 
     906           0 :   Preferences::SetBool(PREF_CONVERT_PAYLOADS, true);
     907           0 :   MOZ_ASSERT(aDBConn);
     908           0 :   if (aDBConn) {
     909             :     RefPtr<FetchAndConvertUnsupportedPayloads> event =
     910           0 :       new FetchAndConvertUnsupportedPayloads(aDBConn);
     911           0 :     nsCOMPtr<nsIEventTarget> target = do_GetInterface(aDBConn);
     912           0 :     MOZ_ASSERT(target);
     913           0 :     if (target) {
     914           0 :       (void)target->Dispatch(event, NS_DISPATCH_NORMAL);
     915             :     }
     916             :   }
     917           0 : }
     918             : 
     919             : NS_IMETHODIMP
     920           0 : nsFaviconService::PreferredSizeFromURI(nsIURI* aURI, uint16_t* _size)
     921             : {
     922           0 :   *_size = UINT16_MAX;
     923           0 :   nsAutoCString ref;
     924             :   // Check for a ref first.
     925           0 :   if (NS_FAILED(aURI->GetRef(ref)) || ref.Length() == 0)
     926           0 :     return NS_OK;
     927             : 
     928             :   // Look for a "size=" fragment.
     929           0 :   int32_t start = ref.RFind("size=");
     930           0 :   if (start >= 0 && ref.Length() > static_cast<uint32_t>(start) + 5) {
     931           0 :     nsDependentCSubstring size;
     932             :     // This is safe regardless, since Rebind checks start is not over Length().
     933           0 :     size.Rebind(ref, start + 5);
     934             :     // Check if the string contains any non-digit.
     935           0 :     auto begin = size.BeginReading(), end = size.EndReading();
     936           0 :     for (auto ch = begin; ch < end; ++ch) {
     937           0 :       if (*ch < '0' || *ch > '9') {
     938             :         // Not a digit.
     939           0 :         return NS_OK;
     940             :       }
     941             :     }
     942             :     // Convert the string to an integer value.
     943             :     nsresult rv;
     944           0 :     uint16_t val = PromiseFlatCString(size).ToInteger(&rv);
     945           0 :     if (NS_SUCCEEDED(rv)) {
     946           0 :       *_size = val;
     947             :     }
     948             :   }
     949           0 :   return NS_OK;
     950             : }
     951             : 
     952             : ////////////////////////////////////////////////////////////////////////////////
     953             : //// ExpireFaviconsStatementCallbackNotifier
     954             : 
     955           0 : ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier()
     956             : {
     957           0 : }
     958             : 
     959             : 
     960             : NS_IMETHODIMP
     961           0 : ExpireFaviconsStatementCallbackNotifier::HandleCompletion(uint16_t aReason)
     962             : {
     963             :   // We should dispatch only if expiration has been successful.
     964           0 :   if (aReason != mozIStorageStatementCallback::REASON_FINISHED)
     965           0 :     return NS_OK;
     966             : 
     967             :   nsCOMPtr<nsIObserverService> observerService =
     968           0 :     mozilla::services::GetObserverService();
     969           0 :   if (observerService) {
     970           0 :     (void)observerService->NotifyObservers(nullptr,
     971             :                                            NS_PLACES_FAVICONS_EXPIRED_TOPIC_ID,
     972           0 :                                            nullptr);
     973             :   }
     974             : 
     975           0 :   return NS_OK;
     976             : }

Generated by: LCOV version 1.13