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