#include "base/strings/string_number_conversions.h"
#include "base/threading/thread.h"
#include "base/values.h"
-#include "content/browser/devtools/devtools_browser_target.h"
#include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
#include "content/browser/devtools/devtools_system_info_handler.h"
-#include "content/browser/devtools/devtools_tracing_handler.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/browser/devtools/protocol/tracing_handler.h"
#include "content/browser/devtools/tethering_handler.h"
#include "content/common/devtools_messages.h"
#include "content/public/browser/browser_thread.h"
// Maximum write buffer size of devtools http/websocket connectinos.
const int32 kSendBufferSizeForDevTools = 100 * 1024 * 1024; // 100Mb
+// DevToolsAgentHostClientImpl -----------------------------------------------
+
// An internal implementation of DevToolsAgentHostClient that delegates
// messages sent to a DebuggerShell instance.
class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient {
agent_host_->AttachClient(this);
}
- virtual ~DevToolsAgentHostClientImpl() {
+ ~DevToolsAgentHostClientImpl() override {
if (agent_host_.get())
agent_host_->DetachClient();
}
- virtual void AgentHostClosed(
- DevToolsAgentHost* agent_host,
- bool replaced_with_another_client) OVERRIDE {
+ void AgentHostClosed(DevToolsAgentHost* agent_host,
+ bool replaced_with_another_client) override {
DCHECK(agent_host == agent_host_.get());
agent_host_ = NULL;
connection_id_));
}
- virtual void DispatchProtocolMessage(
- DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE {
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override {
DCHECK(agent_host == agent_host_.get());
message_loop_->PostTask(
FROM_HERE,
} // namespace
+// DevToolsHttpHandlerImpl::BrowserTarget ------------------------------------
+
+class DevToolsHttpHandlerImpl::BrowserTarget {
+ public:
+ BrowserTarget(base::MessageLoop* message_loop,
+ net::HttpServer* server,
+ int connection_id)
+ : message_loop_(message_loop),
+ server_(server),
+ connection_id_(connection_id),
+ tracing_handler_(new devtools::tracing::TracingHandler(
+ devtools::tracing::TracingHandler::Browser)),
+ protocol_handler_(new DevToolsProtocolHandlerImpl()) {
+ protocol_handler_->SetNotifier(
+ base::Bind(&BrowserTarget::Respond, base::Unretained(this)));
+ protocol_handler_->SetTracingHandler(tracing_handler_.get());
+ }
+
+ ~BrowserTarget() {
+ STLDeleteElements(&handlers_);
+ }
+
+ // Takes ownership.
+ void RegisterHandler(DevToolsProtocol::Handler* handler) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ handler->SetNotifier(
+ base::Bind(&BrowserTarget::Respond, base::Unretained(this)));
+ handlers_.push_back(handler);
+ }
+
+ void HandleMessage(const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::string error_response;
+ scoped_refptr<DevToolsProtocol::Command> command =
+ DevToolsProtocol::ParseCommand(message, &error_response);
+ if (!command.get()) {
+ Respond(error_response);
+ return;
+ }
+
+ scoped_refptr<DevToolsProtocol::Response> response =
+ protocol_handler_->HandleCommand(command);
+ for (const auto& handler : handlers_) {
+ if (response.get())
+ break;
+ response = handler->HandleCommand(command);
+ }
+
+ if (response.get()) {
+ if (!response->is_async_promise())
+ Respond(response->Serialize());
+ } else {
+ Respond(command->NoSuchMethodErrorResponse()->Serialize());
+ }
+ }
+
+ void Respond(const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&net::HttpServer::SendOverWebSocket,
+ base::Unretained(server_),
+ connection_id_,
+ message));
+ }
+
+ private:
+ base::MessageLoop* const message_loop_;
+ net::HttpServer* const server_;
+ const int connection_id_;
+ scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_;
+ scoped_ptr<DevToolsProtocolHandlerImpl> protocol_handler_;
+ std::vector<DevToolsProtocol::Handler*> handlers_;
+};
+
+// DevToolsHttpHandler -------------------------------------------------------
+
// static
bool DevToolsHttpHandler::IsSupportedProtocolVersion(
const std::string& version) {
return http_handler;
}
+// DevToolsHttpHandler::ServerSocketFactory ----------------------------------
+
DevToolsHttpHandler::ServerSocketFactory::ServerSocketFactory(
const std::string& address,
int port,
return scoped_ptr<net::ServerSocket>();
}
+// DevToolsHttpHandlerImpl ---------------------------------------------------
+
DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Stop() must be called prior to destruction.
void DevToolsHttpHandlerImpl::ResetHandlerThread() {
thread_.reset();
+ server_ip_address_.reset();
}
void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
}
GURL DevToolsHttpHandlerImpl::GetFrontendURL() {
- net::IPEndPoint ip_address;
- if (server_ && server_->GetLocalAddress(&ip_address))
+ if (!server_ip_address_)
return GURL();
- return GURL(std::string("http://") + ip_address.ToString() + frontend_url_);
+ return GURL(std::string("http://") + server_ip_address_->ToString() + frontend_url_);
}
static std::string PathWithoutParams(const std::string& path) {
int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
if (resource_id != -1) {
base::StringPiece data = GetContentClient()->GetDataResource(
- resource_id, ui::SCALE_FACTOR_NONE);
+ resource_id, ui::SCALE_FACTOR_NONE);
server_->Send200(connection_id, data.as_string(), mime_type);
return;
}
void DevToolsHttpHandlerImpl::OnWebSocketRequest(
int connection_id,
const net::HttpServerRequestInfo& request) {
- std::string browser_prefix = "/devtools/browser";
- size_t browser_pos = request.path.find(browser_prefix);
- if (browser_pos == 0) {
- scoped_refptr<DevToolsBrowserTarget> browser_target =
- new DevToolsBrowserTarget(server_.get(), connection_id);
- browser_target->RegisterDomainHandler(
- devtools::Tracing::kName,
- new DevToolsTracingHandler(DevToolsTracingHandler::Browser),
- true /* handle on UI thread */);
- browser_target->RegisterDomainHandler(
- devtools::Tethering::kName,
- new TetheringHandler(delegate_.get()),
- false /* handle on this thread */);
- browser_target->RegisterDomainHandler(
- devtools::SystemInfo::kName,
- new DevToolsSystemInfoHandler(),
- true /* handle on UI thread */);
- browser_targets_[connection_id] = browser_target;
-
- server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
- server_->AcceptWebSocket(connection_id, request);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
void DevToolsHttpHandlerImpl::OnWebSocketMessage(
int connection_id,
const std::string& data) {
- BrowserTargets::iterator it = browser_targets_.find(connection_id);
- if (it != browser_targets_.end()) {
- it->second->HandleMessage(data);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
}
void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
- BrowserTargets::iterator it = browser_targets_.find(connection_id);
- if (it != browser_targets_.end()) {
- it->second->Detach();
- browser_targets_.erase(it);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
if (!thread_)
return;
+ std::string browser_prefix = "/devtools/browser";
+ size_t browser_pos = request.path.find(browser_prefix);
+ if (browser_pos == 0) {
+ BrowserTarget* browser_target = new BrowserTarget(
+ thread_->message_loop(), server_.get(), connection_id);
+ browser_target->RegisterHandler(
+ new TetheringHandler(delegate_.get(), thread_->message_loop_proxy()));
+ browser_target->RegisterHandler(
+ new DevToolsSystemInfoHandler());
+ browser_targets_[connection_id] = browser_target;
+ AcceptWebSocket(connection_id, request);
+ return;
+ }
+
size_t pos = request.path.find(kPageUrlPrefix);
if (pos != 0) {
Send404(connection_id);
void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
int connection_id,
const std::string& data) {
+ BrowserTargets::iterator browser_it = browser_targets_.find(connection_id);
+ if (browser_it != browser_targets_.end()) {
+ browser_it->second->HandleMessage(data);
+ return;
+ }
+
ConnectionToClientMap::iterator it =
connection_to_client_ui_.find(connection_id);
if (it == connection_to_client_ui_.end())
}
void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
+ BrowserTargets::iterator browser_it = browser_targets_.find(connection_id);
+ if (browser_it != browser_targets_.end()) {
+ delete browser_it->second;
+ browser_targets_.erase(connection_id);
+ return;
+ }
+
ConnectionToClientMap::iterator it =
connection_to_client_ui_.find(connection_id);
if (it != connection_to_client_ui_.end()) {
}
}
+void DevToolsHttpHandlerImpl::OnHttpServerInitialized(
+ const net::IPEndPoint& ip_address) {
+ server_ip_address_.reset(new net::IPEndPoint(ip_address));
+}
+
DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
scoped_ptr<ServerSocketFactory> server_socket_factory,
const std::string& frontend_url,
}
server_.reset(new net::HttpServer(server_socket.Pass(), this));
+ net::IPEndPoint ip_address;
+ server_->GetLocalAddress(&ip_address);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DevToolsHttpHandlerImpl::OnHttpServerInitialized,
+ this, ip_address));
if (!active_port_output_directory_.empty())
WriteActivePortToUserProfile();
}
// Runs on the handler thread
void DevToolsHttpHandlerImpl::Teardown() {
- server_.reset(NULL);
+ server_.reset();
}
// Runs on FILE thread to make sure that it is serialized against