author | Sinker Li <thinker@codemud.net> |
Fri, 30 Mar 2012 20:52:06 -0400 | |
changeset 90760 | cdd005fde96d6649e4b7779a344f1b9cccda8e27 |
parent 90759 | 324368cce885f9a9fef478d1cdd8218e35ddf34b |
child 90761 | dd0291644c67b6e7356f5e8fff6b3ce35d3db0e8 |
push id | 22382 |
push user | bmo@edmorley.co.uk |
push date | Sat, 31 Mar 2012 21:44:34 +0000 |
treeherder | mozilla-central@bbe5086163c9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | honzab |
bugs | 674728 |
milestone | 14.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/netwerk/base/public/nsIApplicationCacheService.idl +++ b/netwerk/base/public/nsIApplicationCacheService.idl @@ -40,17 +40,17 @@ #include "nsISupports.idl" interface nsIApplicationCache; /** * The application cache service manages the set of application cache * groups. */ -[scriptable, uuid(611161c8-37d0-450f-a4fe-457c47bbaf64)] +[scriptable, uuid(10fdea21-1224-4c29-8507-8f3205a121d5)] interface nsIApplicationCacheService : nsISupports { /** * Create a new, empty application cache for the given cache * group. */ nsIApplicationCache createApplicationCache(in ACString group); @@ -88,9 +88,16 @@ interface nsIApplicationCacheService : n */ void cacheOpportunistically(in nsIApplicationCache cache, in ACString key); /** * Get the list of application cache groups. */ void getGroups([optional] out unsigned long count, [array, size_is(count), retval] out string groupIDs); + + /** + * Get the list of application cache groups in the order of + * activating time. + */ + void getGroupsTimeOrdered([optional] out unsigned long count, + [array, size_is(count), retval] out string groupIDs); };
--- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp +++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp @@ -1167,17 +1167,18 @@ nsOfflineCacheDevice::Init() " ON ns.ClientID = groups.ActiveClientID" " WHERE ns.NameSpace <= ?1 AND ?1 GLOB ns.NameSpace || '*'" " ORDER BY ns.NameSpace DESC, groups.ActivateTimeStamp DESC;"), StatementSql ( mStatement_FindNamespaceEntry, "SELECT NameSpace, Data, ItemType FROM moz_cache_namespaces" " WHERE ClientID = ?1" " AND NameSpace <= ?2 AND ?2 GLOB NameSpace || '*'" " ORDER BY NameSpace DESC;"), StatementSql ( mStatement_InsertNamespaceEntry, "INSERT INTO moz_cache_namespaces (ClientID, NameSpace, Data, ItemType) VALUES(?, ?, ?, ?);"), - StatementSql ( mStatement_EnumerateGroups, "SELECT GroupID, ActiveClientID FROM moz_cache_groups;") + StatementSql ( mStatement_EnumerateGroups, "SELECT GroupID, ActiveClientID FROM moz_cache_groups;"), + StatementSql ( mStatement_EnumerateGroupsTimeOrder, "SELECT GroupID, ActiveClientID FROM moz_cache_groups ORDER BY ActivateTimeStamp;") }; for (PRUint32 i = 0; NS_SUCCEEDED(rv) && i < ArrayLength(prepared); ++i) { LOG(("Creating statement: %s\n", prepared[i].sql)); rv = mDB->CreateStatement(nsDependentCString(prepared[i].sql), getter_AddRefs(prepared[i].statement)); NS_ENSURE_SUCCESS(rv, rv); @@ -1298,16 +1299,17 @@ nsOfflineCacheDevice::Shutdown() mStatement_InsertNamespaceEntry = nsnull; mStatement_CleanupUnmarked = nsnull; mStatement_GatherEntries = nsnull; mStatement_ActivateClient = nsnull; mStatement_DeactivateGroup = nsnull; mStatement_FindClient = nsnull; mStatement_FindClientByNamespace = nsnull; mStatement_EnumerateGroups = nsnull; + mStatement_EnumerateGroupsTimeOrder = nsnull; } // Close Database on the correct thread bool isOnCurrentThread = true; if (mInitThread) mInitThread->IsOnCurrentThread(&isOnCurrentThread); if (!isOnCurrentThread) { @@ -1747,27 +1749,47 @@ nsOfflineCacheDevice::EvictEntries(const if (clientID) { rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE ClientID=? AND Flags = 0;"), getter_AddRefs(statement)); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringByIndex(0, nsDependentCString(clientID)); NS_ENSURE_SUCCESS(rv, rv); + + rv = statement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache_groups WHERE ActiveClientID=?;"), + getter_AddRefs(statement)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = statement->BindUTF8StringByIndex(0, nsDependentCString(clientID)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = statement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); } else { rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache WHERE Flags = 0;"), getter_AddRefs(statement)); NS_ENSURE_SUCCESS(rv, rv); + + rv = statement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache_groups;"), + getter_AddRefs(statement)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = statement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); } - rv = statement->Execute(); - NS_ENSURE_SUCCESS(rv, rv); - evictionObserver.Apply(); statement = nsnull; // Also evict any namespaces associated with this clientID. if (clientID) { rv = mDB->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cache_namespaces WHERE ClientID=?"), getter_AddRefs(statement)); @@ -2035,20 +2057,29 @@ nsOfflineCacheDevice::GetUsage(const nsA NS_IMETHODIMP nsOfflineCacheDevice::GetGroups(PRUint32 *count, char ***keys) { LOG(("nsOfflineCacheDevice::GetGroups")); - AutoResetStatement statement(mStatement_EnumerateGroups); return RunSimpleQuery(mStatement_EnumerateGroups, 0, count, keys); } +NS_IMETHODIMP +nsOfflineCacheDevice::GetGroupsTimeOrdered(PRUint32 *count, + char ***keys) +{ + + LOG(("nsOfflineCacheDevice::GetGroupsTimeOrder")); + + return RunSimpleQuery(mStatement_EnumerateGroupsTimeOrder, 0, count, keys); +} + nsresult nsOfflineCacheDevice::RunSimpleQuery(mozIStorageStatement * statement, PRUint32 resultIndex, PRUint32 * count, char *** values) { bool hasRows; nsresult rv = statement->ExecuteStep(&hasRows);
--- a/netwerk/cache/nsDiskCacheDeviceSQL.h +++ b/netwerk/cache/nsDiskCacheDeviceSQL.h @@ -258,16 +258,17 @@ private: nsCOMPtr<mozIStorageStatement> mStatement_InsertNamespaceEntry; nsCOMPtr<mozIStorageStatement> mStatement_CleanupUnmarked; nsCOMPtr<mozIStorageStatement> mStatement_GatherEntries; nsCOMPtr<mozIStorageStatement> mStatement_ActivateClient; nsCOMPtr<mozIStorageStatement> mStatement_DeactivateGroup; nsCOMPtr<mozIStorageStatement> mStatement_FindClient; nsCOMPtr<mozIStorageStatement> mStatement_FindClientByNamespace; nsCOMPtr<mozIStorageStatement> mStatement_EnumerateGroups; + nsCOMPtr<mozIStorageStatement> mStatement_EnumerateGroupsTimeOrder; nsCOMPtr<nsILocalFile> mCacheDirectory; PRUint32 mCacheCapacity; // in bytes PRInt32 mDeltaCounter; nsInterfaceHashtable<nsCStringHashKey, nsIWeakReference> mCaches; nsClassHashtable<nsCStringHashKey, nsCString> mActiveCachesByGroup; nsTHashtable<nsCStringHashKey> mActiveCaches;
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp @@ -71,16 +71,18 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "mozilla/Preferences.h" #include "nsXULAppAPI.h" using namespace mozilla; static const PRUint32 kRescheduleLimit = 3; +// Max number of retries for every entry of pinned app. +static const PRUint32 kPinnedEntryRetriesLimit = 3; #if defined(PR_LOGGING) // // To enable logging (see prlog.h for full details): // // set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5 // set NSPR_LOG_FILE=offlineupdate.log // @@ -728,17 +730,17 @@ nsOfflineManifestItem::ReadManifest(nsII nsCString::const_iterator begin, iter, end; manifest->mReadBuf.BeginReading(begin); manifest->mReadBuf.EndReading(end); for (iter = begin; iter != end; iter++) { if (*iter == '\r' || *iter == '\n') { nsresult rv = manifest->HandleManifestLine(begin, iter); - + if (NS_FAILED(rv)) { LOG(("HandleManifestLine failed with 0x%08x", rv)); return NS_ERROR_ABORT; } begin = iter; begin++; } @@ -950,41 +952,41 @@ nsOfflineManifestItem::HandleManifestLin spec, EmptyCString()); break; } } return NS_OK; } -nsresult +nsresult nsOfflineManifestItem::GetOldManifestContentHash(nsIRequest *aRequest) { nsresult rv; nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv); NS_ENSURE_SUCCESS(rv, rv); - // load the main cache token that is actually the old offline cache token and + // load the main cache token that is actually the old offline cache token and // read previous manifest content hash value nsCOMPtr<nsISupports> cacheToken; cachingChannel->GetCacheToken(getter_AddRefs(cacheToken)); if (cacheToken) { nsCOMPtr<nsICacheEntryDescriptor> cacheDescriptor(do_QueryInterface(cacheToken, &rv)); NS_ENSURE_SUCCESS(rv, rv); - + rv = cacheDescriptor->GetMetaDataElement("offline-manifest-hash", getter_Copies(mOldManifestHashValue)); if (NS_FAILED(rv)) mOldManifestHashValue.Truncate(); } return NS_OK; } -nsresult +nsresult nsOfflineManifestItem::CheckNewManifestContentHash(nsIRequest *aRequest) { nsresult rv; if (!mManifestHash) { // Nothing to compare against... return NS_OK; } @@ -1014,17 +1016,17 @@ nsOfflineManifestItem::CheckNewManifestC nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsISupports> cacheToken; cachingChannel->GetOfflineCacheToken(getter_AddRefs(cacheToken)); if (cacheToken) { nsCOMPtr<nsICacheEntryDescriptor> cacheDescriptor(do_QueryInterface(cacheToken, &rv)); NS_ENSURE_SUCCESS(rv, rv); - + rv = cacheDescriptor->SetMetaDataElement("offline-manifest-hash", mManifestHashValue.get()); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; } void @@ -1135,16 +1137,18 @@ nsOfflineCacheUpdate::nsOfflineCacheUpda : mState(STATE_UNINITIALIZED) , mOwner(nsnull) , mAddedItems(false) , mPartialUpdate(false) , mSucceeded(true) , mObsolete(false) , mCurrentItem(-1) , mRescheduleCount(0) + , mPinnedEntryRetriesCount(0) + , mPinned(false) { } nsOfflineCacheUpdate::~nsOfflineCacheUpdate() { LOG(("nsOfflineCacheUpdate::~nsOfflineCacheUpdate [%p]", this)); } @@ -1215,16 +1219,21 @@ nsOfflineCacheUpdate::Init(nsIURI *aMani rv = cacheService->CreateApplicationCache(manifestSpec, getter_AddRefs(mApplicationCache)); NS_ENSURE_SUCCESS(rv, rv); rv = mApplicationCache->GetClientID(mClientID); NS_ENSURE_SUCCESS(rv, rv); + rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aDocumentURI, + NULL, + &mPinned); + NS_ENSURE_SUCCESS(rv, rv); + mState = STATE_INITIALIZED; return NS_OK; } nsresult nsOfflineCacheUpdate::InitPartial(nsIURI *aManifestURI, const nsACString& clientID, nsIURI *aDocumentURI) @@ -1267,16 +1276,21 @@ nsOfflineCacheUpdate::InitPartial(nsIURI nsCAutoString groupID; rv = mApplicationCache->GetGroupID(groupID); NS_ENSURE_SUCCESS(rv, rv); rv = NS_NewURI(getter_AddRefs(mManifestURI), groupID); NS_ENSURE_SUCCESS(rv, rv); + rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(aDocumentURI, + NULL, + &mPinned); + NS_ENSURE_SUCCESS(rv, rv); + mState = STATE_INITIALIZED; return NS_OK; } nsresult nsOfflineCacheUpdate::HandleManifest(bool *aDoUpdate) { // Be pessimistic @@ -1354,21 +1368,27 @@ nsOfflineCacheUpdate::LoadCompleted() // A 404 or 410 is interpreted as an intentional removal of // the manifest file, rather than a transient server error. // Obsolete this cache group if one of these is returned. PRUint16 status; rv = mManifestItem->GetStatus(&status); if (status == 404 || status == 410) { mSucceeded = false; - mObsolete = true; if (mPreviousApplicationCache) { - NotifyState(nsIOfflineCacheUpdateObserver::STATE_OBSOLETE); + if (mPinned) { + // Do not obsolete a pinned application. + NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE); + } else { + NotifyState(nsIOfflineCacheUpdateObserver::STATE_OBSOLETE); + mObsolete = true; + } } else { NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); + mObsolete = true; } Finish(); return; } bool doUpdate; if (NS_FAILED(HandleManifest(&doUpdate))) { mSucceeded = false; @@ -1409,21 +1429,56 @@ nsOfflineCacheUpdate::LoadCompleted() ProcessNextURI(); return; } // Normal load finished. nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[mCurrentItem]; - mCurrentItem++; bool succeeded; rv = item->GetRequestSucceeded(&succeeded); + if (mPinned) { + PRUint32 dummy_cache_type; + rv = mApplicationCache->GetTypes(item->mCacheKey, &dummy_cache_type); + bool item_doomed = NS_FAILED(rv); // can not find it? -> doomed + + if (item_doomed && + mPinnedEntryRetriesCount < kPinnedEntryRetriesLimit && + (item->mItemType & (nsIApplicationCache::ITEM_EXPLICIT | + nsIApplicationCache::ITEM_FALLBACK))) { + rv = EvictOneNonPinned(); + if (NS_FAILED(rv)) { + mSucceeded = false; + NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); + Finish(); + return; + } + + rv = item->Cancel(); + if (NS_FAILED(rv)) { + mSucceeded = false; + NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); + Finish(); + return; + } + + mPinnedEntryRetriesCount++; + // Retry current item, so mCurrentItem is not advanced. + ProcessNextURI(); + return; + } + } + + // Advance to next item. + mCurrentItem++; + mPinnedEntryRetriesCount = 0; + // Check for failures. 3XX, 4XX and 5XX errors on items explicitly // listed in the manifest will cause the update to fail. if (NS_FAILED(rv) || !succeeded) { if (item->mItemType & (nsIApplicationCache::ITEM_EXPLICIT | nsIApplicationCache::ITEM_FALLBACK)) { mSucceeded = false; } @@ -1463,26 +1518,26 @@ nsOfflineCacheUpdate::ManifestCheckCompl } if (NS_FAILED(aStatus)) { mSucceeded = false; NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR); } if (NS_FAILED(aStatus) && mRescheduleCount < kRescheduleLimit) { - // Do the final stuff but prevent notification of STATE_FINISHED. + // Do the final stuff but prevent notification of STATE_FINISHED. // That would disconnect listeners that are responsible for document // association after a successful update. Forwarding notifications // from a new update through this dead update to them is absolutely // correct. FinishNoNotify(); nsRefPtr<nsOfflineCacheUpdate> newUpdate = new nsOfflineCacheUpdate(); - // Leave aDocument argument null. Only glues and children keep + // Leave aDocument argument null. Only glues and children keep // document instances. newUpdate->Init(mManifestURI, mDocumentURI, nsnull); // In a rare case the manifest will not be modified on the next refetch // transfer all master document URIs to the new update to ensure that // all documents refering it will be properly cached. for (PRInt32 i = 0; i < mDocumentURIs.Count(); i++) { newUpdate->StickDocument(mDocumentURIs[i]); @@ -1750,17 +1805,17 @@ nsOfflineCacheUpdate::ScheduleImplicit() else { clientID = mClientID; } rv = update->InitPartial(mManifestURI, clientID, mDocumentURI); NS_ENSURE_SUCCESS(rv, rv); for (PRInt32 i = 0; i < mDocumentURIs.Count(); i++) { - rv = update->AddURI(mDocumentURIs[i], + rv = update->AddURI(mDocumentURIs[i], nsIApplicationCache::ITEM_IMPLICIT); NS_ENSURE_SUCCESS(rv, rv); } update->SetOwner(this); rv = update->Begin(); NS_ENSURE_SUCCESS(rv, rv); @@ -1829,16 +1884,70 @@ nsOfflineCacheUpdate::Finish() { nsresult rv = FinishNoNotify(); NotifyState(nsIOfflineCacheUpdateObserver::STATE_FINISHED); return rv; } +static nsresult +EvictOneOfCacheGroups(nsIApplicationCacheService *cacheService, + PRUint32 count, const char * const *groups) +{ + nsresult rv; + unsigned int i; + + for (i = 0; i < count; i++) { + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs(uri), groups[i]); + NS_ENSURE_SUCCESS(rv, rv); + + nsDependentCString group_name(groups[i]); + nsCOMPtr<nsIApplicationCache> cache; + rv = cacheService->GetActiveCache(group_name, getter_AddRefs(cache)); + // Maybe someone in another thread or process have deleted it. + if (NS_FAILED(rv) || !cache) + continue; + + bool pinned; + rv = nsOfflineCacheUpdateService::OfflineAppPinnedForURI(uri, + NULL, + &pinned); + NS_ENSURE_SUCCESS(rv, rv); + + if (!pinned) { + rv = cache->Discard(); + return NS_OK; + } + } + + return NS_ERROR_FILE_NOT_FOUND; +} + +nsresult +nsOfflineCacheUpdate::EvictOneNonPinned() +{ + nsresult rv; + + nsCOMPtr<nsIApplicationCacheService> cacheService = + do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 count; + char **groups; + rv = cacheService->GetGroupsTimeOrdered(&count, &groups); + NS_ENSURE_SUCCESS(rv, rv); + + rv = EvictOneOfCacheGroups(cacheService, count, groups); + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, groups); + return rv; +} + //----------------------------------------------------------------------------- // nsOfflineCacheUpdate::nsIOfflineCacheUpdate //----------------------------------------------------------------------------- NS_IMETHODIMP nsOfflineCacheUpdate::GetUpdateDomain(nsACString &aUpdateDomain) { NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED); @@ -1937,17 +2046,17 @@ nsOfflineCacheUpdate::AddURI(nsIURI *aUR mAddedItems = true; return NS_OK; } NS_IMETHODIMP nsOfflineCacheUpdate::AddDynamicURI(nsIURI *aURI) { - if (GeckoProcessType_Default != XRE_GetProcessType()) + if (GeckoProcessType_Default != XRE_GetProcessType()) return NS_ERROR_NOT_IMPLEMENTED; // If this is a partial update and the resource is already in the // cache, we should only mark the entry, not fetch it again. if (mPartialUpdate) { nsCAutoString key; GetCacheKey(aURI, key); @@ -2026,17 +2135,17 @@ nsOfflineCacheUpdate::Schedule() } NS_IMETHODIMP nsOfflineCacheUpdate::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate, PRUint32 aState) { if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED) { // Take the mSucceeded flag from the underlying update, we will be - // queried for it soon. mSucceeded of this update is false (manifest + // queried for it soon. mSucceeded of this update is false (manifest // check failed) but the subsequent re-fetch update might succeed bool succeeded; aUpdate->GetSucceeded(&succeeded); mSucceeded = succeeded; } nsresult rv = NotifyState(aState); if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED)
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h +++ b/uriloader/prefetch/nsOfflineCacheUpdate.h @@ -252,16 +252,19 @@ private: nsresult ScheduleImplicit(); nsresult AssociateDocuments(nsIApplicationCache* cache); nsresult GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers); nsresult NotifyState(PRUint32 state); nsresult Finish(); nsresult FinishNoNotify(); + // Find one non-pinned cache group and evict it. + nsresult EvictOneNonPinned(); + enum { STATE_UNINITIALIZED, STATE_INITIALIZED, STATE_CHECKING, STATE_DOWNLOADING, STATE_CANCELLED, STATE_FINISHED } mState; @@ -295,17 +298,23 @@ private: /* Documents that requested this update */ nsCOMArray<nsIURI> mDocumentURIs; /* Reschedule count. When an update is rescheduled due to * mismatched manifests, the reschedule count will be increased. */ PRUint32 mRescheduleCount; + /* Whena an entry for a pinned app is retried, retries count is + * increaded. */ + PRUint32 mPinnedEntryRetriesCount; + nsRefPtr<nsOfflineCacheUpdate> mImplicitUpdate; + + bool mPinned; }; class nsOfflineCacheUpdateService : public nsIOfflineCacheUpdateService , public nsIObserver , public nsOfflineCacheUpdateOwner , public nsSupportsWeakReference { public: @@ -335,16 +344,20 @@ public: * Returns the singleton nsOfflineCacheUpdateService without an addref, or * nsnull if the service couldn't be created. */ static nsOfflineCacheUpdateService *EnsureService(); /** Addrefs and returns the singleton nsOfflineCacheUpdateService. */ static nsOfflineCacheUpdateService *GetInstance(); + static nsresult OfflineAppPinnedForURI(nsIURI *aDocumentURI, + nsIPrefBranch *aPrefBranch, + bool *aPinned); + private: nsresult ProcessNextUpdate(); nsTArray<nsRefPtr<nsOfflineCacheUpdate> > mUpdates; bool mDisabled; bool mUpdateRunning; };
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp @@ -530,20 +530,21 @@ nsOfflineCacheUpdateService::OfflineAppA { nsCOMPtr<nsIURI> codebaseURI; nsresult rv = aPrincipal->GetURI(getter_AddRefs(codebaseURI)); NS_ENSURE_SUCCESS(rv, rv); return OfflineAppAllowedForURI(codebaseURI, aPrefBranch, aAllowed); } -NS_IMETHODIMP -nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI *aURI, - nsIPrefBranch *aPrefBranch, - bool *aAllowed) +static nsresult +OfflineAppPermForURI(nsIURI *aURI, + nsIPrefBranch *aPrefBranch, + bool pinned, + bool *aAllowed) { *aAllowed = false; if (!aURI) return NS_OK; nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); if (!innerURI) return NS_OK; @@ -563,29 +564,44 @@ nsOfflineCacheUpdateService::OfflineAppA nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); if (!permissionManager) { return NS_OK; } PRUint32 perm; - permissionManager->TestExactPermission(innerURI, "offline-app", &perm); + const char *permName = pinned ? "pin-app" : "offline-app"; + permissionManager->TestExactPermission(innerURI, permName, &perm); - if (perm == nsIPermissionManager::UNKNOWN_ACTION) { + if (perm == nsIPermissionManager::UNKNOWN_ACTION && !pinned) { static const char kPrefName[] = "offline-apps.allow_by_default"; if (aPrefBranch) { aPrefBranch->GetBoolPref(kPrefName, aAllowed); } else { *aAllowed = Preferences::GetBool(kPrefName, false); } return NS_OK; } - if (perm == nsIPermissionManager::DENY_ACTION) { - return NS_OK; + if (perm == nsIPermissionManager::ALLOW_ACTION) { + *aAllowed = true; } - *aAllowed = true; - return NS_OK; } + +NS_IMETHODIMP +nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI *aURI, + nsIPrefBranch *aPrefBranch, + bool *aAllowed) +{ + return OfflineAppPermForURI(aURI, aPrefBranch, false, aAllowed); +} + +nsresult +nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI, + nsIPrefBranch *aPrefBranch, + bool *aPinned) +{ + return OfflineAppPermForURI(aDocumentURI, aPrefBranch, true, aPinned); +}