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 CONTENT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ 6 #define CONTENT_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 "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" 27 #include "url/gurl.h" 28 29 namespace content { 30 FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate); 31 class AppCacheGroupTest; 32 class AppCacheUpdateJobTest; 33 class HostNotifier; 34 35 // Application cache Update algorithm and state. 36 class CONTENT_EXPORT AppCacheUpdateJob 37 : public AppCacheStorage::Delegate, 38 public AppCacheHost::Observer, 39 public AppCacheServiceImpl::Observer { 40 public: 41 // Used for uma stats only for now, so new values are append only. 42 enum ResultType { 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 46 }; 47 48 AppCacheUpdateJob(AppCacheServiceImpl* service, AppCacheGroup* group); 49 virtual ~AppCacheUpdateJob(); 50 51 // Triggers the update process or adds more info if this update is already 52 // in progress. 53 void StartUpdate(AppCacheHost* host, const GURL& new_master_resource); 54 55 private: 56 friend class content::AppCacheGroupTest; 57 friend class content::AppCacheUpdateJobTest; 58 class URLFetcher; 59 60 // Master entries have multiple hosts, for example, the same page is opened 61 // in different tabs. 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; 66 67 static const int kRerunDelayMs = 1000; 68 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. 72 73 enum UpdateType { 74 UNKNOWN_TYPE, 75 UPGRADE_ATTEMPT, 76 CACHE_ATTEMPT, 77 }; 78 79 enum InternalUpdateState { 80 FETCH_MANIFEST, 81 NO_UPDATE, 82 DOWNLOADING, 83 84 // Every state after this comment indicates the update is terminating. 85 REFETCH_MANIFEST, 86 CACHE_FAILURE, 87 CANCELLED, 88 COMPLETED, 89 }; 90 91 enum StoredState { 92 UNSTORED, 93 STORING, 94 STORED, 95 }; 96 97 struct UrlToFetch { 98 UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info); 99 ~UrlToFetch(); 100 101 GURL url; 102 bool storage_checked; 103 scoped_refptr<AppCacheResponseInfo> existing_response_info; 104 }; 105 106 class URLFetcher : public net::URLRequest::Delegate { 107 public: 108 enum FetchType { 109 MANIFEST_FETCH, 110 URL_FETCH, 111 MASTER_ENTRY_FETCH, 112 MANIFEST_REFETCH, 113 }; 114 URLFetcher(const GURL& url, 115 FetchType fetch_type, 116 AppCacheUpdateJob* job); 117 virtual ~URLFetcher(); 118 void Start(); 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(); 125 } 126 void set_existing_response_headers(net::HttpResponseHeaders* headers) { 127 existing_response_headers_ = headers; 128 } 129 void set_existing_entry(const AppCacheEntry& entry) { 130 existing_entry_ = entry; 131 } 132 ResultType result() const { return result_; } 133 int redirect_response_code() const { return redirect_response_code_; } 134 135 private: 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; 143 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(); 150 151 GURL url_; 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_; 160 ResultType result_; 161 int redirect_response_code_; 162 scoped_ptr<AppCacheResponseWriter> response_writer_; 163 }; // class URLFetcher 164 165 AppCacheResponseWriter* CreateResponseWriter(); 166 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, 172 bool success, 173 bool would_exceed_quota) OVERRIDE; 174 virtual void OnGroupMadeObsolete(AppCacheGroup* group, 175 bool success, 176 int response_code) OVERRIDE; 177 178 // Methods for AppCacheHost::Observer. 179 virtual void OnCacheSelectionComplete(AppCacheHost* host) OVERRIDE {} // N/A 180 virtual void OnDestructionImminent(AppCacheHost* host) OVERRIDE; 181 182 // Methods for AppCacheServiceImpl::Observer. 183 virtual void OnServiceReinitialized( 184 AppCacheStorageReference* old_storage) OVERRIDE; 185 186 void HandleCacheFailure(const AppCacheErrorDetails& details, 187 ResultType result, 188 const GURL& failed_resource_url); 189 190 void FetchManifest(bool is_first_fetch); 191 void HandleManifestFetchCompleted(URLFetcher* fetcher); 192 void ContinueHandleManifestFetchCompleted(bool changed); 193 194 void HandleUrlFetchCompleted(URLFetcher* fetcher); 195 void HandleMasterEntryFetchCompleted(URLFetcher* fetcher); 196 197 void HandleManifestRefetchCompleted(URLFetcher* fetcher); 198 void OnManifestInfoWriteComplete(int result); 199 void OnManifestDataWriteComplete(int result); 200 201 void StoreGroupAndCache(); 202 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); 210 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); 215 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 AppCacheManifest& manifest); 219 void AddUrlToFileList(const GURL& url, int type); 220 void FetchUrls(); 221 void CancelAllUrlFetches(); 222 bool ShouldSkipUrlFetch(const AppCacheEntry& entry); 223 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); 228 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 231 // fetches. 232 void AddMasterEntryToFetchList(AppCacheHost* host, const GURL& url, 233 bool is_new); 234 void FetchMasterEntries(); 235 void CancelAllMasterEntryFetches(const AppCacheErrorDetails& details); 236 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); 244 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(); 249 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); 253 254 void Cancel(); 255 void ClearPendingMasterEntries(); 256 void DiscardInprogressCache(); 257 void DiscardDuplicateResponses(); 258 259 void LogHistogramStats(ResultType result, const GURL& failed_resource_url); 260 void MadeProgress() { last_progress_time_ = base::Time::Now(); } 261 262 // Deletes this object after letting the stack unwind. 263 void DeleteSoon(); 264 265 bool IsTerminating() { return internal_state_ >= REFETCH_MANIFEST || 266 stored_state_ != UNSTORED; } 267 268 AppCacheServiceImpl* service_; 269 const GURL manifest_url_; // here for easier access 270 271 // Defined prior to refs to AppCaches and Groups because destruction 272 // order matters, the disabled_storage_reference_ must outlive those 273 // objects. 274 scoped_refptr<AppCacheStorageReference> disabled_storage_reference_; 275 276 scoped_refptr<AppCache> inprogress_cache_; 277 278 AppCacheGroup* group_; 279 280 UpdateType update_type_; 281 InternalUpdateState internal_state_; 282 base::Time last_progress_time_; 283 284 PendingMasters pending_master_entries_; 285 size_t master_entries_completed_; 286 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_; 294 295 // URLs of files to fetch along with their flags. 296 AppCache::EntryMap url_file_list_; 297 size_t url_fetches_completed_; 298 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_; 303 304 // Helper container to track which urls are being loaded from response 305 // storage. 306 LoadingResponses loading_responses_; 307 308 // Keep track of pending URL requests so we can cancel them if necessary. 309 URLFetcher* manifest_fetcher_; 310 PendingUrlFetches pending_url_fetches_; 311 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_; 320 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_; 324 325 // Response ids stored by this update job, used to cleanup in 326 // error conditions. 327 std::vector<int64> stored_response_ids_; 328 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_; 335 336 // Whether we've stored the resulting group/cache yet. 337 StoredState stored_state_; 338 339 AppCacheStorage* storage_; 340 341 FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate); 342 343 DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob); 344 }; 345 346 } // namespace content 347 348 #endif // CONTENT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_ 349