Home | History | Annotate | Download | only in appcache
      1 // Copyright (c) 2011 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_HOST_H_
      6 #define CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
      7 
      8 #include "base/callback.h"
      9 #include "base/gtest_prod_util.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/observer_list.h"
     12 #include "content/browser/appcache/appcache_group.h"
     13 #include "content/browser/appcache/appcache_service_impl.h"
     14 #include "content/browser/appcache/appcache_storage.h"
     15 #include "content/common/appcache_interfaces.h"
     16 #include "content/common/content_export.h"
     17 #include "content/public/common/resource_type.h"
     18 #include "url/gurl.h"
     19 
     20 namespace net {
     21 class URLRequest;
     22 }  // namespace net
     23 
     24 namespace content {
     25 FORWARD_DECLARE_TEST(AppCacheGroupTest, CleanupUnusedGroup);
     26 FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
     27 FORWARD_DECLARE_TEST(AppCacheHostTest, Basic);
     28 FORWARD_DECLARE_TEST(AppCacheHostTest, SelectNoCache);
     29 FORWARD_DECLARE_TEST(AppCacheHostTest, ForeignEntry);
     30 FORWARD_DECLARE_TEST(AppCacheHostTest, FailedCacheLoad);
     31 FORWARD_DECLARE_TEST(AppCacheHostTest, FailedGroupLoad);
     32 FORWARD_DECLARE_TEST(AppCacheHostTest, SetSwappableCache);
     33 FORWARD_DECLARE_TEST(AppCacheHostTest, ForDedicatedWorker);
     34 FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheAllowed);
     35 FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheBlocked);
     36 FORWARD_DECLARE_TEST(AppCacheTest, CleanupUnusedCache);
     37 class AppCache;
     38 class AppCacheFrontend;
     39 class AppCacheGroupTest;
     40 class AppCacheHostTest;
     41 class AppCacheRequestHandler;
     42 class AppCacheRequestHandlerTest;
     43 class AppCacheStorageImplTest;
     44 class AppCacheTest;
     45 class AppCacheUpdateJobTest;
     46 
     47 typedef base::Callback<void(AppCacheStatus, void*)> GetStatusCallback;
     48 typedef base::Callback<void(bool, void*)> StartUpdateCallback;
     49 typedef base::Callback<void(bool, void*)> SwapCacheCallback;
     50 
     51 // Server-side representation of an application cache host.
     52 class CONTENT_EXPORT AppCacheHost
     53     : public AppCacheStorage::Delegate,
     54       public AppCacheGroup::UpdateObserver,
     55       public AppCacheServiceImpl::Observer {
     56  public:
     57 
     58   class CONTENT_EXPORT Observer {
     59    public:
     60     // Called just after the cache selection algorithm completes.
     61     virtual void OnCacheSelectionComplete(AppCacheHost* host) = 0;
     62 
     63     // Called just prior to the instance being deleted.
     64     virtual void OnDestructionImminent(AppCacheHost* host) = 0;
     65 
     66     virtual ~Observer() {}
     67   };
     68 
     69   AppCacheHost(int host_id, AppCacheFrontend* frontend,
     70                AppCacheServiceImpl* service);
     71   virtual ~AppCacheHost();
     72 
     73   // Adds/removes an observer, the AppCacheHost does not take
     74   // ownership of the observer.
     75   void AddObserver(Observer* observer);
     76   void RemoveObserver(Observer* observer);
     77 
     78   // Support for cache selection and scriptable method calls.
     79   void SelectCache(const GURL& document_url,
     80                    const int64 cache_document_was_loaded_from,
     81                    const GURL& manifest_url);
     82   void SelectCacheForWorker(int parent_process_id,
     83                             int parent_host_id);
     84   void SelectCacheForSharedWorker(int64 appcache_id);
     85   void MarkAsForeignEntry(const GURL& document_url,
     86                           int64 cache_document_was_loaded_from);
     87   void GetStatusWithCallback(const GetStatusCallback& callback,
     88                              void* callback_param);
     89   void StartUpdateWithCallback(const StartUpdateCallback& callback,
     90                                void* callback_param);
     91   void SwapCacheWithCallback(const SwapCacheCallback& callback,
     92                              void* callback_param);
     93 
     94   // Called prior to the main resource load. When the system contains multiple
     95   // candidates for a main resource load, the appcache preferred by the host
     96   // that created this host is used to break ties.
     97   void SetSpawningHostId(int spawning_process_id, int spawning_host_id);
     98 
     99   // May return NULL if the spawning host context has been closed, or if a
    100   // spawning host context was never identified.
    101   const AppCacheHost* GetSpawningHost() const;
    102 
    103   const GURL& preferred_manifest_url() const {
    104     return preferred_manifest_url_;
    105   }
    106   void set_preferred_manifest_url(const GURL& url) {
    107     preferred_manifest_url_ = url;
    108   }
    109 
    110   // Support for loading resources out of the appcache.
    111   // May return NULL if the request isn't subject to retrieval from an appache.
    112   AppCacheRequestHandler* CreateRequestHandler(
    113       net::URLRequest* request,
    114       ResourceType resource_type);
    115 
    116   // Support for devtools inspecting appcache resources.
    117   void GetResourceList(std::vector<AppCacheResourceInfo>* resource_infos);
    118 
    119   // Breaks any existing association between this host and a cache.
    120   // 'manifest_url' is sent to DevTools as the manifest url that could have
    121   // been associated before or could be associated later with this host.
    122   // Associations are broken either thru the cache selection algorithm
    123   // implemented in this class, or by the update algorithm (see
    124   // AppCacheUpdateJob).
    125   void AssociateNoCache(const GURL& manifest_url);
    126 
    127   // Establishes an association between this host and an incomplete cache.
    128   // 'manifest_url' is manifest url of the cache group being updated.
    129   // Associations with incomplete caches are established by the update algorithm
    130   // (see AppCacheUpdateJob).
    131   void AssociateIncompleteCache(AppCache* cache, const GURL& manifest_url);
    132 
    133   // Establishes an association between this host and a complete cache.
    134   // Associations with complete caches are established either thru the cache
    135   // selection algorithm implemented (in this class), or by the update algorithm
    136   // (see AppCacheUpdateJob).
    137   void AssociateCompleteCache(AppCache* cache);
    138 
    139   // Adds a reference to the newest complete cache in a group, unless it's the
    140   // same as the cache that is currently associated with the host.
    141   void SetSwappableCache(AppCacheGroup* group);
    142 
    143   // Used to ensure that a loaded appcache survives a frame navigation.
    144   void LoadMainResourceCache(int64 cache_id);
    145 
    146   // Used to notify the host that a namespace resource is being delivered as
    147   // the main resource of the page and to provide its url.
    148   void NotifyMainResourceIsNamespaceEntry(const GURL& namespace_entry_url);
    149 
    150   // Used to notify the host that the main resource was blocked by a policy. To
    151   // work properly, this method needs to by invoked prior to cache selection.
    152   void NotifyMainResourceBlocked(const GURL& manifest_url);
    153 
    154   // Used by the update job to keep track of which hosts are associated
    155   // with which pending master entries.
    156   const GURL& pending_master_entry_url() const {
    157     return new_master_entry_url_;
    158   }
    159 
    160   int host_id() const { return host_id_; }
    161   AppCacheServiceImpl* service() const { return service_; }
    162   AppCacheStorage* storage() const { return storage_; }
    163   AppCacheFrontend* frontend() const { return frontend_; }
    164   AppCache* associated_cache() const { return associated_cache_.get(); }
    165 
    166   bool is_selection_pending() const {
    167     return pending_selected_cache_id_ != kAppCacheNoCacheId ||
    168            !pending_selected_manifest_url_.is_empty();
    169   }
    170 
    171   const GURL& first_party_url() const { return first_party_url_; }
    172 
    173   // Methods to support cross site navigations.
    174   void PrepareForTransfer();
    175   void CompleteTransfer(int host_id, AppCacheFrontend* frontend);
    176 
    177  private:
    178   friend class content::AppCacheHostTest;
    179   friend class content::AppCacheStorageImplTest;
    180   friend class content::AppCacheRequestHandlerTest;
    181   friend class content::AppCacheUpdateJobTest;
    182 
    183   AppCacheStatus GetStatus();
    184   void LoadSelectedCache(int64 cache_id);
    185   void LoadOrCreateGroup(const GURL& manifest_url);
    186 
    187   // See public Associate*Host() methods above.
    188   void AssociateCacheHelper(AppCache* cache, const GURL& manifest_url);
    189 
    190   // AppCacheStorage::Delegate impl
    191   virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE;
    192   virtual void OnGroupLoaded(AppCacheGroup* group,
    193                              const GURL& manifest_url) OVERRIDE;
    194   // AppCacheServiceImpl::Observer impl
    195   virtual void OnServiceReinitialized(
    196       AppCacheStorageReference* old_storage_ref) OVERRIDE;
    197 
    198   void FinishCacheSelection(AppCache* cache, AppCacheGroup* group);
    199   void DoPendingGetStatus();
    200   void DoPendingStartUpdate();
    201   void DoPendingSwapCache();
    202 
    203   void ObserveGroupBeingUpdated(AppCacheGroup* group);
    204 
    205   // AppCacheGroup::UpdateObserver methods.
    206   virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE;
    207 
    208   // Returns true if this host is for a dedicated worker context.
    209   bool is_for_dedicated_worker() const {
    210     return parent_host_id_ != kAppCacheNoHostId;
    211   }
    212 
    213   // Returns the parent context's host instance. This is only valid
    214   // to call when this instance is_for_dedicated_worker.
    215   AppCacheHost* GetParentAppCacheHost() const;
    216 
    217   // Identifies the corresponding appcache host in the child process.
    218   int host_id_;
    219 
    220   // Information about the host that created this one; the manifest
    221   // preferred by our creator influences which cache our main resource
    222   // should be loaded from.
    223   int spawning_host_id_;
    224   int spawning_process_id_;
    225   GURL preferred_manifest_url_;
    226 
    227   // Hosts for dedicated workers are special cased to shunt
    228   // request handling off to the dedicated worker's parent.
    229   // The scriptable api is not accessible in dedicated workers
    230   // so the other aspects of this class are not relevant for
    231   // these special case instances.
    232   int parent_host_id_;
    233   int parent_process_id_;
    234 
    235   // Defined prior to refs to AppCaches and Groups because destruction
    236   // order matters, the disabled_storage_reference_ must outlive those
    237   // objects. See additional comments for the storage_ member.
    238   scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
    239 
    240   // The cache associated with this host, if any.
    241   scoped_refptr<AppCache> associated_cache_;
    242 
    243   // Hold a reference to the newest complete cache (if associated cache is
    244   // not the newest) to keep the newest cache in existence while the app cache
    245   // group is in use. The newest complete cache may have no associated hosts
    246   // holding any references to it and would otherwise be deleted prematurely.
    247   scoped_refptr<AppCache> swappable_cache_;
    248 
    249   // Keep a reference to the group being updated until the update completes.
    250   scoped_refptr<AppCacheGroup> group_being_updated_;
    251 
    252   // Similarly, keep a reference to the newest cache of the group until the
    253   // update completes. When adding a new master entry to a cache that is not
    254   // in use in any other host, this reference keeps the cache in  memory.
    255   scoped_refptr<AppCache> newest_cache_of_group_being_updated_;
    256 
    257   // Keep a reference to the cache of the main resource so it survives frame
    258   // navigations.
    259   scoped_refptr<AppCache> main_resource_cache_;
    260   int64 pending_main_resource_cache_id_;
    261 
    262   // Cache loading is async, if we're loading a specific cache or group
    263   // for the purposes of cache selection, one or the other of these will
    264   // indicate which cache or group is being loaded.
    265   int64 pending_selected_cache_id_;
    266   GURL pending_selected_manifest_url_;
    267 
    268   // A new master entry to be added to the cache, may be empty.
    269   GURL new_master_entry_url_;
    270 
    271   // The frontend proxy to deliver notifications to the child process.
    272   AppCacheFrontend* frontend_;
    273 
    274   // Our central service object.
    275   AppCacheServiceImpl* service_;
    276 
    277   // And the equally central storage object, with a twist. In some error
    278   // conditions the storage object gets recreated and reinitialized. The
    279   // disabled_storage_reference_ (defined earlier) allows for cleanup of an
    280   // instance that got disabled  after we had latched onto it. In normal
    281   // circumstances, disabled_storage_reference_ is expected to be NULL.
    282   // When non-NULL both storage_ and disabled_storage_reference_ refer to the
    283   // same instance.
    284   AppCacheStorage* storage_;
    285 
    286   // Since these are synchronous scriptable API calls in the client, there can
    287   // only be one type of callback pending. Also, we have to wait until we have a
    288   // cache selection prior to responding to these calls, as cache selection
    289   // involves async loading of a cache or a group from storage.
    290   GetStatusCallback pending_get_status_callback_;
    291   StartUpdateCallback pending_start_update_callback_;
    292   SwapCacheCallback pending_swap_cache_callback_;
    293   void* pending_callback_param_;
    294 
    295   // True if an intercept or fallback namespace resource was
    296   // delivered as the main resource.
    297   bool main_resource_was_namespace_entry_;
    298   GURL namespace_entry_url_;
    299 
    300   // True if requests for this host were blocked by a policy.
    301   bool main_resource_blocked_;
    302   GURL blocked_manifest_url_;
    303 
    304   // Tells if info about associated cache is pending. Info is pending
    305   // when update job has not returned success yet.
    306   bool associated_cache_info_pending_;
    307 
    308   // List of objects observing us.
    309   ObserverList<Observer> observers_;
    310 
    311   // Used to inform the QuotaManager of what origins are currently in use.
    312   GURL origin_in_use_;
    313 
    314   // First party url to be used in policy checks.
    315   GURL first_party_url_;
    316 
    317   FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, CleanupUnusedGroup);
    318   FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
    319   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, Basic);
    320   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectNoCache);
    321   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, ForeignEntry);
    322   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedCacheLoad);
    323   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedGroupLoad);
    324   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SetSwappableCache);
    325   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, ForDedicatedWorker);
    326   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheAllowed);
    327   FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheBlocked);
    328   FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, CleanupUnusedCache);
    329 
    330   DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
    331 };
    332 
    333 }  // namespace content
    334 
    335 #endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
    336