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_H_
6#define CONTENT_BROWSER_APPCACHE_APPCACHE_H_
7
8#include <map>
9#include <set>
10#include <vector>
11
12#include "base/gtest_prod_util.h"
13#include "base/memory/ref_counted.h"
14#include "base/time/time.h"
15#include "content/browser/appcache/appcache_database.h"
16#include "content/browser/appcache/appcache_entry.h"
17#include "content/browser/appcache/appcache_manifest_parser.h"
18#include "content/common/content_export.h"
19#include "url/gurl.h"
20
21namespace net {
22class IOBuffer;
23}
24
25namespace content {
26FORWARD_DECLARE_TEST(AppCacheTest, InitializeWithManifest);
27FORWARD_DECLARE_TEST(AppCacheTest, ToFromDatabaseRecords);
28class AppCacheExecutableHandler;
29class AppCacheGroup;
30class AppCacheHost;
31class AppCacheStorage;
32class AppCacheTest;
33class AppCacheStorageImplTest;
34class AppCacheUpdateJobTest;
35
36// Set of cached resources for an application. A cache exists as long as a
37// host is associated with it, the cache is in an appcache group or the
38// cache is being created during an appcache upate.
39class CONTENT_EXPORT AppCache
40    : public base::RefCounted<AppCache> {
41 public:
42  typedef std::map<GURL, AppCacheEntry> EntryMap;
43  typedef std::set<AppCacheHost*> AppCacheHosts;
44
45  AppCache(AppCacheStorage* storage, int64 cache_id);
46
47  int64 cache_id() const { return cache_id_; }
48
49  AppCacheGroup* owning_group() const { return owning_group_.get(); }
50
51  bool is_complete() const { return is_complete_; }
52  void set_complete(bool value) { is_complete_ = value; }
53
54  // Adds a new entry. Entry must not already be in cache.
55  void AddEntry(const GURL& url, const AppCacheEntry& entry);
56
57  // Adds a new entry or modifies an existing entry by merging the types
58  // of the new entry with the existing entry. Returns true if a new entry
59  // is added, false if the flags are merged into an existing entry.
60  bool AddOrModifyEntry(const GURL& url, const AppCacheEntry& entry);
61
62  // Removes an entry from the EntryMap, the URL must be in the set.
63  void RemoveEntry(const GURL& url);
64
65  // Do not store or delete the returned ptr, they're owned by 'this'.
66  AppCacheEntry* GetEntry(const GURL& url);
67  const AppCacheEntry* GetEntryWithResponseId(int64 response_id) {
68    return GetEntryAndUrlWithResponseId(response_id, NULL);
69  }
70  const AppCacheEntry* GetEntryAndUrlWithResponseId(
71      int64 response_id, GURL* optional_url);
72  const EntryMap& entries() const { return entries_; }
73
74  // The AppCache owns the collection of executable handlers that have
75  // been started for this instance. The getter looks up an existing
76  // handler returning null if not found, the GetOrCreate method will
77  // cons one up if not found.
78  // Do not store the returned ptrs, they're owned by 'this'.
79  AppCacheExecutableHandler* GetExecutableHandler(int64 response_id);
80  AppCacheExecutableHandler* GetOrCreateExecutableHandler(
81      int64 response_id, net::IOBuffer* handler_source);
82
83  // Returns the URL of the resource used as entry for 'namespace_url'.
84  GURL GetFallbackEntryUrl(const GURL& namespace_url) const {
85    return GetNamespaceEntryUrl(fallback_namespaces_, namespace_url);
86  }
87  GURL GetInterceptEntryUrl(const GURL& namespace_url) const {
88    return GetNamespaceEntryUrl(intercept_namespaces_, namespace_url);
89  }
90
91  AppCacheHosts& associated_hosts() { return associated_hosts_; }
92
93  bool IsNewerThan(AppCache* cache) const {
94    // TODO(michaeln): revisit, the system clock can be set
95    // back in time which would confuse this logic.
96    if (update_time_ > cache->update_time_)
97      return true;
98
99    // Tie breaker. Newer caches have a larger cache ID.
100    if (update_time_ == cache->update_time_)
101      return cache_id_ > cache->cache_id_;
102
103    return false;
104  }
105
106  base::Time update_time() const { return update_time_; }
107
108  int64 cache_size() const { return cache_size_; }
109
110  void set_update_time(base::Time ticks) { update_time_ = ticks; }
111
112  // Initializes the cache with information in the manifest.
113  // Do not use the manifest after this call.
114  void InitializeWithManifest(AppCacheManifest* manifest);
115
116  // Initializes the cache with the information in the database records.
117  void InitializeWithDatabaseRecords(
118      const AppCacheDatabase::CacheRecord& cache_record,
119      const std::vector<AppCacheDatabase::EntryRecord>& entries,
120      const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts,
121      const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks,
122      const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists);
123
124  // Returns the database records to be stored in the AppCacheDatabase
125  // to represent this cache.
126  void ToDatabaseRecords(
127      const AppCacheGroup* group,
128      AppCacheDatabase::CacheRecord* cache_record,
129      std::vector<AppCacheDatabase::EntryRecord>* entries,
130      std::vector<AppCacheDatabase::NamespaceRecord>* intercepts,
131      std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks,
132      std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists);
133
134  bool FindResponseForRequest(const GURL& url,
135      AppCacheEntry* found_entry, GURL* found_intercept_namespace,
136      AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace,
137      bool* found_network_namespace);
138
139  // Populates the 'infos' vector with an element per entry in the appcache.
140  void ToResourceInfoVector(AppCacheResourceInfoVector* infos) const;
141
142  static const AppCacheNamespace* FindNamespace(
143      const AppCacheNamespaceVector& namespaces,
144      const GURL& url);
145
146 private:
147  friend class AppCacheGroup;
148  friend class AppCacheHost;
149  friend class content::AppCacheTest;
150  friend class content::AppCacheStorageImplTest;
151  friend class content::AppCacheUpdateJobTest;
152  friend class base::RefCounted<AppCache>;
153
154  ~AppCache();
155
156  // Use AppCacheGroup::Add/RemoveCache() to manipulate owning group.
157  void set_owning_group(AppCacheGroup* group) { owning_group_ = group; }
158
159  // FindResponseForRequest helpers
160  const AppCacheNamespace* FindInterceptNamespace(const GURL& url) {
161    return FindNamespace(intercept_namespaces_, url);
162  }
163  const AppCacheNamespace* FindFallbackNamespace(const GURL& url) {
164    return FindNamespace(fallback_namespaces_, url);
165  }
166  bool IsInNetworkNamespace(const GURL& url) {
167    return FindNamespace(online_whitelist_namespaces_, url) != NULL;
168  }
169
170  GURL GetNamespaceEntryUrl(const AppCacheNamespaceVector& namespaces,
171                            const GURL& namespace_url) const;
172
173  // Use AppCacheHost::Associate*Cache() to manipulate host association.
174  void AssociateHost(AppCacheHost* host) {
175    associated_hosts_.insert(host);
176  }
177  void UnassociateHost(AppCacheHost* host);
178
179  const int64 cache_id_;
180  scoped_refptr<AppCacheGroup> owning_group_;
181  AppCacheHosts associated_hosts_;
182
183  EntryMap entries_;    // contains entries of all types
184
185  AppCacheNamespaceVector intercept_namespaces_;
186  AppCacheNamespaceVector fallback_namespaces_;
187  AppCacheNamespaceVector online_whitelist_namespaces_;
188  bool online_whitelist_all_;
189
190  bool is_complete_;
191
192  // when this cache was last updated
193  base::Time update_time_;
194
195  int64 cache_size_;
196
197  typedef std::map<int64, AppCacheExecutableHandler*> HandlerMap;
198  HandlerMap executable_handlers_;
199
200  // to notify storage when cache is deleted
201  AppCacheStorage* storage_;
202
203  FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, InitializeWithManifest);
204  FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, ToFromDatabaseRecords);
205  DISALLOW_COPY_AND_ASSIGN(AppCache);
206};
207
208}  // namespace content
209
210#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_H_
211