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 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