mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 460300 - Expire favicons when they expire from cache, and when the cache is cleared
This makes favicons expire from the favicon service much less often. They are now expired when the cache headers says they expire, or one week - whichever is shorter. Additionally, all favicons expire when the cache is cleared. r=MaK77
This commit is contained in:
parent
bec05aaa7b
commit
2b99203875
@ -47,6 +47,7 @@
|
||||
*/
|
||||
|
||||
#include "nsFaviconService.h"
|
||||
#include "nsICacheService.h"
|
||||
#include "nsICacheVisitor.h"
|
||||
#include "nsICachingChannel.h"
|
||||
#include "nsICategoryManager.h"
|
||||
@ -64,6 +65,7 @@
|
||||
#include "mozStorageHelper.h"
|
||||
#include "plbase64.h"
|
||||
#include "nsPlacesTables.h"
|
||||
#include "mozIStoragePendingStatement.h"
|
||||
|
||||
// For favicon optimization
|
||||
#include "imgITools.h"
|
||||
@ -86,6 +88,14 @@
|
||||
// This still allows us to accept a favicon even if we cannot optimize it.
|
||||
#define MAX_FAVICON_SIZE 10240
|
||||
|
||||
/**
|
||||
* The maximum time we will keep a favicon around. We always ask the cache, if
|
||||
* we can, but default to this value if we do not get a time back, or the time
|
||||
* is more in the future than this.
|
||||
* Currently set to one week from now.
|
||||
*/
|
||||
#define MAX_FAVICON_EXPIRATION PRTime(7 * 24 * 60 * 60 * PR_USEC_PER_SEC)
|
||||
|
||||
class FaviconLoadListener : public nsIStreamListener,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIChannelEventSink
|
||||
@ -104,7 +114,7 @@ public:
|
||||
private:
|
||||
~FaviconLoadListener();
|
||||
|
||||
nsCOMPtr<nsFaviconService> mFaviconService;
|
||||
nsRefPtr<nsFaviconService> mFaviconService;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIURI> mPageURI;
|
||||
nsCOMPtr<nsIURI> mFaviconURI;
|
||||
@ -115,7 +125,11 @@ private:
|
||||
|
||||
nsFaviconService* nsFaviconService::gFaviconService;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFaviconService, nsIFaviconService)
|
||||
NS_IMPL_ISUPPORTS2(
|
||||
nsFaviconService
|
||||
, nsIFaviconService
|
||||
, nsIObserver
|
||||
)
|
||||
|
||||
// nsFaviconService::nsFaviconService
|
||||
|
||||
@ -219,6 +233,55 @@ nsFaviconService::InitTables(mozIStorageConnection* aDBConn)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFaviconService::ExpireAllFavicons()
|
||||
{
|
||||
// Remove all references to favicons. We would love to not have to do this
|
||||
// because it could result in copying almost all of the moz_places into
|
||||
// memory for some sync in the future. We mitigate this some by checking for
|
||||
// non-null favicon ids, but views do not use indexes when querying.
|
||||
nsCOMPtr<mozIStorageStatement> removeReferences;
|
||||
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_places_view "
|
||||
"SET favicon_id = NULL "
|
||||
"WHERE favicon_id <> NULL"
|
||||
), getter_AddRefs(removeReferences));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Remove all favicons
|
||||
nsCOMPtr<mozIStorageStatement> removeFavicons;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_favicons"
|
||||
), getter_AddRefs(removeFavicons));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozIStorageStatement *stmts[] = {
|
||||
removeReferences,
|
||||
removeFavicons
|
||||
};
|
||||
nsCOMPtr<mozIStoragePendingStatement> ps;
|
||||
rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
|
||||
getter_AddRefs(ps));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFaviconService::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
if (strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) == 0)
|
||||
(void)ExpireAllFavicons();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIFaviconService
|
||||
|
||||
// nsFaviconService::SetFaviconUrlForPage
|
||||
|
||||
@ -228,11 +291,9 @@ nsFaviconService::SetFaviconUrlForPage(nsIURI* aPageURI, nsIURI* aFaviconURI)
|
||||
NS_ENSURE_ARG_POINTER(aPageURI);
|
||||
NS_ENSURE_ARG_POINTER(aFaviconURI);
|
||||
|
||||
// we don't care whether there was data or what the expiration was
|
||||
// we don't care if there was data
|
||||
PRBool hasData;
|
||||
PRTime expiration;
|
||||
nsresult rv = SetFaviconUrlForPageInternal(aPageURI, aFaviconURI,
|
||||
&hasData, &expiration);
|
||||
nsresult rv = SetFaviconUrlForPageInternal(aPageURI, aFaviconURI, &hasData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// send favicon change notifications if the URL has any data
|
||||
@ -266,16 +327,13 @@ nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
|
||||
// This sets aHasData if there was already icon data for this favicon. Used
|
||||
// to know if we should try reloading.
|
||||
//
|
||||
// Expiration will be 0 if the icon has not been set yet.
|
||||
//
|
||||
// Does NOT send out notifications. Caller should send out notifications
|
||||
// if the favicon has data.
|
||||
|
||||
nsresult
|
||||
nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
|
||||
nsIURI* aFaviconURI,
|
||||
PRBool* aHasData,
|
||||
PRTime* aExpiration)
|
||||
PRBool* aHasData)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt64 iconId = -1;
|
||||
@ -297,10 +355,6 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (dataSize > 0)
|
||||
*aHasData = PR_TRUE;
|
||||
|
||||
// expiration
|
||||
rv = mDBGetIconInfo->GetInt64(2, aExpiration);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +367,6 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
|
||||
if (iconId == -1) {
|
||||
// We did not find any entry, so create a new one
|
||||
*aHasData = PR_FALSE;
|
||||
*aExpiration = 0;
|
||||
|
||||
// not-binded params are automatically nullified by mozStorage
|
||||
mozStorageStatementScoper scoper(mDBInsertIcon);
|
||||
@ -391,9 +444,7 @@ nsFaviconService::UpdateBookmarkRedirectFavicon(nsIURI* aPageURI,
|
||||
return NS_OK; // bookmarked directly, not through a redirect
|
||||
|
||||
PRBool hasData = PR_FALSE;
|
||||
PRTime expiration = 0;
|
||||
rv = SetFaviconUrlForPageInternal(bookmarkURI, aFaviconURI,
|
||||
&hasData, &expiration);
|
||||
rv = SetFaviconUrlForPageInternal(bookmarkURI, aFaviconURI, &hasData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasData) {
|
||||
@ -520,12 +571,11 @@ nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI,
|
||||
if (isErrorPage)
|
||||
return NS_OK;
|
||||
|
||||
// See if we have data and get the expiration time for this favicon. It might
|
||||
// be nice to say SetFaviconUrlForPageInternal here but we DON'T want to set
|
||||
// the favicon for the page unless we know we have it. For example, if I go
|
||||
// to random site x.com, the browser will still tell us that the favicon is
|
||||
// x.com/favicon.ico even if there is no such file. We don't want to pollute
|
||||
// our tables with this useless data.
|
||||
// See if we have data and get the expiration time for this favicon. We DO
|
||||
// NOT want to set the favicon for the page unless we know we have it. For
|
||||
// example, if I go to random site x.com, the browser will still tell us that
|
||||
// the favicon is x.com/favicon.ico even if there is no such file. We don't
|
||||
// want to pollute our tables with this useless data.
|
||||
PRBool hasData = PR_FALSE;
|
||||
PRTime expiration = 0;
|
||||
{ // scope for statement
|
||||
@ -562,7 +612,7 @@ nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI,
|
||||
return NS_OK; // already set
|
||||
|
||||
// This will associate the favicon URL with the page.
|
||||
rv = SetFaviconUrlForPageInternal(page, aFaviconURI, &hasData, &expiration);
|
||||
rv = SetFaviconUrlForPageInternal(page, aFaviconURI, &hasData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SendFaviconNotifications(page, aFaviconURI);
|
||||
@ -1119,15 +1169,27 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Expire this favicon in one day. An old version of this actually extracted
|
||||
// the expiration time from the cache. But what if people (especially web
|
||||
// developers) get a bad favicon or change it? The problem is that we're not
|
||||
// aware when the icon has been reloaded in the cache or cleared. This way
|
||||
// we'll always pick up any changes in the cache after a day. In most cases
|
||||
// re-set favicons will come from the cache anyway and reloading them is not
|
||||
// very expensive.
|
||||
PRTime expiration = PR_Now() +
|
||||
(PRInt64)(24 * 60 * 60) * (PRInt64)PR_USEC_PER_SEC;
|
||||
// Attempt to get an expiration time from the cache. If this fails, we'll
|
||||
// make one up.
|
||||
PRTime expiration = -1;
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel(do_QueryInterface(mChannel));
|
||||
if (cachingChannel) {
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
rv = cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsICacheEntryInfo> cacheEntry(do_QueryInterface(cacheToken));
|
||||
PRUint32 seconds;
|
||||
rv = cacheEntry->GetExpirationTime(&seconds);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Set the expiration, but make sure we honor our cap.
|
||||
expiration = PR_Now() + PR_MIN(seconds * PR_USEC_PER_SEC,
|
||||
MAX_FAVICON_EXPIRATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we did not obtain a time from the cache, or it was negative, use our cap
|
||||
if (expiration < 0)
|
||||
expiration = PR_Now() + MAX_FAVICON_EXPIRATION;
|
||||
|
||||
mozStorageTransaction transaction(mFaviconService->mDBConn, PR_FALSE);
|
||||
// save the favicon data
|
||||
@ -1140,7 +1202,7 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
||||
// set the favicon for the page
|
||||
PRBool hasData;
|
||||
rv = mFaviconService->SetFaviconUrlForPageInternal(mPageURI, mFaviconURI,
|
||||
&hasData, &expiration);
|
||||
&hasData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mFaviconService->UpdateBookmarkRedirectFavicon(mPageURI, mFaviconURI);
|
||||
|
@ -44,11 +44,13 @@
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageValueArray.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
// forward definition for friend class
|
||||
class FaviconLoadListener;
|
||||
|
||||
class nsFaviconService : public nsIFaviconService
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
nsFaviconService();
|
||||
@ -98,6 +100,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~nsFaviconService();
|
||||
@ -125,11 +128,16 @@ private:
|
||||
nsDataHashtable<nsCStringHashKey, PRUint32> mFailedFavicons;
|
||||
|
||||
nsresult SetFaviconUrlForPageInternal(nsIURI* aURI, nsIURI* aFavicon,
|
||||
PRBool* aHasData, PRTime* aExpiration);
|
||||
PRBool* aHasData);
|
||||
|
||||
nsresult UpdateBookmarkRedirectFavicon(nsIURI* aPage, nsIURI* aFavicon);
|
||||
void SendFaviconNotifications(nsIURI* aPage, nsIURI* aFaviconURI);
|
||||
|
||||
/**
|
||||
* Expires all favicons
|
||||
*/
|
||||
nsresult ExpireAllFavicons();
|
||||
|
||||
friend class FaviconLoadListener;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user