Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_ |
| 6 | #define CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_ |
| 7 | |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 8 | #include "chrome/browser/bad_message.h" |
| 9 | #include "content/public/browser/render_frame_host.h" |
| 10 | #include "content/public/browser/web_contents.h" |
Lei Zhang | 4b21e9c | 2020-02-28 00:32:02 | [diff] [blame] | 11 | #include "content/public/browser/web_ui.h" |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 12 | #include "content/public/browser/web_ui_controller.h" |
Robert Sesek | 5a5fbb8 | 2020-05-04 16:18:28 | [diff] [blame] | 13 | #include "mojo/public/cpp/bindings/binder_map.h" |
Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 14 | |
| 15 | namespace content { |
| 16 | |
| 17 | class RenderFrameHost; |
| 18 | } // namespace content |
| 19 | |
| 20 | namespace chrome { |
| 21 | namespace internal { |
| 22 | |
Mario Sanchez Prada | fe81d6c | 2019-12-16 11:25:05 | [diff] [blame] | 23 | // The mechanism implemented by the PopulateChrome*FrameBinders() functions |
| 24 | // below will replace interface registries and binders used for handling |
| 25 | // InterfaceProvider's GetInterface() calls (see crbug.com/718652). |
| 26 | |
Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 27 | // PopulateChromeFrameBinders() registers BrowserInterfaceBroker's |
| 28 | // GetInterface() handler callbacks for chrome-specific document-scoped |
Mario Sanchez Prada | fe81d6c | 2019-12-16 11:25:05 | [diff] [blame] | 29 | // interfaces. |
Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 30 | void PopulateChromeFrameBinders( |
Wei-Yin Chen (陳威尹) | 5c2761d | 2021-03-06 09:15:53 | [diff] [blame] | 31 | mojo::BinderMapWithContext<content::RenderFrameHost*>* map, |
| 32 | content::RenderFrameHost* render_frame_host); |
Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 33 | |
Mario Sanchez Prada | fe81d6c | 2019-12-16 11:25:05 | [diff] [blame] | 34 | // PopulateChromeWebUIFrameBinders() registers BrowserInterfaceBroker's |
| 35 | // GetInterface() handler callbacks for chrome-specific document-scoped |
| 36 | // interfaces used from WebUI pages (e.g. chrome://bluetooth-internals). |
| 37 | void PopulateChromeWebUIFrameBinders( |
Robert Sesek | 5a5fbb8 | 2020-05-04 16:18:28 | [diff] [blame] | 38 | mojo::BinderMapWithContext<content::RenderFrameHost*>* map); |
Mario Sanchez Prada | fe81d6c | 2019-12-16 11:25:05 | [diff] [blame] | 39 | |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 40 | template <typename Interface, int N, typename... Subclasses> |
| 41 | struct BinderHelper; |
| 42 | |
| 43 | template <typename Interface, typename WebUIControllerSubclass> |
| 44 | bool SafeDownCastAndBindInterface(content::WebUI* web_ui, |
| 45 | mojo::PendingReceiver<Interface>& receiver) { |
| 46 | // Performs a safe downcast to the concrete WebUIController subclass. |
| 47 | WebUIControllerSubclass* concrete_controller = |
| 48 | web_ui ? web_ui->GetController()->GetAs<WebUIControllerSubclass>() |
| 49 | : nullptr; |
| 50 | |
| 51 | if (!concrete_controller) |
| 52 | return false; |
| 53 | |
| 54 | // Fails to compile if |Subclass| does not implement the appropriate overload |
| 55 | // for |Interface|. |
| 56 | concrete_controller->BindInterface(std::move(receiver)); |
| 57 | return true; |
| 58 | } |
| 59 | |
| 60 | template <typename Interface, int N, typename Subclass, typename... Subclasses> |
| 61 | struct BinderHelper<Interface, N, std::tuple<Subclass, Subclasses...>> { |
| 62 | static bool BindInterface(content::WebUI* web_ui, |
| 63 | mojo::PendingReceiver<Interface> receiver) { |
| 64 | // Try a different subclass if the current one is not the right |
| 65 | // WebUIController for the current WebUI page, and only fail if none of the |
| 66 | // passed subclasses match. |
| 67 | if (!SafeDownCastAndBindInterface<Interface, Subclass>(web_ui, receiver)) { |
| 68 | return BinderHelper<Interface, N - 1, std::tuple<Subclasses...>>:: |
| 69 | BindInterface(web_ui, std::move(receiver)); |
| 70 | } |
| 71 | return true; |
| 72 | } |
| 73 | }; |
| 74 | |
| 75 | template <typename Interface, typename Subclass, typename... Subclasses> |
| 76 | struct BinderHelper<Interface, 0, std::tuple<Subclass, Subclasses...>> { |
| 77 | static bool BindInterface(content::WebUI* web_ui, |
| 78 | mojo::PendingReceiver<Interface> receiver) { |
| 79 | return SafeDownCastAndBindInterface<Interface, Subclass>(web_ui, receiver); |
| 80 | } |
| 81 | }; |
| 82 | |
| 83 | // Registers a binder in |map| that binds |Interface| iff the RenderFrameHost |
| 84 | // has a WebUIController among type |WebUIControllerSubclasses|. |
| 85 | template <typename Interface, typename... WebUIControllerSubclasses> |
| 86 | void RegisterWebUIControllerInterfaceBinder( |
Robert Sesek | 5a5fbb8 | 2020-05-04 16:18:28 | [diff] [blame] | 87 | mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 88 | map->Add<Interface>( |
| 89 | base::BindRepeating([](content::RenderFrameHost* host, |
| 90 | mojo::PendingReceiver<Interface> receiver) { |
| 91 | // This is expected to be called only for main frames. |
| 92 | if (host->GetParent()) { |
| 93 | ReceivedBadMessage( |
| 94 | host->GetProcess(), |
| 95 | bad_message::BadMessageReason::RFH_INVALID_WEB_UI_CONTROLLER); |
| 96 | return; |
| 97 | } |
| 98 | |
| 99 | const int size = sizeof...(WebUIControllerSubclasses); |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 100 | bool is_bound = BinderHelper<Interface, size - 1, |
| 101 | std::tuple<WebUIControllerSubclasses...>>:: |
Nasko Oskov | 310c66a | 2020-05-18 21:58:57 | [diff] [blame] | 102 | BindInterface(host->GetWebUI(), std::move(receiver)); |
Christopher Lam | 2b09b82 | 2020-01-29 03:10:52 | [diff] [blame] | 103 | |
| 104 | // This is expected to be called only for the right WebUI pages matching |
| 105 | // the same WebUI associated to the RenderFrameHost. |
| 106 | if (!is_bound) { |
| 107 | ReceivedBadMessage( |
| 108 | host->GetProcess(), |
| 109 | bad_message::BadMessageReason::RFH_INVALID_WEB_UI_CONTROLLER); |
| 110 | return; |
| 111 | } |
| 112 | })); |
| 113 | } |
| 114 | |
Oksana Zhuravlova | 4dd171e8 | 2019-08-16 20:54:00 | [diff] [blame] | 115 | } // namespace internal |
| 116 | } // namespace chrome |
| 117 | |
| 118 | #endif // CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_ |