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_storage.h" 24 #include "webkit/browser/webkit_storage_browser_export.h" 25 #include "webkit/common/appcache/appcache_interfaces.h" 26 27 namespace appcache { 28 29 class HostNotifier; 30 31 // Application cache Update algorithm and state. 32 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheUpdateJob 33 : public AppCacheStorage::Delegate, 34 public AppCacheHost::Observer { 35 public: 36 AppCacheUpdateJob(AppCacheService* service, AppCacheGroup* group); 37 virtual ~AppCacheUpdateJob(); 38 39 // Triggers the update process or adds more info if this update is already 40 // in progress. 41 void StartUpdate(AppCacheHost* host, const GURL& new_master_resource); 42 43 private: 44 friend class AppCacheUpdateJobTest; 45 class URLFetcher; 46 47 // Master entries have multiple hosts, for example, the same page is opened 48 // in different tabs. 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; 53 54 static const int kRerunDelayMs = 1000; 55 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. 59 60 enum UpdateType { 61 UNKNOWN_TYPE, 62 UPGRADE_ATTEMPT, 63 CACHE_ATTEMPT, 64 }; 65 66 enum InternalUpdateState { 67 FETCH_MANIFEST, 68 NO_UPDATE, 69 DOWNLOADING, 70 71 // Every state after this comment indicates the update is terminating. 72 REFETCH_MANIFEST, 73 CACHE_FAILURE, 74 CANCELLED, 75 COMPLETED, 76 }; 77 78 enum StoredState { 79 UNSTORED, 80 STORING, 81 STORED, 82 }; 83 84 struct UrlToFetch { 85 UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info); 86 ~UrlToFetch(); 87 88 GURL url; 89 bool storage_checked; 90 scoped_refptr<AppCacheResponseInfo> existing_response_info; 91 }; 92 93 class URLFetcher : public net::URLRequest::Delegate { 94 public: 95 enum FetchType { 96 MANIFEST_FETCH, 97 URL_FETCH, 98 MASTER_ENTRY_FETCH, 99 MANIFEST_REFETCH, 100 }; 101 URLFetcher(const GURL& url, 102 FetchType fetch_type, 103 AppCacheUpdateJob* job); 104 virtual ~URLFetcher(); 105 void Start(); 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(); 112 } 113 void set_existing_response_headers(net::HttpResponseHeaders* headers) { 114 existing_response_headers_ = headers; 115 } 116 void set_existing_entry(const AppCacheEntry& entry) { 117 existing_entry_ = entry; 118 } 119 120 private: 121 // URLRequest::Delegate overrides 122 virtual void OnReceivedRedirect(net::URLRequest* request, 123 const GURL& new_url, 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; 128 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(); 135 136 GURL url_; 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 147 148 AppCacheResponseWriter* CreateResponseWriter(); 149 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, 155 bool success, 156 bool would_exceed_quota) OVERRIDE; 157 virtual void OnGroupMadeObsolete(AppCacheGroup* group, bool success) OVERRIDE; 158 159 // Methods for AppCacheHost::Observer. 160 virtual void OnCacheSelectionComplete(AppCacheHost* host) OVERRIDE {} // N/A 161 virtual void OnDestructionImminent(AppCacheHost* host) OVERRIDE; 162 163 void HandleCacheFailure(const std::string& error_message); 164 165 void FetchManifest(bool is_first_fetch); 166 void HandleManifestFetchCompleted(URLFetcher* fetcher); 167 void ContinueHandleManifestFetchCompleted(bool changed); 168 169 void HandleUrlFetchCompleted(URLFetcher* fetcher); 170 void HandleMasterEntryFetchCompleted(URLFetcher* fetcher); 171 172 void HandleManifestRefetchCompleted(URLFetcher* fetcher); 173 void OnManifestInfoWriteComplete(int result); 174 void OnManifestDataWriteComplete(int result); 175 176 void StoreGroupAndCache(); 177 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); 184 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); 189 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); 194 void FetchUrls(); 195 void CancelAllUrlFetches(); 196 bool ShouldSkipUrlFetch(const AppCacheEntry& entry); 197 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); 202 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 205 // fetches. 206 void AddMasterEntryToFetchList(AppCacheHost* host, const GURL& url, 207 bool is_new); 208 void FetchMasterEntries(); 209 void CancelAllMasterEntryFetches(const std::string& error_message); 210 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); 218 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(); 223 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); 227 228 void Cancel(); 229 void ClearPendingMasterEntries(); 230 void DiscardInprogressCache(); 231 void DiscardDuplicateResponses(); 232 233 // Deletes this object after letting the stack unwind. 234 void DeleteSoon(); 235 236 bool IsTerminating() { return internal_state_ >= REFETCH_MANIFEST || 237 stored_state_ != UNSTORED; } 238 239 AppCacheService* service_; 240 const GURL manifest_url_; // here for easier access 241 242 scoped_refptr<AppCache> inprogress_cache_; 243 244 AppCacheGroup* group_; 245 246 UpdateType update_type_; 247 InternalUpdateState internal_state_; 248 249 PendingMasters pending_master_entries_; 250 size_t master_entries_completed_; 251 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_; 259 260 // URLs of files to fetch along with their flags. 261 AppCache::EntryMap url_file_list_; 262 size_t url_fetches_completed_; 263 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_; 268 269 // Helper container to track which urls are being loaded from response 270 // storage. 271 LoadingResponses loading_responses_; 272 273 // Keep track of pending URL requests so we can cancel them if necessary. 274 URLFetcher* manifest_fetcher_; 275 PendingUrlFetches pending_url_fetches_; 276 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_; 284 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_; 288 289 // Response ids stored by this update job, used to cleanup in 290 // error conditions. 291 std::vector<int64> stored_response_ids_; 292 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_; 299 300 // Whether we've stored the resulting group/cache yet. 301 StoredState stored_state_; 302 303 FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest, QueueUpdate); 304 305 DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob); 306 }; 307 308 } // namespace appcache 309 310 #endif // WEBKIT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ 311