michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsOfflineCacheUpdate_h__ michael@0: #define nsOfflineCacheUpdate_h__ michael@0: michael@0: #include "nsIOfflineCacheUpdate.h" michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsICacheService.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIApplicationCache.h" michael@0: #include "nsIRequestObserver.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIWebProgressListener.h" michael@0: #include "nsClassHashtable.h" michael@0: #include "nsString.h" michael@0: #include "nsTArray.h" michael@0: #include "nsWeakReference.h" michael@0: #include "nsICryptoHash.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/WeakPtr.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: michael@0: class nsOfflineCacheUpdate; michael@0: michael@0: class nsICacheEntryDescriptor; michael@0: class nsIUTF8StringEnumerator; michael@0: class nsILoadContext; michael@0: michael@0: class nsOfflineCacheUpdateItem : public nsIStreamListener michael@0: , public nsIRunnable michael@0: , public nsIInterfaceRequestor michael@0: , public nsIChannelEventSink michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMLISTENER michael@0: NS_DECL_NSIRUNNABLE michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSICHANNELEVENTSINK michael@0: michael@0: nsOfflineCacheUpdateItem(nsIURI *aURI, michael@0: nsIURI *aReferrerURI, michael@0: nsIApplicationCache *aApplicationCache, michael@0: nsIApplicationCache *aPreviousApplicationCache, michael@0: uint32_t aType); michael@0: virtual ~nsOfflineCacheUpdateItem(); michael@0: michael@0: nsCOMPtr mURI; michael@0: nsCOMPtr mReferrerURI; michael@0: nsCOMPtr mApplicationCache; michael@0: nsCOMPtr mPreviousApplicationCache; michael@0: nsCString mCacheKey; michael@0: uint32_t mItemType; michael@0: michael@0: nsresult OpenChannel(nsOfflineCacheUpdate *aUpdate); michael@0: nsresult Cancel(); michael@0: nsresult GetRequestSucceeded(bool * succeeded); michael@0: michael@0: bool IsInProgress(); michael@0: bool IsScheduled(); michael@0: bool IsCompleted(); michael@0: michael@0: nsresult GetStatus(uint16_t *aStatus); michael@0: michael@0: private: michael@0: enum LoadStatus MOZ_ENUM_TYPE(uint16_t) { michael@0: UNINITIALIZED = 0U, michael@0: REQUESTED = 1U, michael@0: RECEIVING = 2U, michael@0: LOADED = 3U michael@0: }; michael@0: michael@0: nsRefPtr mUpdate; michael@0: nsCOMPtr mChannel; michael@0: uint16_t mState; michael@0: michael@0: protected: michael@0: int64_t mBytesRead; michael@0: }; michael@0: michael@0: michael@0: class nsOfflineManifestItem : public nsOfflineCacheUpdateItem michael@0: { michael@0: public: michael@0: NS_DECL_NSISTREAMLISTENER michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: michael@0: nsOfflineManifestItem(nsIURI *aURI, michael@0: nsIURI *aReferrerURI, michael@0: nsIApplicationCache *aApplicationCache, michael@0: nsIApplicationCache *aPreviousApplicationCache); michael@0: virtual ~nsOfflineManifestItem(); michael@0: michael@0: nsCOMArray &GetExplicitURIs() { return mExplicitURIs; } michael@0: nsCOMArray &GetFallbackURIs() { return mFallbackURIs; } michael@0: michael@0: nsTArray &GetOpportunisticNamespaces() michael@0: { return mOpportunisticNamespaces; } michael@0: nsIArray *GetNamespaces() michael@0: { return mNamespaces.get(); } michael@0: michael@0: bool ParseSucceeded() michael@0: { return (mParserState != PARSE_INIT && mParserState != PARSE_ERROR); } michael@0: bool NeedsUpdate() { return mParserState != PARSE_INIT && mNeedsUpdate; } michael@0: michael@0: void GetManifestHash(nsCString &aManifestHash) michael@0: { aManifestHash = mManifestHashValue; } michael@0: michael@0: private: michael@0: static NS_METHOD ReadManifest(nsIInputStream *aInputStream, michael@0: void *aClosure, michael@0: const char *aFromSegment, michael@0: uint32_t aOffset, michael@0: uint32_t aCount, michael@0: uint32_t *aBytesConsumed); michael@0: michael@0: nsresult AddNamespace(uint32_t namespaceType, michael@0: const nsCString &namespaceSpec, michael@0: const nsCString &data); michael@0: michael@0: nsresult HandleManifestLine(const nsCString::const_iterator &aBegin, michael@0: const nsCString::const_iterator &aEnd); michael@0: michael@0: /** michael@0: * Saves "offline-manifest-hash" meta data from the old offline cache michael@0: * token to mOldManifestHashValue member to be compared on michael@0: * successfull load. michael@0: */ michael@0: nsresult GetOldManifestContentHash(nsIRequest *aRequest); michael@0: /** michael@0: * This method setups the mNeedsUpdate to false when hash value michael@0: * of the just downloaded manifest file is the same as stored in cache's michael@0: * "offline-manifest-hash" meta data. Otherwise stores the new value michael@0: * to this meta data. michael@0: */ michael@0: nsresult CheckNewManifestContentHash(nsIRequest *aRequest); michael@0: michael@0: void ReadStrictFileOriginPolicyPref(); michael@0: michael@0: enum { michael@0: PARSE_INIT, michael@0: PARSE_CACHE_ENTRIES, michael@0: PARSE_FALLBACK_ENTRIES, michael@0: PARSE_BYPASS_ENTRIES, michael@0: PARSE_UNKNOWN_SECTION, michael@0: PARSE_ERROR michael@0: } mParserState; michael@0: michael@0: nsCString mReadBuf; michael@0: michael@0: nsCOMArray mExplicitURIs; michael@0: nsCOMArray mFallbackURIs; michael@0: michael@0: // All opportunistic caching namespaces. Used to decide whether michael@0: // to include previously-opportunistically-cached entries. michael@0: nsTArray mOpportunisticNamespaces; michael@0: michael@0: // Array of nsIApplicationCacheNamespace objects specified by the michael@0: // manifest. michael@0: nsCOMPtr mNamespaces; michael@0: michael@0: bool mNeedsUpdate; michael@0: bool mStrictFileOriginPolicy; michael@0: michael@0: // manifest hash data michael@0: nsCOMPtr mManifestHash; michael@0: bool mManifestHashInitialized; michael@0: nsCString mManifestHashValue; michael@0: nsCString mOldManifestHashValue; michael@0: }; michael@0: michael@0: class nsOfflineCacheUpdateOwner michael@0: : public mozilla::SupportsWeakPtr michael@0: { michael@0: public: michael@0: MOZ_DECLARE_REFCOUNTED_TYPENAME(nsOfflineCacheUpdateOwner) michael@0: virtual ~nsOfflineCacheUpdateOwner() {} michael@0: virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) = 0; michael@0: }; michael@0: michael@0: class nsOfflineCacheUpdate MOZ_FINAL : public nsIOfflineCacheUpdate michael@0: , public nsIOfflineCacheUpdateObserver michael@0: , public nsIRunnable michael@0: , public nsOfflineCacheUpdateOwner michael@0: { michael@0: public: michael@0: MOZ_DECLARE_REFCOUNTED_TYPENAME(nsOfflineCacheUpdate) michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOFFLINECACHEUPDATE michael@0: NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: nsOfflineCacheUpdate(); michael@0: ~nsOfflineCacheUpdate(); michael@0: michael@0: static nsresult GetCacheKey(nsIURI *aURI, nsACString &aKey); michael@0: michael@0: nsresult Init(); michael@0: michael@0: nsresult Begin(); michael@0: michael@0: void LoadCompleted(nsOfflineCacheUpdateItem *aItem); michael@0: void ManifestCheckCompleted(nsresult aStatus, michael@0: const nsCString &aManifestHash); michael@0: void StickDocument(nsIURI *aDocumentURI); michael@0: michael@0: void SetOwner(nsOfflineCacheUpdateOwner *aOwner); michael@0: michael@0: bool IsForGroupID(const nsCSubstring &groupID); michael@0: michael@0: virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate); michael@0: michael@0: protected: michael@0: friend class nsOfflineCacheUpdateItem; michael@0: void OnByteProgress(uint64_t byteIncrement); michael@0: michael@0: private: michael@0: nsresult InitInternal(nsIURI *aManifestURI); michael@0: nsresult HandleManifest(bool *aDoUpdate); michael@0: nsresult AddURI(nsIURI *aURI, uint32_t aItemType); michael@0: michael@0: nsresult ProcessNextURI(); michael@0: michael@0: // Adds items from the previous cache witha type matching aType. michael@0: // If namespaceFilter is non-null, only items matching the michael@0: // specified namespaces will be added. michael@0: nsresult AddExistingItems(uint32_t aType, michael@0: nsTArray* namespaceFilter = nullptr); michael@0: nsresult ScheduleImplicit(); michael@0: void AssociateDocuments(nsIApplicationCache* cache); michael@0: bool CheckUpdateAvailability(); michael@0: void NotifyUpdateAvailability(bool updateAvailable); michael@0: michael@0: void GatherObservers(nsCOMArray &aObservers); michael@0: void NotifyState(uint32_t state); michael@0: nsresult Finish(); michael@0: nsresult FinishNoNotify(); michael@0: michael@0: void AsyncFinishWithError(); michael@0: michael@0: // Find one non-pinned cache group and evict it. michael@0: nsresult EvictOneNonPinned(); michael@0: michael@0: enum { michael@0: STATE_UNINITIALIZED, michael@0: STATE_INITIALIZED, michael@0: STATE_CHECKING, michael@0: STATE_DOWNLOADING, michael@0: STATE_CANCELLED, michael@0: STATE_FINISHED michael@0: } mState; michael@0: michael@0: mozilla::WeakPtr mOwner; michael@0: michael@0: bool mAddedItems; michael@0: bool mPartialUpdate; michael@0: bool mOnlyCheckUpdate; michael@0: bool mSucceeded; michael@0: bool mObsolete; michael@0: michael@0: nsCString mUpdateDomain; michael@0: nsCString mGroupID; michael@0: nsCOMPtr mManifestURI; michael@0: nsCOMPtr mDocumentURI; michael@0: nsCOMPtr mCustomProfileDir; michael@0: michael@0: uint32_t mAppID; michael@0: bool mInBrowser; michael@0: michael@0: nsCOMPtr mUpdateAvailableObserver; michael@0: michael@0: nsCOMPtr mApplicationCache; michael@0: nsCOMPtr mPreviousApplicationCache; michael@0: michael@0: nsCOMPtr mObserverService; michael@0: michael@0: nsRefPtr mManifestItem; michael@0: michael@0: /* Items being updated */ michael@0: uint32_t mItemsInProgress; michael@0: nsTArray > mItems; michael@0: michael@0: /* Clients watching this update for changes */ michael@0: nsCOMArray mWeakObservers; michael@0: nsCOMArray mObservers; michael@0: michael@0: /* Documents that requested this update */ michael@0: nsCOMArray mDocumentURIs; michael@0: michael@0: /* Reschedule count. When an update is rescheduled due to michael@0: * mismatched manifests, the reschedule count will be increased. */ michael@0: uint32_t mRescheduleCount; michael@0: michael@0: /* Whena an entry for a pinned app is retried, retries count is michael@0: * increaded. */ michael@0: uint32_t mPinnedEntryRetriesCount; michael@0: michael@0: nsRefPtr mImplicitUpdate; michael@0: michael@0: bool mPinned; michael@0: michael@0: uint64_t mByteProgress; michael@0: }; michael@0: michael@0: class nsOfflineCacheUpdateService MOZ_FINAL : public nsIOfflineCacheUpdateService michael@0: , public nsIObserver michael@0: , public nsOfflineCacheUpdateOwner michael@0: , public nsSupportsWeakReference michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOFFLINECACHEUPDATESERVICE michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: nsOfflineCacheUpdateService(); michael@0: ~nsOfflineCacheUpdateService(); michael@0: michael@0: nsresult Init(); michael@0: michael@0: nsresult ScheduleUpdate(nsOfflineCacheUpdate *aUpdate); michael@0: nsresult FindUpdate(nsIURI *aManifestURI, michael@0: uint32_t aAppID, michael@0: bool aInBrowser, michael@0: nsOfflineCacheUpdate **aUpdate); michael@0: michael@0: nsresult Schedule(nsIURI *aManifestURI, michael@0: nsIURI *aDocumentURI, michael@0: nsIDOMDocument *aDocument, michael@0: nsIDOMWindow* aWindow, michael@0: nsIFile* aCustomProfileDir, michael@0: uint32_t aAppID, michael@0: bool aInBrowser, michael@0: nsIOfflineCacheUpdate **aUpdate); michael@0: michael@0: virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate); michael@0: michael@0: /** michael@0: * Returns the singleton nsOfflineCacheUpdateService without an addref, or michael@0: * nullptr if the service couldn't be created. michael@0: */ michael@0: static nsOfflineCacheUpdateService *EnsureService(); michael@0: michael@0: /** Addrefs and returns the singleton nsOfflineCacheUpdateService. */ michael@0: static nsOfflineCacheUpdateService *GetInstance(); michael@0: michael@0: static nsresult OfflineAppPinnedForURI(nsIURI *aDocumentURI, michael@0: nsIPrefBranch *aPrefBranch, michael@0: bool *aPinned); michael@0: michael@0: static nsTHashtable* AllowedDomains(); michael@0: michael@0: private: michael@0: nsresult ProcessNextUpdate(); michael@0: michael@0: nsTArray > mUpdates; michael@0: static nsTHashtable* mAllowedDomains; michael@0: michael@0: bool mDisabled; michael@0: bool mUpdateRunning; michael@0: bool mLowFreeSpace; michael@0: }; michael@0: michael@0: #endif