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