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
content / public / browser / web_ui_controller_interface_binder.h [blame]
// Copyright 2022 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_WEB_UI_CONTROLLER_INTERFACE_BINDER_H_
#define CONTENT_PUBLIC_BROWSER_WEB_UI_CONTROLLER_INTERFACE_BINDER_H_
#include <type_traits>
#include "content/common/content_export.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "mojo/public/cpp/bindings/binder_map.h"
namespace content {
namespace internal {
template <typename Interface, int N, typename... Subclasses>
struct BinderHelper;
template <typename Interface, typename WebUIControllerSubclass, typename = void>
struct BinderTakesRenderFrameHost : std::false_type {};
template <typename Interface, typename WebUIControllerSubclass>
struct BinderTakesRenderFrameHost<
Interface,
WebUIControllerSubclass,
decltype(std::declval<WebUIControllerSubclass>().BindInterface(
std::declval<RenderFrameHost*>(),
std::declval<mojo::PendingReceiver<Interface>>()))> : std::true_type {};
template <typename Interface, typename WebUIControllerSubclass>
bool SafeDownCastAndBindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface>& receiver) {
// Performs a safe downcast to the concrete WebUIController subclass.
WebUI* web_ui = host->GetWebUI();
WebUIControllerSubclass* concrete_controller =
web_ui ? web_ui->GetController()->GetAs<WebUIControllerSubclass>()
: nullptr;
if (!concrete_controller)
return false;
// Fails to compile if |Subclass| does not implement the appropriate overload
// for |Interface|.
if constexpr (BinderTakesRenderFrameHost<Interface,
WebUIControllerSubclass>::value) {
concrete_controller->BindInterface(host, std::move(receiver));
} else {
concrete_controller->BindInterface(std::move(receiver));
}
return true;
}
template <typename Interface, int N, typename Subclass, typename... Subclasses>
struct BinderHelper<Interface, N, std::tuple<Subclass, Subclasses...>> {
static bool BindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface> receiver) {
// Try a different subclass if the current one is not the right
// WebUIController for the current WebUI page, and only fail if none of the
// passed subclasses match.
if (!SafeDownCastAndBindInterface<Interface, Subclass>(host, receiver)) {
return BinderHelper<Interface, N - 1, std::tuple<Subclasses...>>::
BindInterface(host, std::move(receiver));
}
return true;
}
};
template <typename Interface, typename Subclass, typename... Subclasses>
struct BinderHelper<Interface, 0, std::tuple<Subclass, Subclasses...>> {
static bool BindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface> receiver) {
return SafeDownCastAndBindInterface<Interface, Subclass>(host, receiver);
}
};
void CONTENT_EXPORT ReceivedInvalidWebUIControllerMessage(RenderFrameHost* rfh);
} // namespace internal
// Registers a binder in |map| that binds |Interface| iff the RenderFrameHost
// has a WebUIController among type |WebUIControllerSubclasses|.
template <typename Interface, typename... WebUIControllerSubclasses>
void RegisterWebUIControllerInterfaceBinder(
mojo::BinderMapWithContext<RenderFrameHost*>* map) {
DCHECK(!map->Contains<Interface>())
<< "A binder for " << Interface::Name_ << " has already been registered.";
map->Add<Interface>(base::BindRepeating(
[](RenderFrameHost* host, mojo::PendingReceiver<Interface> receiver) {
// This is expected to be called only for outermost main frames.
if (host->GetParentOrOuterDocument()) {
internal::ReceivedInvalidWebUIControllerMessage(host);
return;
}
const int size = sizeof...(WebUIControllerSubclasses);
bool is_bound =
internal::BinderHelper<Interface, size - 1,
std::tuple<WebUIControllerSubclasses...>>::
BindInterface(host, std::move(receiver));
// This is expected to be called only for the right WebUI pages matching
// the same WebUI associated to the RenderFrameHost.
if (!is_bound) {
internal::ReceivedInvalidWebUIControllerMessage(host);
return;
}
}));
}
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_WEB_UI_CONTROLLER_INTERFACE_BINDER_H_