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
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/
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
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
23 * Dave Camp <dcamp@mozilla.com>
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.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsOfflineCacheUpdate.h"
41 #include "nsCPrefetchService.h"
42 #include "nsCURILoader.h"
43 #include "nsIApplicationCacheContainer.h"
44 #include "nsIApplicationCacheChannel.h"
45 #include "nsIApplicationCacheService.h"
47 #include "nsICacheService.h"
48 #include "nsICacheSession.h"
49 #include "nsICachingChannel.h"
50 #include "nsIContent.h"
51 #include "nsIDocumentLoader.h"
52 #include "nsIDOMElement.h"
53 #include "nsIDOMWindow.h"
54 #include "nsIDOMOfflineResourceList.h"
55 #include "nsIDocument.h"
56 #include "nsIObserverService.h"
58 #include "nsIWebProgress.h"
59 #include "nsICryptoHash.h"
60 #include "nsICacheEntryDescriptor.h"
61 #include "nsIPermissionManager.h"
62 #include "nsIPrincipal.h"
63 #include "nsIPrefBranch.h"
64 #include "nsIPrefService.h"
66 #include "nsNetUtil.h"
67 #include "nsServiceManagerUtils.h"
68 #include "nsStreamUtils.h"
69 #include "nsThreadUtils.h"
72 static nsOfflineCacheUpdateService
*gOfflineCacheUpdateService
= nsnull
;
74 static const PRUint32 kRescheduleLimit
= 3;
76 #if defined(PR_LOGGING)
78 // To enable logging (see prlog.h for full details):
80 // set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
81 // set NSPR_LOG_FILE=offlineupdate.log
83 // this enables PR_LOG_ALWAYS level information and places all output in
84 // the file offlineupdate.log
86 static PRLogModuleInfo
*gOfflineCacheUpdateLog
;
88 #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args)
89 #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4)
93 AutoFreeArray(PRUint32 count
, char **values
)
94 : mCount(count
), mValues(values
) {};
95 ~AutoFreeArray() { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount
, mValues
); }
102 DropReferenceFromURL(nsIURI
* aURI
)
104 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
106 nsresult rv
= url
->SetRef(EmptyCString());
107 NS_ENSURE_SUCCESS(rv
, rv
);
113 //-----------------------------------------------------------------------------
115 //-----------------------------------------------------------------------------
117 class nsManifestCheck
: public nsIStreamListener
118 , public nsIChannelEventSink
119 , public nsIInterfaceRequestor
122 nsManifestCheck(nsOfflineCacheUpdate
*aUpdate
,
124 nsIURI
*aReferrerURI
)
127 , mReferrerURI(aReferrerURI
)
131 NS_DECL_NSIREQUESTOBSERVER
132 NS_DECL_NSISTREAMLISTENER
133 NS_DECL_NSICHANNELEVENTSINK
134 NS_DECL_NSIINTERFACEREQUESTOR
140 static NS_METHOD
ReadManifest(nsIInputStream
*aInputStream
,
142 const char *aFromSegment
,
145 PRUint32
*aBytesConsumed
);
147 nsRefPtr
<nsOfflineCacheUpdate
> mUpdate
;
148 nsCOMPtr
<nsIURI
> mURI
;
149 nsCOMPtr
<nsIURI
> mReferrerURI
;
150 nsCOMPtr
<nsICryptoHash
> mManifestHash
;
151 nsCOMPtr
<nsIChannel
> mChannel
;
154 //-----------------------------------------------------------------------------
155 // nsManifestCheck::nsISupports
156 //-----------------------------------------------------------------------------
157 NS_IMPL_ISUPPORTS4(nsManifestCheck
,
161 nsIInterfaceRequestor
)
163 //-----------------------------------------------------------------------------
164 // nsManifestCheck <public>
165 //-----------------------------------------------------------------------------
168 nsManifestCheck::Begin()
171 mManifestHash
= do_CreateInstance("@mozilla.org/security/hash;1", &rv
);
172 NS_ENSURE_SUCCESS(rv
, rv
);
174 rv
= mManifestHash
->Init(nsICryptoHash::MD5
);
175 NS_ENSURE_SUCCESS(rv
, rv
);
177 rv
= NS_NewChannel(getter_AddRefs(mChannel
),
179 nsnull
, nsnull
, nsnull
,
180 nsIRequest::LOAD_BYPASS_CACHE
);
181 NS_ENSURE_SUCCESS(rv
, rv
);
183 // configure HTTP specific stuff
184 nsCOMPtr
<nsIHttpChannel
> httpChannel
=
185 do_QueryInterface(mChannel
);
187 httpChannel
->SetReferrer(mReferrerURI
);
188 httpChannel
->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
189 NS_LITERAL_CSTRING("offline-resource"),
193 rv
= mChannel
->AsyncOpen(this, nsnull
);
194 NS_ENSURE_SUCCESS(rv
, rv
);
199 //-----------------------------------------------------------------------------
200 // nsManifestCheck <public>
201 //-----------------------------------------------------------------------------
205 nsManifestCheck::ReadManifest(nsIInputStream
*aInputStream
,
207 const char *aFromSegment
,
210 PRUint32
*aBytesConsumed
)
212 nsManifestCheck
*manifestCheck
=
213 static_cast<nsManifestCheck
*>(aClosure
);
216 *aBytesConsumed
= aCount
;
218 rv
= manifestCheck
->mManifestHash
->Update(
219 reinterpret_cast<const PRUint8
*>(aFromSegment
), aCount
);
220 NS_ENSURE_SUCCESS(rv
, rv
);
225 //-----------------------------------------------------------------------------
226 // nsManifestCheck::nsIStreamListener
227 //-----------------------------------------------------------------------------
230 nsManifestCheck::OnStartRequest(nsIRequest
*aRequest
,
231 nsISupports
*aContext
)
237 nsManifestCheck::OnDataAvailable(nsIRequest
*aRequest
,
238 nsISupports
*aContext
,
239 nsIInputStream
*aStream
,
244 aStream
->ReadSegments(ReadManifest
, this, aCount
, &bytesRead
);
249 nsManifestCheck::OnStopRequest(nsIRequest
*aRequest
,
250 nsISupports
*aContext
,
253 nsCAutoString manifestHash
;
254 if (NS_SUCCEEDED(aStatus
)) {
255 mManifestHash
->Finish(PR_TRUE
, manifestHash
);
258 mUpdate
->ManifestCheckCompleted(aStatus
, manifestHash
);
263 //-----------------------------------------------------------------------------
264 // nsManifestCheck::nsIInterfaceRequestor
265 //-----------------------------------------------------------------------------
268 nsManifestCheck::GetInterface(const nsIID
&aIID
, void **aResult
)
270 if (aIID
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
272 *aResult
= static_cast<nsIChannelEventSink
*>(this);
276 return NS_ERROR_NO_INTERFACE
;
279 //-----------------------------------------------------------------------------
280 // nsManifestCheck::nsIChannelEventSink
281 //-----------------------------------------------------------------------------
284 nsManifestCheck::OnChannelRedirect(nsIChannel
*aOldChannel
,
285 nsIChannel
*aNewChannel
,
288 // Redirects should cause the load (and therefore the update) to fail.
289 if (aFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
)
291 aOldChannel
->Cancel(NS_ERROR_ABORT
);
292 return NS_ERROR_ABORT
;
295 //-----------------------------------------------------------------------------
296 // nsOfflineCacheUpdateItem::nsISupports
297 //-----------------------------------------------------------------------------
299 NS_IMPL_ISUPPORTS6(nsOfflineCacheUpdateItem
,
304 nsIInterfaceRequestor
,
307 //-----------------------------------------------------------------------------
308 // nsOfflineCacheUpdateItem <public>
309 //-----------------------------------------------------------------------------
311 nsOfflineCacheUpdateItem::nsOfflineCacheUpdateItem(nsOfflineCacheUpdate
*aUpdate
,
313 nsIURI
*aReferrerURI
,
314 nsIApplicationCache
*aPreviousApplicationCache
,
315 const nsACString
&aClientID
,
318 , mReferrerURI(aReferrerURI
)
319 , mPreviousApplicationCache(aPreviousApplicationCache
)
320 , mClientID(aClientID
)
324 , mState(nsIDOMLoadStatus::UNINITIALIZED
)
329 nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem()
334 nsOfflineCacheUpdateItem::OpenChannel()
336 #if defined(PR_LOGGING)
340 LOG(("%p: Opening channel for %s", this, spec
.get()));
344 nsresult rv
= nsOfflineCacheUpdate::GetCacheKey(mURI
, mCacheKey
);
345 NS_ENSURE_SUCCESS(rv
, rv
);
347 rv
= NS_NewChannel(getter_AddRefs(mChannel
),
349 nsnull
, nsnull
, this,
350 nsIRequest::LOAD_BACKGROUND
|
351 nsICachingChannel::LOAD_ONLY_IF_MODIFIED
|
352 nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE
);
353 NS_ENSURE_SUCCESS(rv
, rv
);
355 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
356 do_QueryInterface(mChannel
, &rv
);
358 // Support for nsIApplicationCacheChannel is required.
359 NS_ENSURE_SUCCESS(rv
, rv
);
361 // Use the existing application cache as the cache to check.
362 rv
= appCacheChannel
->SetApplicationCache(mPreviousApplicationCache
);
363 NS_ENSURE_SUCCESS(rv
, rv
);
365 // configure HTTP specific stuff
366 nsCOMPtr
<nsIHttpChannel
> httpChannel
=
367 do_QueryInterface(mChannel
);
369 httpChannel
->SetReferrer(mReferrerURI
);
370 httpChannel
->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
371 NS_LITERAL_CSTRING("offline-resource"),
375 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
376 do_QueryInterface(mChannel
);
377 if (cachingChannel
) {
378 rv
= cachingChannel
->SetCacheForOfflineUse(PR_TRUE
);
379 NS_ENSURE_SUCCESS(rv
, rv
);
381 if (!mClientID
.IsEmpty()) {
382 rv
= cachingChannel
->SetOfflineCacheClientID(mClientID
);
383 NS_ENSURE_SUCCESS(rv
, rv
);
387 rv
= mChannel
->AsyncOpen(this, nsnull
);
388 NS_ENSURE_SUCCESS(rv
, rv
);
390 mState
= nsIDOMLoadStatus::REQUESTED
;
396 nsOfflineCacheUpdateItem::Cancel()
399 mChannel
->Cancel(NS_ERROR_ABORT
);
403 mState
= nsIDOMLoadStatus::UNINITIALIZED
;
408 //-----------------------------------------------------------------------------
409 // nsOfflineCacheUpdateItem::nsIStreamListener
410 //-----------------------------------------------------------------------------
413 nsOfflineCacheUpdateItem::OnStartRequest(nsIRequest
*aRequest
,
414 nsISupports
*aContext
)
416 mState
= nsIDOMLoadStatus::RECEIVING
;
422 nsOfflineCacheUpdateItem::OnDataAvailable(nsIRequest
*aRequest
,
423 nsISupports
*aContext
,
424 nsIInputStream
*aStream
,
428 PRUint32 bytesRead
= 0;
429 aStream
->ReadSegments(NS_DiscardSegment
, nsnull
, aCount
, &bytesRead
);
430 mBytesRead
+= bytesRead
;
431 LOG(("loaded %u bytes into offline cache [offset=%u]\n",
432 bytesRead
, aOffset
));
437 nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest
*aRequest
,
438 nsISupports
*aContext
,
441 LOG(("done fetching offline item [status=%x]\n", aStatus
));
443 mState
= nsIDOMLoadStatus::LOADED
;
445 if (mBytesRead
== 0 && aStatus
== NS_OK
) {
446 // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
447 // specified), but the object should report loadedSize as if it
449 mChannel
->GetContentLength(&mBytesRead
);
452 // We need to notify the update that the load is complete, but we
453 // want to give the channel a chance to close the cache entries.
454 NS_DispatchToCurrentThread(this);
460 //-----------------------------------------------------------------------------
461 // nsOfflineCacheUpdateItem::nsIRunnable
462 //-----------------------------------------------------------------------------
464 nsOfflineCacheUpdateItem::Run()
466 mUpdate
->LoadCompleted();
471 //-----------------------------------------------------------------------------
472 // nsOfflineCacheUpdateItem::nsIInterfaceRequestor
473 //-----------------------------------------------------------------------------
476 nsOfflineCacheUpdateItem::GetInterface(const nsIID
&aIID
, void **aResult
)
478 if (aIID
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
480 *aResult
= static_cast<nsIChannelEventSink
*>(this);
484 return NS_ERROR_NO_INTERFACE
;
487 //-----------------------------------------------------------------------------
488 // nsOfflineCacheUpdateItem::nsIChannelEventSink
489 //-----------------------------------------------------------------------------
492 nsOfflineCacheUpdateItem::OnChannelRedirect(nsIChannel
*aOldChannel
,
493 nsIChannel
*aNewChannel
,
496 nsCOMPtr
<nsIURI
> newURI
;
497 nsresult rv
= aNewChannel
->GetURI(getter_AddRefs(newURI
));
501 nsCOMPtr
<nsICachingChannel
> oldCachingChannel
=
502 do_QueryInterface(aOldChannel
);
503 nsCOMPtr
<nsICachingChannel
> newCachingChannel
=
504 do_QueryInterface(aOldChannel
);
505 if (newCachingChannel
) {
506 rv
= newCachingChannel
->SetCacheForOfflineUse(PR_TRUE
);
507 NS_ENSURE_SUCCESS(rv
, rv
);
508 if (!mClientID
.IsEmpty()) {
509 rv
= newCachingChannel
->SetOfflineCacheClientID(mClientID
);
510 NS_ENSURE_SUCCESS(rv
, rv
);
514 nsCAutoString oldScheme
;
515 mURI
->GetScheme(oldScheme
);
518 if (NS_FAILED(newURI
->SchemeIs(oldScheme
.get(), &match
)) || !match
) {
519 LOG(("rejected: redirected to a different scheme\n"));
520 return NS_ERROR_ABORT
;
523 // HTTP request headers are not automatically forwarded to the new channel.
524 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aNewChannel
);
525 NS_ENSURE_STATE(httpChannel
);
527 httpChannel
->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
528 NS_LITERAL_CSTRING("offline-resource"),
531 mChannel
= aNewChannel
;
536 //-----------------------------------------------------------------------------
537 // nsOfflineCacheUpdateItem::nsIDOMLoadStatus
538 //-----------------------------------------------------------------------------
541 nsOfflineCacheUpdateItem::GetSource(nsIDOMNode
**aSource
)
548 nsOfflineCacheUpdateItem::GetUri(nsAString
&aURI
)
551 nsresult rv
= mURI
->GetSpec(spec
);
552 NS_ENSURE_SUCCESS(rv
, rv
);
554 CopyUTF8toUTF16(spec
, aURI
);
559 nsOfflineCacheUpdateItem::GetTotalSize(PRInt32
*aTotalSize
)
562 return mChannel
->GetContentLength(aTotalSize
);
570 nsOfflineCacheUpdateItem::GetLoadedSize(PRInt32
*aLoadedSize
)
572 *aLoadedSize
= mBytesRead
;
577 nsOfflineCacheUpdateItem::GetReadyState(PRUint16
*aReadyState
)
579 *aReadyState
= mState
;
584 nsOfflineCacheUpdateItem::GetStatus(PRUint16
*aStatus
)
592 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(mChannel
, &rv
);
593 NS_ENSURE_SUCCESS(rv
, rv
);
596 rv
= httpChannel
->GetResponseStatus(&httpStatus
);
597 if (rv
== NS_ERROR_NOT_AVAILABLE
) {
598 // Someone's calling this before we got a response... Check our
599 // ReadyState. If we're at RECEIVING or LOADED, then this means the
600 // connection errored before we got any data; return a somewhat
601 // sensible error code in that case.
602 if (mState
>= nsIDOMLoadStatus::RECEIVING
) {
603 *aStatus
= NS_ERROR_NOT_AVAILABLE
;
611 NS_ENSURE_SUCCESS(rv
, rv
);
612 *aStatus
= PRUint16(httpStatus
);
616 //-----------------------------------------------------------------------------
617 // nsOfflineManifestItem
618 //-----------------------------------------------------------------------------
620 //-----------------------------------------------------------------------------
621 // nsOfflineManifestItem <public>
622 //-----------------------------------------------------------------------------
624 nsOfflineManifestItem::nsOfflineManifestItem(nsOfflineCacheUpdate
*aUpdate
,
626 nsIURI
*aReferrerURI
,
627 nsIApplicationCache
*aPreviousApplicationCache
,
628 const nsACString
&aClientID
)
629 : nsOfflineCacheUpdateItem(aUpdate
, aURI
, aReferrerURI
,
630 aPreviousApplicationCache
, aClientID
,
631 nsIApplicationCache::ITEM_MANIFEST
)
632 , mParserState(PARSE_INIT
)
633 , mNeedsUpdate(PR_TRUE
)
634 , mManifestHashInitialized(PR_FALSE
)
636 ReadStrictFileOriginPolicyPref();
639 nsOfflineManifestItem::~nsOfflineManifestItem()
643 //-----------------------------------------------------------------------------
644 // nsOfflineManifestItem <private>
645 //-----------------------------------------------------------------------------
649 nsOfflineManifestItem::ReadManifest(nsIInputStream
*aInputStream
,
651 const char *aFromSegment
,
654 PRUint32
*aBytesConsumed
)
656 nsOfflineManifestItem
*manifest
=
657 static_cast<nsOfflineManifestItem
*>(aClosure
);
661 *aBytesConsumed
= aCount
;
663 if (manifest
->mParserState
== PARSE_ERROR
) {
664 // parse already failed, ignore this
668 if (!manifest
->mManifestHashInitialized
) {
669 // Avoid re-creation of crypto hash when it fails from some reason the first time
670 manifest
->mManifestHashInitialized
= PR_TRUE
;
672 manifest
->mManifestHash
= do_CreateInstance("@mozilla.org/security/hash;1", &rv
);
673 if (NS_SUCCEEDED(rv
)) {
674 rv
= manifest
->mManifestHash
->Init(nsICryptoHash::MD5
);
676 manifest
->mManifestHash
= nsnull
;
677 LOG(("Could not initialize manifest hash for byte-to-byte check, rv=%08x", rv
));
682 if (manifest
->mManifestHash
) {
683 rv
= manifest
->mManifestHash
->Update(reinterpret_cast<const PRUint8
*>(aFromSegment
), aCount
);
685 manifest
->mManifestHash
= nsnull
;
686 LOG(("Could not update manifest hash, rv=%08x", rv
));
690 manifest
->mReadBuf
.Append(aFromSegment
, aCount
);
692 nsCString::const_iterator begin
, iter
, end
;
693 manifest
->mReadBuf
.BeginReading(begin
);
694 manifest
->mReadBuf
.EndReading(end
);
696 for (iter
= begin
; iter
!= end
; iter
++) {
697 if (*iter
== '\r' || *iter
== '\n') {
698 nsresult rv
= manifest
->HandleManifestLine(begin
, iter
);
701 LOG(("HandleManifestLine failed with 0x%08x", rv
));
702 return NS_ERROR_ABORT
;
710 // any leftovers are saved for next time
711 manifest
->mReadBuf
= Substring(begin
, end
);
717 nsOfflineManifestItem::AddNamespace(PRUint32 namespaceType
,
718 const nsCString
&namespaceSpec
,
719 const nsCString
&data
)
724 mNamespaces
= do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
725 NS_ENSURE_SUCCESS(rv
, rv
);
728 nsCOMPtr
<nsIApplicationCacheNamespace
> ns
=
729 do_CreateInstance(NS_APPLICATIONCACHENAMESPACE_CONTRACTID
, &rv
);
730 NS_ENSURE_SUCCESS(rv
, rv
);
732 rv
= ns
->Init(namespaceType
, namespaceSpec
, data
);
733 NS_ENSURE_SUCCESS(rv
, rv
);
735 rv
= mNamespaces
->AppendElement(ns
, PR_FALSE
);
736 NS_ENSURE_SUCCESS(rv
, rv
);
742 nsOfflineManifestItem::HandleManifestLine(const nsCString::const_iterator
&aBegin
,
743 const nsCString::const_iterator
&aEnd
)
745 nsCString::const_iterator begin
= aBegin
;
746 nsCString::const_iterator end
= aEnd
;
748 // all lines ignore trailing spaces and tabs
749 nsCString::const_iterator last
= end
;
751 while (end
!= begin
&& (*last
== ' ' || *last
== '\t')) {
756 if (mParserState
== PARSE_INIT
) {
758 if (begin
!= end
&& static_cast<unsigned char>(*begin
) == 0xef) {
759 if (++begin
== end
|| static_cast<unsigned char>(*begin
) != 0xbb ||
760 ++begin
== end
|| static_cast<unsigned char>(*begin
) != 0xbf) {
761 mParserState
= PARSE_ERROR
;
767 const nsCSubstring
&magic
= Substring(begin
, end
);
769 if (!magic
.EqualsLiteral("CACHE MANIFEST")) {
770 mParserState
= PARSE_ERROR
;
774 mParserState
= PARSE_CACHE_ENTRIES
;
778 // lines other than the first ignore leading spaces and tabs
779 while (begin
!= end
&& (*begin
== ' ' || *begin
== '\t'))
782 // ignore blank lines and comments
783 if (begin
== end
|| *begin
== '#')
786 const nsCSubstring
&line
= Substring(begin
, end
);
788 if (line
.EqualsLiteral("CACHE:")) {
789 mParserState
= PARSE_CACHE_ENTRIES
;
793 if (line
.EqualsLiteral("FALLBACK:")) {
794 mParserState
= PARSE_FALLBACK_ENTRIES
;
798 if (line
.EqualsLiteral("NETWORK:")) {
799 mParserState
= PARSE_BYPASS_ENTRIES
;
805 switch(mParserState
) {
808 // this should have been dealt with earlier
809 return NS_ERROR_FAILURE
;
812 case PARSE_CACHE_ENTRIES
: {
813 nsCOMPtr
<nsIURI
> uri
;
814 rv
= NS_NewURI(getter_AddRefs(uri
), line
, nsnull
, mURI
);
817 if (NS_FAILED(DropReferenceFromURL(uri
)))
820 nsCAutoString scheme
;
821 uri
->GetScheme(scheme
);
823 // Manifest URIs must have the same scheme as the manifest.
825 if (NS_FAILED(mURI
->SchemeIs(scheme
.get(), &match
)) || !match
)
828 mExplicitURIs
.AppendObject(uri
);
832 case PARSE_FALLBACK_ENTRIES
: {
833 PRInt32 separator
= line
.FindChar(' ');
834 if (separator
== kNotFound
) {
835 separator
= line
.FindChar('\t');
836 if (separator
== kNotFound
)
840 nsCString
namespaceSpec(Substring(line
, 0, separator
));
841 nsCString
fallbackSpec(Substring(line
, separator
+ 1));
842 namespaceSpec
.CompressWhitespace();
843 fallbackSpec
.CompressWhitespace();
845 nsCOMPtr
<nsIURI
> namespaceURI
;
846 rv
= NS_NewURI(getter_AddRefs(namespaceURI
), namespaceSpec
, nsnull
, mURI
);
849 if (NS_FAILED(DropReferenceFromURL(namespaceURI
)))
851 rv
= namespaceURI
->GetAsciiSpec(namespaceSpec
);
856 nsCOMPtr
<nsIURI
> fallbackURI
;
857 rv
= NS_NewURI(getter_AddRefs(fallbackURI
), fallbackSpec
, nsnull
, mURI
);
860 if (NS_FAILED(DropReferenceFromURL(fallbackURI
)))
862 rv
= fallbackURI
->GetAsciiSpec(fallbackSpec
);
866 // Manifest and namespace must be same origin
867 if (!NS_SecurityCompareURIs(mURI
, namespaceURI
,
868 mStrictFileOriginPolicy
))
871 // Fallback and namespace must be same origin
872 if (!NS_SecurityCompareURIs(namespaceURI
, fallbackURI
,
873 mStrictFileOriginPolicy
))
876 mFallbackURIs
.AppendObject(fallbackURI
);
878 AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_FALLBACK
,
879 namespaceSpec
, fallbackSpec
);
883 case PARSE_BYPASS_ENTRIES
: {
884 nsCOMPtr
<nsIURI
> bypassURI
;
885 rv
= NS_NewURI(getter_AddRefs(bypassURI
), line
, nsnull
, mURI
);
889 nsCAutoString scheme
;
890 bypassURI
->GetScheme(scheme
);
892 if (NS_FAILED(mURI
->SchemeIs(scheme
.get(), &equals
)) || !equals
)
894 if (NS_FAILED(DropReferenceFromURL(bypassURI
)))
897 if (NS_FAILED(bypassURI
->GetAsciiSpec(spec
)))
900 AddNamespace(nsIApplicationCacheNamespace::NAMESPACE_BYPASS
,
901 spec
, EmptyCString());
910 nsOfflineManifestItem::GetOldManifestContentHash(nsIRequest
*aRequest
)
914 nsCOMPtr
<nsICachingChannel
> cachingChannel
= do_QueryInterface(aRequest
, &rv
);
915 NS_ENSURE_SUCCESS(rv
, rv
);
917 // load the main cache token that is actually the old offline cache token and
918 // read previous manifest content hash value
919 nsCOMPtr
<nsISupports
> cacheToken
;
920 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
922 nsCOMPtr
<nsICacheEntryDescriptor
> cacheDescriptor(do_QueryInterface(cacheToken
, &rv
));
923 NS_ENSURE_SUCCESS(rv
, rv
);
925 rv
= cacheDescriptor
->GetMetaDataElement("offline-manifest-hash", getter_Copies(mOldManifestHashValue
));
927 mOldManifestHashValue
.Truncate();
934 nsOfflineManifestItem::CheckNewManifestContentHash(nsIRequest
*aRequest
)
938 if (!mManifestHash
) {
939 // Nothing to compare against...
943 nsCString newManifestHashValue
;
944 rv
= mManifestHash
->Finish(PR_TRUE
, mManifestHashValue
);
945 mManifestHash
= nsnull
;
948 LOG(("Could not finish manifest hash, rv=%08x", rv
));
949 // This is not critical error
953 if (!ParseSucceeded()) {
954 // Parsing failed, the hash is not valid
958 if (mOldManifestHashValue
== mManifestHashValue
) {
959 LOG(("Update not needed, downloaded manifest content is byte-for-byte identical"));
960 mNeedsUpdate
= PR_FALSE
;
963 // Store the manifest content hash value to the new
964 // offline cache token
965 nsCOMPtr
<nsICachingChannel
> cachingChannel
= do_QueryInterface(aRequest
, &rv
);
966 NS_ENSURE_SUCCESS(rv
, rv
);
968 nsCOMPtr
<nsISupports
> cacheToken
;
969 cachingChannel
->GetOfflineCacheToken(getter_AddRefs(cacheToken
));
971 nsCOMPtr
<nsICacheEntryDescriptor
> cacheDescriptor(do_QueryInterface(cacheToken
, &rv
));
972 NS_ENSURE_SUCCESS(rv
, rv
);
974 rv
= cacheDescriptor
->SetMetaDataElement("offline-manifest-hash", mManifestHashValue
.get());
975 NS_ENSURE_SUCCESS(rv
, rv
);
982 nsOfflineManifestItem::ReadStrictFileOriginPolicyPref()
984 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
985 mStrictFileOriginPolicy
=
987 NS_FAILED(prefs
->GetBoolPref("security.fileuri.strict_origin_policy",
988 &mStrictFileOriginPolicy
)));
992 nsOfflineManifestItem::OnStartRequest(nsIRequest
*aRequest
,
993 nsISupports
*aContext
)
997 nsCOMPtr
<nsIHttpChannel
> channel
= do_QueryInterface(aRequest
, &rv
);
998 NS_ENSURE_SUCCESS(rv
, rv
);
1001 rv
= channel
->GetRequestSucceeded(&succeeded
);
1002 NS_ENSURE_SUCCESS(rv
, rv
);
1005 LOG(("HTTP request failed"));
1006 mParserState
= PARSE_ERROR
;
1007 return NS_ERROR_ABORT
;
1010 nsCAutoString contentType
;
1011 rv
= channel
->GetContentType(contentType
);
1012 NS_ENSURE_SUCCESS(rv
, rv
);
1014 if (!contentType
.EqualsLiteral("text/cache-manifest")) {
1015 LOG(("Rejected cache manifest with Content-Type %s (expecting text/cache-manifest)",
1016 contentType
.get()));
1017 mParserState
= PARSE_ERROR
;
1018 return NS_ERROR_ABORT
;
1021 rv
= GetOldManifestContentHash(aRequest
);
1022 NS_ENSURE_SUCCESS(rv
, rv
);
1024 return nsOfflineCacheUpdateItem::OnStartRequest(aRequest
, aContext
);
1028 nsOfflineManifestItem::OnDataAvailable(nsIRequest
*aRequest
,
1029 nsISupports
*aContext
,
1030 nsIInputStream
*aStream
,
1034 PRUint32 bytesRead
= 0;
1035 aStream
->ReadSegments(ReadManifest
, this, aCount
, &bytesRead
);
1036 mBytesRead
+= bytesRead
;
1038 if (mParserState
== PARSE_ERROR
) {
1039 LOG(("OnDataAvailable is canceling the request due a parse error\n"));
1040 return NS_ERROR_ABORT
;
1043 LOG(("loaded %u bytes into offline cache [offset=%u]\n",
1044 bytesRead
, aOffset
));
1046 // All the parent method does is read and discard, don't bother
1053 nsOfflineManifestItem::OnStopRequest(nsIRequest
*aRequest
,
1054 nsISupports
*aContext
,
1057 // handle any leftover manifest data
1058 nsCString::const_iterator begin
, end
;
1059 mReadBuf
.BeginReading(begin
);
1060 mReadBuf
.EndReading(end
);
1061 nsresult rv
= HandleManifestLine(begin
, end
);
1062 NS_ENSURE_SUCCESS(rv
, rv
);
1064 if (mBytesRead
== 0) {
1065 // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
1067 mNeedsUpdate
= PR_FALSE
;
1069 rv
= CheckNewManifestContentHash(aRequest
);
1070 NS_ENSURE_SUCCESS(rv
, rv
);
1073 return nsOfflineCacheUpdateItem::OnStopRequest(aRequest
, aContext
, aStatus
);
1076 //-----------------------------------------------------------------------------
1077 // nsOfflineCacheUpdate::nsISupports
1078 //-----------------------------------------------------------------------------
1080 NS_IMPL_ISUPPORTS1(nsOfflineCacheUpdate
,
1081 nsIOfflineCacheUpdate
)
1083 //-----------------------------------------------------------------------------
1084 // nsOfflineCacheUpdate <public>
1085 //-----------------------------------------------------------------------------
1087 nsOfflineCacheUpdate::nsOfflineCacheUpdate()
1088 : mState(STATE_UNINITIALIZED
)
1089 , mAddedItems(PR_FALSE
)
1090 , mPartialUpdate(PR_FALSE
)
1091 , mSucceeded(PR_TRUE
)
1092 , mObsolete(PR_FALSE
)
1094 , mRescheduleCount(0)
1098 nsOfflineCacheUpdate::~nsOfflineCacheUpdate()
1100 LOG(("nsOfflineCacheUpdate::~nsOfflineCacheUpdate [%p]", this));
1105 nsOfflineCacheUpdate::GetCacheKey(nsIURI
*aURI
, nsACString
&aKey
)
1109 nsCOMPtr
<nsIURI
> newURI
;
1110 nsresult rv
= aURI
->Clone(getter_AddRefs(newURI
));
1111 NS_ENSURE_SUCCESS(rv
, rv
);
1113 nsCOMPtr
<nsIURL
> newURL
;
1114 newURL
= do_QueryInterface(newURI
);
1116 newURL
->SetRef(EmptyCString());
1119 rv
= newURI
->GetAsciiSpec(aKey
);
1120 NS_ENSURE_SUCCESS(rv
, rv
);
1126 nsOfflineCacheUpdate::Init(nsIURI
*aManifestURI
,
1127 nsIURI
*aDocumentURI
)
1131 // Make sure the service has been initialized
1132 nsOfflineCacheUpdateService
* service
=
1133 nsOfflineCacheUpdateService::EnsureService();
1135 return NS_ERROR_FAILURE
;
1137 LOG(("nsOfflineCacheUpdate::Init [%p]", this));
1139 mPartialUpdate
= PR_FALSE
;
1141 // Only http and https applications are supported.
1143 rv
= aManifestURI
->SchemeIs("http", &match
);
1144 NS_ENSURE_SUCCESS(rv
, rv
);
1147 rv
= aManifestURI
->SchemeIs("https", &match
);
1148 NS_ENSURE_SUCCESS(rv
, rv
);
1150 return NS_ERROR_ABORT
;
1153 mManifestURI
= aManifestURI
;
1155 rv
= mManifestURI
->GetAsciiHost(mUpdateDomain
);
1156 NS_ENSURE_SUCCESS(rv
, rv
);
1158 nsCAutoString manifestSpec
;
1160 rv
= GetCacheKey(mManifestURI
, manifestSpec
);
1161 NS_ENSURE_SUCCESS(rv
, rv
);
1163 mDocumentURI
= aDocumentURI
;
1165 nsCOMPtr
<nsIApplicationCacheService
> cacheService
=
1166 do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID
, &rv
);
1167 NS_ENSURE_SUCCESS(rv
, rv
);
1169 rv
= cacheService
->GetActiveCache(manifestSpec
,
1170 getter_AddRefs(mPreviousApplicationCache
));
1171 NS_ENSURE_SUCCESS(rv
, rv
);
1173 rv
= cacheService
->CreateApplicationCache(manifestSpec
,
1174 getter_AddRefs(mApplicationCache
));
1175 NS_ENSURE_SUCCESS(rv
, rv
);
1177 rv
= mApplicationCache
->GetClientID(mClientID
);
1178 NS_ENSURE_SUCCESS(rv
, rv
);
1180 mState
= STATE_INITIALIZED
;
1185 nsOfflineCacheUpdate::InitPartial(nsIURI
*aManifestURI
,
1186 const nsACString
& clientID
,
1187 nsIURI
*aDocumentURI
)
1191 // Make sure the service has been initialized
1192 nsOfflineCacheUpdateService
* service
=
1193 nsOfflineCacheUpdateService::EnsureService();
1195 return NS_ERROR_FAILURE
;
1197 LOG(("nsOfflineCacheUpdate::InitPartial [%p]", this));
1199 mPartialUpdate
= PR_TRUE
;
1200 mClientID
= clientID
;
1201 mDocumentURI
= aDocumentURI
;
1203 mManifestURI
= aManifestURI
;
1204 rv
= mManifestURI
->GetAsciiHost(mUpdateDomain
);
1205 NS_ENSURE_SUCCESS(rv
, rv
);
1207 nsCOMPtr
<nsIApplicationCacheService
> cacheService
=
1208 do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID
, &rv
);
1209 NS_ENSURE_SUCCESS(rv
, rv
);
1211 rv
= cacheService
->GetApplicationCache(mClientID
,
1212 getter_AddRefs(mApplicationCache
));
1213 NS_ENSURE_SUCCESS(rv
, rv
);
1215 if (!mApplicationCache
) {
1216 nsCAutoString manifestSpec
;
1217 rv
= GetCacheKey(mManifestURI
, manifestSpec
);
1218 NS_ENSURE_SUCCESS(rv
, rv
);
1220 rv
= cacheService
->CreateApplicationCache
1221 (manifestSpec
, getter_AddRefs(mApplicationCache
));
1222 NS_ENSURE_SUCCESS(rv
, rv
);
1225 nsCAutoString groupID
;
1226 rv
= mApplicationCache
->GetGroupID(groupID
);
1227 NS_ENSURE_SUCCESS(rv
, rv
);
1229 rv
= NS_NewURI(getter_AddRefs(mManifestURI
), groupID
);
1230 NS_ENSURE_SUCCESS(rv
, rv
);
1232 mState
= STATE_INITIALIZED
;
1237 nsOfflineCacheUpdate::HandleManifest(PRBool
*aDoUpdate
)
1240 *aDoUpdate
= PR_FALSE
;
1243 nsresult rv
= mManifestItem
->GetStatus(&status
);
1244 NS_ENSURE_SUCCESS(rv
, rv
);
1246 if (status
== 0 || status
>= 400 || !mManifestItem
->ParseSucceeded()) {
1247 return NS_ERROR_FAILURE
;
1250 if (!mManifestItem
->NeedsUpdate()) {
1254 // Add items requested by the manifest.
1255 const nsCOMArray
<nsIURI
> &manifestURIs
= mManifestItem
->GetExplicitURIs();
1256 for (PRInt32 i
= 0; i
< manifestURIs
.Count(); i
++) {
1257 rv
= AddURI(manifestURIs
[i
], nsIApplicationCache::ITEM_EXPLICIT
);
1258 NS_ENSURE_SUCCESS(rv
, rv
);
1261 const nsCOMArray
<nsIURI
> &fallbackURIs
= mManifestItem
->GetFallbackURIs();
1262 for (PRInt32 i
= 0; i
< fallbackURIs
.Count(); i
++) {
1263 rv
= AddURI(fallbackURIs
[i
], nsIApplicationCache::ITEM_FALLBACK
);
1264 NS_ENSURE_SUCCESS(rv
, rv
);
1267 // The document that requested the manifest is implicitly included
1268 // as part of that manifest update.
1269 rv
= AddURI(mDocumentURI
, nsIApplicationCache::ITEM_IMPLICIT
);
1270 NS_ENSURE_SUCCESS(rv
, rv
);
1272 // Add items previously cached implicitly
1273 rv
= AddExistingItems(nsIApplicationCache::ITEM_IMPLICIT
);
1274 NS_ENSURE_SUCCESS(rv
, rv
);
1276 // Add items requested by the script API
1277 rv
= AddExistingItems(nsIApplicationCache::ITEM_DYNAMIC
);
1278 NS_ENSURE_SUCCESS(rv
, rv
);
1280 // Add opportunistically cached items conforming current opportunistic
1282 rv
= AddExistingItems(nsIApplicationCache::ITEM_OPPORTUNISTIC
,
1283 &mManifestItem
->GetOpportunisticNamespaces());
1284 NS_ENSURE_SUCCESS(rv
, rv
);
1286 *aDoUpdate
= PR_TRUE
;
1292 nsOfflineCacheUpdate::LoadCompleted()
1296 LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this));
1298 if (mState
== STATE_CANCELLED
) {
1303 if (mState
== STATE_CHECKING
) {
1304 // Manifest load finished.
1306 NS_ASSERTION(mManifestItem
,
1307 "Must have a manifest item in STATE_CHECKING.");
1309 // A 404 or 410 is interpreted as an intentional removal of
1310 // the manifest file, rather than a transient server error.
1311 // Obsolete this cache group if one of these is returned.
1313 rv
= mManifestItem
->GetStatus(&status
);
1314 if (status
== 404 || status
== 410) {
1315 mSucceeded
= PR_FALSE
;
1316 mObsolete
= PR_TRUE
;
1323 if (NS_FAILED(HandleManifest(&doUpdate
))) {
1324 mSucceeded
= PR_FALSE
;
1331 mSucceeded
= PR_FALSE
;
1338 rv
= mApplicationCache
->MarkEntry(mManifestItem
->mCacheKey
,
1339 mManifestItem
->mItemType
);
1340 if (NS_FAILED(rv
)) {
1341 mSucceeded
= PR_FALSE
;
1347 mState
= STATE_DOWNLOADING
;
1348 NotifyDownloading();
1350 // Start fetching resources.
1356 // Normal load finished.
1358 nsRefPtr
<nsOfflineCacheUpdateItem
> item
= mItems
[mCurrentItem
];
1362 rv
= item
->GetStatus(&status
);
1364 // Check for failures. 4XX and 5XX errors on items explicitly
1365 // listed in the manifest will cause the update to fail.
1366 if (NS_FAILED(rv
) || status
== 0 || status
>= 400) {
1367 if (item
->mItemType
&
1368 (nsIApplicationCache::ITEM_EXPLICIT
|
1369 nsIApplicationCache::ITEM_FALLBACK
)) {
1370 mSucceeded
= PR_FALSE
;
1373 rv
= mApplicationCache
->MarkEntry(item
->mCacheKey
, item
->mItemType
);
1374 if (NS_FAILED(rv
)) {
1375 mSucceeded
= PR_FALSE
;
1385 rv
= NotifyCompleted(item
);
1386 if (NS_FAILED(rv
)) return;
1392 nsOfflineCacheUpdate::ManifestCheckCompleted(nsresult aStatus
,
1393 const nsCString
&aManifestHash
)
1395 if (NS_SUCCEEDED(aStatus
)) {
1396 nsCAutoString firstManifestHash
;
1397 mManifestItem
->GetManifestHash(firstManifestHash
);
1398 if (aManifestHash
!= firstManifestHash
) {
1399 aStatus
= NS_ERROR_FAILURE
;
1403 if (NS_FAILED(aStatus
)) {
1404 mSucceeded
= PR_FALSE
;
1410 if (NS_FAILED(aStatus
) && mRescheduleCount
< kRescheduleLimit
) {
1411 // Reschedule this update.
1412 nsRefPtr
<nsOfflineCacheUpdate
> newUpdate
=
1413 new nsOfflineCacheUpdate();
1414 newUpdate
->Init(mManifestURI
, mDocumentURI
);
1416 for (PRInt32 i
= 0; i
< mDocuments
.Count(); i
++) {
1417 newUpdate
->AddDocument(mDocuments
[i
]);
1420 newUpdate
->mRescheduleCount
= mRescheduleCount
+ 1;
1421 newUpdate
->Schedule();
1426 nsOfflineCacheUpdate::Begin()
1428 LOG(("nsOfflineCacheUpdate::Begin [%p]", this));
1432 if (mPartialUpdate
) {
1433 mState
= STATE_DOWNLOADING
;
1434 NotifyDownloading();
1439 // Start checking the manifest.
1440 nsCOMPtr
<nsIURI
> uri
;
1442 mManifestItem
= new nsOfflineManifestItem(this, mManifestURI
,
1444 mPreviousApplicationCache
,
1446 if (!mManifestItem
) {
1447 return NS_ERROR_OUT_OF_MEMORY
;
1450 mState
= STATE_CHECKING
;
1453 nsresult rv
= mManifestItem
->OpenChannel();
1454 if (NS_FAILED(rv
)) {
1462 nsOfflineCacheUpdate::Cancel()
1464 LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
1466 mState
= STATE_CANCELLED
;
1467 mSucceeded
= PR_FALSE
;
1469 if (mCurrentItem
>= 0 &&
1470 mCurrentItem
< static_cast<PRInt32
>(mItems
.Length())) {
1471 // Load might be running
1472 mItems
[mCurrentItem
]->Cancel();
1478 //-----------------------------------------------------------------------------
1479 // nsOfflineCacheUpdate <private>
1480 //-----------------------------------------------------------------------------
1483 nsOfflineCacheUpdate::AddExistingItems(PRUint32 aType
,
1484 nsTArray
<nsCString
>* namespaceFilter
)
1486 if (!mPreviousApplicationCache
) {
1490 if (namespaceFilter
&& namespaceFilter
->Length() == 0) {
1491 // Don't bother to walk entries when there are no namespaces
1497 char **keys
= nsnull
;
1498 nsresult rv
= mPreviousApplicationCache
->GatherEntries(aType
,
1500 NS_ENSURE_SUCCESS(rv
, rv
);
1502 AutoFreeArray
autoFree(count
, keys
);
1504 for (PRUint32 i
= 0; i
< count
; i
++) {
1505 if (namespaceFilter
) {
1506 PRBool found
= PR_FALSE
;
1507 for (PRUint32 j
= 0; j
< namespaceFilter
->Length() && !found
; j
++) {
1508 found
= StringBeginsWith(nsDependentCString(keys
[i
]),
1509 namespaceFilter
->ElementAt(j
));
1516 nsCOMPtr
<nsIURI
> uri
;
1517 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri
), keys
[i
]))) {
1518 rv
= AddURI(uri
, aType
);
1519 NS_ENSURE_SUCCESS(rv
, rv
);
1527 nsOfflineCacheUpdate::ProcessNextURI()
1529 LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, current=%d, numItems=%d]",
1530 this, mCurrentItem
, mItems
.Length()));
1532 NS_ASSERTION(mState
== STATE_DOWNLOADING
,
1533 "ProcessNextURI should only be called from the DOWNLOADING state");
1535 if (mCurrentItem
>= static_cast<PRInt32
>(mItems
.Length())) {
1536 if (mPartialUpdate
) {
1539 // Verify that the manifest wasn't changed during the
1540 // update, to prevent capturing a cache while the server
1541 // is being updated. The check will call
1542 // ManifestCheckCompleted() when it's done.
1543 nsRefPtr
<nsManifestCheck
> manifestCheck
=
1544 new nsManifestCheck(this, mManifestURI
, mDocumentURI
);
1545 if (NS_FAILED(manifestCheck
->Begin())) {
1546 mSucceeded
= PR_FALSE
;
1555 #if defined(PR_LOGGING)
1556 if (LOG_ENABLED()) {
1558 mItems
[mCurrentItem
]->mURI
->GetSpec(spec
);
1559 LOG(("%p: Opening channel for %s", this, spec
.get()));
1563 NotifyStarted(mItems
[mCurrentItem
]);
1565 nsresult rv
= mItems
[mCurrentItem
]->OpenChannel();
1566 if (NS_FAILED(rv
)) {
1575 nsOfflineCacheUpdate::GatherObservers(nsCOMArray
<nsIOfflineCacheUpdateObserver
> &aObservers
)
1577 for (PRInt32 i
= 0; i
< mWeakObservers
.Count(); i
++) {
1578 nsCOMPtr
<nsIOfflineCacheUpdateObserver
> observer
=
1579 do_QueryReferent(mWeakObservers
[i
]);
1581 aObservers
.AppendObject(observer
);
1583 mWeakObservers
.RemoveObjectAt(i
--);
1586 for (PRInt32 i
= 0; i
< mObservers
.Count(); i
++) {
1587 aObservers
.AppendObject(mObservers
[i
]);
1594 nsOfflineCacheUpdate::NotifyError()
1596 LOG(("nsOfflineCacheUpdate::NotifyError [%p]", this));
1598 mState
= STATE_FINISHED
;
1600 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1601 nsresult rv
= GatherObservers(observers
);
1602 NS_ENSURE_SUCCESS(rv
, rv
);
1604 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1605 observers
[i
]->Error(this);
1612 nsOfflineCacheUpdate::NotifyChecking()
1614 LOG(("nsOfflineCacheUpdate::NotifyChecking [%p]", this));
1616 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1617 nsresult rv
= GatherObservers(observers
);
1618 NS_ENSURE_SUCCESS(rv
, rv
);
1620 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1621 observers
[i
]->Checking(this);
1628 nsOfflineCacheUpdate::NotifyNoUpdate()
1630 LOG(("nsOfflineCacheUpdate::NotifyNoUpdate [%p]", this));
1632 mState
= STATE_FINISHED
;
1634 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1635 nsresult rv
= GatherObservers(observers
);
1636 NS_ENSURE_SUCCESS(rv
, rv
);
1638 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1639 observers
[i
]->NoUpdate(this);
1646 nsOfflineCacheUpdate::NotifyObsolete()
1648 LOG(("nsOfflineCacheUpdate::NotifyObsolete [%p]", this));
1650 mState
= STATE_FINISHED
;
1652 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1653 nsresult rv
= GatherObservers(observers
);
1654 NS_ENSURE_SUCCESS(rv
, rv
);
1656 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1657 observers
[i
]->Obsolete(this);
1664 nsOfflineCacheUpdate::NotifyDownloading()
1666 LOG(("nsOfflineCacheUpdate::NotifyDownloading [%p]", this));
1668 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1669 nsresult rv
= GatherObservers(observers
);
1670 NS_ENSURE_SUCCESS(rv
, rv
);
1672 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1673 observers
[i
]->Downloading(this);
1680 nsOfflineCacheUpdate::NotifyStarted(nsOfflineCacheUpdateItem
*aItem
)
1682 LOG(("nsOfflineCacheUpdate::NotifyStarted [%p, %p]", this, aItem
));
1684 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1685 nsresult rv
= GatherObservers(observers
);
1686 NS_ENSURE_SUCCESS(rv
, rv
);
1688 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1689 observers
[i
]->ItemStarted(this, aItem
);
1696 nsOfflineCacheUpdate::NotifyCompleted(nsOfflineCacheUpdateItem
*aItem
)
1698 LOG(("nsOfflineCacheUpdate::NotifyCompleted [%p, %p]", this, aItem
));
1700 nsCOMArray
<nsIOfflineCacheUpdateObserver
> observers
;
1701 nsresult rv
= GatherObservers(observers
);
1702 NS_ENSURE_SUCCESS(rv
, rv
);
1704 for (PRInt32 i
= 0; i
< observers
.Count(); i
++) {
1705 observers
[i
]->ItemCompleted(this, aItem
);
1712 nsOfflineCacheUpdate::AddDocument(nsIDOMDocument
*aDocument
)
1714 // Add document only if it was not loaded from an offline cache.
1715 // If it were loaded from an offline cache then it has already
1716 // been associated with it and must not be again cached as
1717 // implicit (which are the reasons we collect documents here).
1718 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(aDocument
);
1722 nsIChannel
* channel
= document
->GetChannel();
1723 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
1724 do_QueryInterface(channel
);
1725 if (!appCacheChannel
)
1728 PRBool loadedFromAppCache
;
1729 appCacheChannel
->GetLoadedFromApplicationCache(&loadedFromAppCache
);
1730 if (loadedFromAppCache
)
1733 mDocuments
.AppendObject(aDocument
);
1737 nsOfflineCacheUpdate::ScheduleImplicit()
1739 if (mDocuments
.Count() == 0)
1744 nsRefPtr
<nsOfflineCacheUpdate
> update
= new nsOfflineCacheUpdate();
1745 NS_ENSURE_TRUE(update
, NS_ERROR_OUT_OF_MEMORY
);
1747 nsCAutoString clientID
;
1748 if (mPreviousApplicationCache
) {
1749 rv
= mPreviousApplicationCache
->GetClientID(clientID
);
1750 NS_ENSURE_SUCCESS(rv
, rv
);
1753 clientID
= mClientID
;
1756 rv
= update
->InitPartial(mManifestURI
, clientID
, mDocumentURI
);
1757 NS_ENSURE_SUCCESS(rv
, rv
);
1759 PRBool added
= PR_FALSE
;
1760 for (PRInt32 i
= 0; i
< mDocuments
.Count(); i
++) {
1761 nsIDOMDocument
* domDoc
= mDocuments
[i
];
1762 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
1766 nsIURI
* uri
= doc
->GetDocumentURI();
1770 nsIContent
* content
= doc
->GetRootContent();
1771 nsCOMPtr
<nsIDOMElement
> root
= do_QueryInterface(content
);
1775 nsAutoString manifestSpec
;
1776 rv
= root
->GetAttribute(NS_LITERAL_STRING("manifest"), manifestSpec
);
1777 NS_ENSURE_SUCCESS(rv
, rv
);
1779 nsCOMPtr
<nsIURI
> manifestURI
;
1780 NS_NewURI(getter_AddRefs(manifestURI
), manifestSpec
,
1781 doc
->GetDocumentCharacterSet().get(),
1782 doc
->GetDocumentURI());
1786 rv
= update
->AddURI(uri
, nsIApplicationCache::ITEM_IMPLICIT
);
1787 NS_ENSURE_SUCCESS(rv
, rv
);
1795 rv
= update
->Schedule();
1796 NS_ENSURE_SUCCESS(rv
, rv
);
1802 nsOfflineCacheUpdate::AssociateDocument(nsIDOMDocument
*aDocument
)
1804 // Check that the document that requested this update was
1805 // previously associated with an application cache. If not, it
1806 // should be associated with the new one.
1807 nsCOMPtr
<nsIApplicationCacheContainer
> container
=
1808 do_QueryInterface(aDocument
);
1812 nsCOMPtr
<nsIApplicationCache
> existingCache
;
1813 nsresult rv
= container
->GetApplicationCache(getter_AddRefs(existingCache
));
1814 NS_ENSURE_SUCCESS(rv
, rv
);
1816 if (!existingCache
) {
1817 LOG(("Update %p: associating app cache %s to document %p", this, mClientID
.get(), aDocument
));
1819 rv
= container
->SetApplicationCache(mApplicationCache
);
1820 NS_ENSURE_SUCCESS(rv
, rv
);
1827 nsOfflineCacheUpdate::Finish()
1829 LOG(("nsOfflineCacheUpdate::Finish [%p]", this));
1831 mState
= STATE_FINISHED
;
1833 nsOfflineCacheUpdateService
* service
=
1834 nsOfflineCacheUpdateService::EnsureService();
1837 return NS_ERROR_FAILURE
;
1839 if (!mPartialUpdate
) {
1841 nsIArray
*namespaces
= mManifestItem
->GetNamespaces();
1842 nsresult rv
= mApplicationCache
->AddNamespaces(namespaces
);
1843 if (NS_FAILED(rv
)) {
1845 mSucceeded
= PR_FALSE
;
1848 rv
= mApplicationCache
->Activate();
1849 if (NS_FAILED(rv
)) {
1851 mSucceeded
= PR_FALSE
;
1854 for (PRInt32 i
= 0; i
< mDocuments
.Count(); i
++) {
1855 AssociateDocument(mDocuments
[i
]);
1860 nsCOMPtr
<nsIApplicationCacheService
> appCacheService
=
1861 do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID
);
1862 if (appCacheService
) {
1863 nsCAutoString groupID
;
1864 mApplicationCache
->GetGroupID(groupID
);
1865 appCacheService
->DeactivateGroup(groupID
);
1870 // Update was not merged, mark all the loads as failures
1871 for (PRUint32 i
= 0; i
< mItems
.Length(); i
++) {
1872 mItems
[i
]->Cancel();
1875 mApplicationCache
->Discard();
1879 return service
->UpdateFinished(this);
1882 //-----------------------------------------------------------------------------
1883 // nsOfflineCacheUpdate::nsIOfflineCacheUpdate
1884 //-----------------------------------------------------------------------------
1887 nsOfflineCacheUpdate::GetUpdateDomain(nsACString
&aUpdateDomain
)
1889 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
1891 aUpdateDomain
= mUpdateDomain
;
1896 nsOfflineCacheUpdate::GetStatus(PRUint16
*aStatus
)
1899 case STATE_CHECKING
:
1900 *aStatus
= nsIDOMOfflineResourceList::CHECKING
;
1902 case STATE_DOWNLOADING
:
1903 *aStatus
= nsIDOMOfflineResourceList::DOWNLOADING
;
1906 *aStatus
= nsIDOMOfflineResourceList::IDLE
;
1910 return NS_ERROR_FAILURE
;
1914 nsOfflineCacheUpdate::GetPartial(PRBool
*aPartial
)
1916 *aPartial
= mPartialUpdate
;
1921 nsOfflineCacheUpdate::GetManifestURI(nsIURI
**aManifestURI
)
1923 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
1925 NS_IF_ADDREF(*aManifestURI
= mManifestURI
);
1930 nsOfflineCacheUpdate::GetSucceeded(PRBool
*aSucceeded
)
1932 NS_ENSURE_TRUE(mState
== STATE_FINISHED
, NS_ERROR_NOT_AVAILABLE
);
1934 *aSucceeded
= mSucceeded
;
1940 nsOfflineCacheUpdate::GetIsUpgrade(PRBool
*aIsUpgrade
)
1942 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
1944 *aIsUpgrade
= (mPreviousApplicationCache
!= nsnull
);
1950 nsOfflineCacheUpdate::AddURI(nsIURI
*aURI
, PRUint32 aType
)
1952 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
1954 if (mState
>= STATE_DOWNLOADING
)
1955 return NS_ERROR_NOT_AVAILABLE
;
1957 // Resource URIs must have the same scheme as the manifest.
1958 nsCAutoString scheme
;
1959 aURI
->GetScheme(scheme
);
1962 if (NS_FAILED(mManifestURI
->SchemeIs(scheme
.get(), &match
)) || !match
)
1963 return NS_ERROR_FAILURE
;
1965 // Don't fetch the same URI twice.
1966 for (PRUint32 i
= 0; i
< mItems
.Length(); i
++) {
1968 if (NS_SUCCEEDED(mItems
[i
]->mURI
->Equals(aURI
, &equals
)) && equals
) {
1969 // retain both types.
1970 mItems
[i
]->mItemType
|= aType
;
1975 nsRefPtr
<nsOfflineCacheUpdateItem
> item
=
1976 new nsOfflineCacheUpdateItem(this, aURI
, mDocumentURI
,
1977 mPreviousApplicationCache
, mClientID
,
1979 if (!item
) return NS_ERROR_OUT_OF_MEMORY
;
1981 mItems
.AppendElement(item
);
1982 mAddedItems
= PR_TRUE
;
1988 nsOfflineCacheUpdate::AddDynamicURI(nsIURI
*aURI
)
1990 // If this is a partial update and the resource is already in the
1991 // cache, we should only mark the entry, not fetch it again.
1992 if (mPartialUpdate
) {
1994 GetCacheKey(aURI
, key
);
1997 nsresult rv
= mApplicationCache
->GetTypes(key
, &types
);
1998 if (NS_SUCCEEDED(rv
)) {
1999 if (!(types
& nsIApplicationCache::ITEM_DYNAMIC
)) {
2000 mApplicationCache
->MarkEntry
2001 (key
, nsIApplicationCache::ITEM_DYNAMIC
);
2007 return AddURI(aURI
, nsIApplicationCache::ITEM_DYNAMIC
);
2011 nsOfflineCacheUpdate::GetCount(PRUint32
*aNumItems
)
2013 LOG(("nsOfflineCacheUpdate::GetNumItems [%p, num=%d]",
2014 this, mItems
.Length()));
2016 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
2018 *aNumItems
= mItems
.Length();
2023 nsOfflineCacheUpdate::Item(PRUint32 aIndex
, nsIDOMLoadStatus
**aItem
)
2025 LOG(("nsOfflineCacheUpdate::GetItems [%p, index=%d]", this, aIndex
));
2027 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
2029 if (aIndex
< mItems
.Length())
2030 NS_IF_ADDREF(*aItem
= mItems
.ElementAt(aIndex
));
2038 nsOfflineCacheUpdate::AddObserver(nsIOfflineCacheUpdateObserver
*aObserver
,
2041 LOG(("nsOfflineCacheUpdate::AddObserver [%p]", this));
2043 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
2046 nsCOMPtr
<nsIWeakReference
> weakRef
= do_GetWeakReference(aObserver
);
2047 mWeakObservers
.AppendObject(weakRef
);
2049 mObservers
.AppendObject(aObserver
);
2056 nsOfflineCacheUpdate::RemoveObserver(nsIOfflineCacheUpdateObserver
*aObserver
)
2058 LOG(("nsOfflineCacheUpdate::RemoveObserver [%p]", this));
2060 NS_ENSURE_TRUE(mState
>= STATE_INITIALIZED
, NS_ERROR_NOT_INITIALIZED
);
2062 for (PRInt32 i
= 0; i
< mWeakObservers
.Count(); i
++) {
2063 nsCOMPtr
<nsIOfflineCacheUpdateObserver
> observer
=
2064 do_QueryReferent(mWeakObservers
[i
]);
2065 if (observer
== aObserver
) {
2066 mWeakObservers
.RemoveObjectAt(i
);
2071 for (PRInt32 i
= 0; i
< mObservers
.Count(); i
++) {
2072 if (mObservers
[i
] == aObserver
) {
2073 mObservers
.RemoveObjectAt(i
);
2083 nsOfflineCacheUpdate::Schedule()
2085 LOG(("nsOfflineCacheUpdate::Schedule [%p]", this));
2087 nsOfflineCacheUpdateService
* service
=
2088 nsOfflineCacheUpdateService::EnsureService();
2091 return NS_ERROR_FAILURE
;
2094 return service
->Schedule(this);
2097 //-----------------------------------------------------------------------------
2098 // nsOfflineCacheUpdateService::nsISupports
2099 //-----------------------------------------------------------------------------
2101 NS_IMPL_ISUPPORTS4(nsOfflineCacheUpdateService
,
2102 nsIOfflineCacheUpdateService
,
2103 nsIWebProgressListener
,
2105 nsISupportsWeakReference
)
2107 //-----------------------------------------------------------------------------
2108 // nsOfflineCacheUpdateService <public>
2109 //-----------------------------------------------------------------------------
2111 nsOfflineCacheUpdateService::nsOfflineCacheUpdateService()
2112 : mDisabled(PR_FALSE
)
2113 , mUpdateRunning(PR_FALSE
)
2117 nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
2119 gOfflineCacheUpdateService
= nsnull
;
2123 nsOfflineCacheUpdateService::Init()
2127 #if defined(PR_LOGGING)
2128 if (!gOfflineCacheUpdateLog
)
2129 gOfflineCacheUpdateLog
= PR_NewLogModule("nsOfflineCacheUpdate");
2132 if (!mDocUpdates
.Init())
2133 return NS_ERROR_FAILURE
;
2135 // Observe xpcom-shutdown event
2136 nsCOMPtr
<nsIObserverService
> observerService
=
2137 do_GetService("@mozilla.org/observer-service;1", &rv
);
2138 NS_ENSURE_SUCCESS(rv
, rv
);
2140 rv
= observerService
->AddObserver(this,
2141 NS_XPCOM_SHUTDOWN_OBSERVER_ID
,
2143 NS_ENSURE_SUCCESS(rv
, rv
);
2145 // Register as an observer for the document loader
2146 nsCOMPtr
<nsIWebProgress
> progress
=
2147 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
2149 nsresult rv
= progress
->AddProgressListener
2150 (this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
);
2151 NS_ENSURE_SUCCESS(rv
, rv
);
2154 gOfflineCacheUpdateService
= this;
2160 nsOfflineCacheUpdateService
*
2161 nsOfflineCacheUpdateService::GetInstance()
2163 if (!gOfflineCacheUpdateService
) {
2164 gOfflineCacheUpdateService
= new nsOfflineCacheUpdateService();
2165 if (!gOfflineCacheUpdateService
)
2167 NS_ADDREF(gOfflineCacheUpdateService
);
2168 nsresult rv
= gOfflineCacheUpdateService
->Init();
2169 if (NS_FAILED(rv
)) {
2170 NS_RELEASE(gOfflineCacheUpdateService
);
2173 return gOfflineCacheUpdateService
;
2176 NS_ADDREF(gOfflineCacheUpdateService
);
2178 return gOfflineCacheUpdateService
;
2182 nsOfflineCacheUpdateService
*
2183 nsOfflineCacheUpdateService::EnsureService()
2185 if (!gOfflineCacheUpdateService
) {
2186 // Make the service manager hold a long-lived reference to the service
2187 nsCOMPtr
<nsIOfflineCacheUpdateService
> service
=
2188 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID
);
2191 return gOfflineCacheUpdateService
;
2195 nsOfflineCacheUpdateService::Schedule(nsOfflineCacheUpdate
*aUpdate
)
2197 LOG(("nsOfflineCacheUpdateService::Schedule [%p, update=%p]",
2201 nsCOMPtr
<nsIObserverService
> observerService
=
2202 do_GetService("@mozilla.org/observer-service;1", &rv
);
2203 NS_ENSURE_SUCCESS(rv
, rv
);
2205 observerService
->NotifyObservers(static_cast<nsIOfflineCacheUpdate
*>(aUpdate
),
2206 "offline-cache-update-added",
2209 mUpdates
.AppendElement(aUpdate
);
2211 ProcessNextUpdate();
2217 nsOfflineCacheUpdateService::ScheduleOnDocumentStop(nsIURI
*aManifestURI
,
2218 nsIURI
*aDocumentURI
,
2219 nsIDOMDocument
*aDocument
)
2221 LOG(("nsOfflineCacheUpdateService::ScheduleOnDocumentStop [%p, manifestURI=%p, documentURI=%p doc=%p]",
2222 this, aManifestURI
, aDocumentURI
, aDocument
));
2224 // Proceed with cache update
2225 PendingUpdate
*update
= new PendingUpdate();
2226 update
->mManifestURI
= aManifestURI
;
2227 update
->mDocumentURI
= aDocumentURI
;
2228 if (!mDocUpdates
.Put(aDocument
, update
))
2229 return NS_ERROR_FAILURE
;
2235 nsOfflineCacheUpdateService::UpdateFinished(nsOfflineCacheUpdate
*aUpdate
)
2237 LOG(("nsOfflineCacheUpdateService::UpdateFinished [%p, update=%p]",
2240 NS_ASSERTION(mUpdates
.Length() > 0 &&
2241 mUpdates
[0] == aUpdate
, "Unknown update completed");
2243 // keep this item alive until we're done notifying observers
2244 nsRefPtr
<nsOfflineCacheUpdate
> update
= mUpdates
[0];
2245 mUpdates
.RemoveElementAt(0);
2246 mUpdateRunning
= PR_FALSE
;
2249 nsCOMPtr
<nsIObserverService
> observerService
=
2250 do_GetService("@mozilla.org/observer-service;1", &rv
);
2251 NS_ENSURE_SUCCESS(rv
, rv
);
2253 observerService
->NotifyObservers(static_cast<nsIOfflineCacheUpdate
*>(aUpdate
),
2254 "offline-cache-update-completed",
2257 ProcessNextUpdate();
2262 //-----------------------------------------------------------------------------
2263 // nsOfflineCacheUpdateService <private>
2264 //-----------------------------------------------------------------------------
2267 nsOfflineCacheUpdateService::ProcessNextUpdate()
2269 LOG(("nsOfflineCacheUpdateService::ProcessNextUpdate [%p, num=%d]",
2270 this, mUpdates
.Length()));
2273 return NS_ERROR_ABORT
;
2278 if (mUpdates
.Length() > 0) {
2279 mUpdateRunning
= PR_TRUE
;
2280 return mUpdates
[0]->Begin();
2286 //-----------------------------------------------------------------------------
2287 // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
2288 //-----------------------------------------------------------------------------
2291 nsOfflineCacheUpdateService::GetNumUpdates(PRUint32
*aNumUpdates
)
2293 LOG(("nsOfflineCacheUpdateService::GetNumUpdates [%p]", this));
2295 *aNumUpdates
= mUpdates
.Length();
2300 nsOfflineCacheUpdateService::GetUpdate(PRUint32 aIndex
,
2301 nsIOfflineCacheUpdate
**aUpdate
)
2303 LOG(("nsOfflineCacheUpdateService::GetUpdate [%p, %d]", this, aIndex
));
2305 if (aIndex
< mUpdates
.Length()) {
2306 NS_ADDREF(*aUpdate
= mUpdates
[aIndex
]);
2315 nsOfflineCacheUpdateService::Schedule(nsIURI
*aManifestURI
,
2316 nsIURI
*aDocumentURI
,
2317 nsIDOMDocument
*aDocument
,
2318 nsIOfflineCacheUpdate
**aUpdate
)
2320 // Check for existing updates
2322 for (PRUint32 i
= 0; i
< mUpdates
.Length(); i
++) {
2323 nsRefPtr
<nsOfflineCacheUpdate
> update
= mUpdates
[i
];
2326 rv
= update
->GetPartial(&partial
);
2327 NS_ENSURE_SUCCESS(rv
, rv
);
2330 // Partial updates aren't considered
2334 nsCOMPtr
<nsIURI
> manifestURI
;
2335 update
->GetManifestURI(getter_AddRefs(manifestURI
));
2338 rv
= manifestURI
->Equals(aManifestURI
, &equals
);
2341 LOG(("Document %p added to update %p", aDocument
, update
.get()));
2342 update
->AddDocument(aDocument
);
2344 NS_ADDREF(*aUpdate
= update
);
2350 // There is no existing update, start one.
2352 nsRefPtr
<nsOfflineCacheUpdate
> update
= new nsOfflineCacheUpdate();
2354 return NS_ERROR_OUT_OF_MEMORY
;
2356 rv
= update
->Init(aManifestURI
, aDocumentURI
);
2357 NS_ENSURE_SUCCESS(rv
, rv
);
2360 LOG(("First document %p added to update %p", aDocument
, update
.get()));
2361 update
->AddDocument(aDocument
);
2364 rv
= update
->Schedule();
2365 NS_ENSURE_SUCCESS(rv
, rv
);
2367 NS_ADDREF(*aUpdate
= update
);
2373 nsOfflineCacheUpdateService::ScheduleUpdate(nsIURI
*aManifestURI
,
2374 nsIURI
*aDocumentURI
,
2375 nsIOfflineCacheUpdate
**aUpdate
)
2377 return Schedule(aManifestURI
, aDocumentURI
, nsnull
, aUpdate
);
2380 //-----------------------------------------------------------------------------
2381 // nsOfflineCacheUpdateService::nsIObserver
2382 //-----------------------------------------------------------------------------
2385 nsOfflineCacheUpdateService::Observe(nsISupports
*aSubject
,
2387 const PRUnichar
*aData
)
2389 if (!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
)) {
2390 if (mUpdates
.Length() > 0)
2391 mUpdates
[0]->Cancel();
2392 mDisabled
= PR_TRUE
;
2398 //-----------------------------------------------------------------------------
2399 // nsOfflineCacheUpdateService::nsIWebProgressListener
2400 //-----------------------------------------------------------------------------
2403 nsOfflineCacheUpdateService::OnProgressChange(nsIWebProgress
*aProgress
,
2404 nsIRequest
*aRequest
,
2405 PRInt32 curSelfProgress
,
2406 PRInt32 maxSelfProgress
,
2407 PRInt32 curTotalProgress
,
2408 PRInt32 maxTotalProgress
)
2410 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
2415 nsOfflineCacheUpdateService::OnStateChange(nsIWebProgress
* aWebProgress
,
2416 nsIRequest
*aRequest
,
2417 PRUint32 progressStateFlags
,
2420 if ((progressStateFlags
& STATE_IS_DOCUMENT
) &&
2421 (progressStateFlags
& STATE_STOP
)) {
2422 if (mDocUpdates
.Count() == 0)
2425 nsCOMPtr
<nsIDOMWindow
> window
;
2426 aWebProgress
->GetDOMWindow(getter_AddRefs(window
));
2427 if (!window
) return NS_OK
;
2429 nsCOMPtr
<nsIDOMDocument
> doc
;
2430 window
->GetDocument(getter_AddRefs(doc
));
2431 if (!doc
) return NS_OK
;
2433 LOG(("nsOfflineCacheUpdateService::OnStateChange [%p, doc=%p]",
2436 PendingUpdate
*pendingUpdate
;
2437 if (mDocUpdates
.Get(doc
, &pendingUpdate
)) {
2438 // Only schedule the update if the document loaded successfully
2439 if (NS_SUCCEEDED(aStatus
)) {
2440 nsCOMPtr
<nsIOfflineCacheUpdate
> update
;
2441 Schedule(pendingUpdate
->mManifestURI
,
2442 pendingUpdate
->mDocumentURI
,
2443 doc
, getter_AddRefs(update
));
2445 mDocUpdates
.Remove(doc
);
2455 nsOfflineCacheUpdateService::OnLocationChange(nsIWebProgress
* aWebProgress
,
2456 nsIRequest
* aRequest
,
2459 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
2464 nsOfflineCacheUpdateService::OnStatusChange(nsIWebProgress
* aWebProgress
,
2465 nsIRequest
* aRequest
,
2467 const PRUnichar
* aMessage
)
2469 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
2474 nsOfflineCacheUpdateService::OnSecurityChange(nsIWebProgress
*aWebProgress
,
2475 nsIRequest
*aRequest
,
2478 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
2483 nsOfflineCacheUpdateService::OfflineAppAllowed(nsIPrincipal
*aPrincipal
,
2484 nsIPrefBranch
*aPrefBranch
,
2487 nsCOMPtr
<nsIURI
> codebaseURI
;
2488 nsresult rv
= aPrincipal
->GetURI(getter_AddRefs(codebaseURI
));
2489 NS_ENSURE_SUCCESS(rv
, rv
);
2491 return OfflineAppAllowedForURI(codebaseURI
, aPrefBranch
, aAllowed
);
2495 nsOfflineCacheUpdateService::OfflineAppAllowedForURI(nsIURI
*aURI
,
2496 nsIPrefBranch
*aPrefBranch
,
2499 *aAllowed
= PR_FALSE
;
2501 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(aURI
);
2505 // only http and https applications can use offline APIs.
2507 nsresult rv
= innerURI
->SchemeIs("http", &match
);
2508 NS_ENSURE_SUCCESS(rv
, rv
);
2511 rv
= innerURI
->SchemeIs("https", &match
);
2512 NS_ENSURE_SUCCESS(rv
, rv
);
2518 nsCOMPtr
<nsIPermissionManager
> permissionManager
=
2519 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID
);
2520 if (!permissionManager
) {
2525 permissionManager
->TestExactPermission(innerURI
, "offline-app", &perm
);
2527 if (perm
== nsIPermissionManager::UNKNOWN_ACTION
) {
2528 nsCOMPtr
<nsIPrefBranch
> branch
= aPrefBranch
;
2530 branch
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
2533 rv
= branch
->GetBoolPref("offline-apps.allow_by_default", aAllowed
);
2534 if (NS_FAILED(rv
)) {
2535 *aAllowed
= PR_FALSE
;
2542 if (perm
== nsIPermissionManager::DENY_ACTION
) {
2546 *aAllowed
= PR_TRUE
;