LCOV - app.info - dom/src/offline/nsDOMOfflineResourceList.cpp

LCOV - code coverage report
| Current view: | directory - dom/src/offline - nsDOMOfflineResourceList.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 435 | 2 | 0.5 %
| Date: | 2012-04-21 | Functions: | 51 | 2 | 3.9 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Mozilla Corporation
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2007
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Dave Camp <dcamp@mozilla.com>
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "nsDOMOfflineResourceList.h"
          40                 : #include "nsDOMClassInfoID.h"
          41                 : #include "nsIScriptSecurityManager.h"
          42                 : #include "nsDOMError.h"
          43                 : #include "nsDOMLists.h"
          44                 : #include "nsIPrefetchService.h"
          45                 : #include "nsCPrefetchService.h"
          46                 : #include "nsNetUtil.h"
          47                 : #include "nsNetCID.h"
          48                 : #include "nsICacheSession.h"
          49                 : #include "nsICacheService.h"
          50                 : #include "nsIOfflineCacheUpdate.h"
          51                 : #include "nsIDOMLoadStatus.h"
          52                 : #include "nsAutoPtr.h"
          53                 : #include "nsContentUtils.h"
          54                 : #include "nsIJSContextStack.h"
          55                 : #include "nsEventDispatcher.h"
          56                 : #include "nsIPrivateDOMEvent.h"
          57                 : #include "nsIObserverService.h"
          58                 : #include "nsIScriptGlobalObject.h"
          59                 : #include "nsIWebNavigation.h"
          60                 : #include "mozilla/Preferences.h"
          61                 :
          62                 : #include "nsXULAppAPI.h"
          63                 : #define IS_CHILD_PROCESS() \
          64                 :     (GeckoProcessType_Default != XRE_GetProcessType())
          65                 :
          66                 : using namespace mozilla;
          67                 :
          68                 : // Event names
          69                 :
          70                 : #define CHECKING_STR    "checking"
          71                 : #define ERROR_STR       "error"
          72                 : #define NOUPDATE_STR    "noupdate"
          73                 : #define DOWNLOADING_STR "downloading"
          74                 : #define PROGRESS_STR    "progress"
          75                 : #define CACHED_STR      "cached"
          76                 : #define UPDATEREADY_STR "updateready"
          77                 : #define OBSOLETE_STR    "obsolete"
          78                 :
          79                 : // To prevent abuse of the resource list for data storage, the number
          80                 : // of offline urls and their length are limited.
          81                 :
          82                 : static const char kMaxEntriesPref[] =  "offline.max_site_resources";
          83                 : #define DEFAULT_MAX_ENTRIES 100
          84                 : #define MAX_URI_LENGTH 2048
          85                 :
          86                 : //
          87                 : // nsDOMOfflineResourceList
          88                 : //
          89                 :
          90            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMOfflineResourceList)
          91                 :
          92               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMOfflineResourceList,
          93                 :                                                   nsDOMEventTargetHelper)
          94               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCacheUpdate)
          95                 :
          96               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnCheckingListener)
          97               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
          98               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnNoUpdateListener)
          99               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnDownloadingListener)
         100               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener)
         101               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnCachedListener)
         102               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUpdateReadyListener)
         103               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnObsoleteListener)
         104                 :
         105               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingEvents);
         106                 :
         107               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
         108                 :
         109               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMOfflineResourceList,
         110                 :                                                 nsDOMEventTargetHelper)
         111               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCacheUpdate)
         112                 :
         113               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnCheckingListener)
         114               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
         115               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnNoUpdateListener)
         116               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnDownloadingListener)
         117               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnProgressListener)
         118               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnCachedListener)
         119               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUpdateReadyListener)
         120               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnObsoleteListener)
         121                 :
         122               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingEvents)
         123                 :
         124               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
         125                 :
         126                 : DOMCI_DATA(OfflineResourceList, nsDOMOfflineResourceList)
         127                 :
         128               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMOfflineResourceList)
         129               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMOfflineResourceList)
         130               0 :   NS_INTERFACE_MAP_ENTRY(nsIOfflineCacheUpdateObserver)
         131               0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
         132               0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
         133               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(OfflineResourceList)
         134               0 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
         135                 :
         136               0 : NS_IMPL_ADDREF_INHERITED(nsDOMOfflineResourceList, nsDOMEventTargetHelper)
         137               0 : NS_IMPL_RELEASE_INHERITED(nsDOMOfflineResourceList, nsDOMEventTargetHelper)
         138                 :
         139               0 : nsDOMOfflineResourceList::nsDOMOfflineResourceList(nsIURI *aManifestURI,
         140                 :                                                    nsIURI *aDocumentURI,
         141                 :                                                    nsPIDOMWindow *aWindow)
         142                 :   : mInitialized(false)
         143                 :   , mManifestURI(aManifestURI)
         144                 :   , mDocumentURI(aDocumentURI)
         145                 :   , mExposeCacheUpdateStatus(true)
         146                 :   , mStatus(nsIDOMOfflineResourceList::IDLE)
         147                 :   , mCachedKeys(nsnull)
         148               0 :   , mCachedKeysCount(0)
         149                 : {
         150               0 :   BindToOwner(aWindow);
         151               0 : }
         152                 :
         153               0 : nsDOMOfflineResourceList::~nsDOMOfflineResourceList()
         154                 : {
         155               0 :   ClearCachedKeys();
         156               0 : }
         157                 :
         158                 : nsresult
         159               0 : nsDOMOfflineResourceList::Init()
         160                 : {
         161               0 :   if (mInitialized) {
         162               0 :     return NS_OK;
         163                 :   }
         164                 :
         165               0 :   if (!mManifestURI) {
         166               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         167                 :   }
         168                 :
         169               0 :   mManifestURI->GetAsciiSpec(mManifestSpec);
         170                 :
         171               0 :   nsresult rv = nsContentUtils::GetSecurityManager()->
         172               0 :                    CheckSameOriginURI(mManifestURI, mDocumentURI, true);
         173               0 :   NS_ENSURE_SUCCESS(rv, rv);
         174                 :
         175                 :   // Dynamically-managed resources are stored as a separate ownership list
         176                 :   // from the manifest.
         177               0 :   nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(mDocumentURI);
         178               0 :   if (!innerURI)
         179               0 :     return NS_ERROR_FAILURE;
         180                 :
         181               0 :   if (!IS_CHILD_PROCESS())
         182                 :   {
         183                 :     mApplicationCacheService =
         184               0 :       do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
         185               0 :     NS_ENSURE_SUCCESS(rv, rv);
         186                 :
         187                 :     // Check for in-progress cache updates
         188                 :     nsCOMPtr<nsIOfflineCacheUpdateService> cacheUpdateService =
         189               0 :       do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &rv);
         190               0 :     NS_ENSURE_SUCCESS(rv, rv);
         191                 :
         192                 :     PRUint32 numUpdates;
         193               0 :     rv = cacheUpdateService->GetNumUpdates(&numUpdates);
         194               0 :     NS_ENSURE_SUCCESS(rv, rv);
         195                 :
         196               0 :     for (PRUint32 i = 0; i < numUpdates; i++) {
         197               0 :       nsCOMPtr<nsIOfflineCacheUpdate> cacheUpdate;
         198               0 :       rv = cacheUpdateService->GetUpdate(i, getter_AddRefs(cacheUpdate));
         199               0 :       NS_ENSURE_SUCCESS(rv, rv);
         200                 :
         201               0 :       UpdateAdded(cacheUpdate);
         202               0 :       NS_ENSURE_SUCCESS(rv, rv);
         203                 :     }
         204                 :   }
         205                 :
         206                 :   // watch for new offline cache updates
         207                 :   nsCOMPtr<nsIObserverService> observerService =
         208               0 :     mozilla::services::GetObserverService();
         209               0 :   if (!observerService)
         210               0 :     return NS_ERROR_FAILURE;
         211                 :
         212               0 :   rv = observerService->AddObserver(this, "offline-cache-update-added", true);
         213               0 :   NS_ENSURE_SUCCESS(rv, rv);
         214               0 :   rv = observerService->AddObserver(this, "offline-cache-update-completed", true);
         215               0 :   NS_ENSURE_SUCCESS(rv, rv);
         216                 :
         217               0 :   mInitialized = true;
         218                 :
         219               0 :   return NS_OK;
         220                 : }
         221                 :
         222                 : void
         223               0 : nsDOMOfflineResourceList::Disconnect()
         224                 : {
         225               0 :   mOnCheckingListener = nsnull;
         226               0 :   mOnErrorListener = nsnull;
         227               0 :   mOnNoUpdateListener = nsnull;
         228               0 :   mOnDownloadingListener = nsnull;
         229               0 :   mOnProgressListener = nsnull;
         230               0 :   mOnCachedListener = nsnull;
         231               0 :   mOnUpdateReadyListener = nsnull;
         232               0 :   mOnObsoleteListener = nsnull;
         233                 :
         234               0 :   mPendingEvents.Clear();
         235                 :
         236               0 :   if (mListenerManager) {
         237               0 :     mListenerManager->Disconnect();
         238               0 :     mListenerManager = nsnull;
         239                 :   }
         240               0 : }
         241                 :
         242                 : //
         243                 : // nsDOMOfflineResourceList::nsIDOMOfflineResourceList
         244                 : //
         245                 :
         246                 : NS_IMETHODIMP
         247               0 : nsDOMOfflineResourceList::GetMozItems(nsIDOMDOMStringList **aItems)
         248                 : {
         249               0 :   if (IS_CHILD_PROCESS())
         250               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         251                 :
         252               0 :   *aItems = nsnull;
         253                 :
         254               0 :   nsRefPtr<nsDOMStringList> items = new nsDOMStringList();
         255               0 :   NS_ENSURE_TRUE(items, NS_ERROR_OUT_OF_MEMORY);
         256                 :
         257                 :   // If we are not associated with an application cache, return an
         258                 :   // empty list.
         259               0 :   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
         260               0 :   if (!appCache) {
         261               0 :     NS_ADDREF(*aItems = items);
         262               0 :     return NS_OK;
         263                 :   }
         264                 :
         265               0 :   nsresult rv = Init();
         266               0 :   NS_ENSURE_SUCCESS(rv, rv);
         267                 :
         268                 :   PRUint32 length;
         269                 :   char **keys;
         270               0 :   rv = appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC,
         271               0 :                                &length, &keys);
         272               0 :   NS_ENSURE_SUCCESS(rv, rv);
         273                 :
         274               0 :   for (PRUint32 i = 0; i < length; i++) {
         275               0 :     items->Add(NS_ConvertUTF8toUTF16(keys[i]));
         276                 :   }
         277                 :
         278               0 :   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, keys);
         279                 :
         280               0 :   NS_ADDREF(*aItems = items);
         281               0 :   return NS_OK;
         282                 : }
         283                 :
         284                 : NS_IMETHODIMP
         285               0 : nsDOMOfflineResourceList::MozHasItem(const nsAString& aURI, bool* aExists)
         286                 : {
         287               0 :   if (IS_CHILD_PROCESS())
         288               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         289                 :
         290               0 :   nsresult rv = Init();
         291               0 :   NS_ENSURE_SUCCESS(rv, rv);
         292                 :
         293               0 :   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
         294               0 :   if (!appCache) {
         295               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         296                 :   }
         297                 :
         298               0 :   nsCAutoString key;
         299               0 :   rv = GetCacheKey(aURI, key);
         300               0 :   NS_ENSURE_SUCCESS(rv, rv);
         301                 :
         302                 :   PRUint32 types;
         303               0 :   rv = appCache->GetTypes(key, &types);
         304               0 :   if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
         305               0 :     *aExists = false;
         306               0 :     return NS_OK;
         307                 :   }
         308               0 :   NS_ENSURE_SUCCESS(rv, rv);
         309                 :
         310               0 :   *aExists = ((types & nsIApplicationCache::ITEM_DYNAMIC) != 0);
         311               0 :   return NS_OK;
         312                 : }
         313                 :
         314                 : NS_IMETHODIMP
         315               0 : nsDOMOfflineResourceList::GetMozLength(PRUint32 *aLength)
         316                 : {
         317               0 :   if (IS_CHILD_PROCESS())
         318               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         319                 :
         320               0 :   if (!mManifestURI) {
         321               0 :     *aLength = 0;
         322               0 :     return NS_OK;
         323                 :   }
         324                 :
         325               0 :   nsresult rv = Init();
         326               0 :   NS_ENSURE_SUCCESS(rv, rv);
         327                 :
         328               0 :   rv = CacheKeys();
         329               0 :   NS_ENSURE_SUCCESS(rv, rv);
         330                 :
         331               0 :   *aLength = mCachedKeysCount;
         332               0 :   return NS_OK;
         333                 : }
         334                 :
         335                 : NS_IMETHODIMP
         336               0 : nsDOMOfflineResourceList::MozItem(PRUint32 aIndex, nsAString& aURI)
         337                 : {
         338               0 :   if (IS_CHILD_PROCESS())
         339               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         340                 :
         341               0 :   nsresult rv = Init();
         342               0 :   NS_ENSURE_SUCCESS(rv, rv);
         343                 :
         344               0 :   SetDOMStringToNull(aURI);
         345                 :
         346               0 :   rv = CacheKeys();
         347               0 :   NS_ENSURE_SUCCESS(rv, rv);
         348                 :
         349               0 :   if (aIndex >= mCachedKeysCount)
         350               0 :     return NS_ERROR_NOT_AVAILABLE;
         351                 :
         352               0 :   CopyUTF8toUTF16(mCachedKeys[aIndex], aURI);
         353                 :
         354               0 :   return NS_OK;
         355                 : }
         356                 :
         357                 : NS_IMETHODIMP
         358               0 : nsDOMOfflineResourceList::MozAdd(const nsAString& aURI)
         359                 : {
         360               0 :   if (IS_CHILD_PROCESS())
         361               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         362                 :
         363               0 :   nsresult rv = Init();
         364               0 :   NS_ENSURE_SUCCESS(rv, rv);
         365                 :
         366               0 :   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
         367               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         368                 :   }
         369                 :
         370               0 :   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
         371               0 :   if (!appCache) {
         372               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         373                 :   }
         374                 :
         375               0 :   if (aURI.Length() > MAX_URI_LENGTH) return NS_ERROR_DOM_BAD_URI;
         376                 :
         377                 :   // this will fail if the URI is not absolute
         378               0 :   nsCOMPtr<nsIURI> requestedURI;
         379               0 :   rv = NS_NewURI(getter_AddRefs(requestedURI), aURI);
         380               0 :   NS_ENSURE_SUCCESS(rv, rv);
         381                 :
         382               0 :   nsCAutoString scheme;
         383               0 :   rv = requestedURI->GetScheme(scheme);
         384               0 :   NS_ENSURE_SUCCESS(rv, rv);
         385                 :
         386                 :   bool match;
         387               0 :   rv = mManifestURI->SchemeIs(scheme.get(), &match);
         388               0 :   NS_ENSURE_SUCCESS(rv, rv);
         389                 :
         390               0 :   if (!match) {
         391               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         392                 :   }
         393                 :
         394                 :   PRUint32 length;
         395               0 :   rv = GetMozLength(&length);
         396               0 :   NS_ENSURE_SUCCESS(rv, rv);
         397                 :   PRUint32 maxEntries =
         398               0 :     Preferences::GetUint(kMaxEntriesPref, DEFAULT_MAX_ENTRIES);
         399                 :
         400               0 :   if (length > maxEntries) return NS_ERROR_NOT_AVAILABLE;
         401                 :
         402               0 :   ClearCachedKeys();
         403                 :
         404                 :   nsCOMPtr<nsIOfflineCacheUpdate> update =
         405               0 :     do_CreateInstance(NS_OFFLINECACHEUPDATE_CONTRACTID, &rv);
         406               0 :   NS_ENSURE_SUCCESS(rv, rv);
         407                 :
         408               0 :   nsCAutoString clientID;
         409               0 :   rv = appCache->GetClientID(clientID);
         410               0 :   NS_ENSURE_SUCCESS(rv, rv);
         411                 :
         412               0 :   rv = update->InitPartial(mManifestURI, clientID, mDocumentURI);
         413               0 :   NS_ENSURE_SUCCESS(rv, rv);
         414                 :
         415               0 :   rv = update->AddDynamicURI(requestedURI);
         416               0 :   NS_ENSURE_SUCCESS(rv, rv);
         417                 :
         418               0 :   rv = update->Schedule();
         419               0 :   NS_ENSURE_SUCCESS(rv, rv);
         420                 :
         421               0 :   return NS_OK;
         422                 : }
         423                 :
         424                 : NS_IMETHODIMP
         425               0 : nsDOMOfflineResourceList::MozRemove(const nsAString& aURI)
         426                 : {
         427               0 :   if (IS_CHILD_PROCESS())
         428               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         429                 :
         430               0 :   nsresult rv = Init();
         431               0 :   NS_ENSURE_SUCCESS(rv, rv);
         432                 :
         433               0 :   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
         434               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         435                 :   }
         436                 :
         437               0 :   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
         438               0 :   if (!appCache) {
         439               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         440                 :   }
         441                 :
         442               0 :   nsCAutoString key;
         443               0 :   rv = GetCacheKey(aURI, key);
         444               0 :   NS_ENSURE_SUCCESS(rv, rv);
         445                 :
         446               0 :   ClearCachedKeys();
         447                 :
         448                 :   // XXX: This is a race condition.  remove() is specced to remove
         449                 :   // from the currently associated application cache, but if this
         450                 :   // happens during an update (or after an update, if we haven't
         451                 :   // swapped yet), that remove() will be lost when the next update is
         452                 :   // finished.  Need to bring this issue up.
         453                 :
         454               0 :   rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC);
         455               0 :   NS_ENSURE_SUCCESS(rv, rv);
         456                 :
         457               0 :   return NS_OK;
         458                 : }
         459                 :
         460                 : NS_IMETHODIMP
         461               0 : nsDOMOfflineResourceList::GetStatus(PRUint16 *aStatus)
         462                 : {
         463               0 :   nsresult rv = Init();
         464                 :
         465                 :   // Init may fail with INVALID_STATE_ERR if there is no manifest URI.
         466                 :   // The status attribute should not throw that exception, convert it
         467                 :   // to an UNCACHED.
         468               0 :   if (rv == NS_ERROR_DOM_INVALID_STATE_ERR ||
         469               0 :       !nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
         470               0 :     *aStatus = nsIDOMOfflineResourceList::UNCACHED;
         471               0 :     return NS_OK;
         472                 :   }
         473                 :
         474               0 :   NS_ENSURE_SUCCESS(rv, rv);
         475                 :
         476                 :   // If this object is not associated with a cache, return UNCACHED
         477               0 :   nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache();
         478               0 :   if (!appCache) {
         479               0 :     *aStatus = nsIDOMOfflineResourceList::UNCACHED;
         480               0 :     return NS_OK;
         481                 :   }
         482                 :
         483                 :
         484                 :   // If there is an update in process, use its status.
         485               0 :   if (mCacheUpdate && mExposeCacheUpdateStatus) {
         486               0 :     rv = mCacheUpdate->GetStatus(aStatus);
         487               0 :     if (NS_SUCCEEDED(rv) && *aStatus != nsIDOMOfflineResourceList::IDLE) {
         488               0 :       return NS_OK;
         489                 :     }
         490                 :   }
         491                 :
         492               0 :   *aStatus = mStatus;
         493               0 :   return NS_OK;
         494                 : }
         495                 :
         496                 : NS_IMETHODIMP
         497               0 : nsDOMOfflineResourceList::Update()
         498                 : {
         499               0 :   nsresult rv = Init();
         500               0 :   NS_ENSURE_SUCCESS(rv, rv);
         501                 :
         502               0 :   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
         503               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         504                 :   }
         505                 :
         506                 :   nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
         507               0 :     do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &rv);
         508               0 :   NS_ENSURE_SUCCESS(rv, rv);
         509                 :
         510                 :   nsCOMPtr<nsIDOMWindow> window =
         511               0 :     do_QueryInterface(GetOwner());
         512                 :
         513               0 :   nsCOMPtr<nsIOfflineCacheUpdate> update;
         514               0 :   rv = updateService->ScheduleUpdate(mManifestURI, mDocumentURI,
         515               0 :                                      window, getter_AddRefs(update));
         516               0 :   NS_ENSURE_SUCCESS(rv, rv);
         517                 :
         518               0 :   return NS_OK;
         519                 : }
         520                 :
         521                 : NS_IMETHODIMP
         522               0 : nsDOMOfflineResourceList::SwapCache()
         523                 : {
         524               0 :   nsresult rv = Init();
         525               0 :   NS_ENSURE_SUCCESS(rv, rv);
         526                 :
         527               0 :   if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) {
         528               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         529                 :   }
         530                 :
         531               0 :   nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache();
         532               0 :   if (!currentAppCache) {
         533               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         534                 :   }
         535                 :
         536                 :   // Check the current and potentially newly available cache are not identical.
         537               0 :   if (mAvailableApplicationCache == currentAppCache) {
         538               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         539                 :   }
         540                 :
         541               0 :   if (mAvailableApplicationCache) {
         542               0 :     nsCString currClientId, availClientId;
         543               0 :     currentAppCache->GetClientID(currClientId);
         544               0 :     mAvailableApplicationCache->GetClientID(availClientId);
         545               0 :     if (availClientId == currClientId)
         546               0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
         547                 :   }
         548                 :
         549               0 :   ClearCachedKeys();
         550                 :
         551                 :   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
         552               0 :     GetDocumentAppCacheContainer();
         553                 :
         554                 :   // In the case of an obsolete cache group, newAppCache might be null.
         555                 :   // We will disassociate from the cache in that case.
         556               0 :   if (appCacheContainer) {
         557               0 :     rv = appCacheContainer->SetApplicationCache(mAvailableApplicationCache);
         558               0 :     NS_ENSURE_SUCCESS(rv, rv);
         559                 :   }
         560                 :
         561               0 :   mAvailableApplicationCache = nsnull;
         562               0 :   mStatus = nsIDOMOfflineResourceList::IDLE;
         563                 :
         564               0 :   return NS_OK;
         565                 : }
         566                 :
         567                 : //
         568                 : // nsDOMOfflineResourceList::nsIDOMEventTarget
         569                 : //
         570                 :
         571                 : NS_IMETHODIMP
         572               0 : nsDOMOfflineResourceList::GetOnchecking(nsIDOMEventListener **aOnchecking)
         573                 : {
         574               0 :   return GetInnerEventListener(mOnCheckingListener, aOnchecking);
         575                 : }
         576                 :
         577                 : NS_IMETHODIMP
         578               0 : nsDOMOfflineResourceList::SetOnchecking(nsIDOMEventListener *aOnchecking)
         579                 : {
         580               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(CHECKING_STR),
         581               0 :                                 mOnCheckingListener, aOnchecking);
         582                 : }
         583                 :
         584                 : NS_IMETHODIMP
         585               0 : nsDOMOfflineResourceList::GetOnerror(nsIDOMEventListener **aOnerror)
         586                 : {
         587               0 :   return GetInnerEventListener(mOnErrorListener, aOnerror);
         588                 : }
         589                 :
         590                 : NS_IMETHODIMP
         591               0 : nsDOMOfflineResourceList::SetOnerror(nsIDOMEventListener *aOnerror)
         592                 : {
         593               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(ERROR_STR), mOnErrorListener,
         594               0 :                                 aOnerror);
         595                 : }
         596                 :
         597                 : NS_IMETHODIMP
         598               0 : nsDOMOfflineResourceList::GetOnnoupdate(nsIDOMEventListener **aOnnoupdate)
         599                 : {
         600               0 :   return GetInnerEventListener(mOnNoUpdateListener, aOnnoupdate);
         601                 : }
         602                 :
         603                 : NS_IMETHODIMP
         604               0 : nsDOMOfflineResourceList::SetOnnoupdate(nsIDOMEventListener *aOnnoupdate)
         605                 : {
         606               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(NOUPDATE_STR),
         607               0 :                                 mOnNoUpdateListener, aOnnoupdate);
         608                 : }
         609                 :
         610                 : NS_IMETHODIMP
         611               0 : nsDOMOfflineResourceList::GetOndownloading(nsIDOMEventListener **aOndownloading)
         612                 : {
         613               0 :   return GetInnerEventListener(mOnDownloadingListener, aOndownloading);
         614                 : }
         615                 :
         616                 : NS_IMETHODIMP
         617               0 : nsDOMOfflineResourceList::SetOndownloading(nsIDOMEventListener *aOndownloading)
         618                 : {
         619               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(DOWNLOADING_STR),
         620               0 :                                 mOnDownloadingListener, aOndownloading);
         621                 : }
         622                 :
         623                 : NS_IMETHODIMP
         624               0 : nsDOMOfflineResourceList::GetOnprogress(nsIDOMEventListener **aOnprogress)
         625                 : {
         626               0 :   return GetInnerEventListener(mOnProgressListener, aOnprogress);
         627                 : }
         628                 :
         629                 : NS_IMETHODIMP
         630               0 : nsDOMOfflineResourceList::SetOnprogress(nsIDOMEventListener *aOnprogress)
         631                 : {
         632               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(PROGRESS_STR),
         633               0 :                                 mOnProgressListener, aOnprogress);
         634                 : }
         635                 :
         636                 :
         637                 : NS_IMETHODIMP
         638               0 : nsDOMOfflineResourceList::GetOnupdateready(nsIDOMEventListener **aOnupdateready)
         639                 : {
         640               0 :   return GetInnerEventListener(mOnUpdateReadyListener, aOnupdateready);
         641                 : }
         642                 :
         643                 : NS_IMETHODIMP
         644               0 : nsDOMOfflineResourceList::SetOncached(nsIDOMEventListener *aOncached)
         645                 : {
         646               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(CACHED_STR),
         647               0 :                                 mOnCachedListener, aOncached);
         648                 : }
         649                 :
         650                 : NS_IMETHODIMP
         651               0 : nsDOMOfflineResourceList::GetOncached(nsIDOMEventListener **aOncached)
         652                 : {
         653               0 :   return GetInnerEventListener(mOnCachedListener, aOncached);
         654                 : }
         655                 :
         656                 : NS_IMETHODIMP
         657               0 : nsDOMOfflineResourceList::SetOnupdateready(nsIDOMEventListener *aOnupdateready)
         658                 : {
         659               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(UPDATEREADY_STR),
         660               0 :                                 mOnUpdateReadyListener, aOnupdateready);
         661                 : }
         662                 :
         663                 : NS_IMETHODIMP
         664               0 : nsDOMOfflineResourceList::GetOnobsolete(nsIDOMEventListener **aOnobsolete)
         665                 : {
         666               0 :   return GetInnerEventListener(mOnObsoleteListener, aOnobsolete);
         667                 : }
         668                 :
         669                 : NS_IMETHODIMP
         670               0 : nsDOMOfflineResourceList::SetOnobsolete(nsIDOMEventListener *aOnobsolete)
         671                 : {
         672               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(OBSOLETE_STR),
         673               0 :                                 mOnObsoleteListener, aOnobsolete);
         674                 : }
         675                 :
         676                 : void
         677               0 : nsDOMOfflineResourceList::FirePendingEvents()
         678                 : {
         679               0 :   for (PRInt32 i = 0; i < mPendingEvents.Count(); ++i) {
         680                 :     bool dummy;
         681               0 :     nsCOMPtr<nsIDOMEvent> event = mPendingEvents[i];
         682               0 :     DispatchEvent(event, &dummy);
         683                 :   }
         684               0 :   mPendingEvents.Clear();
         685               0 : }
         686                 :
         687                 : nsresult
         688               0 : nsDOMOfflineResourceList::SendEvent(const nsAString &aEventName)
         689                 : {
         690                 :   // Don't send events to closed windows
         691               0 :   if (!GetOwner()) {
         692               0 :     return NS_OK;
         693                 :   }
         694                 :
         695               0 :   if (!GetOwner()->GetDocShell()) {
         696               0 :     return NS_OK;
         697                 :   }
         698                 :
         699               0 :   nsCOMPtr<nsIDOMEvent> event;
         700                 :   nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
         701               0 :                                                NS_LITERAL_STRING("Events"),
         702               0 :                                                getter_AddRefs(event));
         703               0 :   NS_ENSURE_SUCCESS(rv, rv);
         704                 :
         705               0 :   nsCOMPtr<nsIPrivateDOMEvent> privevent = do_QueryInterface(event);
         706               0 :   if (!privevent) {
         707               0 :     return NS_ERROR_FAILURE;
         708                 :   }
         709                 :
         710               0 :   event->InitEvent(aEventName, false, true);
         711                 :
         712                 :   // We assume anyone that managed to call SendEvent is trusted
         713               0 :   privevent->SetTrusted(true);
         714                 :
         715                 :   // If the window is frozen or we're still catching up on events that were
         716                 :   // queued while frozen, save the event for later.
         717               0 :   if (GetOwner()->IsFrozen() || mPendingEvents.Count() > 0) {
         718               0 :     mPendingEvents.AppendObject(event);
         719               0 :     return NS_OK;
         720                 :   }
         721                 :
         722                 :   bool dummy;
         723               0 :   DispatchEvent(event, &dummy);
         724                 :
         725               0 :   return NS_OK;
         726                 : }
         727                 :
         728                 :
         729                 : //
         730                 : // nsDOMOfflineResourceList::nsIObserver
         731                 : //
         732                 : NS_IMETHODIMP
         733               0 : nsDOMOfflineResourceList::Observe(nsISupports *aSubject,
         734                 :                                     const char *aTopic,
         735                 :                                     const PRUnichar *aData)
         736                 : {
         737               0 :   if (!strcmp(aTopic, "offline-cache-update-added")) {
         738               0 :     nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
         739               0 :     if (update) {
         740               0 :       UpdateAdded(update);
         741                 :     }
         742               0 :   } else if (!strcmp(aTopic, "offline-cache-update-completed")) {
         743               0 :     nsCOMPtr<nsIOfflineCacheUpdate> update = do_QueryInterface(aSubject);
         744               0 :     if (update) {
         745               0 :       UpdateCompleted(update);
         746                 :     }
         747                 :   }
         748                 :
         749               0 :   return NS_OK;
         750                 : }
         751                 :
         752                 : //
         753                 : // nsDOMOfflineResourceList::nsIOfflineCacheUpdateObserver
         754                 : //
         755                 : NS_IMETHODIMP
         756               0 : nsDOMOfflineResourceList::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate,
         757                 :                                      PRUint32 event)
         758                 : {
         759                 :   mExposeCacheUpdateStatus =
         760                 :       (event == STATE_CHECKING) ||
         761                 :       (event == STATE_DOWNLOADING) ||
         762                 :       (event == STATE_ITEMSTARTED) ||
         763                 :       (event == STATE_ITEMCOMPLETED) ||
         764                 :       // During notification of "obsolete" we must expose state of the update
         765               0 :       (event == STATE_OBSOLETE);
         766                 :
         767               0 :   switch (event) {
         768                 :     case STATE_ERROR:
         769               0 :       SendEvent(NS_LITERAL_STRING(ERROR_STR));
         770               0 :       break;
         771                 :     case STATE_CHECKING:
         772               0 :       SendEvent(NS_LITERAL_STRING(CHECKING_STR));
         773               0 :       break;
         774                 :     case STATE_NOUPDATE:
         775               0 :       SendEvent(NS_LITERAL_STRING(NOUPDATE_STR));
         776               0 :       break;
         777                 :     case STATE_OBSOLETE:
         778               0 :       mStatus = nsIDOMOfflineResourceList::OBSOLETE;
         779               0 :       mAvailableApplicationCache = nsnull;
         780               0 :       SendEvent(NS_LITERAL_STRING(OBSOLETE_STR));
         781               0 :       break;
         782                 :     case STATE_DOWNLOADING:
         783               0 :       SendEvent(NS_LITERAL_STRING(DOWNLOADING_STR));
         784               0 :       break;
         785                 :     case STATE_ITEMSTARTED:
         786               0 :       SendEvent(NS_LITERAL_STRING(PROGRESS_STR));
         787               0 :       break;
         788                 :     case STATE_ITEMCOMPLETED:
         789                 :       // Nothing to do here...
         790               0 :       break;
         791                 :   }
         792                 :
         793               0 :   return NS_OK;
         794                 : }
         795                 :
         796                 : NS_IMETHODIMP
         797               0 : nsDOMOfflineResourceList::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache)
         798                 : {
         799               0 :   mAvailableApplicationCache = aApplicationCache;
         800               0 :   return NS_OK;
         801                 : }
         802                 :
         803                 : nsresult
         804               0 : nsDOMOfflineResourceList::GetCacheKey(const nsAString &aURI, nsCString &aKey)
         805                 : {
         806               0 :   nsCOMPtr<nsIURI> requestedURI;
         807               0 :   nsresult rv = NS_NewURI(getter_AddRefs(requestedURI), aURI);
         808               0 :   NS_ENSURE_SUCCESS(rv, rv);
         809                 :
         810               0 :   return GetCacheKey(requestedURI, aKey);
         811                 : }
         812                 :
         813                 : nsresult
         814               0 : nsDOMOfflineResourceList::UpdateAdded(nsIOfflineCacheUpdate *aUpdate)
         815                 : {
         816                 :   // Ignore partial updates.
         817                 :   bool partial;
         818               0 :   nsresult rv = aUpdate->GetPartial(&partial);
         819               0 :   NS_ENSURE_SUCCESS(rv, rv);
         820                 :
         821               0 :   if (partial) {
         822               0 :     return NS_OK;
         823                 :   }
         824                 :
         825               0 :   nsCOMPtr<nsIURI> updateURI;
         826               0 :   rv = aUpdate->GetManifestURI(getter_AddRefs(updateURI));
         827               0 :   NS_ENSURE_SUCCESS(rv, rv);
         828                 :
         829                 :   bool equals;
         830               0 :   rv = updateURI->Equals(mManifestURI, &equals);
         831               0 :   NS_ENSURE_SUCCESS(rv, rv);
         832                 :
         833               0 :   if (!equals) {
         834                 :     // This update doesn't belong to us
         835               0 :     return NS_OK;
         836                 :   }
         837                 :
         838               0 :   NS_ENSURE_TRUE(!mCacheUpdate, NS_ERROR_FAILURE);
         839                 :
         840                 :   // We don't need to emit signals here.  Updates are either added
         841                 :   // when they are scheduled (in which case they are always IDLE) or
         842                 :   // they are added when the applicationCache object is initialized, so there
         843                 :   // are no listeners to accept signals anyway.
         844                 :
         845               0 :   mCacheUpdate = aUpdate;
         846               0 :   mCacheUpdate->AddObserver(this, true);
         847                 :
         848               0 :   return NS_OK;
         849                 : }
         850                 :
         851                 : already_AddRefed<nsIApplicationCacheContainer>
         852               0 : nsDOMOfflineResourceList::GetDocumentAppCacheContainer()
         853                 : {
         854               0 :   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(GetOwner());
         855               0 :   if (!webnav) {
         856               0 :     return nsnull;
         857                 :   }
         858                 :
         859                 :   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
         860               0 :     do_GetInterface(webnav);
         861               0 :   return appCacheContainer.forget();
         862                 : }
         863                 :
         864                 : already_AddRefed<nsIApplicationCache>
         865               0 : nsDOMOfflineResourceList::GetDocumentAppCache()
         866                 : {
         867                 :   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
         868               0 :     GetDocumentAppCacheContainer();
         869                 :
         870               0 :   if (appCacheContainer) {
         871               0 :     nsCOMPtr<nsIApplicationCache> applicationCache;
         872               0 :     appCacheContainer->GetApplicationCache(
         873               0 :       getter_AddRefs(applicationCache));
         874               0 :     return applicationCache.forget();
         875                 :   }
         876                 :
         877               0 :   return nsnull;
         878                 : }
         879                 :
         880                 : nsresult
         881               0 : nsDOMOfflineResourceList::UpdateCompleted(nsIOfflineCacheUpdate *aUpdate)
         882                 : {
         883               0 :   if (aUpdate != mCacheUpdate) {
         884                 :     // This isn't the update we're watching.
         885               0 :     return NS_OK;
         886                 :   }
         887                 :
         888                 :   bool partial;
         889               0 :   mCacheUpdate->GetPartial(&partial);
         890                 :   bool isUpgrade;
         891               0 :   mCacheUpdate->GetIsUpgrade(&isUpgrade);
         892                 :
         893                 :   bool succeeded;
         894               0 :   nsresult rv = mCacheUpdate->GetSucceeded(&succeeded);
         895                 :
         896               0 :   mCacheUpdate->RemoveObserver(this);
         897               0 :   mCacheUpdate = nsnull;
         898                 :
         899               0 :   if (NS_SUCCEEDED(rv) && succeeded && !partial) {
         900               0 :     if (isUpgrade) {
         901               0 :       mStatus = nsIDOMOfflineResourceList::UPDATEREADY;
         902               0 :       SendEvent(NS_LITERAL_STRING(UPDATEREADY_STR));
         903                 :     } else {
         904               0 :       mStatus = nsIDOMOfflineResourceList::IDLE;
         905               0 :       SendEvent(NS_LITERAL_STRING(CACHED_STR));
         906                 :     }
         907                 :   }
         908                 :
         909               0 :   return NS_OK;
         910                 : }
         911                 :
         912                 : nsresult
         913               0 : nsDOMOfflineResourceList::GetCacheKey(nsIURI *aURI, nsCString &aKey)
         914                 : {
         915               0 :   nsresult rv = aURI->GetAsciiSpec(aKey);
         916               0 :   NS_ENSURE_SUCCESS(rv, rv);
         917                 :
         918                 :   // url fragments aren't used in cache keys
         919               0 :   nsCAutoString::const_iterator specStart, specEnd;
         920               0 :   aKey.BeginReading(specStart);
         921               0 :   aKey.EndReading(specEnd);
         922               0 :   if (FindCharInReadable('#', specStart, specEnd)) {
         923               0 :     aKey.BeginReading(specEnd);
         924               0 :     aKey = Substring(specEnd, specStart);
         925                 :   }
         926                 :
         927               0 :   return NS_OK;
         928                 : }
         929                 :
         930                 : nsresult
         931               0 : nsDOMOfflineResourceList::CacheKeys()
         932                 : {
         933               0 :   if (IS_CHILD_PROCESS())
         934               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         935                 :
         936               0 :   if (mCachedKeys)
         937               0 :     return NS_OK;
         938                 :
         939               0 :   nsCOMPtr<nsIApplicationCache> appCache;
         940               0 :   mApplicationCacheService->GetActiveCache(mManifestSpec,
         941               0 :                                            getter_AddRefs(appCache));
         942                 :
         943               0 :   if (!appCache) {
         944               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
         945                 :   }
         946                 :
         947               0 :   return appCache->GatherEntries(nsIApplicationCache::ITEM_DYNAMIC,
         948               0 :                                  &mCachedKeysCount, &mCachedKeys);
         949                 : }
         950                 :
         951                 : void
         952               0 : nsDOMOfflineResourceList::ClearCachedKeys()
         953                 : {
         954               0 :   if (mCachedKeys) {
         955               0 :     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCachedKeysCount, mCachedKeys);
         956               0 :     mCachedKeys = nsnull;
         957               0 :     mCachedKeysCount = 0;
         958                 :   }
         959            4188 : }

Generated by: LCOV version 1.7