LCOV - code coverage report
Current view: directory - uriloader/prefetch - nsOfflineCacheUpdate.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 854 480 56.2 %
Date: 2012-06-02 Functions: 85 60 70.6 %

       1                 : /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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 "nsOfflineCacheUpdate.h"
      40                 : 
      41                 : #include "nsCPrefetchService.h"
      42                 : #include "nsCURILoader.h"
      43                 : #include "nsIApplicationCacheContainer.h"
      44                 : #include "nsIApplicationCacheChannel.h"
      45                 : #include "nsIApplicationCacheService.h"
      46                 : #include "nsICache.h"
      47                 : #include "nsICacheService.h"
      48                 : #include "nsICacheSession.h"
      49                 : #include "nsICachingChannel.h"
      50                 : #include "nsIContent.h"
      51                 : #include "mozilla/dom/Element.h"
      52                 : #include "nsIDocumentLoader.h"
      53                 : #include "nsIDOMElement.h"
      54                 : #include "nsIDOMWindow.h"
      55                 : #include "nsIDOMOfflineResourceList.h"
      56                 : #include "nsIDocument.h"
      57                 : #include "nsIObserverService.h"
      58                 : #include "nsIURL.h"
      59                 : #include "nsIWebProgress.h"
      60                 : #include "nsICryptoHash.h"
      61                 : #include "nsICacheEntryDescriptor.h"
      62                 : #include "nsIPermissionManager.h"
      63                 : #include "nsIPrincipal.h"
      64                 : #include "nsNetCID.h"
      65                 : #include "nsNetUtil.h"
      66                 : #include "nsServiceManagerUtils.h"
      67                 : #include "nsStreamUtils.h"
      68                 : #include "nsThreadUtils.h"
      69                 : #include "nsProxyRelease.h"
      70                 : #include "prlog.h"
      71                 : #include "nsIAsyncVerifyRedirectCallback.h"
      72                 : #include "mozilla/Preferences.h"
      73                 : 
      74                 : #include "nsXULAppAPI.h"
      75                 : 
      76                 : using namespace mozilla;
      77                 : 
      78                 : static const PRUint32 kRescheduleLimit = 3;
      79                 : 
      80                 : #if defined(PR_LOGGING)
      81                 : //
      82                 : // To enable logging (see prlog.h for full details):
      83                 : //
      84                 : //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
      85                 : //    set NSPR_LOG_FILE=offlineupdate.log
      86                 : //
      87                 : // this enables PR_LOG_ALWAYS level information and places all output in
      88                 : // the file offlineupdate.log
      89                 : //
      90                 : extern PRLogModuleInfo *gOfflineCacheUpdateLog;
      91                 : #endif
      92                 : #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args)
      93                 : #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4)
      94                 : 
      95                 : class AutoFreeArray {
      96                 : public:
      97               0 :     AutoFreeArray(PRUint32 count, char **values)
      98               0 :         : mCount(count), mValues(values) {};
      99               0 :     ~AutoFreeArray() { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mValues); }
     100                 : private:
     101                 :     PRUint32 mCount;
     102                 :     char **mValues;
     103                 : };
     104                 : 
     105                 : static nsresult
     106              16 : DropReferenceFromURL(nsIURI * aURI)
     107                 : {
     108                 :     // XXXdholbert If this SetRef fails, callers of this method probably
     109                 :     // want to call aURI->CloneIgnoringRef() and use the result of that.
     110              16 :     return aURI->SetRef(EmptyCString());
     111                 : }
     112                 : 
     113                 : //-----------------------------------------------------------------------------
     114                 : // nsManifestCheck
     115                 : //-----------------------------------------------------------------------------
     116                 : 
     117                 : class nsManifestCheck : public nsIStreamListener
     118                 :                       , public nsIChannelEventSink
     119                 :                       , public nsIInterfaceRequestor
     120               8 : {
     121                 : public:
     122               8 :     nsManifestCheck(nsOfflineCacheUpdate *aUpdate,
     123                 :                     nsIURI *aURI,
     124                 :                     nsIURI *aReferrerURI)
     125                 :         : mUpdate(aUpdate)
     126                 :         , mURI(aURI)
     127               8 :         , mReferrerURI(aReferrerURI)
     128               8 :         {}
     129                 : 
     130                 :     NS_DECL_ISUPPORTS
     131                 :     NS_DECL_NSIREQUESTOBSERVER
     132                 :     NS_DECL_NSISTREAMLISTENER
     133                 :     NS_DECL_NSICHANNELEVENTSINK
     134                 :     NS_DECL_NSIINTERFACEREQUESTOR
     135                 : 
     136                 :     nsresult Begin();
     137                 : 
     138                 : private:
     139                 : 
     140                 :     static NS_METHOD ReadManifest(nsIInputStream *aInputStream,
     141                 :                                   void *aClosure,
     142                 :                                   const char *aFromSegment,
     143                 :                                   PRUint32 aOffset,
     144                 :                                   PRUint32 aCount,
     145                 :                                   PRUint32 *aBytesConsumed);
     146                 : 
     147                 :     nsRefPtr<nsOfflineCacheUpdate> mUpdate;
     148                 :     nsCOMPtr<nsIURI> mURI;
     149                 :     nsCOMPtr<nsIURI> mReferrerURI;
     150                 :     nsCOMPtr<nsICryptoHash> mManifestHash;
     151                 :     nsCOMPtr<nsIChannel> mChannel;
     152                 : };
     153                 : 
     154                 : //-----------------------------------------------------------------------------
     155                 : // nsManifestCheck::nsISupports
     156                 : //-----------------------------------------------------------------------------
     157             104 : NS_IMPL_ISUPPORTS4(nsManifestCheck,
     158                 :                    nsIRequestObserver,
     159                 :                    nsIStreamListener,
     160                 :                    nsIChannelEventSink,
     161                 :                    nsIInterfaceRequestor)
     162                 : 
     163                 : //-----------------------------------------------------------------------------
     164                 : // nsManifestCheck <public>
     165                 : //-----------------------------------------------------------------------------
     166                 : 
     167                 : nsresult
     168               8 : nsManifestCheck::Begin()
     169                 : {
     170                 :     nsresult rv;
     171               8 :     mManifestHash = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
     172               8 :     NS_ENSURE_SUCCESS(rv, rv);
     173                 : 
     174               8 :     rv = mManifestHash->Init(nsICryptoHash::MD5);
     175               8 :     NS_ENSURE_SUCCESS(rv, rv);
     176                 : 
     177               8 :     rv = NS_NewChannel(getter_AddRefs(mChannel),
     178                 :                        mURI,
     179                 :                        nsnull, nsnull, nsnull,
     180               8 :                        nsIRequest::LOAD_BYPASS_CACHE);
     181               8 :     NS_ENSURE_SUCCESS(rv, rv);
     182                 : 
     183                 :     // configure HTTP specific stuff
     184                 :     nsCOMPtr<nsIHttpChannel> httpChannel =
     185              16 :         do_QueryInterface(mChannel);
     186               8 :     if (httpChannel) {
     187               8 :         httpChannel->SetReferrer(mReferrerURI);
     188              16 :         httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
     189               8 :                                       NS_LITERAL_CSTRING("offline-resource"),
     190               8 :                                       false);
     191                 :     }
     192                 : 
     193               8 :     rv = mChannel->AsyncOpen(this, nsnull);
     194               8 :     NS_ENSURE_SUCCESS(rv, rv);
     195                 : 
     196               8 :     return NS_OK;
     197                 : }
     198                 : 
     199                 : //-----------------------------------------------------------------------------
     200                 : // nsManifestCheck <public>
     201                 : //-----------------------------------------------------------------------------
     202                 : 
     203                 : /* static */
     204                 : NS_METHOD
     205               8 : nsManifestCheck::ReadManifest(nsIInputStream *aInputStream,
     206                 :                               void *aClosure,
     207                 :                               const char *aFromSegment,
     208                 :                               PRUint32 aOffset,
     209                 :                               PRUint32 aCount,
     210                 :                               PRUint32 *aBytesConsumed)
     211                 : {
     212                 :     nsManifestCheck *manifestCheck =
     213               8 :         static_cast<nsManifestCheck*>(aClosure);
     214                 : 
     215                 :     nsresult rv;
     216               8 :     *aBytesConsumed = aCount;
     217                 : 
     218               8 :     rv = manifestCheck->mManifestHash->Update(
     219               8 :         reinterpret_cast<const PRUint8 *>(aFromSegment), aCount);
     220               8 :     NS_ENSURE_SUCCESS(rv, rv);
     221                 : 
     222               8 :     return NS_OK;
     223                 : }
     224                 : 
     225                 : //-----------------------------------------------------------------------------
     226                 : // nsManifestCheck::nsIStreamListener
     227                 : //-----------------------------------------------------------------------------
     228                 : 
     229                 : NS_IMETHODIMP
     230               8 : nsManifestCheck::OnStartRequest(nsIRequest *aRequest,
     231                 :                                 nsISupports *aContext)
     232                 : {
     233               8 :     return NS_OK;
     234                 : }
     235                 : 
     236                 : NS_IMETHODIMP
     237               8 : nsManifestCheck::OnDataAvailable(nsIRequest *aRequest,
     238                 :                                  nsISupports *aContext,
     239                 :                                  nsIInputStream *aStream,
     240                 :                                  PRUint32 aOffset,
     241                 :                                  PRUint32 aCount)
     242                 : {
     243                 :     PRUint32 bytesRead;
     244               8 :     aStream->ReadSegments(ReadManifest, this, aCount, &bytesRead);
     245               8 :     return NS_OK;
     246                 : }
     247                 : 
     248                 : NS_IMETHODIMP
     249               8 : nsManifestCheck::OnStopRequest(nsIRequest *aRequest,
     250                 :                                nsISupports *aContext,
     251                 :                                nsresult aStatus)
     252                 : {
     253              16 :     nsCAutoString manifestHash;
     254               8 :     if (NS_SUCCEEDED(aStatus)) {
     255               8 :         mManifestHash->Finish(true, manifestHash);
     256                 :     }
     257                 : 
     258               8 :     mUpdate->ManifestCheckCompleted(aStatus, manifestHash);
     259                 : 
     260               8 :     return NS_OK;
     261                 : }
     262                 : 
     263                 : //-----------------------------------------------------------------------------
     264                 : // nsManifestCheck::nsIInterfaceRequestor
     265                 : //-----------------------------------------------------------------------------
     266                 : 
     267                 : NS_IMETHODIMP
     268               0 : nsManifestCheck::GetInterface(const nsIID &aIID, void **aResult)
     269                 : {
     270               0 :     if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     271               0 :         NS_ADDREF_THIS();
     272               0 :         *aResult = static_cast<nsIChannelEventSink *>(this);
     273               0 :         return NS_OK;
     274                 :     }
     275                 : 
     276               0 :     return NS_ERROR_NO_INTERFACE;
     277                 : }
     278                 : 
     279                 : //-----------------------------------------------------------------------------
     280                 : // nsManifestCheck::nsIChannelEventSink
     281                 : //-----------------------------------------------------------------------------
     282                 : 
     283                 : NS_IMETHODIMP
     284               0 : nsManifestCheck::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
     285                 :                                         nsIChannel *aNewChannel,
     286                 :                                         PRUint32 aFlags,
     287                 :                                         nsIAsyncVerifyRedirectCallback *callback)
     288                 : {
     289                 :     // Redirects should cause the load (and therefore the update) to fail.
     290               0 :     if (aFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
     291               0 :         callback->OnRedirectVerifyCallback(NS_OK);
     292               0 :         return NS_OK;
     293                 :     }
     294               0 :     aOldChannel->Cancel(NS_ERROR_ABORT);
     295               0 :     return NS_ERROR_ABORT;
     296                 : }
     297                 : 
     298                 : //-----------------------------------------------------------------------------
     299                 : // nsOfflineCacheUpdateItem::nsISupports
     300                 : //-----------------------------------------------------------------------------
     301                 : 
     302             712 : NS_IMPL_ISUPPORTS6(nsOfflineCacheUpdateItem,
     303                 :                    nsIDOMLoadStatus,
     304                 :                    nsIRequestObserver,
     305                 :                    nsIStreamListener,
     306                 :                    nsIRunnable,
     307                 :                    nsIInterfaceRequestor,
     308                 :                    nsIChannelEventSink)
     309                 : 
     310                 : //-----------------------------------------------------------------------------
     311                 : // nsOfflineCacheUpdateItem <public>
     312                 : //-----------------------------------------------------------------------------
     313                 : 
     314              24 : nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate *aUpdate,
     315                 :                                                    nsIURI *aURI,
     316                 :                                                    nsIURI *aReferrerURI,
     317                 :                                                    nsIApplicationCache *aPreviousApplicationCache,
     318                 :                                                    const nsACString &aClientID,
     319                 :                                                    PRUint32 type)
     320                 :     : mURI(aURI)
     321                 :     , mReferrerURI(aReferrerURI)
     322                 :     , mPreviousApplicationCache(aPreviousApplicationCache)
     323                 :     , mClientID(aClientID)
     324                 :     , mItemType(type)
     325                 :     , mUpdate(aUpdate)
     326                 :     , mChannel(nsnull)
     327                 :     , mState(nsIDOMLoadStatus::UNINITIALIZED)
     328              24 :     , mBytesRead(0)
     329                 : {
     330              24 : }
     331                 : 
     332              40 : nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem()
     333                 : {
     334              80 : }
     335                 : 
     336                 : nsresult
     337              24 : nsOfflineCacheUpdateItem::OpenChannel()
     338                 : {
     339                 : #if defined(PR_LOGGING)
     340              24 :     if (LOG_ENABLED()) {
     341               0 :         nsCAutoString spec;
     342               0 :         mURI->GetSpec(spec);
     343               0 :         LOG(("%p: Opening channel for %s", this, spec.get()));
     344                 :     }
     345                 : #endif
     346                 : 
     347              24 :     nsresult rv = nsOfflineCacheUpdate::GetCacheKey(mURI, mCacheKey);
     348              24 :     NS_ENSURE_SUCCESS(rv, rv);
     349                 : 
     350              24 :     rv = NS_NewChannel(getter_AddRefs(mChannel),
     351                 :                        mURI,
     352                 :                        nsnull, nsnull, this,
     353                 :                        nsIRequest::LOAD_BACKGROUND |
     354                 :                        nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
     355              24 :                        nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE);
     356              24 :     NS_ENSURE_SUCCESS(rv, rv);
     357                 : 
     358                 :     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
     359              48 :         do_QueryInterface(mChannel, &rv);
     360                 : 
     361                 :     // Support for nsIApplicationCacheChannel is required.
     362              24 :     NS_ENSURE_SUCCESS(rv, rv);
     363                 : 
     364                 :     // Use the existing application cache as the cache to check.
     365              24 :     rv = appCacheChannel->SetApplicationCache(mPreviousApplicationCache);
     366              24 :     NS_ENSURE_SUCCESS(rv, rv);
     367                 : 
     368                 :     // configure HTTP specific stuff
     369                 :     nsCOMPtr<nsIHttpChannel> httpChannel =
     370              48 :         do_QueryInterface(mChannel);
     371              24 :     if (httpChannel) {
     372              24 :         httpChannel->SetReferrer(mReferrerURI);
     373              48 :         httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
     374              24 :                                       NS_LITERAL_CSTRING("offline-resource"),
     375              24 :                                       false);
     376                 :     }
     377                 : 
     378                 :     nsCOMPtr<nsICachingChannel> cachingChannel =
     379              48 :         do_QueryInterface(mChannel);
     380              24 :     if (cachingChannel) {
     381              24 :         rv = cachingChannel->SetCacheForOfflineUse(true);
     382              24 :         NS_ENSURE_SUCCESS(rv, rv);
     383                 : 
     384              24 :         if (!mClientID.IsEmpty()) {
     385              24 :             rv = cachingChannel->SetOfflineCacheClientID(mClientID);
     386              24 :             NS_ENSURE_SUCCESS(rv, rv);
     387                 :         }
     388                 :     }
     389                 : 
     390              24 :     rv = mChannel->AsyncOpen(this, nsnull);
     391              24 :     NS_ENSURE_SUCCESS(rv, rv);
     392                 : 
     393              24 :     mState = nsIDOMLoadStatus::REQUESTED;
     394                 : 
     395              24 :     return NS_OK;
     396                 : }
     397                 : 
     398                 : nsresult
     399               0 : nsOfflineCacheUpdateItem::Cancel()
     400                 : {
     401               0 :     if (mChannel) {
     402               0 :         mChannel->Cancel(NS_ERROR_ABORT);
     403               0 :         mChannel = nsnull;
     404                 :     }
     405                 : 
     406               0 :     mState = nsIDOMLoadStatus::UNINITIALIZED;
     407                 : 
     408               0 :     return NS_OK;
     409                 : }
     410                 : 
     411                 : //-----------------------------------------------------------------------------
     412                 : // nsOfflineCacheUpdateItem::nsIStreamListener
     413                 : //-----------------------------------------------------------------------------
     414                 : 
     415                 : NS_IMETHODIMP
     416              24 : nsOfflineCacheUpdateItem::OnStartRequest(nsIRequest *aRequest,
     417                 :                                          nsISupports *aContext)
     418                 : {
     419              24 :     mState = nsIDOMLoadStatus::RECEIVING;
     420                 : 
     421              24 :     return NS_OK;
     422                 : }
     423                 : 
     424                 : NS_IMETHODIMP
     425              16 : nsOfflineCacheUpdateItem::OnDataAvailable(nsIRequest *aRequest,
     426                 :                                           nsISupports *aContext,
     427                 :                                           nsIInputStream *aStream,
     428                 :                                           PRUint32 aOffset,
     429                 :                                           PRUint32 aCount)
     430                 : {
     431              16 :     PRUint32 bytesRead = 0;
     432              16 :     aStream->ReadSegments(NS_DiscardSegment, nsnull, aCount, &bytesRead);
     433              16 :     mBytesRead += bytesRead;
     434              16 :     LOG(("loaded %u bytes into offline cache [offset=%u]\n",
     435                 :          bytesRead, aOffset));
     436              16 :     return NS_OK;
     437                 : }
     438                 : 
     439                 : NS_IMETHODIMP
     440              24 : nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest,
     441                 :                                         nsISupports *aContext,
     442                 :                                         nsresult aStatus)
     443                 : {
     444              24 :     LOG(("done fetching offline item [status=%x]\n", aStatus));
     445                 : 
     446              24 :     mState = nsIDOMLoadStatus::LOADED;
     447                 : 
     448              24 :     if (mBytesRead == 0 && aStatus == NS_OK) {
     449                 :         // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
     450                 :         // specified), but the object should report loadedSize as if it
     451                 :         // did.
     452               0 :         mChannel->GetContentLength(&mBytesRead);
     453                 :     }
     454                 : 
     455                 :     // We need to notify the update that the load is complete, but we
     456                 :     // want to give the channel a chance to close the cache entries.
     457              24 :     NS_DispatchToCurrentThread(this);
     458                 : 
     459              24 :     return NS_OK;
     460                 : }
     461                 : 
     462                 : 
     463                 : //-----------------------------------------------------------------------------
     464                 : // nsOfflineCacheUpdateItem::nsIRunnable
     465                 : //-----------------------------------------------------------------------------
     466                 : NS_IMETHODIMP
     467              24 : nsOfflineCacheUpdateItem::Run()
     468                 : {
     469              24 :     mUpdate->LoadCompleted();
     470                 : 
     471              24 :     return NS_OK;
     472                 : }
     473                 : 
     474                 : //-----------------------------------------------------------------------------
     475                 : // nsOfflineCacheUpdateItem::nsIInterfaceRequestor
     476                 : //-----------------------------------------------------------------------------
     477                 : 
     478                 : NS_IMETHODIMP
     479             110 : nsOfflineCacheUpdateItem::GetInterface(const nsIID &aIID, void **aResult)
     480                 : {
     481             110 :     if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     482               0 :         NS_ADDREF_THIS();
     483               0 :         *aResult = static_cast<nsIChannelEventSink *>(this);
     484               0 :         return NS_OK;
     485                 :     }
     486                 : 
     487             110 :     return NS_ERROR_NO_INTERFACE;
     488                 : }
     489                 : 
     490                 : //-----------------------------------------------------------------------------
     491                 : // nsOfflineCacheUpdateItem::nsIChannelEventSink
     492                 : //-----------------------------------------------------------------------------
     493                 : 
     494                 : NS_IMETHODIMP
     495               0 : nsOfflineCacheUpdateItem::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
     496                 :                                                  nsIChannel *aNewChannel,
     497                 :                                                  PRUint32 aFlags,
     498                 :                                                  nsIAsyncVerifyRedirectCallback *cb)
     499                 : {
     500               0 :     if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
     501                 :         // Don't allow redirect in case of non-internal redirect and cancel
     502                 :         // the channel to clean the cache entry.
     503               0 :         aOldChannel->Cancel(NS_ERROR_ABORT);
     504               0 :         return NS_ERROR_ABORT;
     505                 :     }
     506                 : 
     507               0 :     nsCOMPtr<nsIURI> newURI;
     508               0 :     nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
     509               0 :     if (NS_FAILED(rv))
     510               0 :         return rv;
     511                 : 
     512                 :     nsCOMPtr<nsICachingChannel> newCachingChannel =
     513               0 :         do_QueryInterface(aNewChannel);
     514               0 :     if (newCachingChannel) {
     515               0 :         rv = newCachingChannel->SetCacheForOfflineUse(true);
     516               0 :         NS_ENSURE_SUCCESS(rv, rv);
     517               0 :         if (!mClientID.IsEmpty()) {
     518               0 :             rv = newCachingChannel->SetOfflineCacheClientID(mClientID);
     519               0 :             NS_ENSURE_SUCCESS(rv, rv);
     520                 :         }
     521                 :     }
     522                 : 
     523               0 :     nsCAutoString oldScheme;
     524               0 :     mURI->GetScheme(oldScheme);
     525                 : 
     526                 :     bool match;
     527               0 :     if (NS_FAILED(newURI->SchemeIs(oldScheme.get(), &match)) || !match) {
     528               0 :         LOG(("rejected: redirected to a different scheme\n"));
     529               0 :         return NS_ERROR_ABORT;
     530                 :     }
     531                 : 
     532                 :     // HTTP request headers are not automatically forwarded to the new channel.
     533               0 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
     534               0 :     NS_ENSURE_STATE(httpChannel);
     535                 : 
     536               0 :     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
     537               0 :                                   NS_LITERAL_CSTRING("offline-resource"),
     538               0 :                                   false);
     539                 : 
     540               0 :     mChannel = aNewChannel;
     541                 : 
     542               0 :     cb->OnRedirectVerifyCallback(NS_OK);
     543               0 :     return NS_OK;
     544                 : }
     545                 : 
     546                 : //-----------------------------------------------------------------------------
     547                 : // nsOfflineCacheUpdateItem::nsIDOMLoadStatus
     548                 : //-----------------------------------------------------------------------------
     549                 : 
     550                 : NS_IMETHODIMP
     551               0 : nsOfflineCacheUpdateItem::GetSource(nsIDOMNode **aSource)
     552                 : {
     553               0 :     *aSource = nsnull;
     554               0 :     return NS_OK;
     555                 : }
     556                 : 
     557                 : NS_IMETHODIMP
     558               0 : nsOfflineCacheUpdateItem::GetUri(nsAString &aURI)
     559                 : {
     560               0 :     nsCAutoString spec;
     561               0 :     nsresult rv = mURI->GetSpec(spec);
     562               0 :     NS_ENSURE_SUCCESS(rv, rv);
     563                 : 
     564               0 :     CopyUTF8toUTF16(spec, aURI);
     565               0 :     return NS_OK;
     566                 : }
     567                 : 
     568                 : NS_IMETHODIMP
     569               0 : nsOfflineCacheUpdateItem::GetTotalSize(PRInt32 *aTotalSize)
     570                 : {
     571               0 :     if (mChannel) {
     572               0 :         return mChannel->GetContentLength(aTotalSize);
     573                 :     }
     574                 : 
     575               0 :     *aTotalSize = -1;
     576               0 :     return NS_OK;
     577                 : }
     578                 : 
     579                 : NS_IMETHODIMP
     580               0 : nsOfflineCacheUpdateItem::GetLoadedSize(PRInt32 *aLoadedSize)
     581                 : {
     582               0 :     *aLoadedSize = mBytesRead;
     583               0 :     return NS_OK;
     584                 : }
     585                 : 
     586                 : NS_IMETHODIMP
     587               0 : nsOfflineCacheUpdateItem::GetReadyState(PRUint16 *aReadyState)
     588                 : {
     589               0 :     *aReadyState = mState;
     590               0 :     return NS_OK;
     591                 : }
     592                 : 
     593                 : nsresult
     594              24 : nsOfflineCacheUpdateItem::GetRequestSucceeded(bool * succeeded)
     595                 : {
     596              24 :     *succeeded = false;
     597                 : 
     598              24 :     if (!mChannel)
     599               0 :         return NS_OK;
     600                 : 
     601                 :     nsresult rv;
     602              48 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
     603              24 :     NS_ENSURE_SUCCESS(rv, rv);
     604                 : 
     605                 :     bool reqSucceeded;
     606              24 :     rv = httpChannel->GetRequestSucceeded(&reqSucceeded);
     607              24 :     if (NS_ERROR_NOT_AVAILABLE == rv)
     608               0 :         return NS_OK;
     609              24 :     NS_ENSURE_SUCCESS(rv, rv);
     610                 : 
     611              24 :     if (!reqSucceeded) {
     612               0 :         LOG(("Request failed"));
     613               0 :         return NS_OK;
     614                 :     }
     615                 : 
     616                 :     nsresult channelStatus;
     617              24 :     rv = httpChannel->GetStatus(&channelStatus);
     618              24 :     NS_ENSURE_SUCCESS(rv, rv);
     619                 : 
     620              24 :     if (NS_FAILED(channelStatus)) {
     621               0 :         LOG(("Channel status=0x%08x", channelStatus));
     622               0 :         return NS_OK;
     623                 :     }
     624                 : 
     625              24 :     *succeeded = true;
     626              24 :     return NS_OK;
     627                 : }
     628                 : 
     629                 : NS_IMETHODIMP
     630               8 : nsOfflineCacheUpdateItem::GetStatus(PRUint16 *aStatus)
     631                 : {
     632               8 :     if (!mChannel) {
     633               0 :         *aStatus = 0;
     634               0 :         return NS_OK;
     635                 :     }
     636                 : 
     637                 :     nsresult rv;
     638              16 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
     639               8 :     NS_ENSURE_SUCCESS(rv, rv);
     640                 : 
     641                 :     PRUint32 httpStatus;
     642               8 :     rv = httpChannel->GetResponseStatus(&httpStatus);
     643               8 :     if (rv == NS_ERROR_NOT_AVAILABLE) {
     644               0 :         *aStatus = 0;
     645               0 :         return NS_OK;
     646                 :     }
     647                 : 
     648               8 :     NS_ENSURE_SUCCESS(rv, rv);
     649               8 :     *aStatus = PRUint16(httpStatus);
     650               8 :     return NS_OK;
     651                 : }
     652                 : 
     653                 : //-----------------------------------------------------------------------------
     654                 : // nsOfflineManifestItem
     655                 : //-----------------------------------------------------------------------------
     656                 : 
     657                 : //-----------------------------------------------------------------------------
     658                 : // nsOfflineManifestItem <public>
     659                 : //-----------------------------------------------------------------------------
     660                 : 
     661               8 : nsOfflineManifestItem::nsOfflineManifestItem(nsOfflineCacheUpdate *aUpdate,
     662                 :                                              nsIURI *aURI,
     663                 :                                              nsIURI *aReferrerURI,
     664                 :                                              nsIApplicationCache *aPreviousApplicationCache,
     665                 :                                              const nsACString &aClientID)
     666                 :     : nsOfflineCacheUpdateItem(aUpdate, aURI, aReferrerURI,
     667                 :                                aPreviousApplicationCache, aClientID,
     668                 :                                nsIApplicationCache::ITEM_MANIFEST)
     669                 :     , mParserState(PARSE_INIT)
     670                 :     , mNeedsUpdate(true)
     671               8 :     , mManifestHashInitialized(false)
     672                 : {
     673               8 :     ReadStrictFileOriginPolicyPref();
     674               8 : }
     675                 : 
     676              16 : nsOfflineManifestItem::~nsOfflineManifestItem()
     677                 : {
     678              32 : }
     679                 : 
     680                 : //-----------------------------------------------------------------------------
     681                 : // nsOfflineManifestItem <private>
     682                 : //-----------------------------------------------------------------------------
     683                 : 
     684                 : /* static */
     685                 : NS_METHOD
     686               8 : nsOfflineManifestItem::ReadManifest(nsIInputStream *aInputStream,
     687                 :                                     void *aClosure,
     688                 :                                     const char *aFromSegment,
     689                 :                                     PRUint32 aOffset,
     690                 :                                     PRUint32 aCount,
     691                 :                                     PRUint32 *aBytesConsumed)
     692                 : {
     693                 :     nsOfflineManifestItem *manifest =
     694               8 :         static_cast<nsOfflineManifestItem*>(aClosure);
     695                 : 
     696                 :     nsresult rv;
     697                 : 
     698               8 :     *aBytesConsumed = aCount;
     699                 : 
     700               8 :     if (manifest->mParserState == PARSE_ERROR) {
     701                 :         // parse already failed, ignore this
     702               0 :         return NS_OK;
     703                 :     }
     704                 : 
     705               8 :     if (!manifest->mManifestHashInitialized) {
     706                 :         // Avoid re-creation of crypto hash when it fails from some reason the first time
     707               8 :         manifest->mManifestHashInitialized = true;
     708                 : 
     709               8 :         manifest->mManifestHash = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
     710               8 :         if (NS_SUCCEEDED(rv)) {
     711               8 :             rv = manifest->mManifestHash->Init(nsICryptoHash::MD5);
     712               8 :             if (NS_FAILED(rv)) {
     713               0 :                 manifest->mManifestHash = nsnull;
     714               0 :                 LOG(("Could not initialize manifest hash for byte-to-byte check, rv=%08x", rv));
     715                 :             }
     716                 :         }
     717                 :     }
     718                 : 
     719               8 :     if (manifest->mManifestHash) {
     720               8 :         rv = manifest->mManifestHash->Update(reinterpret_cast<const PRUint8 *>(aFromSegment), aCount);
     721               8 :         if (NS_FAILED(rv)) {
     722               0 :             manifest->mManifestHash = nsnull;
     723               0 :             LOG(("Could not update manifest hash, rv=%08x", rv));
     724                 :         }
     725                 :     }
     726                 : 
     727               8 :     manifest->mReadBuf.Append(aFromSegment, aCount);
     728                 : 
     729               8 :     nsCString::const_iterator begin, iter, end;
     730               8 :     manifest->mReadBuf.BeginReading(begin);
     731               8 :     manifest->mReadBuf.EndReading(end);
     732                 : 
     733             346 :     for (iter = begin; iter != end; iter++) {
     734             338 :         if (*iter == '\r' || *iter == '\n') {
     735              24 :             nsresult rv = manifest->HandleManifestLine(begin, iter);
     736                 :             
     737              24 :             if (NS_FAILED(rv)) {
     738               0 :                 LOG(("HandleManifestLine failed with 0x%08x", rv));
     739               0 :                 return NS_ERROR_ABORT;
     740                 :             }
     741                 : 
     742              24 :             begin = iter;
     743              24 :             begin++;
     744                 :         }
     745                 :     }
     746                 : 
     747                 :     // any leftovers are saved for next time
     748               8 :     manifest->mReadBuf = Substring(begin, end);
     749                 : 
     750               8 :     return NS_OK;
     751                 : }
     752                 : 
     753                 : nsresult
     754               8 : nsOfflineManifestItem::AddNamespace(PRUint32 namespaceType,
     755                 :                                     const nsCString &namespaceSpec,
     756                 :                                     const nsCString &data)
     757                 : 
     758                 : {
     759                 :     nsresult rv;
     760               8 :     if (!mNamespaces) {
     761               8 :         mNamespaces = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
     762               8 :         NS_ENSURE_SUCCESS(rv, rv);
     763                 :     }
     764                 : 
     765                 :     nsCOMPtr<nsIApplicationCacheNamespace> ns =
     766              16 :         do_CreateInstance(NS_APPLICATIONCACHENAMESPACE_CONTRACTID, &rv);
     767               8 :     NS_ENSURE_SUCCESS(rv, rv);
     768                 : 
     769               8 :     rv = ns->Init(namespaceType, namespaceSpec, data);
     770               8 :     NS_ENSURE_SUCCESS(rv, rv);
     771                 : 
     772               8 :     rv = mNamespaces->AppendElement(ns, false);
     773               8 :     NS_ENSURE_SUCCESS(rv, rv);
     774                 : 
     775               8 :     return NS_OK;
     776                 : }
     777                 : 
     778                 : nsresult
     779              32 : nsOfflineManifestItem::HandleManifestLine(const nsCString::const_iterator &aBegin,
     780                 :                                           const nsCString::const_iterator &aEnd)
     781                 : {
     782              32 :     nsCString::const_iterator begin = aBegin;
     783              32 :     nsCString::const_iterator end = aEnd;
     784                 : 
     785                 :     // all lines ignore trailing spaces and tabs
     786              32 :     nsCString::const_iterator last = end;
     787              32 :     --last;
     788              64 :     while (end != begin && (*last == ' ' || *last == '\t')) {
     789               0 :         --end;
     790               0 :         --last;
     791                 :     }
     792                 : 
     793              32 :     if (mParserState == PARSE_INIT) {
     794                 :         // Allow a UTF-8 BOM
     795               8 :         if (begin != end && static_cast<unsigned char>(*begin) == 0xef) {
     796               0 :             if (++begin == end || static_cast<unsigned char>(*begin) != 0xbb ||
     797               0 :                 ++begin == end || static_cast<unsigned char>(*begin) != 0xbf) {
     798               0 :                 mParserState = PARSE_ERROR;
     799               0 :                 return NS_OK;
     800                 :             }
     801               0 :             ++begin;
     802                 :         }
     803                 : 
     804              16 :         const nsCSubstring &magic = Substring(begin, end);
     805                 : 
     806               8 :         if (!magic.EqualsLiteral("CACHE MANIFEST")) {
     807               0 :             mParserState = PARSE_ERROR;
     808               0 :             return NS_OK;
     809                 :         }
     810                 : 
     811               8 :         mParserState = PARSE_CACHE_ENTRIES;
     812               8 :         return NS_OK;
     813                 :     }
     814                 : 
     815                 :     // lines other than the first ignore leading spaces and tabs
     816              48 :     while (begin != end && (*begin == ' ' || *begin == '\t'))
     817               0 :         begin++;
     818                 : 
     819                 :     // ignore blank lines and comments
     820              24 :     if (begin == end || *begin == '#')
     821               8 :         return NS_OK;
     822                 : 
     823              32 :     const nsCSubstring &line = Substring(begin, end);
     824                 : 
     825              16 :     if (line.EqualsLiteral("CACHE:")) {
     826               0 :         mParserState = PARSE_CACHE_ENTRIES;
     827               0 :         return NS_OK;
     828                 :     }
     829                 : 
     830              16 :     if (line.EqualsLiteral("FALLBACK:")) {
     831               8 :         mParserState = PARSE_FALLBACK_ENTRIES;
     832               8 :         return NS_OK;
     833                 :     }
     834                 : 
     835               8 :     if (line.EqualsLiteral("NETWORK:")) {
     836               0 :         mParserState = PARSE_BYPASS_ENTRIES;
     837               0 :         return NS_OK;
     838                 :     }
     839                 : 
     840                 :     nsresult rv;
     841                 : 
     842               8 :     switch(mParserState) {
     843                 :     case PARSE_INIT:
     844                 :     case PARSE_ERROR: {
     845                 :         // this should have been dealt with earlier
     846               0 :         return NS_ERROR_FAILURE;
     847                 :     }
     848                 : 
     849                 :     case PARSE_CACHE_ENTRIES: {
     850               0 :         nsCOMPtr<nsIURI> uri;
     851               0 :         rv = NS_NewURI(getter_AddRefs(uri), line, nsnull, mURI);
     852               0 :         if (NS_FAILED(rv))
     853                 :             break;
     854               0 :         if (NS_FAILED(DropReferenceFromURL(uri)))
     855                 :             break;
     856                 : 
     857               0 :         nsCAutoString scheme;
     858               0 :         uri->GetScheme(scheme);
     859                 : 
     860                 :         // Manifest URIs must have the same scheme as the manifest.
     861                 :         bool match;
     862               0 :         if (NS_FAILED(mURI->SchemeIs(scheme.get(), &match)) || !match)
     863                 :             break;
     864                 : 
     865               0 :         mExplicitURIs.AppendObject(uri);
     866                 :         break;
     867                 :     }
     868                 : 
     869                 :     case PARSE_FALLBACK_ENTRIES: {
     870               8 :         PRInt32 separator = line.FindChar(' ');
     871               8 :         if (separator == kNotFound) {
     872               0 :             separator = line.FindChar('\t');
     873               0 :             if (separator == kNotFound)
     874               0 :                 break;
     875                 :         }
     876                 : 
     877              16 :         nsCString namespaceSpec(Substring(line, 0, separator));
     878              16 :         nsCString fallbackSpec(Substring(line, separator + 1));
     879               8 :         namespaceSpec.CompressWhitespace();
     880               8 :         fallbackSpec.CompressWhitespace();
     881                 : 
     882              16 :         nsCOMPtr<nsIURI> namespaceURI;
     883               8 :         rv = NS_NewURI(getter_AddRefs(namespaceURI), namespaceSpec, nsnull, mURI);
     884               8 :         if (NS_FAILED(rv))
     885                 :             break;
     886               8 :         if (NS_FAILED(DropReferenceFromURL(namespaceURI)))
     887                 :             break;
     888               8 :         rv = namespaceURI->GetAsciiSpec(namespaceSpec);
     889               8 :         if (NS_FAILED(rv))
     890                 :             break;
     891                 : 
     892                 : 
     893              16 :         nsCOMPtr<nsIURI> fallbackURI;
     894               8 :         rv = NS_NewURI(getter_AddRefs(fallbackURI), fallbackSpec, nsnull, mURI);
     895               8 :         if (NS_FAILED(rv))
     896                 :             break;
     897               8 :         if (NS_FAILED(DropReferenceFromURL(fallbackURI)))
     898                 :             break;
     899               8 :         rv = fallbackURI->GetAsciiSpec(fallbackSpec);
     900               8 :         if (NS_FAILED(rv))
     901                 :             break;
     902                 : 
     903                 :         // Manifest and namespace must be same origin
     904               8 :         if (!NS_SecurityCompareURIs(mURI, namespaceURI,
     905               8 :                                     mStrictFileOriginPolicy))
     906                 :             break;
     907                 : 
     908                 :         // Fallback and namespace must be same origin
     909               8 :         if (!NS_SecurityCompareURIs(namespaceURI, fallbackURI,
     910               8 :                                     mStrictFileOriginPolicy))
     911                 :             break;
     912                 : 
     913               8 :         mFallbackURIs.AppendObject(fallbackURI);
     914                 : 
     915                 :         AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_FALLBACK,
     916               8 :                      namespaceSpec, fallbackSpec);
     917                 :         break;
     918                 :     }
     919                 : 
     920                 :     case PARSE_BYPASS_ENTRIES: {
     921               0 :         if (line[0] == '*' && (line.Length() == 1 || line[1] == ' ' || line[1] == '\t'))
     922                 :         {
     923                 :           // '*' indicates to make the online whitelist wildcard flag open,
     924                 :           // i.e. do allow load of resources not present in the offline cache
     925                 :           // or not conforming any namespace.
     926                 :           // We achive that simply by adding an 'empty' - i.e. universal
     927                 :           // namespace of BYPASS type into the cache.
     928                 :           AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_BYPASS,
     929               0 :                        EmptyCString(), EmptyCString());
     930               0 :           break;
     931                 :         }
     932                 : 
     933               0 :         nsCOMPtr<nsIURI> bypassURI;
     934               0 :         rv = NS_NewURI(getter_AddRefs(bypassURI), line, nsnull, mURI);
     935               0 :         if (NS_FAILED(rv))
     936                 :             break;
     937                 : 
     938               0 :         nsCAutoString scheme;
     939               0 :         bypassURI->GetScheme(scheme);
     940                 :         bool equals;
     941               0 :         if (NS_FAILED(mURI->SchemeIs(scheme.get(), &equals)) || !equals)
     942                 :             break;
     943               0 :         if (NS_FAILED(DropReferenceFromURL(bypassURI)))
     944                 :             break;
     945               0 :         nsCString spec;
     946               0 :         if (NS_FAILED(bypassURI->GetAsciiSpec(spec)))
     947                 :             break;
     948                 : 
     949                 :         AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_BYPASS,
     950               0 :                      spec, EmptyCString());
     951                 :         break;
     952                 :     }
     953                 :     }
     954                 : 
     955               8 :     return NS_OK;
     956                 : }
     957                 : 
     958                 : nsresult 
     959               8 : nsOfflineManifestItem::GetOldManifestContentHash(nsIRequest *aRequest)
     960                 : {
     961                 :     nsresult rv;
     962                 : 
     963              16 :     nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv);
     964               8 :     NS_ENSURE_SUCCESS(rv, rv);
     965                 : 
     966                 :     // load the main cache token that is actually the old offline cache token and 
     967                 :     // read previous manifest content hash value
     968              16 :     nsCOMPtr<nsISupports> cacheToken;
     969               8 :     cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
     970               8 :     if (cacheToken) {
     971              16 :         nsCOMPtr<nsICacheEntryDescriptor> cacheDescriptor(do_QueryInterface(cacheToken, &rv));
     972               8 :         NS_ENSURE_SUCCESS(rv, rv);
     973                 :     
     974               8 :         rv = cacheDescriptor->GetMetaDataElement("offline-manifest-hash", getter_Copies(mOldManifestHashValue));
     975               8 :         if (NS_FAILED(rv))
     976               8 :             mOldManifestHashValue.Truncate();
     977                 :     }
     978                 : 
     979               8 :     return NS_OK;
     980                 : }
     981                 : 
     982                 : nsresult 
     983               8 : nsOfflineManifestItem::CheckNewManifestContentHash(nsIRequest *aRequest)
     984                 : {
     985                 :     nsresult rv;
     986                 : 
     987               8 :     if (!mManifestHash) {
     988                 :         // Nothing to compare against...
     989               0 :         return NS_OK;
     990                 :     }
     991                 : 
     992              16 :     nsCString newManifestHashValue;
     993               8 :     rv = mManifestHash->Finish(true, mManifestHashValue);
     994               8 :     mManifestHash = nsnull;
     995                 : 
     996               8 :     if (NS_FAILED(rv)) {
     997               0 :         LOG(("Could not finish manifest hash, rv=%08x", rv));
     998                 :         // This is not critical error
     999               0 :         return NS_OK;
    1000                 :     }
    1001                 : 
    1002               8 :     if (!ParseSucceeded()) {
    1003                 :         // Parsing failed, the hash is not valid
    1004               0 :         return NS_OK;
    1005                 :     }
    1006                 : 
    1007               8 :     if (mOldManifestHashValue == mManifestHashValue) {
    1008               0 :         LOG(("Update not needed, downloaded manifest content is byte-for-byte identical"));
    1009               0 :         mNeedsUpdate = false;
    1010                 :     }
    1011                 : 
    1012                 :     // Store the manifest content hash value to the new
    1013                 :     // offline cache token
    1014              16 :     nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(aRequest, &rv);
    1015               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1016                 : 
    1017              16 :     nsCOMPtr<nsISupports> cacheToken;
    1018               8 :     cachingChannel->GetOfflineCacheToken(getter_AddRefs(cacheToken));
    1019               8 :     if (cacheToken) {
    1020              16 :         nsCOMPtr<nsICacheEntryDescriptor> cacheDescriptor(do_QueryInterface(cacheToken, &rv));
    1021               8 :         NS_ENSURE_SUCCESS(rv, rv);
    1022                 :     
    1023               8 :         rv = cacheDescriptor->SetMetaDataElement("offline-manifest-hash", mManifestHashValue.get());
    1024               8 :         NS_ENSURE_SUCCESS(rv, rv);
    1025                 :     }
    1026                 : 
    1027               8 :     return NS_OK;
    1028                 : }
    1029                 : 
    1030                 : void
    1031               8 : nsOfflineManifestItem::ReadStrictFileOriginPolicyPref()
    1032                 : {
    1033                 :     mStrictFileOriginPolicy =
    1034               8 :         Preferences::GetBool("security.fileuri.strict_origin_policy", true);
    1035               8 : }
    1036                 : 
    1037                 : NS_IMETHODIMP
    1038               8 : nsOfflineManifestItem::OnStartRequest(nsIRequest *aRequest,
    1039                 :                                       nsISupports *aContext)
    1040                 : {
    1041                 :     nsresult rv;
    1042                 : 
    1043              16 :     nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest, &rv);
    1044               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1045                 : 
    1046                 :     bool succeeded;
    1047               8 :     rv = channel->GetRequestSucceeded(&succeeded);
    1048               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1049                 : 
    1050               8 :     if (!succeeded) {
    1051               0 :         LOG(("HTTP request failed"));
    1052               0 :         mParserState = PARSE_ERROR;
    1053               0 :         return NS_ERROR_ABORT;
    1054                 :     }
    1055                 : 
    1056              16 :     nsCAutoString contentType;
    1057               8 :     rv = channel->GetContentType(contentType);
    1058               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1059                 : 
    1060               8 :     if (!contentType.EqualsLiteral("text/cache-manifest")) {
    1061               0 :         LOG(("Rejected cache manifest with Content-Type %s (expecting text/cache-manifest)",
    1062                 :              contentType.get()));
    1063               0 :         mParserState = PARSE_ERROR;
    1064               0 :         return NS_ERROR_ABORT;
    1065                 :     }
    1066                 : 
    1067               8 :     rv = GetOldManifestContentHash(aRequest);
    1068               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1069                 : 
    1070               8 :     return nsOfflineCacheUpdateItem::OnStartRequest(aRequest, aContext);
    1071                 : }
    1072                 : 
    1073                 : NS_IMETHODIMP
    1074               8 : nsOfflineManifestItem::OnDataAvailable(nsIRequest *aRequest,
    1075                 :                                        nsISupports *aContext,
    1076                 :                                        nsIInputStream *aStream,
    1077                 :                                        PRUint32 aOffset,
    1078                 :                                        PRUint32 aCount)
    1079                 : {
    1080               8 :     PRUint32 bytesRead = 0;
    1081               8 :     aStream->ReadSegments(ReadManifest, this, aCount, &bytesRead);
    1082               8 :     mBytesRead += bytesRead;
    1083                 : 
    1084               8 :     if (mParserState == PARSE_ERROR) {
    1085               0 :         LOG(("OnDataAvailable is canceling the request due a parse error\n"));
    1086               0 :         return NS_ERROR_ABORT;
    1087                 :     }
    1088                 : 
    1089               8 :     LOG(("loaded %u bytes into offline cache [offset=%u]\n",
    1090                 :          bytesRead, aOffset));
    1091                 : 
    1092                 :     // All the parent method does is read and discard, don't bother
    1093                 :     // chaining up.
    1094                 : 
    1095               8 :     return NS_OK;
    1096                 : }
    1097                 : 
    1098                 : NS_IMETHODIMP
    1099               8 : nsOfflineManifestItem::OnStopRequest(nsIRequest *aRequest,
    1100                 :                                      nsISupports *aContext,
    1101                 :                                      nsresult aStatus)
    1102                 : {
    1103                 :     // handle any leftover manifest data
    1104               8 :     nsCString::const_iterator begin, end;
    1105               8 :     mReadBuf.BeginReading(begin);
    1106               8 :     mReadBuf.EndReading(end);
    1107               8 :     nsresult rv = HandleManifestLine(begin, end);
    1108               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1109                 : 
    1110               8 :     if (mBytesRead == 0) {
    1111                 :         // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
    1112                 :         // specified.)
    1113               0 :         mNeedsUpdate = false;
    1114                 :     } else {
    1115               8 :         rv = CheckNewManifestContentHash(aRequest);
    1116               8 :         NS_ENSURE_SUCCESS(rv, rv);
    1117                 :     }
    1118                 : 
    1119               8 :     return nsOfflineCacheUpdateItem::OnStopRequest(aRequest, aContext, aStatus);
    1120                 : }
    1121                 : 
    1122                 : //-----------------------------------------------------------------------------
    1123                 : // nsOfflineCacheUpdate::nsISupports
    1124                 : //-----------------------------------------------------------------------------
    1125                 : 
    1126             392 : NS_IMPL_ISUPPORTS2(nsOfflineCacheUpdate,
    1127                 :                    nsIOfflineCacheUpdateObserver,
    1128                 :                    nsIOfflineCacheUpdate)
    1129                 : 
    1130                 : //-----------------------------------------------------------------------------
    1131                 : // nsOfflineCacheUpdate <public>
    1132                 : //-----------------------------------------------------------------------------
    1133                 : 
    1134               8 : nsOfflineCacheUpdate::nsOfflineCacheUpdate()
    1135                 :     : mState(STATE_UNINITIALIZED)
    1136                 :     , mOwner(nsnull)
    1137                 :     , mAddedItems(false)
    1138                 :     , mPartialUpdate(false)
    1139                 :     , mSucceeded(true)
    1140                 :     , mObsolete(false)
    1141                 :     , mCurrentItem(-1)
    1142               8 :     , mRescheduleCount(0)
    1143                 : {
    1144               8 : }
    1145                 : 
    1146              16 : nsOfflineCacheUpdate::~nsOfflineCacheUpdate()
    1147                 : {
    1148               8 :     LOG(("nsOfflineCacheUpdate::~nsOfflineCacheUpdate [%p]", this));
    1149               8 : }
    1150                 : 
    1151                 : /* static */
    1152                 : nsresult
    1153              32 : nsOfflineCacheUpdate::GetCacheKey(nsIURI *aURI, nsACString &aKey)
    1154                 : {
    1155              32 :     aKey.Truncate();
    1156                 : 
    1157              64 :     nsCOMPtr<nsIURI> newURI;
    1158              32 :     nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(newURI));
    1159              32 :     NS_ENSURE_SUCCESS(rv, rv);
    1160                 : 
    1161              32 :     rv = newURI->GetAsciiSpec(aKey);
    1162              32 :     NS_ENSURE_SUCCESS(rv, rv);
    1163                 : 
    1164              32 :     return NS_OK;
    1165                 : }
    1166                 : 
    1167                 : nsresult
    1168               8 : nsOfflineCacheUpdate::Init(nsIURI *aManifestURI,
    1169                 :                            nsIURI *aDocumentURI,
    1170                 :                            nsIDOMDocument *aDocument)
    1171                 : {
    1172                 :     nsresult rv;
    1173                 : 
    1174                 :     // Make sure the service has been initialized
    1175                 :     nsOfflineCacheUpdateService* service =
    1176               8 :         nsOfflineCacheUpdateService::EnsureService();
    1177               8 :     if (!service)
    1178               0 :         return NS_ERROR_FAILURE;
    1179                 : 
    1180               8 :     LOG(("nsOfflineCacheUpdate::Init [%p]", this));
    1181                 : 
    1182               8 :     mPartialUpdate = false;
    1183                 : 
    1184                 :     // Only http and https applications are supported.
    1185                 :     bool match;
    1186               8 :     rv = aManifestURI->SchemeIs("http", &match);
    1187               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1188                 : 
    1189               8 :     if (!match) {
    1190               0 :         rv = aManifestURI->SchemeIs("https", &match);
    1191               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1192               0 :         if (!match)
    1193               0 :             return NS_ERROR_ABORT;
    1194                 :     }
    1195                 : 
    1196               8 :     mManifestURI = aManifestURI;
    1197                 : 
    1198               8 :     rv = mManifestURI->GetAsciiHost(mUpdateDomain);
    1199               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1200                 : 
    1201              16 :     nsCAutoString manifestSpec;
    1202                 : 
    1203               8 :     rv = GetCacheKey(mManifestURI, manifestSpec);
    1204               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1205                 : 
    1206               8 :     mDocumentURI = aDocumentURI;
    1207                 : 
    1208                 :     nsCOMPtr<nsIApplicationCacheService> cacheService =
    1209              16 :         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
    1210               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1211                 : 
    1212               8 :     rv = cacheService->GetActiveCache(manifestSpec,
    1213               8 :                                       getter_AddRefs(mPreviousApplicationCache));
    1214               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1215                 : 
    1216               8 :     rv = cacheService->CreateApplicationCache(manifestSpec,
    1217               8 :                                               getter_AddRefs(mApplicationCache));
    1218               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1219                 : 
    1220               8 :     rv = mApplicationCache->GetClientID(mClientID);
    1221               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1222                 : 
    1223               8 :     mState = STATE_INITIALIZED;
    1224               8 :     return NS_OK;
    1225                 : }
    1226                 : 
    1227                 : nsresult
    1228               0 : nsOfflineCacheUpdate::InitPartial(nsIURI *aManifestURI,
    1229                 :                                   const nsACString& clientID,
    1230                 :                                   nsIURI *aDocumentURI)
    1231                 : {
    1232                 :     nsresult rv;
    1233                 : 
    1234                 :     // Make sure the service has been initialized
    1235                 :     nsOfflineCacheUpdateService* service =
    1236               0 :         nsOfflineCacheUpdateService::EnsureService();
    1237               0 :     if (!service)
    1238               0 :         return NS_ERROR_FAILURE;
    1239                 : 
    1240               0 :     LOG(("nsOfflineCacheUpdate::InitPartial [%p]", this));
    1241                 : 
    1242               0 :     mPartialUpdate = true;
    1243               0 :     mClientID = clientID;
    1244               0 :     mDocumentURI = aDocumentURI;
    1245                 : 
    1246               0 :     mManifestURI = aManifestURI;
    1247               0 :     rv = mManifestURI->GetAsciiHost(mUpdateDomain);
    1248               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1249                 : 
    1250                 :     nsCOMPtr<nsIApplicationCacheService> cacheService =
    1251               0 :         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
    1252               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1253                 : 
    1254               0 :     rv = cacheService->GetApplicationCache(mClientID,
    1255               0 :                                            getter_AddRefs(mApplicationCache));
    1256               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1257                 : 
    1258               0 :     if (!mApplicationCache) {
    1259               0 :         nsCAutoString manifestSpec;
    1260               0 :         rv = GetCacheKey(mManifestURI, manifestSpec);
    1261               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1262                 : 
    1263               0 :         rv = cacheService->CreateApplicationCache
    1264               0 :             (manifestSpec, getter_AddRefs(mApplicationCache));
    1265               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1266                 :     }
    1267                 : 
    1268               0 :     nsCAutoString groupID;
    1269               0 :     rv = mApplicationCache->GetGroupID(groupID);
    1270               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1271                 : 
    1272               0 :     rv = NS_NewURI(getter_AddRefs(mManifestURI), groupID);
    1273               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1274                 : 
    1275               0 :     mState = STATE_INITIALIZED;
    1276               0 :     return NS_OK;
    1277                 : }
    1278                 : 
    1279                 : nsresult
    1280               8 : nsOfflineCacheUpdate::HandleManifest(bool *aDoUpdate)
    1281                 : {
    1282                 :     // Be pessimistic
    1283               8 :     *aDoUpdate = false;
    1284                 : 
    1285                 :     bool succeeded;
    1286               8 :     nsresult rv = mManifestItem->GetRequestSucceeded(&succeeded);
    1287               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1288                 : 
    1289               8 :     if (!succeeded || !mManifestItem->ParseSucceeded()) {
    1290               0 :         return NS_ERROR_FAILURE;
    1291                 :     }
    1292                 : 
    1293               8 :     if (!mManifestItem->NeedsUpdate()) {
    1294               0 :         return NS_OK;
    1295                 :     }
    1296                 : 
    1297                 :     // Add items requested by the manifest.
    1298               8 :     const nsCOMArray<nsIURI> &manifestURIs = mManifestItem->GetExplicitURIs();
    1299               8 :     for (PRInt32 i = 0; i < manifestURIs.Count(); i++) {
    1300               0 :         rv = AddURI(manifestURIs[i], nsIApplicationCache::ITEM_EXPLICIT);
    1301               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1302                 :     }
    1303                 : 
    1304               8 :     const nsCOMArray<nsIURI> &fallbackURIs = mManifestItem->GetFallbackURIs();
    1305              16 :     for (PRInt32 i = 0; i < fallbackURIs.Count(); i++) {
    1306               8 :         rv = AddURI(fallbackURIs[i], nsIApplicationCache::ITEM_FALLBACK);
    1307               8 :         NS_ENSURE_SUCCESS(rv, rv);
    1308                 :     }
    1309                 : 
    1310                 :     // The document that requested the manifest is implicitly included
    1311                 :     // as part of that manifest update.
    1312               8 :     rv = AddURI(mDocumentURI, nsIApplicationCache::ITEM_IMPLICIT);
    1313               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1314                 : 
    1315                 :     // Add items previously cached implicitly
    1316               8 :     rv = AddExistingItems(nsIApplicationCache::ITEM_IMPLICIT);
    1317               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1318                 : 
    1319                 :     // Add items requested by the script API
    1320               8 :     rv = AddExistingItems(nsIApplicationCache::ITEM_DYNAMIC);
    1321               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1322                 : 
    1323                 :     // Add opportunistically cached items conforming current opportunistic
    1324                 :     // namespace list
    1325                 :     rv = AddExistingItems(nsIApplicationCache::ITEM_OPPORTUNISTIC,
    1326               8 :                           &mManifestItem->GetOpportunisticNamespaces());
    1327               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1328                 : 
    1329               8 :     *aDoUpdate = true;
    1330                 : 
    1331               8 :     return NS_OK;
    1332                 : }
    1333                 : 
    1334                 : void
    1335              24 : nsOfflineCacheUpdate::LoadCompleted()
    1336                 : {
    1337                 :     nsresult rv;
    1338                 : 
    1339                 :     // Keep the object alive through a Finish() call.
    1340              48 :     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
    1341                 : 
    1342              24 :     LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this));
    1343                 : 
    1344              24 :     if (mState == STATE_CANCELLED) {
    1345               0 :         Finish();
    1346                 :         return;
    1347                 :     }
    1348                 : 
    1349              24 :     if (mState == STATE_CHECKING) {
    1350                 :         // Manifest load finished.
    1351                 : 
    1352               8 :         NS_ASSERTION(mManifestItem,
    1353                 :                      "Must have a manifest item in STATE_CHECKING.");
    1354                 : 
    1355                 :         // A 404 or 410 is interpreted as an intentional removal of
    1356                 :         // the manifest file, rather than a transient server error.
    1357                 :         // Obsolete this cache group if one of these is returned.
    1358                 :         PRUint16 status;
    1359               8 :         rv = mManifestItem->GetStatus(&status);
    1360               8 :         if (status == 404 || status == 410) {
    1361               0 :             mSucceeded = false;
    1362               0 :             mObsolete = true;
    1363               0 :             if (mPreviousApplicationCache) {
    1364               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_OBSOLETE);
    1365                 :             } else {
    1366               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1367                 :             }
    1368               0 :             Finish();
    1369                 :             return;
    1370                 :         }
    1371                 : 
    1372                 :         bool doUpdate;
    1373               8 :         if (NS_FAILED(HandleManifest(&doUpdate))) {
    1374               0 :             mSucceeded = false;
    1375               0 :             NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1376               0 :             Finish();
    1377                 :             return;
    1378                 :         }
    1379                 : 
    1380               8 :         if (!doUpdate) {
    1381               0 :             mSucceeded = false;
    1382                 : 
    1383               0 :             AssociateDocuments(mPreviousApplicationCache);
    1384                 : 
    1385               0 :             ScheduleImplicit();
    1386                 : 
    1387                 :             // If we didn't need an implicit update, we can
    1388                 :             // send noupdate and end the update now.
    1389               0 :             if (!mImplicitUpdate) {
    1390               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE);
    1391               0 :                 Finish();
    1392                 :             }
    1393                 :             return;
    1394                 :         }
    1395                 : 
    1396              16 :         rv = mApplicationCache->MarkEntry(mManifestItem->mCacheKey,
    1397              16 :                                           mManifestItem->mItemType);
    1398               8 :         if (NS_FAILED(rv)) {
    1399               0 :             mSucceeded = false;
    1400               0 :             NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1401               0 :             Finish();
    1402                 :             return;
    1403                 :         }
    1404                 : 
    1405               8 :         mState = STATE_DOWNLOADING;
    1406               8 :         NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING);
    1407                 : 
    1408                 :         // Start fetching resources.
    1409               8 :         ProcessNextURI();
    1410                 : 
    1411                 :         return;
    1412                 :     }
    1413                 : 
    1414                 :     // Normal load finished.
    1415                 : 
    1416              32 :     nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[mCurrentItem];
    1417              16 :     mCurrentItem++;
    1418                 : 
    1419                 :     bool succeeded;
    1420              16 :     rv = item->GetRequestSucceeded(&succeeded);
    1421                 : 
    1422                 :     // Check for failures.  3XX, 4XX and 5XX errors on items explicitly
    1423                 :     // listed in the manifest will cause the update to fail.
    1424              16 :     if (NS_FAILED(rv) || !succeeded) {
    1425               0 :         if (item->mItemType &
    1426                 :             (nsIApplicationCache::ITEM_EXPLICIT |
    1427                 :              nsIApplicationCache::ITEM_FALLBACK)) {
    1428               0 :             mSucceeded = false;
    1429                 :         }
    1430                 :     } else {
    1431              16 :         rv = mApplicationCache->MarkEntry(item->mCacheKey, item->mItemType);
    1432              16 :         if (NS_FAILED(rv)) {
    1433               0 :             mSucceeded = false;
    1434                 :         }
    1435                 :     }
    1436                 : 
    1437              16 :     if (!mSucceeded) {
    1438               0 :         NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1439               0 :         Finish();
    1440                 :         return;
    1441                 :     }
    1442                 : 
    1443              16 :     rv = NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMCOMPLETED);
    1444              16 :     if (NS_FAILED(rv)) return;
    1445                 : 
    1446              32 :     ProcessNextURI();
    1447                 : }
    1448                 : 
    1449                 : void
    1450               8 : nsOfflineCacheUpdate::ManifestCheckCompleted(nsresult aStatus,
    1451                 :                                              const nsCString &aManifestHash)
    1452                 : {
    1453                 :     // Keep the object alive through a Finish() call.
    1454              16 :     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
    1455                 : 
    1456               8 :     if (NS_SUCCEEDED(aStatus)) {
    1457              16 :         nsCAutoString firstManifestHash;
    1458               8 :         mManifestItem->GetManifestHash(firstManifestHash);
    1459               8 :         if (aManifestHash != firstManifestHash) {
    1460               0 :             LOG(("Manifest has changed during cache items download [%p]", this));
    1461               0 :             aStatus = NS_ERROR_FAILURE;
    1462                 :         }
    1463                 :     }
    1464                 : 
    1465               8 :     if (NS_FAILED(aStatus)) {
    1466               0 :         mSucceeded = false;
    1467               0 :         NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1468                 :     }
    1469                 : 
    1470               8 :     if (NS_FAILED(aStatus) && mRescheduleCount < kRescheduleLimit) {
    1471                 :         // Do the final stuff but prevent notification of STATE_FINISHED.  
    1472                 :         // That would disconnect listeners that are responsible for document
    1473                 :         // association after a successful update. Forwarding notifications
    1474                 :         // from a new update through this dead update to them is absolutely
    1475                 :         // correct.
    1476               0 :         FinishNoNotify();
    1477                 : 
    1478                 :         nsRefPtr<nsOfflineCacheUpdate> newUpdate =
    1479               0 :             new nsOfflineCacheUpdate();
    1480                 :         // Leave aDocument argument null. Only glues and children keep 
    1481                 :         // document instances.
    1482               0 :         newUpdate->Init(mManifestURI, mDocumentURI, nsnull);
    1483                 : 
    1484                 :         // In a rare case the manifest will not be modified on the next refetch
    1485                 :         // transfer all master document URIs to the new update to ensure that
    1486                 :         // all documents refering it will be properly cached.
    1487               0 :         for (PRInt32 i = 0; i < mDocumentURIs.Count(); i++) {
    1488               0 :             newUpdate->StickDocument(mDocumentURIs[i]);
    1489                 :         }
    1490                 : 
    1491               0 :         newUpdate->mRescheduleCount = mRescheduleCount + 1;
    1492               0 :         newUpdate->AddObserver(this, false);
    1493               0 :         newUpdate->Schedule();
    1494                 :     }
    1495                 :     else {
    1496               8 :         Finish();
    1497                 :     }
    1498               8 : }
    1499                 : 
    1500                 : nsresult
    1501               8 : nsOfflineCacheUpdate::Begin()
    1502                 : {
    1503               8 :     LOG(("nsOfflineCacheUpdate::Begin [%p]", this));
    1504                 : 
    1505                 :     // Keep the object alive through a ProcessNextURI()/Finish() call.
    1506              16 :     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
    1507                 : 
    1508               8 :     mCurrentItem = 0;
    1509                 : 
    1510               8 :     if (mPartialUpdate) {
    1511               0 :         mState = STATE_DOWNLOADING;
    1512               0 :         NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING);
    1513               0 :         ProcessNextURI();
    1514               0 :         return NS_OK;
    1515                 :     }
    1516                 : 
    1517                 :     // Start checking the manifest.
    1518              16 :     nsCOMPtr<nsIURI> uri;
    1519                 : 
    1520                 :     mManifestItem = new nsOfflineManifestItem(this, mManifestURI,
    1521                 :                                               mDocumentURI,
    1522                 :                                               mPreviousApplicationCache,
    1523              16 :                                               mClientID);
    1524               8 :     if (!mManifestItem) {
    1525               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1526                 :     }
    1527                 : 
    1528               8 :     mState = STATE_CHECKING;
    1529               8 :     NotifyState(nsIOfflineCacheUpdateObserver::STATE_CHECKING);
    1530                 : 
    1531               8 :     nsresult rv = mManifestItem->OpenChannel();
    1532               8 :     if (NS_FAILED(rv)) {
    1533               0 :         LoadCompleted();
    1534                 :     }
    1535                 : 
    1536               8 :     return NS_OK;
    1537                 : }
    1538                 : 
    1539                 : nsresult
    1540               0 : nsOfflineCacheUpdate::Cancel()
    1541                 : {
    1542               0 :     LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
    1543                 : 
    1544               0 :     mState = STATE_CANCELLED;
    1545               0 :     mSucceeded = false;
    1546                 : 
    1547               0 :     if (mCurrentItem >= 0 &&
    1548               0 :         mCurrentItem < static_cast<PRInt32>(mItems.Length())) {
    1549                 :         // Load might be running
    1550               0 :         mItems[mCurrentItem]->Cancel();
    1551                 :     }
    1552                 : 
    1553               0 :     return NS_OK;
    1554                 : }
    1555                 : 
    1556                 : //-----------------------------------------------------------------------------
    1557                 : // nsOfflineCacheUpdate <private>
    1558                 : //-----------------------------------------------------------------------------
    1559                 : 
    1560                 : nsresult
    1561              24 : nsOfflineCacheUpdate::AddExistingItems(PRUint32 aType,
    1562                 :                                        nsTArray<nsCString>* namespaceFilter)
    1563                 : {
    1564              24 :     if (!mPreviousApplicationCache) {
    1565              24 :         return NS_OK;
    1566                 :     }
    1567                 : 
    1568               0 :     if (namespaceFilter && namespaceFilter->Length() == 0) {
    1569                 :         // Don't bother to walk entries when there are no namespaces
    1570                 :         // defined.
    1571               0 :         return NS_OK;
    1572                 :     }
    1573                 : 
    1574               0 :     PRUint32 count = 0;
    1575               0 :     char **keys = nsnull;
    1576               0 :     nsresult rv = mPreviousApplicationCache->GatherEntries(aType,
    1577               0 :                                                            &count, &keys);
    1578               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1579                 : 
    1580               0 :     AutoFreeArray autoFree(count, keys);
    1581                 : 
    1582               0 :     for (PRUint32 i = 0; i < count; i++) {
    1583               0 :         if (namespaceFilter) {
    1584               0 :             bool found = false;
    1585               0 :             for (PRUint32 j = 0; j < namespaceFilter->Length() && !found; j++) {
    1586               0 :                 found = StringBeginsWith(nsDependentCString(keys[i]),
    1587               0 :                                          namespaceFilter->ElementAt(j));
    1588                 :             }
    1589                 : 
    1590               0 :             if (!found)
    1591               0 :                 continue;
    1592                 :         }
    1593                 : 
    1594               0 :         nsCOMPtr<nsIURI> uri;
    1595               0 :         if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), keys[i]))) {
    1596               0 :             rv = AddURI(uri, aType);
    1597               0 :             NS_ENSURE_SUCCESS(rv, rv);
    1598                 :         }
    1599                 :     }
    1600                 : 
    1601               0 :     return NS_OK;
    1602                 : }
    1603                 : 
    1604                 : nsresult
    1605              24 : nsOfflineCacheUpdate::ProcessNextURI()
    1606                 : {
    1607                 :     // Keep the object alive through a Finish() call.
    1608              48 :     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
    1609                 : 
    1610              24 :     LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, current=%d, numItems=%d]",
    1611                 :          this, mCurrentItem, mItems.Length()));
    1612                 : 
    1613              24 :     NS_ASSERTION(mState == STATE_DOWNLOADING,
    1614                 :                  "ProcessNextURI should only be called from the DOWNLOADING state");
    1615                 : 
    1616              24 :     if (mCurrentItem >= static_cast<PRInt32>(mItems.Length())) {
    1617               8 :         if (mPartialUpdate) {
    1618               0 :             return Finish();
    1619                 :         } else {
    1620                 :             // Verify that the manifest wasn't changed during the
    1621                 :             // update, to prevent capturing a cache while the server
    1622                 :             // is being updated.  The check will call
    1623                 :             // ManifestCheckCompleted() when it's done.
    1624                 :             nsRefPtr<nsManifestCheck> manifestCheck =
    1625              24 :                 new nsManifestCheck(this, mManifestURI, mDocumentURI);
    1626               8 :             if (NS_FAILED(manifestCheck->Begin())) {
    1627               0 :                 mSucceeded = false;
    1628               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1629               0 :                 return Finish();
    1630                 :             }
    1631                 : 
    1632               8 :             return NS_OK;
    1633                 :         }
    1634                 :     }
    1635                 : 
    1636                 : #if defined(PR_LOGGING)
    1637              16 :     if (LOG_ENABLED()) {
    1638               0 :         nsCAutoString spec;
    1639               0 :         mItems[mCurrentItem]->mURI->GetSpec(spec);
    1640               0 :         LOG(("%p: Opening channel for %s", this, spec.get()));
    1641                 :     }
    1642                 : #endif
    1643                 : 
    1644              16 :     NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMSTARTED);
    1645                 : 
    1646              16 :     nsresult rv = mItems[mCurrentItem]->OpenChannel();
    1647              16 :     if (NS_FAILED(rv)) {
    1648               0 :         LoadCompleted();
    1649               0 :         return rv;
    1650                 :     }
    1651                 : 
    1652              16 :     return NS_OK;
    1653                 : }
    1654                 : 
    1655                 : nsresult
    1656              64 : nsOfflineCacheUpdate::GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers)
    1657                 : {
    1658              64 :     for (PRInt32 i = 0; i < mWeakObservers.Count(); i++) {
    1659                 :         nsCOMPtr<nsIOfflineCacheUpdateObserver> observer =
    1660               0 :             do_QueryReferent(mWeakObservers[i]);
    1661               0 :         if (observer)
    1662               0 :             aObservers.AppendObject(observer);
    1663                 :         else
    1664               0 :             mWeakObservers.RemoveObjectAt(i--);
    1665                 :     }
    1666                 : 
    1667             128 :     for (PRInt32 i = 0; i < mObservers.Count(); i++) {
    1668              64 :         aObservers.AppendObject(mObservers[i]);
    1669                 :     }
    1670                 : 
    1671              64 :     return NS_OK;
    1672                 : }
    1673                 : 
    1674                 : nsresult
    1675              56 : nsOfflineCacheUpdate::NotifyState(PRUint32 state)
    1676                 : {
    1677              56 :     LOG(("nsOfflineCacheUpdate::NotifyState [%p, %d]", this, state));
    1678                 : 
    1679             112 :     nsCOMArray<nsIOfflineCacheUpdateObserver> observers;
    1680              56 :     nsresult rv = GatherObservers(observers);
    1681              56 :     NS_ENSURE_SUCCESS(rv, rv);
    1682                 : 
    1683             112 :     for (PRInt32 i = 0; i < observers.Count(); i++) {
    1684              56 :         observers[i]->UpdateStateChanged(this, state);
    1685                 :     }
    1686                 : 
    1687              56 :     return NS_OK;
    1688                 : }
    1689                 : 
    1690                 : nsresult
    1691               8 : nsOfflineCacheUpdate::AssociateDocuments(nsIApplicationCache* cache)
    1692                 : {
    1693              16 :     nsCOMArray<nsIOfflineCacheUpdateObserver> observers;
    1694               8 :     nsresult rv = GatherObservers(observers);
    1695               8 :     NS_ENSURE_SUCCESS(rv, rv);
    1696                 : 
    1697              16 :     for (PRInt32 i = 0; i < observers.Count(); i++) {
    1698               8 :         observers[i]->ApplicationCacheAvailable(cache);
    1699                 :     }
    1700                 : 
    1701               8 :     return NS_OK;
    1702                 : }
    1703                 : 
    1704                 : void
    1705               0 : nsOfflineCacheUpdate::StickDocument(nsIURI *aDocumentURI)
    1706                 : {
    1707               0 :     if (!aDocumentURI)
    1708               0 :       return;
    1709                 : 
    1710               0 :     mDocumentURIs.AppendObject(aDocumentURI);
    1711                 : }
    1712                 : 
    1713                 : void
    1714               8 : nsOfflineCacheUpdate::SetOwner(nsOfflineCacheUpdateOwner *aOwner)
    1715                 : {
    1716               8 :     NS_ASSERTION(!mOwner, "Tried to set cache update owner twice.");
    1717               8 :     mOwner = aOwner;
    1718               8 : }
    1719                 : 
    1720                 : nsresult
    1721               0 : nsOfflineCacheUpdate::UpdateFinished(nsOfflineCacheUpdate *aUpdate)
    1722                 : {
    1723                 :     // Keep the object alive through a Finish() call.
    1724               0 :     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
    1725                 : 
    1726               0 :     mImplicitUpdate = nsnull;
    1727                 : 
    1728               0 :     NotifyState(nsIOfflineCacheUpdateObserver::STATE_NOUPDATE);
    1729               0 :     Finish();
    1730                 : 
    1731               0 :     return NS_OK;
    1732                 : }
    1733                 : 
    1734                 : nsresult
    1735               0 : nsOfflineCacheUpdate::ScheduleImplicit()
    1736                 : {
    1737               0 :     if (mDocumentURIs.Count() == 0)
    1738               0 :         return NS_OK;
    1739                 : 
    1740                 :     nsresult rv;
    1741                 : 
    1742               0 :     nsRefPtr<nsOfflineCacheUpdate> update = new nsOfflineCacheUpdate();
    1743               0 :     NS_ENSURE_TRUE(update, NS_ERROR_OUT_OF_MEMORY);
    1744                 : 
    1745               0 :     nsCAutoString clientID;
    1746               0 :     if (mPreviousApplicationCache) {
    1747               0 :         rv = mPreviousApplicationCache->GetClientID(clientID);
    1748               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1749                 :     }
    1750                 :     else {
    1751               0 :         clientID = mClientID;
    1752                 :     }
    1753                 : 
    1754               0 :     rv = update->InitPartial(mManifestURI, clientID, mDocumentURI);
    1755               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1756                 : 
    1757               0 :     for (PRInt32 i = 0; i < mDocumentURIs.Count(); i++) {
    1758                 :         rv = update->AddURI(mDocumentURIs[i], 
    1759               0 :               nsIApplicationCache::ITEM_IMPLICIT);
    1760               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1761                 :     }
    1762                 : 
    1763               0 :     update->SetOwner(this);
    1764               0 :     rv = update->Begin();
    1765               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1766                 : 
    1767               0 :     mImplicitUpdate = update;
    1768                 : 
    1769               0 :     return NS_OK;
    1770                 : }
    1771                 : 
    1772                 : nsresult
    1773               8 : nsOfflineCacheUpdate::FinishNoNotify()
    1774                 : {
    1775               8 :     LOG(("nsOfflineCacheUpdate::Finish [%p]", this));
    1776                 : 
    1777               8 :     mState = STATE_FINISHED;
    1778                 : 
    1779               8 :     if (!mPartialUpdate) {
    1780               8 :         if (mSucceeded) {
    1781               8 :             nsIArray *namespaces = mManifestItem->GetNamespaces();
    1782               8 :             nsresult rv = mApplicationCache->AddNamespaces(namespaces);
    1783               8 :             if (NS_FAILED(rv)) {
    1784               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1785               0 :                 mSucceeded = false;
    1786                 :             }
    1787                 : 
    1788               8 :             rv = mApplicationCache->Activate();
    1789               8 :             if (NS_FAILED(rv)) {
    1790               0 :                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
    1791               0 :                 mSucceeded = false;
    1792                 :             }
    1793                 : 
    1794               8 :             AssociateDocuments(mApplicationCache);
    1795                 :         }
    1796                 : 
    1797               8 :         if (mObsolete) {
    1798                 :             nsCOMPtr<nsIApplicationCacheService> appCacheService =
    1799               0 :                 do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
    1800               0 :             if (appCacheService) {
    1801               0 :                 nsCAutoString groupID;
    1802               0 :                 mApplicationCache->GetGroupID(groupID);
    1803               0 :                 appCacheService->DeactivateGroup(groupID);
    1804                 :              }
    1805                 :          }
    1806                 : 
    1807               8 :         if (!mSucceeded) {
    1808                 :             // Update was not merged, mark all the loads as failures
    1809               0 :             for (PRUint32 i = 0; i < mItems.Length(); i++) {
    1810               0 :                 mItems[i]->Cancel();
    1811                 :             }
    1812                 : 
    1813               0 :             mApplicationCache->Discard();
    1814                 :         }
    1815                 :     }
    1816                 : 
    1817               8 :     nsresult rv = NS_OK;
    1818                 : 
    1819               8 :     if (mOwner) {
    1820               8 :         rv = mOwner->UpdateFinished(this);
    1821               8 :         mOwner = nsnull;
    1822                 :     }
    1823                 : 
    1824               8 :     return rv;
    1825                 : }
    1826                 : 
    1827                 : nsresult
    1828               8 : nsOfflineCacheUpdate::Finish()
    1829                 : {
    1830               8 :     nsresult rv = FinishNoNotify();
    1831                 : 
    1832               8 :     NotifyState(nsIOfflineCacheUpdateObserver::STATE_FINISHED);
    1833                 : 
    1834               8 :     return rv;
    1835                 : }
    1836                 : 
    1837                 : //-----------------------------------------------------------------------------
    1838                 : // nsOfflineCacheUpdate::nsIOfflineCacheUpdate
    1839                 : //-----------------------------------------------------------------------------
    1840                 : 
    1841                 : NS_IMETHODIMP
    1842               0 : nsOfflineCacheUpdate::GetUpdateDomain(nsACString &aUpdateDomain)
    1843                 : {
    1844               0 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1845                 : 
    1846               0 :     aUpdateDomain = mUpdateDomain;
    1847               0 :     return NS_OK;
    1848                 : }
    1849                 : 
    1850                 : NS_IMETHODIMP
    1851               0 : nsOfflineCacheUpdate::GetStatus(PRUint16 *aStatus)
    1852                 : {
    1853               0 :     switch (mState) {
    1854                 :     case STATE_CHECKING :
    1855               0 :         *aStatus = nsIDOMOfflineResourceList::CHECKING;
    1856               0 :         return NS_OK;
    1857                 :     case STATE_DOWNLOADING :
    1858               0 :         *aStatus = nsIDOMOfflineResourceList::DOWNLOADING;
    1859               0 :         return NS_OK;
    1860                 :     default :
    1861               0 :         *aStatus = nsIDOMOfflineResourceList::IDLE;
    1862               0 :         return NS_OK;
    1863                 :     }
    1864                 : 
    1865                 :     return NS_ERROR_FAILURE;
    1866                 : }
    1867                 : 
    1868                 : NS_IMETHODIMP
    1869               0 : nsOfflineCacheUpdate::GetPartial(bool *aPartial)
    1870                 : {
    1871               0 :     *aPartial = mPartialUpdate;
    1872               0 :     return NS_OK;
    1873                 : }
    1874                 : 
    1875                 : NS_IMETHODIMP
    1876               0 : nsOfflineCacheUpdate::GetManifestURI(nsIURI **aManifestURI)
    1877                 : {
    1878               0 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1879                 : 
    1880               0 :     NS_IF_ADDREF(*aManifestURI = mManifestURI);
    1881               0 :     return NS_OK;
    1882                 : }
    1883                 : 
    1884                 : NS_IMETHODIMP
    1885               0 : nsOfflineCacheUpdate::GetSucceeded(bool *aSucceeded)
    1886                 : {
    1887               0 :     NS_ENSURE_TRUE(mState == STATE_FINISHED, NS_ERROR_NOT_AVAILABLE);
    1888                 : 
    1889               0 :     *aSucceeded = mSucceeded;
    1890                 : 
    1891               0 :     return NS_OK;
    1892                 : }
    1893                 : 
    1894                 : NS_IMETHODIMP
    1895               0 : nsOfflineCacheUpdate::GetIsUpgrade(bool *aIsUpgrade)
    1896                 : {
    1897               0 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1898                 : 
    1899               0 :     *aIsUpgrade = (mPreviousApplicationCache != nsnull);
    1900                 : 
    1901               0 :     return NS_OK;
    1902                 : }
    1903                 : 
    1904                 : nsresult
    1905              16 : nsOfflineCacheUpdate::AddURI(nsIURI *aURI, PRUint32 aType)
    1906                 : {
    1907              16 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1908                 : 
    1909              16 :     if (mState >= STATE_DOWNLOADING)
    1910               0 :         return NS_ERROR_NOT_AVAILABLE;
    1911                 : 
    1912                 :     // Resource URIs must have the same scheme as the manifest.
    1913              32 :     nsCAutoString scheme;
    1914              16 :     aURI->GetScheme(scheme);
    1915                 : 
    1916                 :     bool match;
    1917              16 :     if (NS_FAILED(mManifestURI->SchemeIs(scheme.get(), &match)) || !match)
    1918               0 :         return NS_ERROR_FAILURE;
    1919                 : 
    1920                 :     // Don't fetch the same URI twice.
    1921              24 :     for (PRUint32 i = 0; i < mItems.Length(); i++) {
    1922                 :         bool equals;
    1923               8 :         if (NS_SUCCEEDED(mItems[i]->mURI->Equals(aURI, &equals)) && equals) {
    1924                 :             // retain both types.
    1925               0 :             mItems[i]->mItemType |= aType;
    1926               0 :             return NS_OK;
    1927                 :         }
    1928                 :     }
    1929                 : 
    1930                 :     nsRefPtr<nsOfflineCacheUpdateItem> item =
    1931                 :         new nsOfflineCacheUpdateItem(this, aURI, mDocumentURI,
    1932                 :                                      mPreviousApplicationCache, mClientID,
    1933              48 :                                      aType);
    1934              16 :     if (!item) return NS_ERROR_OUT_OF_MEMORY;
    1935                 : 
    1936              16 :     mItems.AppendElement(item);
    1937              16 :     mAddedItems = true;
    1938                 : 
    1939              16 :     return NS_OK;
    1940                 : }
    1941                 : 
    1942                 : NS_IMETHODIMP
    1943               0 : nsOfflineCacheUpdate::AddDynamicURI(nsIURI *aURI)
    1944                 : {
    1945               0 :     if (GeckoProcessType_Default != XRE_GetProcessType()) 
    1946               0 :         return NS_ERROR_NOT_IMPLEMENTED;
    1947                 : 
    1948                 :     // If this is a partial update and the resource is already in the
    1949                 :     // cache, we should only mark the entry, not fetch it again.
    1950               0 :     if (mPartialUpdate) {
    1951               0 :         nsCAutoString key;
    1952               0 :         GetCacheKey(aURI, key);
    1953                 : 
    1954                 :         PRUint32 types;
    1955               0 :         nsresult rv = mApplicationCache->GetTypes(key, &types);
    1956               0 :         if (NS_SUCCEEDED(rv)) {
    1957               0 :             if (!(types & nsIApplicationCache::ITEM_DYNAMIC)) {
    1958               0 :                 mApplicationCache->MarkEntry
    1959               0 :                     (key, nsIApplicationCache::ITEM_DYNAMIC);
    1960                 :             }
    1961               0 :             return NS_OK;
    1962                 :         }
    1963                 :     }
    1964                 : 
    1965               0 :     return AddURI(aURI, nsIApplicationCache::ITEM_DYNAMIC);
    1966                 : }
    1967                 : 
    1968                 : NS_IMETHODIMP
    1969               8 : nsOfflineCacheUpdate::AddObserver(nsIOfflineCacheUpdateObserver *aObserver,
    1970                 :                                   bool aHoldWeak)
    1971                 : {
    1972               8 :     LOG(("nsOfflineCacheUpdate::AddObserver [%p] to update [%p]", aObserver, this));
    1973                 : 
    1974               8 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1975                 : 
    1976               8 :     if (aHoldWeak) {
    1977               0 :         nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(aObserver);
    1978               0 :         mWeakObservers.AppendObject(weakRef);
    1979                 :     } else {
    1980               8 :         mObservers.AppendObject(aObserver);
    1981                 :     }
    1982                 : 
    1983               8 :     return NS_OK;
    1984                 : }
    1985                 : 
    1986                 : NS_IMETHODIMP
    1987               8 : nsOfflineCacheUpdate::RemoveObserver(nsIOfflineCacheUpdateObserver *aObserver)
    1988                 : {
    1989               8 :     LOG(("nsOfflineCacheUpdate::RemoveObserver [%p] from update [%p]", aObserver, this));
    1990                 : 
    1991               8 :     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
    1992                 : 
    1993               8 :     for (PRInt32 i = 0; i < mWeakObservers.Count(); i++) {
    1994                 :         nsCOMPtr<nsIOfflineCacheUpdateObserver> observer =
    1995               0 :             do_QueryReferent(mWeakObservers[i]);
    1996               0 :         if (observer == aObserver) {
    1997               0 :             mWeakObservers.RemoveObjectAt(i);
    1998               0 :             return NS_OK;
    1999                 :         }
    2000                 :     }
    2001                 : 
    2002               8 :     for (PRInt32 i = 0; i < mObservers.Count(); i++) {
    2003               8 :         if (mObservers[i] == aObserver) {
    2004               8 :             mObservers.RemoveObjectAt(i);
    2005               8 :             return NS_OK;
    2006                 :         }
    2007                 :     }
    2008                 : 
    2009               0 :     return NS_OK;
    2010                 : }
    2011                 : 
    2012                 : 
    2013                 : NS_IMETHODIMP
    2014               8 : nsOfflineCacheUpdate::Schedule()
    2015                 : {
    2016               8 :     LOG(("nsOfflineCacheUpdate::Schedule [%p]", this));
    2017                 : 
    2018                 :     nsOfflineCacheUpdateService* service =
    2019               8 :         nsOfflineCacheUpdateService::EnsureService();
    2020                 : 
    2021               8 :     if (!service) {
    2022               0 :         return NS_ERROR_FAILURE;
    2023                 :     }
    2024                 : 
    2025               8 :     return service->ScheduleUpdate(this);
    2026                 : }
    2027                 : 
    2028                 : NS_IMETHODIMP
    2029               0 : nsOfflineCacheUpdate::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate,
    2030                 :                                          PRUint32 aState)
    2031                 : {
    2032               0 :     if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED) {
    2033                 :         // Take the mSucceeded flag from the underlying update, we will be
    2034                 :         // queried for it soon. mSucceeded of this update is false (manifest 
    2035                 :         // check failed) but the subsequent re-fetch update might succeed
    2036                 :         bool succeeded;
    2037               0 :         aUpdate->GetSucceeded(&succeeded);
    2038               0 :         mSucceeded = succeeded;
    2039                 :     }
    2040                 : 
    2041               0 :     nsresult rv = NotifyState(aState);
    2042               0 :     if (aState == nsIOfflineCacheUpdateObserver::STATE_FINISHED)
    2043               0 :         aUpdate->RemoveObserver(this);
    2044                 : 
    2045               0 :     return rv;
    2046                 : }
    2047                 : 
    2048                 : NS_IMETHODIMP
    2049               0 : nsOfflineCacheUpdate::ApplicationCacheAvailable(nsIApplicationCache *applicationCache)
    2050                 : {
    2051               0 :     return AssociateDocuments(applicationCache);
    2052                 : }

Generated by: LCOV version 1.7