Home | History | Annotate | Download | only in appcache
      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