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