diff options
author | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-06 10:13:00 +0000 |
---|---|---|
committer | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-06 10:13:00 +0000 |
commit | a9bf679843d02a5655cccb53655d8561b140709a (patch) | |
tree | 4345425b602e964deeb4f1cc22f0d2ece6b12414 /chrome/browser/debugger | |
parent | 02d8de1ba500e934ef840062a8d1fd03f88ddce1 (diff) | |
download | chromium_src-a9bf679843d02a5655cccb53655d8561b140709a.zip chromium_src-a9bf679843d02a5655cccb53655d8561b140709a.tar.gz chromium_src-a9bf679843d02a5655cccb53655d8561b140709a.tar.bz2 |
DevTools: add stub for HTTP-based remote debugger interface.
Review URL: http://codereview.chromium.org/2802032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51661 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/debugger')
-rw-r--r-- | chrome/browser/debugger/debugger_wrapper.cc | 36 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_wrapper.h | 4 | ||||
-rw-r--r-- | chrome/browser/debugger/devtools_http_protocol_handler.cc | 256 | ||||
-rw-r--r-- | chrome/browser/debugger/devtools_http_protocol_handler.h | 70 |
4 files changed, 351 insertions, 15 deletions
diff --git a/chrome/browser/debugger/debugger_wrapper.cc b/chrome/browser/debugger/debugger_wrapper.cc index c551846..644bf05 100644 --- a/chrome/browser/debugger/debugger_wrapper.cc +++ b/chrome/browser/debugger/debugger_wrapper.cc @@ -4,29 +4,37 @@ #include "chrome/browser/debugger/debugger_wrapper.h" +#include "chrome/browser/debugger/devtools_http_protocol_handler.h" #include "chrome/browser/debugger/debugger_remote_service.h" #include "chrome/browser/debugger/devtools_protocol_handler.h" #include "chrome/browser/debugger/devtools_remote_service.h" #include "chrome/browser/debugger/extension_ports_remote_service.h" -DebuggerWrapper::DebuggerWrapper(int port) { +DebuggerWrapper::DebuggerWrapper(int port, bool useHttp) { if (port > 0) { - proto_handler_ = new DevToolsProtocolHandler(port); - proto_handler_->RegisterDestination( - new DevToolsRemoteService(proto_handler_), - DevToolsRemoteService::kToolName); - proto_handler_->RegisterDestination( - new DebuggerRemoteService(proto_handler_), - DebuggerRemoteService::kToolName); - proto_handler_->RegisterDestination( - new ExtensionPortsRemoteService(proto_handler_), - ExtensionPortsRemoteService::kToolName); - proto_handler_->Start(); + if (useHttp) { + http_handler_ = new DevToolsHttpProtocolHandler(port); + http_handler_->Start(); + } else { + proto_handler_ = new DevToolsProtocolHandler(port); + proto_handler_->RegisterDestination( + new DevToolsRemoteService(proto_handler_), + DevToolsRemoteService::kToolName); + proto_handler_->RegisterDestination( + new DebuggerRemoteService(proto_handler_), + DebuggerRemoteService::kToolName); + proto_handler_->RegisterDestination( + new ExtensionPortsRemoteService(proto_handler_), + ExtensionPortsRemoteService::kToolName); + proto_handler_->Start(); + } } } DebuggerWrapper::~DebuggerWrapper() { - if (proto_handler_.get() != NULL) { + if (proto_handler_.get() != NULL) proto_handler_->Stop(); - } + + if (http_handler_.get() != NULL) + http_handler_->Stop(); } diff --git a/chrome/browser/debugger/debugger_wrapper.h b/chrome/browser/debugger/debugger_wrapper.h index 11ecb0c..0a82366 100644 --- a/chrome/browser/debugger/debugger_wrapper.h +++ b/chrome/browser/debugger/debugger_wrapper.h @@ -15,12 +15,13 @@ #include "base/ref_counted.h" class DebuggerHost; +class DevToolsHttpProtocolHandler; class DevToolsProtocolHandler; class DevToolsRemoteListenSocket; class DebuggerWrapper : public base::RefCountedThreadSafe<DebuggerWrapper> { public: - explicit DebuggerWrapper(int port); + DebuggerWrapper(int port, bool useHttp); private: friend class base::RefCountedThreadSafe<DebuggerWrapper>; @@ -28,6 +29,7 @@ class DebuggerWrapper : public base::RefCountedThreadSafe<DebuggerWrapper> { virtual ~DebuggerWrapper(); scoped_refptr<DevToolsProtocolHandler> proto_handler_; + scoped_refptr<DevToolsHttpProtocolHandler> http_handler_; }; #endif // CHROME_BROWSER_DEBUGGER_DEBUGGER_WRAPPER_H_ diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.cc b/chrome/browser/debugger/devtools_http_protocol_handler.cc new file mode 100644 index 0000000..8d8718c --- /dev/null +++ b/chrome/browser/debugger/devtools_http_protocol_handler.cc @@ -0,0 +1,256 @@ +// Copyright (c) 2010 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 "chrome/browser/debugger/devtools_http_protocol_handler.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/debugger/devtools_client_host.h" +#include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/devtools_messages.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "googleurl/src/gurl.h" +#include "net/base/io_buffer.h" +#include "net/base/listen_socket.h" +#include "net/server/http_server_request_info.h" +#include "net/url_request/url_request_context.h" + +const int kBufferSize = 16 * 1024; + +namespace { + +// An internal implementation of DevToolsClientHost that delegates +// messages sent for DevToolsClient to a DebuggerShell instance. +class DevToolsClientHostImpl : public DevToolsClientHost { + public: + explicit DevToolsClientHostImpl(HttpListenSocket* socket) + : socket_(socket) {} + ~DevToolsClientHostImpl() {} + + // DevToolsClientHost interface + virtual void InspectedTabClosing() {} + virtual void SendMessageToClient(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg) + IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage); + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() + } + + private: + // Message handling routines + void OnRpcMessage(const DevToolsMessageData& data) { + std::string message; + message += "devtools$$dispatch(\"" + data.class_name + "\", \"" + + data.method_name + "\""; + for (std::vector<std::string>::const_iterator it = data.arguments.begin(); + it != data.arguments.end(); ++it) { + std::string param = *it; + if (!param.empty()) + message += ", " + param; + } + message += ")"; + socket_->SendOverWebSocket(message); + } + HttpListenSocket* socket_; +}; + +} + +DevToolsHttpProtocolHandler::~DevToolsHttpProtocolHandler() { + // Stop() must be called prior to this being called + DCHECK(server_.get() == NULL); +} + +void DevToolsHttpProtocolHandler::Start() { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Init)); +} + +void DevToolsHttpProtocolHandler::Stop() { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Teardown)); +} + +void DevToolsHttpProtocolHandler::OnHttpRequest(HttpListenSocket* socket, + HttpServerRequestInfo* info) { + URLRequest* request = new URLRequest(GURL("chrome:/" + info->path), this); + Bind(request, socket); + request->set_context( + Profile::GetDefaultRequestContext()->GetURLRequestContext()); + request->Start(); +} + +void DevToolsHttpProtocolHandler::OnWebSocketRequest( + HttpListenSocket* socket, + HttpServerRequestInfo* request) { + socket->AcceptWebSocket(request); +} + +void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket, + const std::string& data) { + ChromeThread::PostTask( + ChromeThread::UI, + FROM_HERE, + NewRunnableMethod( + this, + &DevToolsHttpProtocolHandler::OnWebSocketMessageUI, + socket, + data)); +} + +void DevToolsHttpProtocolHandler::OnWebSocketMessageUI( + HttpListenSocket* socket, + const std::string& d) { + std::string data = d; + if (!client_host_.get() && data == "attach") { + client_host_.reset(new DevToolsClientHostImpl(socket)); + BrowserList::const_iterator it = BrowserList::begin(); + TabContents* tab_contents = (*it)->tabstrip_model()->GetTabContentsAt(0); + DevToolsManager* manager = DevToolsManager::GetInstance(); + manager->RegisterDevToolsClientHostFor(tab_contents->render_view_host(), + client_host_.get()); + } else { + // TODO(pfeldman): Replace with proper parsing / dispatching. + DevToolsMessageData message_data; + message_data.class_name = "ToolsAgent"; + message_data.method_name = "dispatchOnInspectorController"; + + size_t pos = data.find(" "); + message_data.arguments.push_back(data.substr(0, pos)); + data = data.substr(pos + 1); + + pos = data.find(" "); + message_data.arguments.push_back(data.substr(0, pos)); + data = data.substr(pos + 1); + + message_data.arguments.push_back(data); + + DevToolsManager* manager = DevToolsManager::GetInstance(); + manager->ForwardToDevToolsAgent(client_host_.get(), + DevToolsAgentMsg_RpcMessage(DevToolsMessageData(message_data))); + } +} + +void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) { + SocketToRequestsMap::iterator it = socket_to_requests_.find(socket); + if (it == socket_to_requests_.end()) + return; + + for (std::set<URLRequest*>::iterator it2 = it->second.begin(); + it2 != it->second.end(); ++it2) { + URLRequest* request = *it2; + request->Cancel(); + request_to_socket_.erase(request); + request_to_buffer_.erase(request); + delete request; + } + socket_to_requests_.erase(socket); +} + +void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) { + RequestToSocketMap::iterator it = request_to_socket_.find(request); + if (it == request_to_socket_.end()) + return; + + HttpListenSocket* socket = it->second; + + int64 expected_size = request->GetExpectedContentSize(); + + std::string content_type; + request->GetMimeType(&content_type); + + if (request->status().is_success()) { + socket->Send(StringPrintf("HTTP/1.1 200 OK\r\n" + "Content-Type:%s\r\n" + "Content-Length:%lld\r\n" + "\r\n", + content_type.c_str(), + expected_size)); + } else { + socket->Send("HTTP/1.1 404 Not Found\r\n" + "Content-Length: 0\r\n" + "\r\n"); + } + + int bytes_read = 0; + // Some servers may treat HEAD requests as GET requests. To free up the + // network connection as soon as possible, signal that the request has + // completed immediately, without trying to read any data back (all we care + // about is the response code and headers, which we already have). + net::IOBuffer* buffer = request_to_buffer_[request].get(); + if (request->status().is_success()) + request->Read(buffer, kBufferSize, &bytes_read); + OnReadCompleted(request, bytes_read); +} + +void DevToolsHttpProtocolHandler::OnReadCompleted(URLRequest* request, + int bytes_read) { + RequestToSocketMap::iterator it = request_to_socket_.find(request); + if (it == request_to_socket_.end()) + return; + + HttpListenSocket* socket = it->second; + + net::IOBuffer* buffer = request_to_buffer_[request].get(); + do { + if (!request->status().is_success() || bytes_read <= 0) + break; + socket->Send(buffer->data(), bytes_read); + } while (request->Read(buffer, kBufferSize, &bytes_read)); + + // See comments re: HEAD requests in OnResponseStarted(). + if (!request->status().is_io_pending()) + RequestCompleted(request); +} + +DevToolsHttpProtocolHandler::DevToolsHttpProtocolHandler(int port) + : port_(port), + server_(NULL) { +} + +void DevToolsHttpProtocolHandler::Init() { + server_ = HttpListenSocket::Listen("127.0.0.1", port_, this); +} + +// Run on I/O thread +void DevToolsHttpProtocolHandler::Teardown() { + server_ = NULL; +} + +void DevToolsHttpProtocolHandler::Bind(URLRequest* request, + HttpListenSocket* socket) { + request_to_socket_[request] = socket; + SocketToRequestsMap::iterator it = socket_to_requests_.find(socket); + if (it == socket_to_requests_.end()) { + std::pair<HttpListenSocket*, std::set<URLRequest*> > value( + socket, + std::set<URLRequest*>()); + it = socket_to_requests_.insert(value).first; + } + it->second.insert(request); + request_to_buffer_[request] = new net::IOBuffer(kBufferSize); +} + +void DevToolsHttpProtocolHandler::RequestCompleted(URLRequest* request) { + RequestToSocketMap::iterator it = request_to_socket_.find(request); + if (it == request_to_socket_.end()) + return; + + HttpListenSocket* socket = it->second; + request_to_socket_.erase(request); + SocketToRequestsMap::iterator it2 = socket_to_requests_.find(socket); + it2->second.erase(request); + request_to_buffer_.erase(request); + delete request; +} diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.h b/chrome/browser/debugger/devtools_http_protocol_handler.h new file mode 100644 index 0000000..14163d5 --- /dev/null +++ b/chrome/browser/debugger/devtools_http_protocol_handler.h @@ -0,0 +1,70 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_HTTP_PROTOCOL_HANDLER_H_ +#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_HTTP_PROTOCOL_HANDLER_H_ + +#include <set> +#include <string> + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "net/server/http_listen_socket.h" +#include "net/url_request/url_request.h" + +class DevToolsClientHost; +class DevToolsHttpServer; + +class DevToolsHttpProtocolHandler + : public HttpListenSocket::Delegate, + public URLRequest::Delegate, + public base::RefCountedThreadSafe<DevToolsHttpProtocolHandler> { + public: + explicit DevToolsHttpProtocolHandler(int port); + + // This method should be called after the object construction. + void Start(); + + // This method should be called before the object destruction. + void Stop(); + + // HttpListenSocket::Delegate implementation. + virtual void OnHttpRequest(HttpListenSocket* socket, + HttpServerRequestInfo* info); + virtual void OnWebSocketRequest(HttpListenSocket* socket, + HttpServerRequestInfo* info); + virtual void OnWebSocketMessage(HttpListenSocket* socket, + const std::string& data); + virtual void OnClose(HttpListenSocket* socket); + + // URLRequest::Delegate implementation. + virtual void OnResponseStarted(URLRequest* request); + virtual void OnReadCompleted(URLRequest* request, int bytes_read); + + private: + friend class base::RefCountedThreadSafe<DevToolsHttpProtocolHandler>; + virtual ~DevToolsHttpProtocolHandler(); + + void Init(); + void Teardown(); + void Bind(URLRequest* request, HttpListenSocket* socket); + void RequestCompleted(URLRequest* request); + void OnWebSocketMessageUI(HttpListenSocket* socket, const std::string& data); + + int port_; + scoped_refptr<HttpListenSocket> server_; + typedef std::map<URLRequest*, HttpListenSocket*> + RequestToSocketMap; + RequestToSocketMap request_to_socket_; + typedef std::map<HttpListenSocket*, std::set<URLRequest*> > + SocketToRequestsMap; + SocketToRequestsMap socket_to_requests_; + typedef std::map<URLRequest*, scoped_refptr<net::IOBuffer> > + BuffersMap; + BuffersMap request_to_buffer_; + scoped_ptr<DevToolsClientHost> client_host_; + DISALLOW_COPY_AND_ASSIGN(DevToolsHttpProtocolHandler); +}; + +#endif // CHROME_BROWSER_DEBUGGER_DEVTOOLS_HTTP_PROTOCOL_HANDLER_H_ |