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
content / browser / shared_storage / shared_storage_header_observer.h [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SHARED_STORAGE_SHARED_STORAGE_HEADER_OBSERVER_H_
#define CONTENT_BROWSER_SHARED_STORAGE_SHARED_STORAGE_HEADER_OBSERVER_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "content/browser/navigation_or_document_handle.h"
#include "content/browser/shared_storage/shared_storage_worklet_host_manager.h"
#include "content/browser/storage_partition_impl.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/message.h"
#include "services/network/public/mojom/optional_bool.mojom.h"
#include "services/network/public/mojom/url_loader_network_service_observer.mojom.h"
#include "url/origin.h"
namespace content {
using AccessType =
SharedStorageWorkletHostManager::SharedStorageObserverInterface::AccessType;
// Receives notifications from `StoragePartitionImpl` when a parsed
// "Shared-Storage-Write" header is received from the network service. The
// parsed header takes the form of a vector of StructPtrs bundling operation
// types with any parameters. The corresponding shared storage operations are
// invoked in the same order, omitting any operations that are missing any
// necessary parameters or for which any necessary parameters are invalid.
class CONTENT_EXPORT SharedStorageHeaderObserver {
public:
using OperationResult = storage::SharedStorageManager::OperationResult;
using OperationType = network::mojom::SharedStorageOperationType;
using OperationPtr = network::mojom::SharedStorageOperationPtr;
using ContextType = StoragePartitionImpl::ContextType;
// Enum for tracking how often the `PermissionsPolicy` double check runs along
// with its results. Recorded to UMA; always add new values to the end and do
// not reorder or delete values from this list. If you add any entries to this
// enum, you must also update the corresponding enum
// `SharedStorageHeaderObserverPermissionsPolicyDoubleCheckStatus` at
// tools/metrics/histograms/metadata/storage/enums.xml.
enum class PermissionsPolicyDoubleCheckStatus {
// RFH is null, so no double check is run. Any previous permissions
// policy checks were only done in the renderer; hence operations
// are dropped.
kSubresourceSourceNoRFH = 0,
// RFH has not yet committed. Defer the operations until a corresponding
// commit notification is received. If none is received, they will be
// dropped when RFH dies.
kSubresourceSourceDefer = 1,
// RFH's LifecycleState is neither kPendingCommit nor kActive. We do not
// handle these cases as the PermissionsPolicy that we have access to may
// not be correct. Any operations are dropped.
kSubresourceSourceOtherLifecycleState = 2,
// RFH is non-null but has no `PermissionsPolicy`, so no double
// check is run. Any previous permissions policy checks were only
// done in the renderer; hence operations are dropped.
kSubresourceSourceNoPolicy = 3,
// RFH is non-null but has no `PermissionsPolicy`, so no double
// check is run, but the request source is an iframe navigation, so
// a previous browser-side permissions policy check was run in
// `NavigationRequest`. Hence it is ok to skip the double-check and
// proceed with the operations.
kNavigationSourceNoPolicy = 4,
// The request source is a navigation request for a main frame,
// which is not supported.
kDisallowedMainFrameNavigation = 5,
// A double check is run and the feature is disabled so
// operations are dropped.
kDisabled = 6,
// A double check is run and the feature is enabled so
// operations are processed.
kEnabled = 7,
// Keep this at the end and equal to the last entry.
kMaxValue = kEnabled,
};
explicit SharedStorageHeaderObserver(StoragePartitionImpl* storage_partition);
virtual ~SharedStorageHeaderObserver();
// Called by `StoragePartitionImpl` to notify that a parsed
// "Shared-Storage-Write" header `operations` for a request to
// `request_origin` from `rfh` has been received. For each operation in
// `operations`, validates each operation and then invokes each valid
// operation in the order received, skipping any operations that are missing
// any necessary parameters or for which any necessary parameters are
// invalid..
void HeaderReceived(const url::Origin& request_origin,
ContextType context_type,
NavigationOrDocumentHandle* navigation_or_document_handle,
std::vector<OperationPtr> operations,
base::OnceClosure callback,
mojo::ReportBadMessageCallback bad_message_callback,
bool can_defer);
protected:
// virtual for testing.
virtual void OnHeaderProcessed(const url::Origin& request_origin,
const std::vector<bool>& header_results) {}
virtual void OnOperationFinished(const url::Origin& request_origin,
OperationPtr operation,
OperationResult result) {}
private:
bool Invoke(const url::Origin& request_origin,
FrameTreeNodeId main_frame_id,
OperationPtr operation);
bool Set(const url::Origin& request_origin,
FrameTreeNodeId main_frame_id,
std::string key,
std::string value,
network::mojom::OptionalBool ignore_if_present);
bool Append(const url::Origin& request_origin,
FrameTreeNodeId main_frame_id,
std::string key,
std::string value);
bool Delete(const url::Origin& request_origin,
FrameTreeNodeId main_frame_id,
std::string key);
bool Clear(const url::Origin& request_origin, FrameTreeNodeId main_frame_id);
storage::SharedStorageManager* GetSharedStorageManager();
PermissionsPolicyDoubleCheckStatus DoPermissionsPolicyDoubleCheck(
const url::Origin& request_origin,
ContextType context_type,
NavigationOrDocumentHandle* navigation_or_document_handle);
bool IsSharedStorageAllowedBySiteSettings(
NavigationOrDocumentHandle* navigation_or_document_handle,
const url::Origin& request_origin,
std::string* out_debug_message = nullptr);
void NotifySharedStorageAccessed(AccessType type,
FrameTreeNodeId main_frame_id,
const url::Origin& request_origin,
const SharedStorageEventParams& params);
// `storage_partition_` owns `this`, so it will outlive `this`.
raw_ptr<StoragePartitionImpl> storage_partition_;
base::WeakPtrFactory<SharedStorageHeaderObserver> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_SHARED_STORAGE_SHARED_STORAGE_HEADER_OBSERVER_H_