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
content / public / browser / document_user_data.h [blame]
// Copyright 2020 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_PUBLIC_BROWSER_DOCUMENT_USER_DATA_H_
#define CONTENT_PUBLIC_BROWSER_DOCUMENT_USER_DATA_H_
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/supports_user_data.h"
#include "content/common/content_export.h"
#include "url/origin.h"
namespace content {
class RenderFrameHost;
namespace internal {
CONTENT_EXPORT base::SupportsUserData::Data* GetDocumentUserData(
const RenderFrameHost* rfh,
const void* key);
CONTENT_EXPORT void SetDocumentUserData(
RenderFrameHost* rfh,
const void* key,
std::unique_ptr<base::SupportsUserData::Data> data);
CONTENT_EXPORT void RemoveDocumentUserData(RenderFrameHost* rfh,
const void* key);
} // namespace internal
// This class approximates the lifetime of a single blink::Document in the
// browser process. At the moment RenderFrameHost can correspond to multiple
// blink::Documents (when RenderFrameHost is reused for same-process
// navigation). DocumentUserData is created when a user of an API
// inherits this class and calls CreateForCurrentDocument.
//
// DocumentUserData is cleared when either:
// - RenderFrameHost is deleted, or
// - A cross-document non-bfcached navigation is committed in the same
// RenderFrameHost i.e., DocumentUserData persists when a document is
// put in the BackForwardCache. It will still be present when the user navigates
// back to the document.
//
// DocumentUserData is assumed to be associated with the document in
// the RenderFrameHost. It can be associated even before RenderFrameHost commits
// i.e., on speculative RFHs and gets destroyed along with speculative RFHs if
// it ends up never committing.
//
// In case of crashes, DocumentUserData's lifetime doesn't match blink::Document
// lifetime. DocumentUserData is not cleared when the RenderFrame is deleted but
// is cleared on a subsequent navigation after a crash. This is done to ensure
// that the data associated with RenderFrameHost is not reset when the non-live
// RenderFrameHost is still in use by browser features like permissions or
// settings, which continue to work on the crashed pages. For more details,
// please refer to crbug.com/1099237.
//
// Note: RenderFrameHost is being replaced with RenderDocumentHost
// [https://crbug.com/936696]. After this is completed, every
// DocumentUserData object will be 1:1 with RenderFrameHost. Also
// RenderFrameHost/RenderDocument would start inheriting directly from
// SupportsUserData then we wouldn't need the use of
// GetDocumentUserData/SetDocumentUserData anymore.
//
// This is similar to WebContentsUserData but attached to a document instead.
// Example usage of DocumentUserData:
//
// --- in foo_document_helper.h ---
// class FooDocumentHelper
// : public content::DocumentUserData<FooDocumentHelper> {
// public:
// ~FooDocumentHelper() override;
//
// // ... more public stuff here ...
//
// private:
// // No public constructors to force going through static methods of
// // DocumentUserData (e.g. CreateForCurrentDocument).
// explicit FooDocumentHelper(content::RenderFrameHost* rfh);
//
// friend DocumentUserData;
// DOCUMENT_USER_DATA_KEY_DECL();
//
// // ... more private stuff here ...
// };
//
// --- in foo_document_helper.cc ---
// DOCUMENT_USER_DATA_KEY_IMPL(FooDocumentHelper);
//
// FooDocumentHelper::FooDocumentHelper(content::RenderFrameHost* rfh)
// : DocumentUserData(rfh) {}
//
// FooDocumentHelper::~FooDocumentHelper() {}
//
template <typename T>
class DocumentUserData : public base::SupportsUserData::Data {
public:
template <typename... Args>
static void CreateForCurrentDocument(RenderFrameHost* rfh, Args&&... args) {
DCHECK(rfh);
if (!GetForCurrentDocument(rfh)) {
T* data = new T(rfh, std::forward<Args>(args)...);
internal::SetDocumentUserData(rfh, UserDataKey(), base::WrapUnique(data));
}
}
static T* GetForCurrentDocument(RenderFrameHost* rfh) {
DCHECK(rfh);
return static_cast<T*>(internal::GetDocumentUserData(rfh, UserDataKey()));
}
static const T* GetForCurrentDocument(const RenderFrameHost* rfh) {
DCHECK(rfh);
return static_cast<const T*>(
internal::GetDocumentUserData(rfh, UserDataKey()));
}
static T* GetOrCreateForCurrentDocument(RenderFrameHost* rfh) {
DCHECK(rfh);
if (auto* data = GetForCurrentDocument(rfh)) {
return data;
}
CreateForCurrentDocument(rfh);
return GetForCurrentDocument(rfh);
}
static void DeleteForCurrentDocument(RenderFrameHost* rfh) {
DCHECK(rfh);
DCHECK(GetForCurrentDocument(rfh));
internal::RemoveDocumentUserData(rfh, UserDataKey());
}
// Returns the RenderFrameHost associated with `this` object of a subclass
// which inherits from DocumentUserData.
//
// The returned `render_frame_host()` is guaranteed to live as long as `this`
// DocumentUserData (due to how UserData works - RenderFrameHost
// owns `this` UserData). Note that only the lifetime of
// `render_frame_host()` is guaranteed, but not its state - e.g. the frame may
// be `!IsActive()`.
RenderFrameHost& render_frame_host() const { return *render_frame_host_; }
protected:
// TODO(crbug.com/40198594): Take a reference instead of a pointer
// (here + transitively/as-far-as-reasonably-possible in callers).
explicit DocumentUserData(RenderFrameHost* rfh) : render_frame_host_(rfh) {
CHECK(rfh);
}
// Returns the origin of the associated document.
//
// Note that a DocumentUserData can be attached to a speculative
// RenderFrameHost, but while the RenderFrameHost remains speculative/pending
// commit, `origin()` returns a meaningless unique opaque origin. Only after
// the commit will the returned value become meaningful.
const url::Origin& origin() const {
// `this` is promptly deleted if `render_frame_host_` commits a
// cross-document navigation, so it is always safe to simply call
// `GetLastCommittedOrigin()` directly, even without RenderDocument.
return render_frame_host().GetLastCommittedOrigin();
}
private:
static const void* UserDataKey() { return &T::kUserDataKey; }
// This is a pointer (rather than a reference) to ensure that go/miracleptr
// can cover this field (see also //base/memory/raw_ptr.md).
const raw_ptr<RenderFrameHost> render_frame_host_ = nullptr;
};
// Users won't be able to instantiate the template if they miss declaring the
// user data key.
// This macro declares a static variable inside the class that inherits from
// DocumentUserData. The address of this static variable is used as
// the key to store/retrieve an instance of the class on/from a WebState.
#define DOCUMENT_USER_DATA_KEY_DECL() static const int kUserDataKey = 0
// This macro instantiates the static variable declared by the previous macro.
// It must live in a .cc file to ensure that there is only one instantiation
// of the static variable.
#define DOCUMENT_USER_DATA_KEY_IMPL(Type) const int Type::kUserDataKey
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_DOCUMENT_USER_DATA_H_