NS_IMETHODIMP nsDOMOfflineResourceList::MozRemove(const nsAString& aURI) { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } nsCAutoString key; rv = GetCacheKey(aURI, key); NS_ENSURE_SUCCESS(rv, rv); ClearCachedKeys(); // XXX: This is a race condition. remove() is specced to remove // from the currently associated application cache, but if this // happens during an update (or after an update, if we haven't // swapped yet), that remove() will be lost when the next update is // finished. Need to bring this issue up. rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::MozHasItem(const nsAString& aURI, PRBool* aExists) { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } nsCAutoString key; rv = GetCacheKey(aURI, key); NS_ENSURE_SUCCESS(rv, rv); PRUint32 types; rv = appCache->GetTypes(key, &types); if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) { *aExists = PR_FALSE; return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); *aExists = ((types & nsIApplicationCache::ITEM_DYNAMIC) != 0); return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::GetMozItems(nsIDOMDOMStringList **aItems) { *aItems = nsnull; nsRefPtr<nsDOMStringList> items = new nsDOMStringList(); NS_ENSURE_TRUE(items, NS_ERROR_OUT_OF_MEMORY); // If we are not associated with an application cache, return an // empty list. nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { NS_ADDREF(*aItems = items); return NS_OK; } nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); PRUint32 length; char **keys; rv = appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC, &length, &keys); NS_ENSURE_SUCCESS(rv, rv); for (PRUint32 i = 0; i < length; i++) { items->Add(NS_ConvertUTF8toUTF16(keys[i])); } NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, keys); NS_ADDREF(*aItems = items); return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::GetStatus(PRUint16 *aStatus) { nsresult rv = Init(); // Init may fail with INVALID_STATE_ERR if there is no manifest URI. // The status attribute should not throw that exception, convert it // to an UNCACHED. if (rv == NS_ERROR_DOM_INVALID_STATE_ERR || !nsContentUtils::OfflineAppAllowed(mDocumentURI)) { *aStatus = nsIDOMOfflineResourceList::UNCACHED; return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); // If this object is not associated with a cache, return UNCACHED nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { *aStatus = nsIDOMOfflineResourceList::UNCACHED; return NS_OK; } // If there is an update in process, use its status. if (mCacheUpdate && mExposeCacheUpdateStatus) { rv = mCacheUpdate->GetStatus(aStatus); if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) { return NS_OK; } } *aStatus = mStatus; return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::GetStatus(PRUint16 *aStatus) { nsresult rv = Init(); // Init may fail with INVALID_STATE_ERR if there is no manifest URI. // The status attribute should not throw that exception, convert it // to an UNCACHED. if (rv == NS_ERROR_DOM_INVALID_STATE_ERR || !nsContentUtils::OfflineAppAllowed(mDocumentURI)) { *aStatus = nsIDOMOfflineResourceList::UNCACHED; return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); // If this object is not associated with a cache, return UNCACHED nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { *aStatus = nsIDOMOfflineResourceList::UNCACHED; return NS_OK; } // If there is an update in process, use its status. if (mCacheUpdate) { rv = mCacheUpdate->GetStatus(aStatus); if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) { return NS_OK; } } nsCOMPtr<nsIApplicationCache> activeCache; rv = mApplicationCacheService->GetActiveCache(mManifestSpec, getter_AddRefs(activeCache)); NS_ENSURE_SUCCESS(rv, rv); if (activeCache == nsnull) { *aStatus = nsIDOMOfflineResourceList::OBSOLETE; } else if (appCache == activeCache) { *aStatus = nsIDOMOfflineResourceList::IDLE; } else { *aStatus = nsIDOMOfflineResourceList::UPDATEREADY; } return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::SwapCache() { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache(); if (!currentAppCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } // Check the current and potentially newly available cache are not identical. if (mAvailableApplicationCache == currentAppCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } if (mAvailableApplicationCache) { nsCString currClientId, availClientId; currentAppCache->GetClientID(currClientId); mAvailableApplicationCache->GetClientID(availClientId); if (availClientId == currClientId) return NS_ERROR_DOM_INVALID_STATE_ERR; } ClearCachedKeys(); nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer = GetDocumentAppCacheContainer(); // In the case of an obsolete cache group, newAppCache might be null. // We will disassociate from the cache in that case. if (appCacheContainer) { rv = appCacheContainer->SetApplicationCache(mAvailableApplicationCache); NS_ENSURE_SUCCESS(rv, rv); } mAvailableApplicationCache = nsnull; mStatus = nsIDOMOfflineResourceList::IDLE; return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::SwapCache() { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCacheService> serv = do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache(); nsCOMPtr<nsIApplicationCache> newAppCache; rv = serv->GetActiveCache(mManifestSpec, getter_AddRefs(newAppCache)); NS_ENSURE_SUCCESS(rv, rv); // In the case of an obsolete cache group, newAppCache might be null. // We will disassociate from the cache in that case. if (newAppCache == currentAppCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } ClearCachedKeys(); nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer = GetDocumentAppCacheContainer(); if (appCacheContainer) { rv = appCacheContainer->SetApplicationCache(newAppCache); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }
NS_IMETHODIMP nsDOMOfflineResourceList::MozAdd(const nsAString& aURI) { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } if (aURI.Length() > MAX_URI_LENGTH) return NS_ERROR_DOM_BAD_URI; // this will fail if the URI is not absolute nsCOMPtr<nsIURI> requestedURI; rv = NS_NewURI(getter_AddRefs(requestedURI), aURI); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString scheme; rv = requestedURI->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); PRBool match; rv = mManifestURI->SchemeIs(scheme.get(), &match); NS_ENSURE_SUCCESS(rv, rv); if (!match) { return NS_ERROR_DOM_SECURITY_ERR; } PRUint32 length; rv = GetMozLength(&length); NS_ENSURE_SUCCESS(rv, rv); PRUint32 maxEntries = nsContentUtils::GetIntPref(kMaxEntriesPref, DEFAULT_MAX_ENTRIES); if (length > maxEntries) return NS_ERROR_NOT_AVAILABLE; ClearCachedKeys(); nsCOMPtr<nsIOfflineCacheUpdate> update = do_CreateInstance(NS_OFFLINECACHEUPDATE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString clientID; rv = appCache->GetClientID(clientID); NS_ENSURE_SUCCESS(rv, rv); rv = update->InitPartial(mManifestURI, clientID, mDocumentURI); NS_ENSURE_SUCCESS(rv, rv); rv = update->AddDynamicURI(requestedURI); NS_ENSURE_SUCCESS(rv, rv); rv = update->Schedule(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }