1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_
6 #define WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_
14 #include "base/gtest_prod_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "net/base/completion_callback.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/url_request/url_request.h"
20 #include "webkit/browser/appcache/appcache.h"
21 #include "webkit/browser/appcache/appcache_host.h"
22 #include "webkit/browser/appcache/appcache_response.h"
23 #include "webkit/browser/appcache/appcache_storage.h"
24 #include "webkit/browser/webkit_storage_browser_export.h"
25 #include "webkit/common/appcache/appcache_interfaces.h"
31 // Application cache Update algorithm and state.
32 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheUpdateJob
33 : public AppCacheStorage::Delegate
,
34 public AppCacheHost::Observer
{
36 AppCacheUpdateJob(AppCacheService
* service
, AppCacheGroup
* group
);
37 virtual ~AppCacheUpdateJob();
39 // Triggers the update process or adds more info if this update is already
41 void StartUpdate(AppCacheHost
* host
, const GURL
& new_master_resource
);
44 friend class AppCacheUpdateJobTest
;
47 // Master entries have multiple hosts, for example, the same page is opened
49 typedef std::vector
<AppCacheHost
*> PendingHosts
;
50 typedef std::map
<GURL
, PendingHosts
> PendingMasters
;
51 typedef std::map
<GURL
, URLFetcher
*> PendingUrlFetches
;
52 typedef std::map
<int64
, GURL
> LoadingResponses
;
54 static const int kRerunDelayMs
= 1000;
56 // TODO(michaeln): Rework the set of states vs update types vs stored states.
57 // The NO_UPDATE state is really more of an update type. For all update types
58 // storing the results is relevant.
66 enum InternalUpdateState
{
71 // Every state after this comment indicates the update is terminating.
85 UrlToFetch(const GURL
& url
, bool checked
, AppCacheResponseInfo
* info
);
90 scoped_refptr
<AppCacheResponseInfo
> existing_response_info
;
93 class URLFetcher
: public net::URLRequest::Delegate
{
101 URLFetcher(const GURL
& url
,
102 FetchType fetch_type
,
103 AppCacheUpdateJob
* job
);
104 virtual ~URLFetcher();
106 FetchType
fetch_type() const { return fetch_type_
; }
107 net::URLRequest
* request() const { return request_
.get(); }
108 const AppCacheEntry
& existing_entry() const { return existing_entry_
; }
109 const std::string
& manifest_data() const { return manifest_data_
; }
110 AppCacheResponseWriter
* response_writer() const {
111 return response_writer_
.get();
113 void set_existing_response_headers(net::HttpResponseHeaders
* headers
) {
114 existing_response_headers_
= headers
;
116 void set_existing_entry(const AppCacheEntry
& entry
) {
117 existing_entry_
= entry
;
121 // URLRequest::Delegate overrides
122 virtual void OnReceivedRedirect(net::URLRequest
* request
,
124 bool* defer_redirect
) OVERRIDE
;
125 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
;
126 virtual void OnReadCompleted(net::URLRequest
* request
,
127 int bytes_read
) OVERRIDE
;
129 void AddConditionalHeaders(const net::HttpResponseHeaders
* headers
);
130 void OnWriteComplete(int result
);
131 void ReadResponseData();
132 bool ConsumeResponseData(int bytes_read
);
133 void OnResponseCompleted();
134 bool MaybeRetryRequest();
137 AppCacheUpdateJob
* job_
;
138 FetchType fetch_type_
;
139 int retry_503_attempts_
;
140 scoped_refptr
<net::IOBuffer
> buffer_
;
141 scoped_ptr
<net::URLRequest
> request_
;
142 AppCacheEntry existing_entry_
;
143 scoped_refptr
<net::HttpResponseHeaders
> existing_response_headers_
;
144 std::string manifest_data_
;
145 scoped_ptr
<AppCacheResponseWriter
> response_writer_
;
146 }; // class URLFetcher
148 AppCacheResponseWriter
* CreateResponseWriter();
150 // Methods for AppCacheStorage::Delegate.
151 virtual void OnResponseInfoLoaded(AppCacheResponseInfo
* response_info
,
152 int64 response_id
) OVERRIDE
;
153 virtual void OnGroupAndNewestCacheStored(AppCacheGroup
* group
,
154 AppCache
* newest_cache
,
156 bool would_exceed_quota
) OVERRIDE
;
157 virtual void OnGroupMadeObsolete(AppCacheGroup
* group
, bool success
) OVERRIDE
;
159 // Methods for AppCacheHost::Observer.
160 virtual void OnCacheSelectionComplete(AppCacheHost
* host
) OVERRIDE
{} // N/A
161 virtual void OnDestructionImminent(AppCacheHost
* host
) OVERRIDE
;
163 void HandleCacheFailure(const std::string
& error_message
);
165 void FetchManifest(bool is_first_fetch
);
166 void HandleManifestFetchCompleted(URLFetcher
* fetcher
);
167 void ContinueHandleManifestFetchCompleted(bool changed
);
169 void HandleUrlFetchCompleted(URLFetcher
* fetcher
);
170 void HandleMasterEntryFetchCompleted(URLFetcher
* fetcher
);
172 void HandleManifestRefetchCompleted(URLFetcher
* fetcher
);
173 void OnManifestInfoWriteComplete(int result
);
174 void OnManifestDataWriteComplete(int result
);
176 void StoreGroupAndCache();
178 void NotifySingleHost(AppCacheHost
* host
, EventID event_id
);
179 void NotifyAllAssociatedHosts(EventID event_id
);
180 void NotifyAllProgress(const GURL
& url
);
181 void NotifyAllFinalProgress();
182 void NotifyAllError(const std::string
& error_message
);
183 void AddAllAssociatedHostsToNotifier(HostNotifier
* notifier
);
185 // Checks if manifest is byte for byte identical with the manifest
186 // in the newest application cache.
187 void CheckIfManifestChanged();
188 void OnManifestDataReadComplete(int result
);
190 // Creates the list of files that may need to be fetched and initiates
191 // fetches. Section 6.9.4 steps 12-17
192 void BuildUrlFileList(const Manifest
& manifest
);
193 void AddUrlToFileList(const GURL
& url
, int type
);
195 void CancelAllUrlFetches();
196 bool ShouldSkipUrlFetch(const AppCacheEntry
& entry
);
198 // If entry already exists in the cache currently being updated, merge
199 // the entry type information with the existing entry.
200 // Returns true if entry exists in cache currently being updated.
201 bool AlreadyFetchedEntry(const GURL
& url
, int entry_type
);
203 // TODO(jennb): Delete when update no longer fetches master entries directly.
204 // Creates the list of master entries that need to be fetched and initiates
206 void AddMasterEntryToFetchList(AppCacheHost
* host
, const GURL
& url
,
208 void FetchMasterEntries();
209 void CancelAllMasterEntryFetches(const std::string
& error_message
);
211 // Asynchronously loads the entry from the newest complete cache if the
212 // HTTP caching semantics allow.
213 // Returns false if immediately obvious that data cannot be loaded from
214 // newest complete cache.
215 bool MaybeLoadFromNewestCache(const GURL
& url
, AppCacheEntry
& entry
);
216 void LoadFromNewestCacheFailed(const GURL
& url
,
217 AppCacheResponseInfo
* newest_response_info
);
219 // Does nothing if update process is still waiting for pending master
220 // entries or URL fetches to complete downloading. Otherwise, completes
221 // the update process.
222 void MaybeCompleteUpdate();
224 // Schedules a rerun of the entire update with the same parameters as
225 // this update job after a short delay.
226 void ScheduleUpdateRetry(int delay_ms
);
229 void ClearPendingMasterEntries();
230 void DiscardInprogressCache();
231 void DiscardDuplicateResponses();
233 // Deletes this object after letting the stack unwind.
236 bool IsTerminating() { return internal_state_
>= REFETCH_MANIFEST
||
237 stored_state_
!= UNSTORED
; }
239 AppCacheService
* service_
;
240 const GURL manifest_url_
; // here for easier access
242 scoped_refptr
<AppCache
> inprogress_cache_
;
244 AppCacheGroup
* group_
;
246 UpdateType update_type_
;
247 InternalUpdateState internal_state_
;
249 PendingMasters pending_master_entries_
;
250 size_t master_entries_completed_
;
252 // TODO(jennb): Delete when update no longer fetches master entries directly.
253 // Helper containers to track which pending master entries have yet to be
254 // fetched and which are currently being fetched. Master entries that
255 // are listed in the manifest may be fetched as a regular URL instead of
256 // as a separate master entry fetch to optimize against duplicate fetches.
257 std::set
<GURL
> master_entries_to_fetch_
;
258 PendingUrlFetches master_entry_fetches_
;
260 // URLs of files to fetch along with their flags.
261 AppCache::EntryMap url_file_list_
;
262 size_t url_fetches_completed_
;
264 // Helper container to track which urls have not been fetched yet. URLs are
265 // removed when the fetch is initiated. Flag indicates whether an attempt
266 // to load the URL from storage has already been tried and failed.
267 std::deque
<UrlToFetch
> urls_to_fetch_
;
269 // Helper container to track which urls are being loaded from response
271 LoadingResponses loading_responses_
;
273 // Keep track of pending URL requests so we can cancel them if necessary.
274 URLFetcher
* manifest_fetcher_
;
275 PendingUrlFetches pending_url_fetches_
;
277 // Temporary storage of manifest response data for parsing and comparison.
278 std::string manifest_data_
;
279 scoped_ptr
<net::HttpResponseInfo
> manifest_response_info_
;
280 scoped_ptr
<AppCacheResponseWriter
> manifest_response_writer_
;
281 scoped_refptr
<net::IOBuffer
> read_manifest_buffer_
;
282 std::string loaded_manifest_data_
;
283 scoped_ptr
<AppCacheResponseReader
> manifest_response_reader_
;
285 // New master entries added to the cache by this job, used to cleanup
286 // in error conditions.
287 std::vector
<GURL
> added_master_entries_
;
289 // Response ids stored by this update job, used to cleanup in
291 std::vector
<int64
> stored_response_ids_
;
293 // In some cases we fetch the same resource multiple times, and then
294 // have to delete the duplicates upon successful update. These ids
295 // are also in the stored_response_ids_ collection so we only schedule
296 // these for deletion on success.
297 // TODO(michaeln): Rework when we no longer fetches master entries directly.
298 std::vector
<int64
> duplicate_response_ids_
;
300 // Whether we've stored the resulting group/cache yet.
301 StoredState stored_state_
;
303 FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest
, QueueUpdate
);
305 DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob
);
308 } // namespace appcache
310 #endif // WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_