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(); fetch_type()123 FetchType fetch_type() const { return fetch_type_; } request()124 net::URLRequest* request() const { return request_.get(); } existing_entry()125 const AppCacheEntry& existing_entry() const { return existing_entry_; } manifest_data()126 const std::string& manifest_data() const { return manifest_data_; } response_writer()127 AppCacheResponseWriter* response_writer() const { 128 return response_writer_.get(); 129 } set_existing_response_headers(net::HttpResponseHeaders * headers)130 void set_existing_response_headers(net::HttpResponseHeaders* headers) { 131 existing_response_headers_ = headers; 132 } set_existing_entry(const AppCacheEntry & entry)133 void set_existing_entry(const AppCacheEntry& entry) { 134 existing_entry_ = entry; 135 } result()136 ResultType result() const { return result_; } redirect_response_code()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. OnCacheSelectionComplete(AppCacheHost * host)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); MadeProgress()264 void MadeProgress() { last_progress_time_ = base::Time::Now(); } 265 266 // Deletes this object after letting the stack unwind. 267 void DeleteSoon(); 268 IsTerminating()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_ 353