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