// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/devtools/devtools_browser_target.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/values.h"
#include "content/public/browser/browser_thread.h"
#include "net/server/http_server.h"
namespace content {
DevToolsBrowserTarget::DevToolsBrowserTarget(
base::MessageLoopProxy* message_loop_proxy,
net::HttpServer* http_server,
int connection_id)
: message_loop_proxy_(message_loop_proxy),
http_server_(http_server),
connection_id_(connection_id),
handlers_deleter_(&handlers_),
weak_factory_(this) {
}
void DevToolsBrowserTarget::RegisterDomainHandler(
const std::string& domain,
DevToolsProtocol::Handler* handler,
bool handle_on_ui_thread) {
DCHECK(handlers_.find(domain) == handlers_.end());
handlers_[domain] = handler;
if (handle_on_ui_thread) {
handle_on_ui_thread_.insert(domain);
handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread,
weak_factory_.GetWeakPtr()));
} else {
handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond,
base::Unretained(this)));
}
}
void DevToolsBrowserTarget::HandleMessage(const std::string& data) {
std::string error_response;
scoped_refptr<DevToolsProtocol::Command> command =
DevToolsProtocol::ParseCommand(data, &error_response);
if (!command) {
Respond(error_response);
return;
}
DomainHandlerMap::iterator it = handlers_.find(command->domain());
if (it == handlers_.end()) {
Respond(command->NoSuchMethodErrorResponse()->Serialize());
return;
}
DevToolsProtocol::Handler* handler = it->second;
bool handle_directly = handle_on_ui_thread_.find(command->domain()) ==
handle_on_ui_thread_.end();
if (handle_directly) {
scoped_refptr<DevToolsProtocol::Response> response =
handler->HandleCommand(command);
if (response && response->is_async_promise())
return;
if (response)
Respond(response->Serialize());
else
Respond(command->NoSuchMethodErrorResponse()->Serialize());
return;
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
this,
handler,
command));
}
void DevToolsBrowserTarget::Detach() {
message_loop_proxy_ = NULL;
http_server_ = NULL;
std::vector<DevToolsProtocol::Handler*> ui_handlers;
for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin();
domain_it != handle_on_ui_thread_.end();
++domain_it) {
DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it);
CHECK(handler_it != handlers_.end());
ui_handlers.push_back(handler_it->second);
handlers_.erase(handler_it);
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread,
this,
ui_handlers));
}
DevToolsBrowserTarget::~DevToolsBrowserTarget() {
}
void DevToolsBrowserTarget::HandleCommandOnUIThread(
DevToolsProtocol::Handler* handler,
scoped_refptr<DevToolsProtocol::Command> command) {
scoped_refptr<DevToolsProtocol::Response> response =
handler->HandleCommand(command);
if (response && response->is_async_promise())
return;
if (response)
RespondFromUIThread(response->Serialize());
else
RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize());
}
void DevToolsBrowserTarget::DeleteHandlersOnUIThread(
std::vector<DevToolsProtocol::Handler*> handlers) {
STLDeleteElements(&handlers);
}
void DevToolsBrowserTarget::Respond(const std::string& message) {
if (!http_server_)
return;
http_server_->SendOverWebSocket(connection_id_, message);
}
void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) {
if (!message_loop_proxy_)
return;
message_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&DevToolsBrowserTarget::Respond, this, message));
}
} // namespace content