dom/src/offline/nsDOMOfflineResourceList.cpp

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

mercurial