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