summaryrefslogtreecommitdiff
path: root/chromium/content/browser/appcache/appcache.h
blob: 14af3e86f15664170369859882417eb3a98187de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_H_
#define CONTENT_BROWSER_APPCACHE_APPCACHE_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "content/browser/appcache/appcache_database.h"
#include "content/browser/appcache/appcache_entry.h"
#include "content/browser/appcache/appcache_group.h"
#include "content/browser/appcache/appcache_manifest_parser.h"
#include "content/browser/appcache/appcache_namespace.h"
#include "content/common/content_export.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom-forward.h"
#include "url/gurl.h"

namespace content {
FORWARD_DECLARE_TEST(AppCacheTest, InitializeWithManifest);
FORWARD_DECLARE_TEST(AppCacheTest, ToFromDatabaseRecords);
class AppCacheHost;
class AppCacheStorage;
class AppCacheTest;
class AppCacheStorageImplTest;

namespace appcache_update_job_unittest {
class AppCacheUpdateJobTest;
}

// Set of cached resources for an application. A cache exists as long as a
// host is associated with it, the cache is in an appcache group or the
// cache is being created during an appcache update.
class CONTENT_EXPORT AppCache
    : public base::RefCounted<AppCache> {
 public:
  using EntryMap = std::map<GURL, AppCacheEntry>;
  using AppCacheHosts = std::set<AppCacheHost*>;

  // Given a manifest URL and a scope, tests that the scope isn't empty and
  // that the result of resolving manifest URL to that scope matches our
  // expectations for the manifest scope (doesn't have a ref, doesn't have a
  // query, and ends in a forward-slash).
  static bool CheckValidManifestScope(const GURL& manifest_url,
                                      const std::string& manifest_scope);

  // Takes a manifest URL and an optional scope.  Returns a string representing
  // the manifest scope given those values.
  //
  // If |optional_scope| isn't empty, resolves |manifest_url| to a URL given
  // |optional_scope|, and tests the resulting path component for whether it's a
  // valid scope.  If so, that scope is returned.  Otherwise, returns the path
  // from a valid |manifest_url|.
  static std::string GetManifestScope(const GURL& manifest_url,
                                      std::string optional_scope);

  AppCache(AppCacheStorage* storage, int64_t cache_id);

  int64_t cache_id() const { return cache_id_; }

  AppCacheGroup* owning_group() const { return owning_group_.get(); }

  bool is_complete() const { return is_complete_; }
  void set_complete(bool value) { is_complete_ = value; }

  // Adds a new entry. Entry must not already be in cache.
  void AddEntry(const GURL& url, const AppCacheEntry& entry);

  // Adds a new entry or modifies an existing entry by merging the types
  // of the new entry with the existing entry. Returns true if a new entry
  // is added, false if the flags are merged into an existing entry.
  bool AddOrModifyEntry(const GURL& url, const AppCacheEntry& entry);

  // Removes an entry from the EntryMap, the URL must be in the set.
  void RemoveEntry(const GURL& url);

  // Do not store or delete the returned ptr, they're owned by 'this'.
  AppCacheEntry* GetEntry(const GURL& url);
  const AppCacheEntry* GetEntryWithResponseId(int64_t response_id) {
    return GetEntryAndUrlWithResponseId(response_id, nullptr);
  }
  const AppCacheEntry* GetEntryAndUrlWithResponseId(int64_t response_id,
                                                    GURL* optional_url);
  const EntryMap& entries() const { return entries_; }

  // Returns the URL of the resource used as entry for 'namespace_url'.
  GURL GetFallbackEntryUrl(const GURL& namespace_url) const {
    return GetNamespaceEntryUrl(fallback_namespaces_, namespace_url);
  }
  GURL GetInterceptEntryUrl(const GURL& namespace_url) const {
    return GetNamespaceEntryUrl(intercept_namespaces_, namespace_url);
  }

  AppCacheHosts& associated_hosts() { return associated_hosts_; }

  bool IsNewerThan(AppCache* cache) const {
    // TODO(michaeln): revisit, the system clock can be set
    // back in time which would confuse this logic.
    if (update_time_ > cache->update_time_)
      return true;

    // Tie breaker. Newer caches have a larger cache ID.
    if (update_time_ == cache->update_time_)
      return cache_id_ > cache->cache_id_;

    return false;
  }

  base::Time update_time() const { return update_time_; }
  void set_update_time(base::Time ticks) { update_time_ = ticks; }

  // The sum of all the padding sizes of the resources in this cache.
  //
  // See AppCacheEntry for a description of how padding size works.
  int64_t padding_size() const { return padding_size_; }

  // The sum of all the sizes of the resources in this cache.
  int64_t cache_size() const { return cache_size_; }

  int64_t manifest_parser_version() const { return manifest_parser_version_; }
  void set_manifest_parser_version(int64_t manifest_parser_version) {
    manifest_parser_version_ = manifest_parser_version;
  }
  const std::string& manifest_scope() const { return manifest_scope_; }
  void set_manifest_scope(const std::string& manifest_scope) {
    manifest_scope_ = manifest_scope;
  }

  base::Time token_expires() const { return token_expires_; }
  void set_token_expires(base::Time expires) { token_expires_ = expires; }

  // Initializes the cache with information in the manifest.
  // Do not use the manifest after this call.
  void InitializeWithManifest(AppCacheManifest* manifest);

  // Initializes the cache with the information in the database records.
  void InitializeWithDatabaseRecords(
      const AppCacheDatabase::CacheRecord& cache_record,
      const std::vector<AppCacheDatabase::EntryRecord>& entries,
      const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts,
      const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks,
      const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists);

  // Returns the database records to be stored in the AppCacheDatabase
  // to represent this cache.
  void ToDatabaseRecords(
      const AppCacheGroup* group,
      AppCacheDatabase::CacheRecord* cache_record,
      std::vector<AppCacheDatabase::EntryRecord>* entries,
      std::vector<AppCacheDatabase::NamespaceRecord>* intercepts,
      std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks,
      std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists);

  bool FindResponseForRequest(const GURL& url,
      AppCacheEntry* found_entry, GURL* found_intercept_namespace,
      AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace,
      bool* found_network_namespace);

  // Populates the 'infos' vector with an element per entry in the appcache.
  void ToResourceInfoVector(
      std::vector<blink::mojom::AppCacheResourceInfo>* infos) const;

  static const AppCacheNamespace* FindNamespace(
      const std::vector<AppCacheNamespace>& namespaces,
      const GURL& url);

 private:
  friend class AppCacheGroup;
  friend class AppCacheHost;
  friend class content::AppCacheTest;
  friend class content::AppCacheStorageImplTest;
  friend class content::appcache_update_job_unittest::AppCacheUpdateJobTest;
  friend class base::RefCounted<AppCache>;

  ~AppCache();

  // Use AppCacheGroup::Add/RemoveCache() to manipulate owning group.
  void set_owning_group(AppCacheGroup* group) { owning_group_ = group; }

  // FindResponseForRequest helpers
  const AppCacheNamespace* FindInterceptNamespace(const GURL& url) {
    return FindNamespace(intercept_namespaces_, url);
  }
  const AppCacheNamespace* FindFallbackNamespace(const GURL& url) {
    return FindNamespace(fallback_namespaces_, url);
  }
  bool IsInNetworkNamespace(const GURL& url) {
    return FindNamespace(online_whitelist_namespaces_, url) != nullptr;
  }

  GURL GetNamespaceEntryUrl(const std::vector<AppCacheNamespace>& namespaces,
                            const GURL& namespace_url) const;

  // Use AppCacheHost::Associate*Cache() to manipulate host association.
  void AssociateHost(AppCacheHost* host) {
    associated_hosts_.insert(host);
  }
  void UnassociateHost(AppCacheHost* host);

  const int64_t cache_id_;
  scoped_refptr<AppCacheGroup> owning_group_;
  AppCacheHosts associated_hosts_;

  EntryMap entries_;    // contains entries of all types

  std::vector<AppCacheNamespace> intercept_namespaces_;
  std::vector<AppCacheNamespace> fallback_namespaces_;
  std::vector<AppCacheNamespace> online_whitelist_namespaces_;
  bool online_whitelist_all_;

  bool is_complete_;

  // when this cache was last updated
  base::Time update_time_;

  // Origin Trial expiration time for the appcache's manifest.
  // This is base::Time() if no Origin Trial token was presented.
  base::Time token_expires_;

  int64_t cache_size_;
  int64_t padding_size_;

  // The version of the manifest parser used to interpret a given AppCache
  // manifest.  Since the features supported by the parser will change over
  // time, we can use the parser version to determine whether we should force a
  // manifest update.
  int64_t manifest_parser_version_;

  // The scope of the manifest determined either by default (the path to the
  // manifest URL without the filename) or given a server override.  The scope
  // is used to determine whether a given manifest is authorized to override a
  // given resource URL it specifies.
  std::string manifest_scope_;

  // to notify storage when cache is deleted
  AppCacheStorage* storage_;

  FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, InitializeWithManifest);
  FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, ToFromDatabaseRecords);
  DISALLOW_COPY_AND_ASSIGN(AppCache);
};

}  // namespace content

#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_H_