Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 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 COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_ |
| 6 | #define COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_ |
| 7 | |
Helmut Januschka | 58a4b28c | 2024-05-01 23:41:02 | [diff] [blame] | 8 | #include <string_view> |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 9 | #include <vector> |
| 10 | |
mhashmi | 6d1b1cb2 | 2016-11-22 16:04:24 | [diff] [blame] | 11 | #include "base/compiler_specific.h" |
Avi Drissman | 12be031 | 2023-01-11 09:16:09 | [diff] [blame] | 12 | #include "base/functional/callback_forward.h" |
Bartek Nowierski | fc9563f | 2024-04-06 19:11:47 | [diff] [blame] | 13 | #include "base/memory/raw_ptr.h" |
Lily Houghton | 7f7b2fb | 2018-05-01 21:40:46 | [diff] [blame] | 14 | #include "base/memory/weak_ptr.h" |
Patrick Monette | 643cdf6 | 2021-10-15 19:13:42 | [diff] [blame] | 15 | #include "base/task/single_thread_task_runner.h" |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 16 | #include "base/thread_annotations.h" |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 17 | #include "components/ui_devtools/devtools_client.h" |
thanhph | 3f396851 | 2017-06-21 00:37:23 | [diff] [blame] | 18 | #include "components/ui_devtools/devtools_export.h" |
Andrey Kosyakov | 103b8f2a | 2021-11-16 08:06:26 | [diff] [blame] | 19 | #include "components/ui_devtools/dom.h" |
| 20 | #include "components/ui_devtools/forward.h" |
| 21 | #include "components/ui_devtools/protocol.h" |
Miyoung Shin | 5ea055b | 2019-10-15 02:53:32 | [diff] [blame] | 22 | #include "mojo/public/cpp/bindings/pending_receiver.h" |
| 23 | #include "mojo/public/cpp/bindings/pending_remote.h" |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 24 | #include "net/server/http_server_request_info.h" |
| 25 | #include "net/traffic_annotation/network_traffic_annotation.h" |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 26 | |
thanhph | 3f396851 | 2017-06-21 00:37:23 | [diff] [blame] | 27 | namespace ui_devtools { |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 28 | |
Mitsuru Oshima | 4de59ac | 2019-09-03 20:49:09 | [diff] [blame] | 29 | class TracingAgent; |
| 30 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 31 | class UI_DEVTOOLS_EXPORT UiDevToolsServer { |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 32 | public: |
Sadrul Habib Chowdhury | 729f250 | 2021-07-16 21:40:15 | [diff] [blame] | 33 | // Network tags to be used for the UI devtools servers. |
Sean Gilhuly | 13fc02ff3 | 2018-11-01 14:05:30 | [diff] [blame] | 34 | static const net::NetworkTrafficAnnotationTag kUIDevtoolsServerTag; |
Sean Gilhuly | 13fc02ff3 | 2018-11-01 14:05:30 | [diff] [blame] | 35 | |
Peter Boström | 09c0182 | 2021-09-20 22:43:27 | [diff] [blame] | 36 | UiDevToolsServer(const UiDevToolsServer&) = delete; |
| 37 | UiDevToolsServer& operator=(const UiDevToolsServer&) = delete; |
| 38 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 39 | ~UiDevToolsServer(); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 40 | |
mhashmi | 6d1b1cb2 | 2016-11-22 16:04:24 | [diff] [blame] | 41 | // Returns an empty unique_ptr if ui devtools flag isn't enabled or if a |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 42 | // server instance has already been created. All network activity is performed |
| 43 | // on `io_thread_task_runner`, which must run tasks on a thread with an IO |
| 44 | // message pump. All other work is done on the thread the UiDevToolsServer is |
| 45 | // created on. If `port` is 0, the server will choose an available port. If |
| 46 | // `port` is 0 and `active_port_output_directory` is present, the server will |
| 47 | // write the chosen port to `kUIDevToolsActivePortFileName` on |
| 48 | // `active_port_output_directory`. |
Sean Gilhuly | 13fc02ff3 | 2018-11-01 14:05:30 | [diff] [blame] | 49 | static std::unique_ptr<UiDevToolsServer> CreateForViews( |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 50 | scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, |
Yuheng Huang | 55e92951 | 2021-06-04 16:33:14 | [diff] [blame] | 51 | int port, |
| 52 | const base::FilePath& active_port_output_directory = base::FilePath()); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 53 | |
mhashmi | 6d1b1cb2 | 2016-11-22 16:04:24 | [diff] [blame] | 54 | // Returns a list of attached UiDevToolsClient name + URL |
| 55 | using NameUrlPair = std::pair<std::string, std::string>; |
leon.han | 030d74f | 2016-12-13 02:52:16 | [diff] [blame] | 56 | static std::vector<NameUrlPair> GetClientNamesAndUrls(); |
mhashmi | 6d1b1cb2 | 2016-11-22 16:04:24 | [diff] [blame] | 57 | |
Mike Wasserman | 8f8b085 | 2018-12-03 22:08:10 | [diff] [blame] | 58 | // Returns true if UI Devtools is enabled by the given commandline switch. |
| 59 | static bool IsUiDevToolsEnabled(const char* enable_devtools_flag); |
| 60 | |
Ahmed Fakhry | f6c1bcd | 2018-11-13 19:08:25 | [diff] [blame] | 61 | // Returns the port number specified by a command line flag. If a number is |
| 62 | // not specified as a command line argument, returns the |default_port|. |
| 63 | static int GetUiDevToolsPort(const char* enable_devtools_flag, |
| 64 | int default_port); |
Sean Gilhuly | 13fc02ff3 | 2018-11-01 14:05:30 | [diff] [blame] | 65 | |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 66 | void AttachClient(std::unique_ptr<UiDevToolsClient> client); |
Helmut Januschka | 58a4b28c | 2024-05-01 23:41:02 | [diff] [blame] | 67 | void SendOverWebSocket(int connection_id, std::string_view message); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 68 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 69 | int port() const { |
| 70 | DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_); |
| 71 | return port_; |
| 72 | } |
Illia Martyniuk | bd1e4485 | 2018-03-13 22:02:59 | [diff] [blame] | 73 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 74 | TracingAgent* tracing_agent() { |
| 75 | DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_); |
| 76 | return tracing_agent_; |
| 77 | } |
| 78 | |
| 79 | void set_tracing_agent(TracingAgent* agent) { |
| 80 | DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_); |
| 81 | tracing_agent_ = agent; |
| 82 | } |
Mitsuru Oshima | 4de59ac | 2019-09-03 20:49:09 | [diff] [blame] | 83 | |
Wei Li | e591507 | 2021-03-09 18:42:45 | [diff] [blame] | 84 | // Sets the callback which will be invoked when the session is closed. |
| 85 | // Marks as a const function so it can be called after the server is set up |
| 86 | // and used as a constant instance. |
| 87 | void SetOnSessionEnded(base::OnceClosure callback) const; |
Leonard Grey | 2039b72 | 2022-04-11 22:52:50 | [diff] [blame] | 88 | // Sets a callback that tests can use to wait for the server to be ready to |
| 89 | // accept connections. |
| 90 | void SetOnSocketConnectedForTesting(base::OnceClosure on_socket_connected); |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 91 | // Allows calling OnWebSocketRequest() with unexpected connection IDs for |
| 92 | // tests, bypassing the HttpServer. |
| 93 | void OnWebSocketRequestForTesting(int connection_id, |
| 94 | net::HttpServerRequestInfo info); |
Wei Li | e591507 | 2021-03-09 18:42:45 | [diff] [blame] | 95 | |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 96 | private: |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 97 | // Class that owns the ServerSocket and, after creation on the main thread, |
| 98 | // may only subsequently be used on the IO thread. The class is needed because |
| 99 | // HttpServers must live on an IO thread. This class contains all state that's |
| 100 | // read or written on the IO thread, to avoid UAF's on teardown. When the |
| 101 | // UiDevToolsServer server is destroyed, a task is posted to destroy the |
| 102 | // IOThreadData, but that task could still be run after the UiDevToolsServer |
| 103 | // is fully torn down. |
| 104 | // |
| 105 | // Because of this pattern, it's always safe to post messages to the IO thread |
| 106 | // to dereference the IOThreadData from the UiDevToolsServer assuming this |
| 107 | // class will still be valid, but tasks it posts back to the main thread to |
| 108 | // dereference the UiDevToolsServer must use weak pointers. |
| 109 | class IOThreadData; |
mhashmi | 6011c1bd | 2016-10-31 15:24:29 | [diff] [blame] | 110 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 111 | UiDevToolsServer( |
| 112 | scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, |
| 113 | int port, |
| 114 | const net::NetworkTrafficAnnotationTag tag, |
| 115 | const base::FilePath& active_port_output_directory); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 116 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 117 | // Invoked on the IO thread, initializes `server_` and starts listening for |
| 118 | // connections on `port`. |
| 119 | void MakeServer(int port); |
| 120 | |
| 121 | // Invoked on the main thread. Called by MakeServer via a post task. |
| 122 | void ServerCreated(int port); |
| 123 | |
| 124 | // These mirror the corresponding HttpServer methods. |
| 125 | void OnWebSocketRequest(int connection_id, net::HttpServerRequestInfo info); |
| 126 | void OnWebSocketMessage(int connection_id, std::string data); |
| 127 | void OnClose(int connection_id); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 128 | |
| 129 | using ClientsList = std::vector<std::unique_ptr<UiDevToolsClient>>; |
Ali Hijazi | 60a72b0a | 2024-09-30 17:58:53 | [diff] [blame] | 130 | using ConnectionsMap = |
| 131 | std::map<uint32_t, raw_ptr<UiDevToolsClient, CtnExperimental>>; |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 132 | ClientsList clients_ GUARDED_BY_CONTEXT(main_sequence_); |
| 133 | ConnectionsMap connections_ GUARDED_BY_CONTEXT(main_sequence_); |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 134 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 135 | const scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_; |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 136 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 137 | // The port the devtools server listens on. |
| 138 | int port_ GUARDED_BY_CONTEXT(main_sequence_); |
Yuheng Huang | 55e92951 | 2021-06-04 16:33:14 | [diff] [blame] | 139 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 140 | raw_ptr<TracingAgent> tracing_agent_ GUARDED_BY_CONTEXT(main_sequence_) = |
| 141 | nullptr; |
Illia Martyniuk | bd1e4485 | 2018-03-13 22:02:59 | [diff] [blame] | 142 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 143 | // Invoked when the server doesn't have any live connections. |
| 144 | mutable base::OnceClosure on_session_ended_ |
| 145 | GUARDED_BY_CONTEXT(main_sequence_); |
Sean Gilhuly | 13fc02ff3 | 2018-11-01 14:05:30 | [diff] [blame] | 146 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 147 | // Set once the server has been started. |
| 148 | bool connected_ GUARDED_BY_CONTEXT(main_sequence_) = false; |
Mitsuru Oshima | 4de59ac | 2019-09-03 20:49:09 | [diff] [blame] | 149 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 150 | // Invoked once the server has been started. |
| 151 | base::OnceClosure on_socket_connected_ GUARDED_BY_CONTEXT(main_sequence_); |
Wei Li | e591507 | 2021-03-09 18:42:45 | [diff] [blame] | 152 | |
Mike Wasserman | 8f8b085 | 2018-12-03 22:08:10 | [diff] [blame] | 153 | // The server (owned by Chrome for now) |
mhashmi | 6d1b1cb2 | 2016-11-22 16:04:24 | [diff] [blame] | 154 | static UiDevToolsServer* devtools_server_; |
| 155 | |
Matt Menke | cde68ab | 2024-08-20 16:05:28 | [diff] [blame] | 156 | std::unique_ptr<IOThreadData> io_thread_data_; |
| 157 | |
| 158 | SEQUENCE_CHECKER(main_sequence_); |
Jeremy Roman | 5c341f6d | 2019-07-15 15:56:10 | [diff] [blame] | 159 | base::WeakPtrFactory<UiDevToolsServer> weak_ptr_factory_{this}; |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 160 | }; |
| 161 | |
thanhph | 3f396851 | 2017-06-21 00:37:23 | [diff] [blame] | 162 | } // namespace ui_devtools |
mhashmi | 1ec338a | 2016-10-25 22:13:34 | [diff] [blame] | 163 | |
| 164 | #endif // COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_ |