forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathappcache_host.h
446 lines (357 loc) · 17.7 KB
/
appcache_host.h
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
// Copyright (c) 2011 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_HOST_H_
#define CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
#include <stdint.h>
#include <memory>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "content/browser/appcache/appcache_group.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/appcache_storage.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/common/appcache_interfaces.h"
#include "content/common/content_export.h"
#include "content/public/common/child_process_host.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-forward.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace net {
class URLRequest;
} // namespace net
namespace content {
FORWARD_DECLARE_TEST(AppCacheGroupTest, CleanupUnusedGroup);
FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
FORWARD_DECLARE_TEST(AppCacheHostTest, FailedCacheLoad);
FORWARD_DECLARE_TEST(AppCacheHostTest, FailedGroupLoad);
FORWARD_DECLARE_TEST(AppCacheHostTest, SetSwappableCache);
FORWARD_DECLARE_TEST(AppCacheTest, CleanupUnusedCache);
class AppCache;
class AppCacheGroupTest;
class AppCacheRequest;
class AppCacheRequestHandler;
class AppCacheRequestHandlerTest;
class AppCacheStorageImplTest;
class AppCacheSubresourceURLFactory;
class AppCacheTest;
namespace appcache_update_job_unittest {
class AppCacheUpdateJobTest;
}
// The browser-side implementation of the document hosting an application cache.
class CONTENT_EXPORT AppCacheHost : public blink::mojom::AppCacheHost,
public AppCacheStorage::Delegate,
public AppCacheGroup::UpdateObserver,
public AppCacheServiceImpl::Observer {
public:
using SecurityPolicyHandle = ChildProcessSecurityPolicyImpl::Handle;
class CONTENT_EXPORT Observer {
public:
Observer(const Observer&) = delete;
Observer& operator=(const Observer&) = delete;
// Called just after the cache selection algorithm completes.
virtual void OnCacheSelectionComplete(AppCacheHost* host) = 0;
// Called just prior to the instance being deleted.
virtual void OnDestructionImminent(AppCacheHost* host) = 0;
protected:
// The constructor and destructor exist to facilitate subclassing, and
// should not be called directly.
Observer() noexcept = default;
virtual ~Observer() = default;
};
AppCacheHost(
const base::UnguessableToken& host_id,
int process_id,
int render_frame_id,
SecurityPolicyHandle security_policy_handle,
mojo::PendingRemote<blink::mojom::AppCacheFrontend> frontend_remote,
AppCacheServiceImpl* service);
~AppCacheHost() override;
void BindReceiver(mojo::PendingReceiver<blink::mojom::AppCacheHost> receiver);
// Adds/removes an observer, the AppCacheHost does not take
// ownership of the observer.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
void Unregister();
// blink::mojom::AppCacheHost
void SelectCache(const GURL& document_url,
const int64_t cache_document_was_loaded_from,
const GURL& manifest_url) override;
void SelectCacheForWorker(int64_t appcache_id) override;
void MarkAsForeignEntry(const GURL& document_url,
int64_t cache_document_was_loaded_from) override;
void GetStatus(GetStatusCallback callback) override;
void StartUpdate(StartUpdateCallback callback) override;
void SwapCache(SwapCacheCallback callback) override;
void SetSpawningHostId(
const base::UnguessableToken& spawning_host_id) override;
void GetResourceList(GetResourceListCallback callback) override;
// May return NULL if the spawning host context has been closed, or if a
// spawning host context was never identified.
const AppCacheHost* GetSpawningHost() const;
const GURL& preferred_manifest_url() const { return preferred_manifest_url_; }
void set_preferred_manifest_url(const GURL& url) {
preferred_manifest_url_ = url;
}
// Support for loading resources out of the appcache.
// May return NULL if the request isn't subject to retrieval from an appache.
std::unique_ptr<AppCacheRequestHandler> CreateRequestHandler(
std::unique_ptr<AppCacheRequest> request,
network::mojom::RequestDestination request_destination,
bool should_reset_appcache);
// Support for devtools inspecting appcache resources.
void GetResourceListSync(
std::vector<blink::mojom::AppCacheResourceInfo>* resource_infos);
// Breaks any existing association between this host and a cache.
// 'manifest_url' is sent to DevTools as the manifest url that could have
// been associated before or could be associated later with this host.
// Associations are broken either thru the cache selection algorithm
// implemented in this class, or by the update algorithm (see
// AppCacheUpdateJob).
void AssociateNoCache(const GURL& manifest_url);
// Establishes an association between this host and an incomplete cache.
// 'manifest_url' is manifest url of the cache group being updated.
// Associations with incomplete caches are established by the update algorithm
// (see AppCacheUpdateJob).
void AssociateIncompleteCache(AppCache* cache, const GURL& manifest_url);
// Establishes an association between this host and a complete cache.
// Associations with complete caches are established either thru the cache
// selection algorithm implemented (in this class), or by the update algorithm
// (see AppCacheUpdateJob).
void AssociateCompleteCache(AppCache* cache);
// Adds a reference to the newest complete cache in a group, unless it's the
// same as the cache that is currently associated with the host.
void SetSwappableCache(AppCacheGroup* group);
// Used to ensure that a loaded appcache survives a frame navigation.
void LoadMainResourceCache(int64_t cache_id);
// Used to notify the host that a namespace resource is being delivered as
// the main resource of the page and to provide its url.
void NotifyMainResourceIsNamespaceEntry(const GURL& namespace_entry_url);
// Used to notify the host that the main resource was blocked by a policy. To
// work properly, this method needs to by invoked prior to cache selection.
void NotifyMainResourceBlocked(const GURL& manifest_url);
// Used by the update job to keep track of which hosts are associated
// with which pending master entries.
const GURL& pending_master_entry_url() const { return new_master_entry_url_; }
const base::UnguessableToken& host_id() const { return host_id_; }
int process_id() const {
DCHECK_NE(process_id_, ChildProcessHost::kInvalidUniqueID);
return process_id_;
}
SecurityPolicyHandle* security_policy_handle() {
return &security_policy_handle_;
}
// SetProcessId may only be called once, and only if kInvalidUniqueID was
// passed to the AppCacheHost's constructor (e.g. in a scenario where
// NavigationRequest needs to delay specifying the |process_id| until
// ReadyToCommit time).
void SetProcessId(int process_id);
AppCacheServiceImpl* service() const { return service_; }
AppCacheStorage* storage() const { return storage_; }
blink::mojom::AppCacheFrontend* frontend() const { return frontend_; }
// The AppCacheHost instance is created with a null AppCacheFrontend
// pointer when the navigation starts. We need to switch it to the
// actual frontend when the navigation commits.
void set_frontend(
mojo::PendingRemote<blink::mojom::AppCacheFrontend> frontend_remote,
int render_frame_id) {
frontend_remote_.Bind(std::move(frontend_remote));
frontend_ = frontend_remote_.get();
render_frame_id_ = render_frame_id;
}
void set_frontend_for_testing(blink::mojom::AppCacheFrontend* frontend) {
frontend_ = frontend;
}
AppCache* associated_cache() const { return associated_cache_.get(); }
void enable_cache_selection(bool enable) {
is_cache_selection_enabled_ = enable;
}
bool is_selection_pending() const {
return pending_selected_cache_id_ != blink::mojom::kAppCacheNoCacheId ||
!pending_selected_manifest_url_.is_empty();
}
const net::SiteForCookies& site_for_cookies() const {
return site_for_cookies_;
}
void SetSiteForCookiesForTesting(
const net::SiteForCookies& site_for_cookies) {
site_for_cookies_ = site_for_cookies;
site_for_cookies_initialized_ = true;
}
const base::Optional<url::Origin>& top_frame_origin() const {
return top_frame_origin_;
}
void set_origin_for_url_loader_factory(const url::Origin& origin) {
origin_for_url_loader_factory_ = origin;
}
// Returns a weak pointer reference to the host.
base::WeakPtr<AppCacheHost> GetWeakPtr();
// In the network service world, we need to pass the URLLoaderFactory
// instance to the renderer which it can use to request subresources.
// This ensures that they can be served out of the AppCache.
void MaybePassSubresourceFactory();
// This is called when the frame is navigated to a page which loads from
// the AppCache.
void SetAppCacheSubresourceFactory(
AppCacheSubresourceURLFactory* subresource_factory);
void OnContentBlocked(const GURL& manifest_url);
bool IsOriginTrialRequiredForAppCache();
private:
friend class content::AppCacheStorageImplTest;
friend class content::AppCacheRequestHandlerTest;
friend class content::appcache_update_job_unittest::AppCacheUpdateJobTest;
blink::mojom::AppCacheStatus GetStatusSync();
void LoadSelectedCache(int64_t cache_id);
void LoadOrCreateGroup(const GURL& manifest_url);
// See public Associate*Host() methods above.
void AssociateCacheHelper(AppCache* cache, const GURL& manifest_url);
// AppCacheStorage::Delegate impl
void OnCacheLoaded(AppCache* cache, int64_t cache_id) override;
void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override;
// AppCacheServiceImpl::Observer impl
void OnServiceReinitialized(
AppCacheStorageReference* old_storage_ref) override;
void FinishCacheSelection(
AppCache* cache,
AppCacheGroup* group,
mojo::ReportBadMessageCallback bad_message_callback);
void DoPendingGetStatus();
void DoPendingStartUpdate();
void DoPendingSwapCache();
void ObserveGroupBeingUpdated(AppCacheGroup* group);
// AppCacheGroup::UpdateObserver methods.
void OnUpdateComplete(AppCacheGroup* group) override;
void OnAppCacheAccessed(const GURL& manifest_url, bool blocked);
// Identifies the corresponding appcache host in the child process.
const base::UnguessableToken host_id_;
// Identifies the renderer process associated with the AppCacheHost. Used for
// selecting the appropriate AppCacheBackend and creating
// |security_policy_handle_|.
int process_id_;
// Security policy handle for the renderer process associated with this
// AppCacheHost. Used for performing CanAccessDataForOrigin() security
// checks.
//
// Using this handle allows these checks to work even after the corresponding
// RenderProcessHost has been destroyed, in the case where there are still
// in-flight appcache requests that need to be processed. See
// https://crbug.com/943887.
SecurityPolicyHandle security_policy_handle_;
// Information about the host that created this one; the manifest
// preferred by our creator influences which cache our main resource
// should be loaded from.
base::UnguessableToken spawning_host_id_;
GURL preferred_manifest_url_;
// Defined prior to refs to AppCaches and Groups because destruction
// order matters, the disabled_storage_reference_ must outlive those
// objects. See additional comments for the storage_ member.
scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
// The cache associated with this host, if any.
scoped_refptr<AppCache> associated_cache_;
// Hold a reference to the newest complete cache (if associated cache is
// not the newest) to keep the newest cache in existence while the app cache
// group is in use. The newest complete cache may have no associated hosts
// holding any references to it and would otherwise be deleted prematurely.
scoped_refptr<AppCache> swappable_cache_;
// Keep a reference to the group being updated until the update completes.
scoped_refptr<AppCacheGroup> group_being_updated_;
// Similarly, keep a reference to the newest cache of the group until the
// update completes. When adding a new master entry to a cache that is not
// in use in any other host, this reference keeps the cache in memory.
scoped_refptr<AppCache> newest_cache_of_group_being_updated_;
// Keep a reference to the cache of the main resource so it survives frame
// navigations.
scoped_refptr<AppCache> main_resource_cache_;
int64_t pending_main_resource_cache_id_;
// Cache loading is async. If we're loading a specific cache or group
// for the purposes of cache selection, one or the other of these will
// indicate which cache or group is being loaded.
int64_t pending_selected_cache_id_;
GURL pending_selected_manifest_url_;
// Cache loading is async. If we determine after loading that the request to
// load the cache was actually invalid we can call this callback to report an
// earlier mojo message as bad to kill the renderer.
// Unlike the pending*callback_ fields further below in this class, it is
// fine for this callback to not get called, and as such it is not included
// in the cleanup code in the destructor.
mojo::ReportBadMessageCallback pending_selected_cache_bad_message_callback_;
// Used to defend against bad IPC messages.
bool was_select_cache_called_;
// Used to avoid stepping on pages controlled by ServiceWorkers.
bool is_cache_selection_enabled_;
// A new master entry to be added to the cache, may be empty.
GURL new_master_entry_url_;
// The frontend to deliver notifications to the child process.
mojo::Remote<blink::mojom::AppCacheFrontend> frontend_remote_;
blink::mojom::AppCacheFrontend* frontend_;
int render_frame_id_;
// Our central service object.
AppCacheServiceImpl* service_;
// And the equally central storage object, with a twist. In some error
// conditions the storage object gets recreated and reinitialized. The
// disabled_storage_reference_ (defined earlier) allows for cleanup of an
// instance that got disabled after we had latched onto it. In normal
// circumstances, disabled_storage_reference_ is expected to be NULL.
// When non-NULL both storage_ and disabled_storage_reference_ refer to the
// same instance.
AppCacheStorage* storage_;
// Since these are synchronous scriptable API calls in the client, there can
// only be one type of callback pending. Also, we have to wait until we have a
// cache selection prior to responding to these calls, as cache selection
// involves async loading of a cache or a group from storage.
// If any of these callbacks are non-null at the time this AppCacheHost is
// destroyed, we have to make sure that they still get called, as the mojo
// pipe the callbacks are associated with will outlive this. So make sure to
// update the destructor if adding more callbacks here.
GetStatusCallback pending_get_status_callback_;
StartUpdateCallback pending_start_update_callback_;
SwapCacheCallback pending_swap_cache_callback_;
// True if an intercept or fallback namespace resource was
// delivered as the main resource.
bool main_resource_was_namespace_entry_;
GURL namespace_entry_url_;
// True if requests for this host were blocked by a policy.
bool main_resource_blocked_;
GURL blocked_manifest_url_;
// Tells if info about associated cache is pending. Info is pending
// when update job has not returned success yet.
bool associated_cache_info_pending_;
// List of objects observing us.
base::ObserverList<Observer>::Unchecked observers_;
// Used to inform the QuotaManager of what origins are currently in use.
url::Origin origin_in_use_;
// The origin used when calling
// ContentBrowserClient::WillCreateURLLoaderFactory().
url::Origin origin_for_url_loader_factory_;
// To be used in policy checks.
net::SiteForCookies site_for_cookies_;
bool site_for_cookies_initialized_ = false;
base::Optional<url::Origin> top_frame_origin_;
bool is_origin_trial_required_ = false;
FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, CleanupUnusedGroup);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedCacheLoad);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedGroupLoad);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SetSwappableCache);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, CleanupUnusedCache);
// In the network service world points to the subresource URLLoaderFactory.
base::WeakPtr<AppCacheSubresourceURLFactory> subresource_url_factory_;
mojo::Receiver<blink::mojom::AppCacheHost> receiver_{this};
base::WeakPtrFactory<AppCacheHost> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
};
} // namespace content
#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_