OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #ifndef WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ | |
6 #define WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ | |
7 | |
8 #include <deque> | |
9 #include <map> | |
10 #include <set> | |
11 #include <string> | |
12 #include <vector> | |
13 | |
14 #include "base/gtest_prod_util.h" | |
15 #include "base/memory/ref_counted.h" | |
16 #include "base/time/time.h" | |
17 #include "net/base/completion_callback.h" | |
18 #include "net/http/http_response_headers.h" | |
19 #include "net/url_request/url_request.h" | |
20 #include "url/gurl.h" | |
21 #include "webkit/browser/appcache/appcache.h" | |
22 #include "webkit/browser/appcache/appcache_host.h" | |
23 #include "webkit/browser/appcache/appcache_response.h" | |
24 #include "webkit/browser/appcache/appcache_service_impl.h" | |
25 #include "webkit/browser/appcache/appcache_storage.h" | |
26 #include "webkit/browser/webkit_storage_browser_export.h" | |
27 #include "webkit/common/appcache/appcache_interfaces.h" | |
28 | |
29 namespace content { | |
30 FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate); | |
31 class AppCacheGroupTest; | |
32 class AppCacheUpdateJobTest; | |
33 } | |
34 | |
35 namespace appcache { | |
36 | |
37 class HostNotifier; | |
38 | |
39 // Application cache Update algorithm and state. | |
40 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheUpdateJob | |
41 : public AppCacheStorage::Delegate, | |
42 public AppCacheHost::Observer, | |
43 public AppCacheServiceImpl::Observer { | |
44 public: | |
45 // Used for uma stats only for now, so new values are append only. | |
46 enum ResultType { | |
47 UPDATE_OK, DB_ERROR, DISKCACHE_ERROR, APPCACHE_QUOTA_ERROR, REDIRECT_ERROR, | |
48 APPCACHE_MANIFEST_ERROR, NETWORK_ERROR, SERVER_ERROR, CANCELLED_ERROR, | |
49 NUM_UPDATE_JOB_RESULT_TYPES | |
50 }; | |
51 | |
52 AppCacheUpdateJob(AppCacheServiceImpl* service, AppCacheGroup* group); | |
53 virtual ~AppCacheUpdateJob(); | |
54 | |
55 // Triggers the update process or adds more info if this update is already | |
56 // in progress. | |
57 void StartUpdate(AppCacheHost* host, const GURL& new_master_resource); | |
58 | |
59 private: | |
60 friend class content::AppCacheGroupTest; | |
61 friend class content::AppCacheUpdateJobTest; | |
62 class URLFetcher; | |
63 | |
64 // Master entries have multiple hosts, for example, the same page is opened | |
65 // in different tabs. | |
66 typedef std::vector<AppCacheHost*> PendingHosts; | |
67 typedef std::map<GURL, PendingHosts> PendingMasters; | |
68 typedef std::map<GURL, URLFetcher*> PendingUrlFetches; | |
69 typedef std::map<int64, GURL> LoadingResponses; | |
70 | |
71 static const int kRerunDelayMs = 1000; | |
72 | |
73 // TODO(michaeln): Rework the set of states vs update types vs stored states. | |
74 // The NO_UPDATE state is really more of an update type. For all update types | |
75 // storing the results is relevant. | |
76 | |
77 enum UpdateType { | |
78 UNKNOWN_TYPE, | |
79 UPGRADE_ATTEMPT, | |
80 CACHE_ATTEMPT, | |
81 }; | |
82 | |
83 enum InternalUpdateState { | |
84 FETCH_MANIFEST, | |
85 NO_UPDATE, | |
86 DOWNLOADING, | |
87 | |
88 // Every state after this comment indicates the update is terminating. | |
89 REFETCH_MANIFEST, | |
90 CACHE_FAILURE, | |
91 CANCELLED, | |
92 COMPLETED, | |
93 }; | |
94 | |
95 enum StoredState { | |
96 UNSTORED, | |
97 STORING, | |
98 STORED, | |
99 }; | |
100 | |
101 struct UrlToFetch { | |
102 UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info); | |
103 ~UrlToFetch(); | |
104 | |
105 GURL url; | |
106 bool storage_checked; | |
107 scoped_refptr<AppCacheResponseInfo> existing_response_info; | |
108 }; | |
109 | |
110 class URLFetcher : public net::URLRequest::Delegate { | |
111 public: | |
112 enum FetchType { | |
113 MANIFEST_FETCH, | |
114 URL_FETCH, | |
115 MASTER_ENTRY_FETCH, | |
116 MANIFEST_REFETCH, | |
117 }; | |
118 URLFetcher(const GURL& url, | |
119 FetchType fetch_type, | |
120 AppCacheUpdateJob* job); | |
121 virtual ~URLFetcher(); | |
122 void Start(); | |
123 FetchType fetch_type() const { return fetch_type_; } | |
124 net::URLRequest* request() const { return request_.get(); } | |
125 const AppCacheEntry& existing_entry() const { return existing_entry_; } | |
126 const std::string& manifest_data() const { return manifest_data_; } | |
127 AppCacheResponseWriter* response_writer() const { | |
128 return response_writer_.get(); | |
129 } | |
130 void set_existing_response_headers(net::HttpResponseHeaders* headers) { | |
131 existing_response_headers_ = headers; | |
132 } | |
133 void set_existing_entry(const AppCacheEntry& entry) { | |
134 existing_entry_ = entry; | |
135 } | |
136 ResultType result() const { return result_; } | |
137 int redirect_response_code() const { return redirect_response_code_; } | |
138 | |
139 private: | |
140 // URLRequest::Delegate overrides | |
141 virtual void OnReceivedRedirect(net::URLRequest* request, | |
142 const GURL& new_url, | |
143 bool* defer_redirect) OVERRIDE; | |
144 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE; | |
145 virtual void OnReadCompleted(net::URLRequest* request, | |
146 int bytes_read) OVERRIDE; | |
147 | |
148 void AddConditionalHeaders(const net::HttpResponseHeaders* headers); | |
149 void OnWriteComplete(int result); | |
150 void ReadResponseData(); | |
151 bool ConsumeResponseData(int bytes_read); | |
152 void OnResponseCompleted(); | |
153 bool MaybeRetryRequest(); | |
154 | |
155 GURL url_; | |
156 AppCacheUpdateJob* job_; | |
157 FetchType fetch_type_; | |
158 int retry_503_attempts_; | |
159 scoped_refptr<net::IOBuffer> buffer_; | |
160 scoped_ptr<net::URLRequest> request_; | |
161 AppCacheEntry existing_entry_; | |
162 scoped_refptr<net::HttpResponseHeaders> existing_response_headers_; | |
163 std::string manifest_data_; | |
164 ResultType result_; | |
165 int redirect_response_code_; | |
166 scoped_ptr<AppCacheResponseWriter> response_writer_; | |
167 }; // class URLFetcher | |
168 | |
169 AppCacheResponseWriter* CreateResponseWriter(); | |
170 | |
171 // Methods for AppCacheStorage::Delegate. | |
172 virtual void OnResponseInfoLoaded(AppCacheResponseInfo* response_info, | |
173 int64 response_id) OVERRIDE; | |
174 virtual void OnGroupAndNewestCacheStored(AppCacheGroup* group, | |
175 AppCache* newest_cache, | |
176 bool success, | |
177 bool would_exceed_quota) OVERRIDE; | |
178 virtual void OnGroupMadeObsolete(AppCacheGroup* group, | |
179 bool success, | |
180 int response_code) OVERRIDE; | |
181 | |
182 // Methods for AppCacheHost::Observer. | |
183 virtual void OnCacheSelectionComplete(AppCacheHost* host) OVERRIDE {} // N/A | |
184 virtual void OnDestructionImminent(AppCacheHost* host) OVERRIDE; | |
185 | |
186 // Methods for AppCacheServiceImpl::Observer. | |
187 virtual void OnServiceReinitialized( | |
188 AppCacheStorageReference* old_storage) OVERRIDE; | |
189 | |
190 void HandleCacheFailure(const AppCacheErrorDetails& details, | |
191 ResultType result, | |
192 const GURL& failed_resource_url); | |
193 | |
194 void FetchManifest(bool is_first_fetch); | |
195 void HandleManifestFetchCompleted(URLFetcher* fetcher); | |
196 void ContinueHandleManifestFetchCompleted(bool changed); | |
197 | |
198 void HandleUrlFetchCompleted(URLFetcher* fetcher); | |
199 void HandleMasterEntryFetchCompleted(URLFetcher* fetcher); | |
200 | |
201 void HandleManifestRefetchCompleted(URLFetcher* fetcher); | |
202 void OnManifestInfoWriteComplete(int result); | |
203 void OnManifestDataWriteComplete(int result); | |
204 | |
205 void StoreGroupAndCache(); | |
206 | |
207 void NotifySingleHost(AppCacheHost* host, AppCacheEventID event_id); | |
208 void NotifyAllAssociatedHosts(AppCacheEventID event_id); | |
209 void NotifyAllProgress(const GURL& url); | |
210 void NotifyAllFinalProgress(); | |
211 void NotifyAllError(const AppCacheErrorDetails& detals); | |
212 void LogConsoleMessageToAll(const std::string& message); | |
213 void AddAllAssociatedHostsToNotifier(HostNotifier* notifier); | |
214 | |
215 // Checks if manifest is byte for byte identical with the manifest | |
216 // in the newest application cache. | |
217 void CheckIfManifestChanged(); | |
218 void OnManifestDataReadComplete(int result); | |
219 | |
220 // Creates the list of files that may need to be fetched and initiates | |
221 // fetches. Section 6.9.4 steps 12-17 | |
222 void BuildUrlFileList(const Manifest& manifest); | |
223 void AddUrlToFileList(const GURL& url, int type); | |
224 void FetchUrls(); | |
225 void CancelAllUrlFetches(); | |
226 bool ShouldSkipUrlFetch(const AppCacheEntry& entry); | |
227 | |
228 // If entry already exists in the cache currently being updated, merge | |
229 // the entry type information with the existing entry. | |
230 // Returns true if entry exists in cache currently being updated. | |
231 bool AlreadyFetchedEntry(const GURL& url, int entry_type); | |
232 | |
233 // TODO(jennb): Delete when update no longer fetches master entries directly. | |
234 // Creates the list of master entries that need to be fetched and initiates | |
235 // fetches. | |
236 void AddMasterEntryToFetchList(AppCacheHost* host, const GURL& url, | |
237 bool is_new); | |
238 void FetchMasterEntries(); | |
239 void CancelAllMasterEntryFetches(const AppCacheErrorDetails& details); | |
240 | |
241 // Asynchronously loads the entry from the newest complete cache if the | |
242 // HTTP caching semantics allow. | |
243 // Returns false if immediately obvious that data cannot be loaded from | |
244 // newest complete cache. | |
245 bool MaybeLoadFromNewestCache(const GURL& url, AppCacheEntry& entry); | |
246 void LoadFromNewestCacheFailed(const GURL& url, | |
247 AppCacheResponseInfo* newest_response_info); | |
248 | |
249 // Does nothing if update process is still waiting for pending master | |
250 // entries or URL fetches to complete downloading. Otherwise, completes | |
251 // the update process. | |
252 void MaybeCompleteUpdate(); | |
253 | |
254 // Schedules a rerun of the entire update with the same parameters as | |
255 // this update job after a short delay. | |
256 void ScheduleUpdateRetry(int delay_ms); | |
257 | |
258 void Cancel(); | |
259 void ClearPendingMasterEntries(); | |
260 void DiscardInprogressCache(); | |
261 void DiscardDuplicateResponses(); | |
262 | |
263 void LogHistogramStats(ResultType result, const GURL& failed_resource_url); | |
264 void MadeProgress() { last_progress_time_ = base::Time::Now(); } | |
265 | |
266 // Deletes this object after letting the stack unwind. | |
267 void DeleteSoon(); | |
268 | |
269 bool IsTerminating() { return internal_state_ >= REFETCH_MANIFEST || | |
270 stored_state_ != UNSTORED; } | |
271 | |
272 AppCacheServiceImpl* service_; | |
273 const GURL manifest_url_; // here for easier access | |
274 | |
275 // Defined prior to refs to AppCaches and Groups because destruction | |
276 // order matters, the disabled_storage_reference_ must outlive those | |
277 // objects. | |
278 scoped_refptr<AppCacheStorageReference> disabled_storage_reference_; | |
279 | |
280 scoped_refptr<AppCache> inprogress_cache_; | |
281 | |
282 AppCacheGroup* group_; | |
283 | |
284 UpdateType update_type_; | |
285 InternalUpdateState internal_state_; | |
286 base::Time last_progress_time_; | |
287 | |
288 PendingMasters pending_master_entries_; | |
289 size_t master_entries_completed_; | |
290 | |
291 // TODO(jennb): Delete when update no longer fetches master entries directly. | |
292 // Helper containers to track which pending master entries have yet to be | |
293 // fetched and which are currently being fetched. Master entries that | |
294 // are listed in the manifest may be fetched as a regular URL instead of | |
295 // as a separate master entry fetch to optimize against duplicate fetches. | |
296 std::set<GURL> master_entries_to_fetch_; | |
297 PendingUrlFetches master_entry_fetches_; | |
298 | |
299 // URLs of files to fetch along with their flags. | |
300 AppCache::EntryMap url_file_list_; | |
301 size_t url_fetches_completed_; | |
302 | |
303 // Helper container to track which urls have not been fetched yet. URLs are | |
304 // removed when the fetch is initiated. Flag indicates whether an attempt | |
305 // to load the URL from storage has already been tried and failed. | |
306 std::deque<UrlToFetch> urls_to_fetch_; | |
307 | |
308 // Helper container to track which urls are being loaded from response | |
309 // storage. | |
310 LoadingResponses loading_responses_; | |
311 | |
312 // Keep track of pending URL requests so we can cancel them if necessary. | |
313 URLFetcher* manifest_fetcher_; | |
314 PendingUrlFetches pending_url_fetches_; | |
315 | |
316 // Temporary storage of manifest response data for parsing and comparison. | |
317 std::string manifest_data_; | |
318 scoped_ptr<net::HttpResponseInfo> manifest_response_info_; | |
319 scoped_ptr<AppCacheResponseWriter> manifest_response_writer_; | |
320 scoped_refptr<net::IOBuffer> read_manifest_buffer_; | |
321 std::string loaded_manifest_data_; | |
322 scoped_ptr<AppCacheResponseReader> manifest_response_reader_; | |
323 bool manifest_has_valid_mime_type_; | |
324 | |
325 // New master entries added to the cache by this job, used to cleanup | |
326 // in error conditions. | |
327 std::vector<GURL> added_master_entries_; | |
328 | |
329 // Response ids stored by this update job, used to cleanup in | |
330 // error conditions. | |
331 std::vector<int64> stored_response_ids_; | |
332 | |
333 // In some cases we fetch the same resource multiple times, and then | |
334 // have to delete the duplicates upon successful update. These ids | |
335 // are also in the stored_response_ids_ collection so we only schedule | |
336 // these for deletion on success. | |
337 // TODO(michaeln): Rework when we no longer fetches master entries directly. | |
338 std::vector<int64> duplicate_response_ids_; | |
339 | |
340 // Whether we've stored the resulting group/cache yet. | |
341 StoredState stored_state_; | |
342 | |
343 AppCacheStorage* storage_; | |
344 | |
345 FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate); | |
346 | |
347 DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob); | |
348 }; | |
349 | |
350 } // namespace appcache | |
351 | |
352 #endif // WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ | |
OLD | NEW |