Remove PassRefPtr from "loader" directory of WebCore
[WebKit-https.git] / Source / WebCore / loader / appcache / ApplicationCacheGroup.cpp
1 /*
2  * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ApplicationCacheGroup.h"
28
29 #include "ApplicationCache.h"
30 #include "ApplicationCacheHost.h"
31 #include "ApplicationCacheResource.h"
32 #include "ApplicationCacheStorage.h"
33 #include "Chrome.h"
34 #include "ChromeClient.h"
35 #include "DOMApplicationCache.h"
36 #include "DocumentLoader.h"
37 #include "EventNames.h"
38 #include "Frame.h"
39 #include "FrameLoader.h"
40 #include "FrameLoaderClient.h"
41 #include "HTTPHeaderNames.h"
42 #include "InspectorInstrumentation.h"
43 #include "ManifestParser.h"
44 #include "Page.h"
45 #include "ProgressTracker.h"
46 #include "ResourceHandle.h"
47 #include "SecurityOrigin.h"
48 #include "Settings.h"
49 #include <wtf/HashMap.h>
50 #include <wtf/MainThread.h>
51
52 namespace WebCore {
53
54 ApplicationCacheGroup::ApplicationCacheGroup(Ref<ApplicationCacheStorage>&& storage, const URL& manifestURL)
55     : m_storage(WTFMove(storage))
56     , m_manifestURL(manifestURL)
57     , m_origin(SecurityOrigin::create(manifestURL))
58     , m_availableSpaceInQuota(ApplicationCacheStorage::unknownQuota())
59 {
60 }
61
62 ApplicationCacheGroup::~ApplicationCacheGroup()
63 {
64     ASSERT(!m_newestCache);
65     ASSERT(m_caches.isEmpty());
66
67     stopLoading();
68
69     m_storage->cacheGroupDestroyed(*this);
70 }
71     
72 ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader)
73 {
74     if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
75         return nullptr;
76
77     URL url(request.url());
78     url.removeFragmentIdentifier();
79
80     auto* page = documentLoader->frame() ? documentLoader->frame()->page() : nullptr;
81     if (!page || page->usesEphemeralSession())
82         return nullptr;
83
84     auto* group = page->applicationCacheStorage().cacheGroupForURL(url);
85     if (!group)
86         return nullptr;
87
88     ASSERT(group->newestCache());
89     ASSERT(!group->isObsolete());
90
91     return group->newestCache();
92 }
93     
94 ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader)
95 {
96     if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
97         return nullptr;
98
99     auto* frame = documentLoader->frame();
100     if (!frame)
101         return nullptr;
102
103     auto* page = frame->page();
104     if (!page)
105         return nullptr;
106
107     URL url(request.url());
108     url.removeFragmentIdentifier();
109
110     auto* group = page->applicationCacheStorage().fallbackCacheGroupForURL(url);
111     if (!group)
112         return nullptr;
113
114     ASSERT(group->newestCache());
115     ASSERT(!group->isObsolete());
116
117     return group->newestCache();
118 }
119
120 void ApplicationCacheGroup::selectCache(Frame& frame, const URL& passedManifestURL)
121 {
122     ASSERT(frame.document());
123     ASSERT(frame.page());
124     ASSERT(frame.loader().documentLoader());
125
126     if (!frame.settings().offlineWebApplicationCacheEnabled())
127         return;
128
129     auto& documentLoader = *frame.loader().documentLoader();
130     ASSERT(!documentLoader.applicationCacheHost().applicationCache());
131
132     if (passedManifestURL.isNull()) {
133         selectCacheWithoutManifestURL(frame);
134         return;
135     }
136
137     // Don't access anything on disk if private browsing is enabled.
138     if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin()->canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
139         postListenerTask(eventNames().checkingEvent, documentLoader);
140         postListenerTask(eventNames().errorEvent, documentLoader);
141         return;
142     }
143
144     URL manifestURL(passedManifestURL);
145     manifestURL.removeFragmentIdentifier();
146
147     auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache();
148     
149     if (mainResourceCache) {
150         ASSERT(mainResourceCache->group());
151         if (manifestURL == mainResourceCache->group()->m_manifestURL) {
152             // The cache may have gotten obsoleted after we've loaded from it, but before we parsed the document and saw cache manifest.
153             if (mainResourceCache->group()->isObsolete())
154                 return;
155             mainResourceCache->group()->associateDocumentLoaderWithCache(&documentLoader, mainResourceCache);
156             mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
157         } else {
158             // The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign.
159             URL resourceURL { documentLoader.responseURL() };
160             resourceURL.removeFragmentIdentifier();
161
162             ASSERT(mainResourceCache->resourceForURL(resourceURL));
163             auto& resource = *mainResourceCache->resourceForURL(resourceURL);
164
165             bool inStorage = resource.storageID();
166             resource.addType(ApplicationCacheResource::Foreign);
167             if (inStorage)
168                 frame.page()->applicationCacheStorage().storeUpdatedType(&resource, mainResourceCache);
169
170             // Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made
171             // as part of the initial load.
172             // The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation.
173             frame.navigationScheduler().scheduleLocationChange(*frame.document(), frame.document()->securityOrigin(), documentLoader.url(), frame.loader().referrer());
174         }
175         return;
176     }
177
178     // The resource was loaded from the network, check if it is a HTTP/HTTPS GET.    
179     auto& request = frame.loader().activeDocumentLoader()->request();
180
181     if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
182         return;
183
184     // Check that the resource URL has the same scheme/host/port as the manifest URL.
185     if (!protocolHostAndPortAreEqual(manifestURL, request.url()))
186         return;
187
188     auto& group = *frame.page()->applicationCacheStorage().findOrCreateCacheGroup(manifestURL);
189
190     documentLoader.applicationCacheHost().setCandidateApplicationCacheGroup(&group);
191     group.m_pendingMasterResourceLoaders.add(&documentLoader);
192     group.m_downloadingPendingMasterResourceLoadersCount++;
193
194     ASSERT(!group.m_cacheBeingUpdated || group.m_updateStatus != Idle);
195     group.update(frame, ApplicationCacheUpdateWithBrowsingContext);
196 }
197
198 void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame& frame)
199 {
200     if (!frame.settings().offlineWebApplicationCacheEnabled())
201         return;
202
203     ASSERT(frame.document());
204     ASSERT(frame.page());
205     ASSERT(frame.loader().documentLoader());
206     auto& documentLoader = *frame.loader().documentLoader();
207     ASSERT(!documentLoader.applicationCacheHost().applicationCache());
208
209     // Don't access anything on disk if private browsing is enabled.
210     if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin()->canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
211         postListenerTask(eventNames().checkingEvent, documentLoader);
212         postListenerTask(eventNames().errorEvent, documentLoader);
213         return;
214     }
215
216     if (auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache()) {
217         ASSERT(mainResourceCache->group());
218         auto& group = *mainResourceCache->group();
219         group.associateDocumentLoaderWithCache(&documentLoader, mainResourceCache);
220         group.update(frame, ApplicationCacheUpdateWithBrowsingContext);
221     }
222 }
223
224 void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader& loader)
225 {
226     ASSERT(m_pendingMasterResourceLoaders.contains(&loader));
227     ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
228     URL url = loader.url();
229     url.removeFragmentIdentifier();
230
231     switch (m_completionType) {
232     case None:
233         // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later.
234         return;
235     case NoUpdate:
236         ASSERT(!m_cacheBeingUpdated);
237         associateDocumentLoaderWithCache(&loader, m_newestCache.get());
238         if (auto* resource = m_newestCache->resourceForURL(url)) {
239             if (!(resource->type() & ApplicationCacheResource::Master)) {
240                 resource->addType(ApplicationCacheResource::Master);
241                 ASSERT(!resource->storageID());
242             }
243         } else
244             m_newestCache->addResource(ApplicationCacheResource::create(url, loader.response(), ApplicationCacheResource::Master, loader.mainResourceData()));
245         break;
246     case Failure:
247         // Cache update has been a failure, so there is no reason to keep the document associated with the incomplete cache
248         // (its main resource was not cached yet, so it is likely that the application changed significantly server-side).
249         ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
250         loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too.
251         m_associatedDocumentLoaders.remove(&loader);
252         postListenerTask(eventNames().errorEvent, loader);
253         break;
254     case Completed:
255         ASSERT(m_associatedDocumentLoaders.contains(&loader));
256         if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) {
257             if (!(resource->type() & ApplicationCacheResource::Master)) {
258                 resource->addType(ApplicationCacheResource::Master);
259                 ASSERT(!resource->storageID());
260             }
261         } else
262             m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader.response(), ApplicationCacheResource::Master, loader.mainResourceData()));
263         // The "cached" event will be posted to all associated documents once update is complete.
264         break;
265     }
266
267     ASSERT(m_downloadingPendingMasterResourceLoadersCount > 0);
268     m_downloadingPendingMasterResourceLoadersCount--;
269     checkIfLoadIsComplete();
270 }
271
272 void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader& loader)
273 {
274     ASSERT(m_pendingMasterResourceLoaders.contains(&loader));
275     ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
276
277     switch (m_completionType) {
278     case None:
279         // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later.
280         return;
281     case NoUpdate:
282         ASSERT(!m_cacheBeingUpdated);
283         // The manifest didn't change, and we have a relevant cache - but the main resource download failed mid-way, so it cannot be stored to the cache,
284         // and the loader does not get associated to it. If there are other main resources being downloaded for this cache group, they may still succeed.
285         postListenerTask(eventNames().errorEvent, loader);
286         break;
287     case Failure:
288         // Cache update failed, too.
289         ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
290         ASSERT(!loader.applicationCacheHost().applicationCache() || loader.applicationCacheHost().applicationCache()->group() == this);
291         loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too.
292         m_associatedDocumentLoaders.remove(&loader);
293         postListenerTask(eventNames().errorEvent, loader);
294         break;
295     case Completed:
296         // The cache manifest didn't list this main resource, and all cache entries were already updated successfully - but the main resource failed to load,
297         // so it cannot be stored to the cache. If there are other main resources being downloaded for this cache group, they may still succeed.
298         ASSERT(m_associatedDocumentLoaders.contains(&loader));
299         ASSERT(loader.applicationCacheHost().applicationCache() == m_cacheBeingUpdated);
300         ASSERT(!loader.applicationCacheHost().candidateApplicationCacheGroup());
301         m_associatedDocumentLoaders.remove(&loader);
302         loader.applicationCacheHost().setApplicationCache(nullptr);
303         postListenerTask(eventNames().errorEvent, loader);
304         break;
305     }
306
307     ASSERT(m_downloadingPendingMasterResourceLoadersCount > 0);
308     m_downloadingPendingMasterResourceLoadersCount--;
309     checkIfLoadIsComplete();
310 }
311
312 void ApplicationCacheGroup::stopLoading()
313 {
314     if (m_manifestHandle) {
315         ASSERT(!m_currentHandle);
316
317         ASSERT(m_manifestHandle->client() == this);
318         m_manifestHandle->clearClient();
319
320         m_manifestHandle->cancel();
321         m_manifestHandle = nullptr;
322     }
323     
324     if (m_currentHandle) {
325         ASSERT(!m_manifestHandle);
326         ASSERT(m_cacheBeingUpdated);
327
328         ASSERT(m_currentHandle->client() == this);
329         m_currentHandle->clearClient();
330
331         m_currentHandle->cancel();
332         m_currentHandle = nullptr;
333     }    
334
335     // FIXME: Resetting just a tiny part of the state in this function is confusing. Callers have to take care of a lot more.
336     m_cacheBeingUpdated = nullptr;
337     m_pendingEntries.clear();
338 }    
339
340 void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader& loader)
341 {
342     m_associatedDocumentLoaders.remove(&loader);
343     m_pendingMasterResourceLoaders.remove(&loader);
344
345     if (auto* host = loader.applicationCacheHostUnlessBeingDestroyed())
346         host->setApplicationCache(nullptr); // Will set candidate group to null, too.
347
348     if (!m_associatedDocumentLoaders.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty())
349         return;
350
351     if (m_caches.isEmpty()) {
352         // There is an initial cache attempt in progress.
353         ASSERT(!m_newestCache);
354         // Delete ourselves, causing the cache attempt to be stopped.
355         delete this;
356         return;
357     }
358
359     ASSERT(m_caches.contains(m_newestCache.get()));
360
361     // Release our reference to the newest cache. This could cause us to be deleted.
362     // Any ongoing updates will be stopped from destructor.
363     m_newestCache = nullptr;
364 }
365
366 void ApplicationCacheGroup::cacheDestroyed(ApplicationCache& cache)
367 {
368     if (m_caches.remove(&cache) && m_caches.isEmpty()) {
369         ASSERT(m_associatedDocumentLoaders.isEmpty());
370         ASSERT(m_pendingMasterResourceLoaders.isEmpty());
371         delete this;
372     }
373 }
374
375 void ApplicationCacheGroup::stopLoadingInFrame(Frame& frame)
376 {
377     if (&frame != m_frame)
378         return;
379
380     cacheUpdateFailed();
381 }
382
383 void ApplicationCacheGroup::setNewestCache(Ref<ApplicationCache>&& newestCache)
384 {
385     m_newestCache = WTFMove(newestCache);
386
387     m_caches.add(m_newestCache.get());
388     m_newestCache->setGroup(this);
389 }
390
391 void ApplicationCacheGroup::makeObsolete()
392 {
393     if (isObsolete())
394         return;
395
396     m_isObsolete = true;
397     m_storage->cacheGroupMadeObsolete(*this);
398     ASSERT(!m_storageID);
399 }
400
401 void ApplicationCacheGroup::update(Frame& frame, ApplicationCacheUpdateOption updateOption)
402 {
403     ASSERT(frame.loader().documentLoader());
404     auto& documentLoader = *frame.loader().documentLoader();
405
406     if (m_updateStatus == Checking || m_updateStatus == Downloading) {
407         if (updateOption == ApplicationCacheUpdateWithBrowsingContext) {
408             postListenerTask(eventNames().checkingEvent, documentLoader);
409             if (m_updateStatus == Downloading)
410                 postListenerTask(eventNames().downloadingEvent, documentLoader);
411         }
412         return;
413     }
414
415     // Don't access anything on disk if private browsing is enabled.
416     if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin()->canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) {
417         ASSERT(m_pendingMasterResourceLoaders.isEmpty());
418         ASSERT(m_pendingEntries.isEmpty());
419         ASSERT(!m_cacheBeingUpdated);
420         postListenerTask(eventNames().checkingEvent, documentLoader);
421         postListenerTask(eventNames().errorEvent, documentLoader);
422         return;
423     }
424
425     ASSERT(!m_frame);
426     m_frame = &frame;
427
428     setUpdateStatus(Checking);
429
430     postListenerTask(eventNames().checkingEvent, m_associatedDocumentLoaders);
431     if (!m_newestCache) {
432         ASSERT(updateOption == ApplicationCacheUpdateWithBrowsingContext);
433         postListenerTask(eventNames().checkingEvent, documentLoader);
434     }
435     
436     ASSERT(!m_manifestHandle);
437     ASSERT(!m_manifestResource);
438     ASSERT(!m_currentHandle);
439     ASSERT(!m_currentResource);
440     ASSERT(m_completionType == None);
441
442     // FIXME: Handle defer loading
443     m_manifestHandle = createResourceHandle(m_manifestURL, m_newestCache ? m_newestCache->manifestResource() : 0);
444 }
445
446 void ApplicationCacheGroup::abort(Frame& frame)
447 {
448     if (m_updateStatus == Idle)
449         return;
450     ASSERT(m_updateStatus == Checking || (m_updateStatus == Downloading && m_cacheBeingUpdated));
451
452     if (m_completionType != None)
453         return;
454
455     frame.document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Debug, ASCIILiteral("Application Cache download process was aborted."));
456     cacheUpdateFailed();
457 }
458
459 RefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const URL& url, ApplicationCacheResource* newestCachedResource)
460 {
461     ResourceRequest request(url);
462     m_frame->loader().applyUserAgent(request);
463     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
464
465     if (newestCachedResource) {
466         const String& lastModified = newestCachedResource->response().httpHeaderField(HTTPHeaderName::LastModified);
467         const String& eTag = newestCachedResource->response().httpHeaderField(HTTPHeaderName::ETag);
468         if (!lastModified.isEmpty() || !eTag.isEmpty()) {
469             if (!lastModified.isEmpty())
470                 request.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
471             if (!eTag.isEmpty())
472                 request.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
473         }
474     }
475
476     RefPtr<ResourceHandle> handle = ResourceHandle::create(m_frame->loader().networkingContext(), request, this, false, true);
477
478     // Because willSendRequest only gets called during redirects, we initialize
479     // the identifier and the first willSendRequest here.
480     m_currentResourceIdentifier = m_frame->page()->progress().createUniqueIdentifier();
481     ResourceResponse redirectResponse = ResourceResponse();
482     InspectorInstrumentation::willSendRequest(m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), request, redirectResponse);
483     return handle;
484 }
485
486 void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, ResourceResponse&& response)
487 {
488     ASSERT(m_frame);
489     InspectorInstrumentation::didReceiveResourceResponse(*m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), response, nullptr);
490
491     if (handle == m_manifestHandle) {
492         didReceiveManifestResponse(response);
493         return;
494     }
495
496     ASSERT(handle == m_currentHandle);
497
498     URL url(handle->firstRequest().url());
499     url.removeFragmentIdentifier();
500     
501     ASSERT(!m_currentResource);
502     ASSERT(m_pendingEntries.contains(url));
503     
504     unsigned type = m_pendingEntries.get(url);
505     
506     // If this is an initial cache attempt, we should not get master resources delivered here.
507     if (!m_newestCache)
508         ASSERT(!(type & ApplicationCacheResource::Master));
509
510     if (m_newestCache && response.httpStatusCode() == 304) { // Not modified.
511         ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url);
512         if (newestCachedResource) {
513             m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
514             m_pendingEntries.remove(m_currentHandle->firstRequest().url());
515             m_currentHandle->cancel();
516             m_currentHandle = nullptr;
517             // Load the next resource, if any.
518             startLoadingEntry();
519             return;
520         }
521         // The server could return 304 for an unconditional request - in this case, we handle the response as a normal error.
522     }
523
524     if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->firstRequest().url()) {
525         if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
526             m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "Application Cache update failed, because " + m_currentHandle->firstRequest().url().stringCenterEllipsizedToLength() +
527                 ((response.httpStatusCode() / 100 != 2) ? " could not be fetched." : " was redirected."));
528             // Note that cacheUpdateFailed() can cause the cache group to be deleted.
529             cacheUpdateFailed();
530         } else if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
531             // Skip this resource. It is dropped from the cache.
532             m_currentHandle->cancel();
533             m_currentHandle = nullptr;
534             m_pendingEntries.remove(url);
535             // Load the next resource, if any.
536             startLoadingEntry();
537         } else {
538             // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act
539             // as if that was the fetched resource, ignoring the resource obtained from the network.
540             ASSERT(m_newestCache);
541             ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->firstRequest().url());
542             ASSERT(newestCachedResource);
543             m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
544             m_pendingEntries.remove(m_currentHandle->firstRequest().url());
545             m_currentHandle->cancel();
546             m_currentHandle = nullptr;
547             // Load the next resource, if any.
548             startLoadingEntry();
549         }
550         return;
551     }
552     
553     m_currentResource = ApplicationCacheResource::create(url, response, type);
554 }
555
556 void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, unsigned length, int encodedDataLength)
557 {
558     UNUSED_PARAM(encodedDataLength);
559
560     InspectorInstrumentation::didReceiveData(m_frame, m_currentResourceIdentifier, 0, length, 0);
561
562     if (handle == m_manifestHandle) {
563         didReceiveManifestData(data, length);
564         return;
565     }
566     
567     ASSERT(handle == m_currentHandle);
568     
569     ASSERT(m_currentResource);
570     m_currentResource->data().append(data, length);
571 }
572
573 void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double finishTime)
574 {
575     InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, finishTime);
576
577     if (handle == m_manifestHandle) {
578         didFinishLoadingManifest();
579         return;
580     }
581
582     ASSERT(m_currentHandle == handle);
583     ASSERT(m_pendingEntries.contains(handle->firstRequest().url()));
584     
585     m_pendingEntries.remove(handle->firstRequest().url());
586     
587     ASSERT(m_cacheBeingUpdated);
588
589     m_cacheBeingUpdated->addResource(m_currentResource.releaseNonNull());
590     m_currentHandle = nullptr;
591
592     // While downloading check to see if we have exceeded the available quota.
593     // We can stop immediately if we have already previously failed
594     // due to an earlier quota restriction. The client was already notified
595     // of the quota being reached and decided not to increase it then.
596     // FIXME: Should we break earlier and prevent redownloading on later page loads?
597     if (m_originQuotaExceededPreviously && m_availableSpaceInQuota < m_cacheBeingUpdated->estimatedSizeInStorage()) {
598         m_currentResource = nullptr;
599         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded."));
600         cacheUpdateFailed();
601         return;
602     }
603     
604     // Load the next resource, if any.
605     startLoadingEntry();
606 }
607
608 void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& error)
609 {
610     InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, error);
611
612     if (handle == m_manifestHandle) {
613         // A network error is logged elsewhere, no need to log again. Also, it's normal for manifest fetching to fail when working offline.
614         cacheUpdateFailed();
615         return;
616     }
617
618     ASSERT(handle == m_currentHandle);
619
620     unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url());
621     URL url(handle->firstRequest().url());
622     url.removeFragmentIdentifier();
623
624     ASSERT(!m_currentResource || !m_pendingEntries.contains(url));
625     m_currentResource = nullptr;
626     m_pendingEntries.remove(url);
627
628     if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
629         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "Application Cache update failed, because " + url.stringCenterEllipsizedToLength() + " could not be fetched.");
630         // Note that cacheUpdateFailed() can cause the cache group to be deleted.
631         cacheUpdateFailed();
632     } else {
633         // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act
634         // as if that was the fetched resource, ignoring the resource obtained from the network.
635         ASSERT(m_newestCache);
636         ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url);
637         ASSERT(newestCachedResource);
638         m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path()));
639         // Load the next resource, if any.
640         startLoadingEntry();
641     }
642 }
643
644 void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& response)
645 {
646     ASSERT(!m_manifestResource);
647     ASSERT(m_manifestHandle);
648
649     if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
650         InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
651         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response."));
652         manifestNotFound();
653         return;
654     }
655
656     if (response.httpStatusCode() == 304)
657         return;
658
659     if (response.httpStatusCode() / 100 != 2) {
660         InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
661         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response."));
662         cacheUpdateFailed();
663         return;
664     }
665
666     if (response.url() != m_manifestHandle->firstRequest().url()) {
667         InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest()));
668         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched, because a redirection was attempted."));
669         cacheUpdateFailed();
670         return;
671     }
672
673     m_manifestResource = ApplicationCacheResource::create(m_manifestHandle->firstRequest().url(), response, ApplicationCacheResource::Manifest);
674 }
675
676 void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length)
677 {
678     if (m_manifestResource)
679         m_manifestResource->data().append(data, length);
680 }
681
682 void ApplicationCacheGroup::didFinishLoadingManifest()
683 {
684     bool isUpgradeAttempt = m_newestCache;
685
686     if (!isUpgradeAttempt && !m_manifestResource) {
687         // The server returned 304 Not Modified even though we didn't send a conditional request.
688         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched because of an unexpected 304 Not Modified server response."));
689         cacheUpdateFailed();
690         return;
691     }
692
693     m_manifestHandle = nullptr;
694
695     // Check if the manifest was not modified.
696     if (isUpgradeAttempt) {
697         ApplicationCacheResource* newestManifest = m_newestCache->manifestResource();
698         ASSERT(newestManifest);
699     
700         if (!m_manifestResource || // The resource will be null if HTTP response was 304 Not Modified.
701             (newestManifest->data().size() == m_manifestResource->data().size() && !memcmp(newestManifest->data().data(), m_manifestResource->data().data(), newestManifest->data().size()))) {
702
703             m_completionType = NoUpdate;
704             m_manifestResource = nullptr;
705             deliverDelayedMainResources();
706
707             return;
708         }
709     }
710     
711     Manifest manifest;
712     if (!parseManifest(m_manifestURL, m_manifestResource->data().data(), m_manifestResource->data().size(), manifest)) {
713         // At the time of this writing, lack of "CACHE MANIFEST" signature is the only reason for parseManifest to fail.
714         m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?"));
715         cacheUpdateFailed();
716         return;
717     }
718
719     ASSERT(!m_cacheBeingUpdated);
720     m_cacheBeingUpdated = ApplicationCache::create();
721     m_cacheBeingUpdated->setGroup(this);
722
723     for (auto& loader : m_pendingMasterResourceLoaders)
724         associateDocumentLoaderWithCache(loader, m_cacheBeingUpdated.get());
725
726     // We have the manifest, now download the resources.
727     setUpdateStatus(Downloading);
728     
729     postListenerTask(eventNames().downloadingEvent, m_associatedDocumentLoaders);
730
731     ASSERT(m_pendingEntries.isEmpty());
732
733     if (isUpgradeAttempt) {
734         for (const auto& urlAndResource : m_newestCache->resources()) {
735             unsigned type = urlAndResource.value->type();
736             if (type & ApplicationCacheResource::Master)
737                 addEntry(urlAndResource.key, type);
738         }
739     }
740     
741     for (const auto& explicitURL : manifest.explicitURLs)
742         addEntry(explicitURL, ApplicationCacheResource::Explicit);
743
744     for (auto& fallbackURL : manifest.fallbackURLs)
745         addEntry(fallbackURL.second, ApplicationCacheResource::Fallback);
746     
747     m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs);
748     m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs);
749     m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests);
750
751     m_progressTotal = m_pendingEntries.size();
752     m_progressDone = 0;
753
754     recalculateAvailableSpaceInQuota();
755
756     startLoadingEntry();
757 }
758
759 void ApplicationCacheGroup::didReachMaxAppCacheSize()
760 {
761     ASSERT(m_frame);
762     ASSERT(m_cacheBeingUpdated);
763     m_frame->page()->chrome().client().reachedMaxAppCacheSize(m_frame->page()->applicationCacheStorage().spaceNeeded(m_cacheBeingUpdated->estimatedSizeInStorage()));
764     m_calledReachedMaxAppCacheSize = true;
765     checkIfLoadIsComplete();
766 }
767
768 void ApplicationCacheGroup::didReachOriginQuota(int64_t totalSpaceNeeded)
769 {
770     // Inform the client the origin quota has been reached, they may decide to increase the quota.
771     // We expect quota to be increased synchronously while waiting for the call to return.
772     m_frame->page()->chrome().client().reachedApplicationCacheOriginQuota(m_origin.get(), totalSpaceNeeded);
773 }
774
775 void ApplicationCacheGroup::cacheUpdateFailed()
776 {
777     stopLoading();
778     m_manifestResource = nullptr;
779
780     // Wait for master resource loads to finish.
781     m_completionType = Failure;
782     deliverDelayedMainResources();
783 }
784
785 void ApplicationCacheGroup::recalculateAvailableSpaceInQuota()
786 {
787     if (!m_frame->page()->applicationCacheStorage().calculateRemainingSizeForOriginExcludingCache(m_origin.get(), m_newestCache.get(), m_availableSpaceInQuota)) {
788         // Failed to determine what is left in the quota. Fallback to allowing anything.
789         m_availableSpaceInQuota = ApplicationCacheStorage::noQuota();
790     }
791 }
792     
793 void ApplicationCacheGroup::manifestNotFound()
794 {
795     makeObsolete();
796
797     postListenerTask(eventNames().obsoleteEvent, m_associatedDocumentLoaders);
798     postListenerTask(eventNames().errorEvent, m_pendingMasterResourceLoaders);
799
800     stopLoading();
801
802     ASSERT(m_pendingEntries.isEmpty());
803     m_manifestResource = nullptr;
804
805     while (!m_pendingMasterResourceLoaders.isEmpty()) {
806         HashSet<DocumentLoader*>::iterator it = m_pendingMasterResourceLoaders.begin();
807         
808         ASSERT((*it)->applicationCacheHost().candidateApplicationCacheGroup() == this);
809         ASSERT(!(*it)->applicationCacheHost().applicationCache());
810         (*it)->applicationCacheHost().setCandidateApplicationCacheGroup(nullptr);
811         m_pendingMasterResourceLoaders.remove(it);
812     }
813
814     m_downloadingPendingMasterResourceLoadersCount = 0;
815     setUpdateStatus(Idle);    
816     m_frame = nullptr;
817
818     if (m_caches.isEmpty()) {
819         ASSERT(m_associatedDocumentLoaders.isEmpty());
820         ASSERT(!m_cacheBeingUpdated);
821         delete this;
822     }
823 }
824
825 void ApplicationCacheGroup::checkIfLoadIsComplete()
826 {
827     if (m_manifestHandle || !m_pendingEntries.isEmpty() || m_downloadingPendingMasterResourceLoadersCount)
828         return;
829     
830     // We're done, all resources have finished downloading (successfully or not).
831
832     bool isUpgradeAttempt = m_newestCache;
833
834     switch (m_completionType) {
835     case None:
836         ASSERT_NOT_REACHED();
837         return;
838     case NoUpdate:
839         ASSERT(isUpgradeAttempt);
840         ASSERT(!m_cacheBeingUpdated);
841
842         // The storage could have been manually emptied by the user.
843         if (!m_storageID)
844             m_storage->storeNewestCache(*this);
845
846         postListenerTask(eventNames().noupdateEvent, m_associatedDocumentLoaders);
847         break;
848     case Failure:
849         ASSERT(!m_cacheBeingUpdated);
850         postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders);
851         if (m_caches.isEmpty()) {
852             ASSERT(m_associatedDocumentLoaders.isEmpty());
853             delete this;
854             return;
855         }
856         break;
857     case Completed: {
858         // FIXME: Fetch the resource from manifest URL again, and check whether it is identical to the one used for update (in case the application was upgraded server-side in the meanwhile). (<rdar://problem/6467625>)
859
860         ASSERT(m_cacheBeingUpdated);
861         if (m_manifestResource)
862             m_cacheBeingUpdated->setManifestResource(m_manifestResource.releaseNonNull());
863         else {
864             // We can get here as a result of retrying the Complete step, following
865             // a failure of the cache storage to save the newest cache due to hitting
866             // the maximum size. In such a case, m_manifestResource may be 0, as
867             // the manifest was already set on the newest cache object.
868             ASSERT(m_cacheBeingUpdated->manifestResource());
869             ASSERT(m_storage->isMaximumSizeReached());
870             ASSERT(m_calledReachedMaxAppCacheSize);
871         }
872
873         RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? RefPtr<ApplicationCache>() : m_newestCache;
874
875         // If we exceeded the origin quota while downloading we can request a quota
876         // increase now, before we attempt to store the cache.
877         int64_t totalSpaceNeeded;
878         if (!m_storage->checkOriginQuota(this, oldNewestCache.get(), m_cacheBeingUpdated.get(), totalSpaceNeeded))
879             didReachOriginQuota(totalSpaceNeeded);
880
881         ApplicationCacheStorage::FailureReason failureReason;
882         setNewestCache(m_cacheBeingUpdated.releaseNonNull());
883         if (m_storage->storeNewestCache(*this, oldNewestCache.get(), failureReason)) {
884             // New cache stored, now remove the old cache.
885             if (oldNewestCache)
886                 m_storage->remove(oldNewestCache.get());
887
888             // Fire the final progress event.
889             ASSERT(m_progressDone == m_progressTotal);
890             postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
891
892             // Fire the success event.
893             postListenerTask(isUpgradeAttempt ? eventNames().updatereadyEvent : eventNames().cachedEvent, m_associatedDocumentLoaders);
894             // It is clear that the origin quota was not reached, so clear the flag if it was set.
895             m_originQuotaExceededPreviously = false;
896         } else {
897             if (failureReason == ApplicationCacheStorage::OriginQuotaReached) {
898                 // We ran out of space for this origin. Fall down to the normal error handling
899                 // after recording this state.
900                 m_originQuotaExceededPreviously = true;
901                 m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded."));
902             }
903
904             if (failureReason == ApplicationCacheStorage::TotalQuotaReached && !m_calledReachedMaxAppCacheSize) {
905                 // FIXME: Should this be handled more like Origin Quotas? Does this fail properly?
906
907                 // We ran out of space. All the changes in the cache storage have
908                 // been rolled back. We roll back to the previous state in here,
909                 // as well, call the chrome client asynchronously and retry to
910                 // save the new cache.
911
912                 // Save a reference to the new cache.
913                 m_cacheBeingUpdated = WTFMove(m_newestCache);
914                 if (oldNewestCache)
915                     setNewestCache(oldNewestCache.releaseNonNull());
916                 scheduleReachedMaxAppCacheSizeCallback();
917                 return;
918             }
919
920             // Run the "cache failure steps"
921             // Fire the error events to all pending master entries, as well any other cache hosts
922             // currently associated with a cache in this group.
923             postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders);
924             // Disassociate the pending master entries from the failed new cache. Note that
925             // all other loaders in the m_associatedDocumentLoaders are still associated with
926             // some other cache in this group. They are not associated with the failed new cache.
927
928             // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
929             Vector<DocumentLoader*> loaders;
930             copyToVector(m_pendingMasterResourceLoaders, loaders);
931             for (auto& loader : loaders)
932                 disassociateDocumentLoader(*loader); // This can delete this group.
933
934             // Reinstate the oldNewestCache, if there was one.
935             if (oldNewestCache) {
936                 // This will discard the failed new cache.
937                 setNewestCache(oldNewestCache.releaseNonNull());
938             } else {
939                 // We must have been deleted by the last call to disassociateDocumentLoader().
940                 return;
941             }
942         }
943         break;
944     }
945     }
946
947     // Empty cache group's list of pending master entries.
948     m_pendingMasterResourceLoaders.clear();
949     m_completionType = None;
950     setUpdateStatus(Idle);
951     m_frame = nullptr;
952     m_availableSpaceInQuota = ApplicationCacheStorage::unknownQuota();
953     m_calledReachedMaxAppCacheSize = false;
954 }
955
956 void ApplicationCacheGroup::startLoadingEntry()
957 {
958     ASSERT(m_cacheBeingUpdated);
959
960     if (m_pendingEntries.isEmpty()) {
961         m_completionType = Completed;
962         deliverDelayedMainResources();
963         return;
964     }
965     
966     auto firstPendingEntryURL = m_pendingEntries.begin()->key;
967
968     postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
969     m_progressDone++;
970
971     ASSERT(!m_currentHandle);
972     m_currentHandle = createResourceHandle(URL(ParsedURLString, firstPendingEntryURL), m_newestCache ? m_newestCache->resourceForURL(firstPendingEntryURL) : 0);
973 }
974
975 void ApplicationCacheGroup::deliverDelayedMainResources()
976 {
977     // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
978     Vector<DocumentLoader*> loaders;
979     copyToVector(m_pendingMasterResourceLoaders, loaders);
980     for (auto* loader : loaders) {
981         if (loader->isLoadingMainResource())
982             continue;
983         if (loader->mainDocumentError().isNull())
984             finishedLoadingMainResource(*loader);
985         else
986             failedLoadingMainResource(*loader);
987     }
988     if (loaders.isEmpty())
989         checkIfLoadIsComplete();
990 }
991
992 void ApplicationCacheGroup::addEntry(const String& url, unsigned type)
993 {
994     ASSERT(m_cacheBeingUpdated);
995     ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier());
996
997     // Don't add the URL if we already have an master resource in the cache
998     // (i.e., the main resource finished loading before the manifest).
999     if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) {
1000         ASSERT(resource->type() & ApplicationCacheResource::Master);
1001         ASSERT(!m_frame->loader().documentLoader()->isLoadingMainResource());
1002         resource->addType(type);
1003         return;
1004     }
1005
1006     // Don't add the URL if it's the same as the manifest URL.
1007     ASSERT(m_manifestResource);
1008     if (m_manifestResource->url() == url) {
1009         m_manifestResource->addType(type);
1010         return;
1011     }
1012
1013     m_pendingEntries.add(url, type).iterator->value |= type;
1014 }
1015
1016 void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loader, ApplicationCache* cache)
1017 {
1018     // If teardown started already, revive the group.
1019     if (!m_newestCache && !m_cacheBeingUpdated)
1020         m_newestCache = cache;
1021
1022     ASSERT(!m_isObsolete);
1023
1024     loader->applicationCacheHost().setApplicationCache(cache);
1025
1026     ASSERT(!m_associatedDocumentLoaders.contains(loader));
1027     m_associatedDocumentLoaders.add(loader);
1028 }
1029
1030 class ChromeClientCallbackTimer final : public TimerBase {
1031 public:
1032     ChromeClientCallbackTimer(ApplicationCacheGroup& group)
1033         : m_group(group)
1034     {
1035     }
1036
1037 private:
1038     void fired() final
1039     {
1040         m_group.didReachMaxAppCacheSize();
1041         delete this;
1042     }
1043
1044     // Note that there is no need to use a Ref here. The ApplicationCacheGroup instance is guaranteed
1045     // to be alive when the timer fires since invoking the callback is part of its normal
1046     // update machinery and nothing can yet cause it to get deleted.
1047     ApplicationCacheGroup& m_group;
1048 };
1049
1050 void ApplicationCacheGroup::scheduleReachedMaxAppCacheSizeCallback()
1051 {
1052     ASSERT(isMainThread());
1053     auto* timer = new ChromeClientCallbackTimer(*this);
1054     timer->startOneShot(0);
1055     // The timer will delete itself once it fires.
1056 }
1057
1058 void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet)
1059 {
1060     for (auto& loader : loaderSet)
1061         postListenerTask(eventType, progressTotal, progressDone, *loader);
1062 }
1063
1064 void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, DocumentLoader& loader)
1065 {
1066     auto* frame = loader.frame();
1067     if (!frame)
1068         return;
1069     
1070     ASSERT(frame->loader().documentLoader() == &loader);
1071
1072     RefPtr<DocumentLoader> protectedLoader(&loader);
1073     frame->document()->postTask([protectedLoader, &eventType, progressTotal, progressDone] (ScriptExecutionContext& context) {
1074         ASSERT_UNUSED(context, context.isDocument());
1075         auto* frame = protectedLoader->frame();
1076         if (!frame)
1077             return;
1078
1079         ASSERT(frame->loader().documentLoader() == protectedLoader);
1080         protectedLoader->applicationCacheHost().notifyDOMApplicationCache(eventType, progressTotal, progressDone);
1081     });
1082 }
1083
1084 void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status)
1085 {
1086     m_updateStatus = status;
1087 }
1088
1089 void ApplicationCacheGroup::clearStorageID()
1090 {
1091     m_storageID = 0;
1092     for (auto& cache : m_caches)
1093         cache->clearStorageID();
1094 }
1095
1096 }