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 "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_
    353