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
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_
#define COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_
#include <string_view>
#include <vector>
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/thread_annotations.h"
#include "components/ui_devtools/devtools_client.h"
#include "components/ui_devtools/devtools_export.h"
#include "components/ui_devtools/dom.h"
#include "components/ui_devtools/forward.h"
#include "components/ui_devtools/protocol.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/server/http_server_request_info.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace ui_devtools {
class TracingAgent;
class UI_DEVTOOLS_EXPORT UiDevToolsServer {
public:
// Network tags to be used for the UI devtools servers.
static const net::NetworkTrafficAnnotationTag kUIDevtoolsServerTag;
UiDevToolsServer(const UiDevToolsServer&) = delete;
UiDevToolsServer& operator=(const UiDevToolsServer&) = delete;
~UiDevToolsServer();
// Returns an empty unique_ptr if ui devtools flag isn't enabled or if a
// server instance has already been created. All network activity is performed
// on `io_thread_task_runner`, which must run tasks on a thread with an IO
// message pump. All other work is done on the thread the UiDevToolsServer is
// created on. If `port` is 0, the server will choose an available port. If
// `port` is 0 and `active_port_output_directory` is present, the server will
// write the chosen port to `kUIDevToolsActivePortFileName` on
// `active_port_output_directory`.
static std::unique_ptr<UiDevToolsServer> CreateForViews(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
int port,
const base::FilePath& active_port_output_directory = base::FilePath());
// Returns a list of attached UiDevToolsClient name + URL
using NameUrlPair = std::pair<std::string, std::string>;
static std::vector<NameUrlPair> GetClientNamesAndUrls();
// Returns true if UI Devtools is enabled by the given commandline switch.
static bool IsUiDevToolsEnabled(const char* enable_devtools_flag);
// Returns the port number specified by a command line flag. If a number is
// not specified as a command line argument, returns the |default_port|.
static int GetUiDevToolsPort(const char* enable_devtools_flag,
int default_port);
void AttachClient(std::unique_ptr<UiDevToolsClient> client);
void SendOverWebSocket(int connection_id, std::string_view message);
int port() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_);
return port_;
}
TracingAgent* tracing_agent() {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_);
return tracing_agent_;
}
void set_tracing_agent(TracingAgent* agent) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_);
tracing_agent_ = agent;
}
// Sets the callback which will be invoked when the session is closed.
// Marks as a const function so it can be called after the server is set up
// and used as a constant instance.
void SetOnSessionEnded(base::OnceClosure callback) const;
// Sets a callback that tests can use to wait for the server to be ready to
// accept connections.
void SetOnSocketConnectedForTesting(base::OnceClosure on_socket_connected);
// Allows calling OnWebSocketRequest() with unexpected connection IDs for
// tests, bypassing the HttpServer.
void OnWebSocketRequestForTesting(int connection_id,
net::HttpServerRequestInfo info);
private:
// Class that owns the ServerSocket and, after creation on the main thread,
// may only subsequently be used on the IO thread. The class is needed because
// HttpServers must live on an IO thread. This class contains all state that's
// read or written on the IO thread, to avoid UAF's on teardown. When the
// UiDevToolsServer server is destroyed, a task is posted to destroy the
// IOThreadData, but that task could still be run after the UiDevToolsServer
// is fully torn down.
//
// Because of this pattern, it's always safe to post messages to the IO thread
// to dereference the IOThreadData from the UiDevToolsServer assuming this
// class will still be valid, but tasks it posts back to the main thread to
// dereference the UiDevToolsServer must use weak pointers.
class IOThreadData;
UiDevToolsServer(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
int port,
const net::NetworkTrafficAnnotationTag tag,
const base::FilePath& active_port_output_directory);
// Invoked on the IO thread, initializes `server_` and starts listening for
// connections on `port`.
void MakeServer(int port);
// Invoked on the main thread. Called by MakeServer via a post task.
void ServerCreated(int port);
// These mirror the corresponding HttpServer methods.
void OnWebSocketRequest(int connection_id, net::HttpServerRequestInfo info);
void OnWebSocketMessage(int connection_id, std::string data);
void OnClose(int connection_id);
using ClientsList = std::vector<std::unique_ptr<UiDevToolsClient>>;
using ConnectionsMap =
std::map<uint32_t, raw_ptr<UiDevToolsClient, CtnExperimental>>;
ClientsList clients_ GUARDED_BY_CONTEXT(main_sequence_);
ConnectionsMap connections_ GUARDED_BY_CONTEXT(main_sequence_);
const scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
// The port the devtools server listens on.
int port_ GUARDED_BY_CONTEXT(main_sequence_);
raw_ptr<TracingAgent> tracing_agent_ GUARDED_BY_CONTEXT(main_sequence_) =
nullptr;
// Invoked when the server doesn't have any live connections.
mutable base::OnceClosure on_session_ended_
GUARDED_BY_CONTEXT(main_sequence_);
// Set once the server has been started.
bool connected_ GUARDED_BY_CONTEXT(main_sequence_) = false;
// Invoked once the server has been started.
base::OnceClosure on_socket_connected_ GUARDED_BY_CONTEXT(main_sequence_);
// The server (owned by Chrome for now)
static UiDevToolsServer* devtools_server_;
std::unique_ptr<IOThreadData> io_thread_data_;
SEQUENCE_CHECKER(main_sequence_);
base::WeakPtrFactory<UiDevToolsServer> weak_ptr_factory_{this};
};
} // namespace ui_devtools
#endif // COMPONENTS_UI_DEVTOOLS_DEVTOOLS_SERVER_H_
|