diff options
Diffstat (limited to 'content/browser/devtools/devtools_http_handler_impl.cc')
-rw-r--r-- | content/browser/devtools/devtools_http_handler_impl.cc | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc new file mode 100644 index 0000000..6d214ab --- /dev/null +++ b/content/browser/devtools/devtools_http_handler_impl.cc @@ -0,0 +1,873 @@ +// 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_http_handler_impl.h" + +#include <algorithm> +#include <utility> + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/file_util.h" +#include "base/json/json_writer.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/string_number_conversions.h" +#include "base/stringprintf.h" +#include "base/threading/thread.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "content/browser/devtools/devtools_browser_target.h" +#include "content/browser/devtools/devtools_tracing_handler.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/devtools_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/devtools_agent_host_registry.h" +#include "content/public/browser/devtools_client_host.h" +#include "content/public/browser/devtools_http_handler_delegate.h" +#include "content/public/browser/devtools_manager.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/common/content_client.h" +#include "content/public/common/url_constants.h" +#include "googleurl/src/gurl.h" +#include "grit/devtools_resources_map.h" +#include "net/base/escape.h" +#include "net/base/io_buffer.h" +#include "net/base/ip_endpoint.h" +#include "net/server/http_server_request_info.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" +#include "ui/base/layout.h" +#include "webkit/user_agent/user_agent.h" +#include "webkit/user_agent/user_agent_util.h" + +namespace content { + +const int kBufferSize = 16 * 1024; + +namespace { + +static const char* kDevToolsHandlerThreadName = "Chrome_DevToolsHandlerThread"; + +class DevToolsDefaultBindingHandler + : public DevToolsHttpHandler::RenderViewHostBinding { + public: + DevToolsDefaultBindingHandler() { + } + + virtual std::string GetIdentifier(RenderViewHost* rvh) OVERRIDE { + int process_id = rvh->GetProcess()->GetID(); + int routing_id = rvh->GetRoutingID(); + return base::StringPrintf("%d_%d", process_id, routing_id); + } + + virtual RenderViewHost* ForIdentifier( + const std::string& identifier) OVERRIDE { + size_t pos = identifier.find("_"); + if (pos == std::string::npos) + return NULL; + + int process_id; + if (!base::StringToInt(identifier.substr(0, pos), &process_id)) + return NULL; + + int routing_id; + if (!base::StringToInt(identifier.substr(pos+1), &routing_id)) + return NULL; + + return RenderViewHost::FromID(process_id, routing_id); + } +}; + + +// An internal implementation of DevToolsClientHost that delegates +// messages sent for DevToolsClient to a DebuggerShell instance. +class DevToolsClientHostImpl : public DevToolsClientHost { + public: + DevToolsClientHostImpl( + MessageLoop* message_loop, + net::HttpServer* server, + int connection_id) + : message_loop_(message_loop), + server_(server), + connection_id_(connection_id), + is_closed_(false), + detach_reason_("target_closed") { + } + + ~DevToolsClientHostImpl() {} + + // DevToolsClientHost interface + virtual void InspectedContentsClosing() { + if (is_closed_) + return; + is_closed_ = true; + + std::string response = + WebKit::WebDevToolsAgent::inspectorDetachedEvent( + WebKit::WebString::fromUTF8(detach_reason_)).utf8(); + message_loop_->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::SendOverWebSocket, + server_, + connection_id_, + response)); + + message_loop_->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::Close, server_, connection_id_)); + } + + virtual void DispatchOnInspectorFrontend(const std::string& data) { + message_loop_->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::SendOverWebSocket, + server_, + connection_id_, + data)); + } + + virtual void ContentsReplaced(WebContents* new_contents) { + } + + virtual void ReplacedWithAnotherClient() { + detach_reason_ = "replaced_with_devtools"; + } + + private: + virtual void FrameNavigating(const std::string& url) {} + MessageLoop* message_loop_; + net::HttpServer* server_; + int connection_id_; + bool is_closed_; + std::string detach_reason_; +}; + +} // namespace + +// static +int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { + for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) { + if (name == kDevtoolsResources[i].name) + return kDevtoolsResources[i].value; + } + return -1; +} + +// static +DevToolsHttpHandler* DevToolsHttpHandler::Start( + const net::StreamListenSocketFactory* socket_factory, + const std::string& frontend_url, + DevToolsHttpHandlerDelegate* delegate) { + DevToolsHttpHandlerImpl* http_handler = + new DevToolsHttpHandlerImpl(socket_factory, + frontend_url, + delegate); + http_handler->Start(); + return http_handler; +} + +DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Stop() must be called prior to destruction. + DCHECK(server_.get() == NULL); + DCHECK(thread_.get() == NULL); +} + +void DevToolsHttpHandlerImpl::Start() { + if (thread_.get()) + return; + thread_.reset(new base::Thread(kDevToolsHandlerThreadName)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this)); +} + +// Runs on FILE thread. +void DevToolsHttpHandlerImpl::StartHandlerThread() { + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + if (!thread_->StartWithOptions(options)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this)); + return; + } + + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::Init, this)); +} + +void DevToolsHttpHandlerImpl::ResetHandlerThread() { + thread_.reset(); +} + +void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() { + ResetHandlerThread(); + Release(); +} + +void DevToolsHttpHandlerImpl::Stop() { + if (!thread_.get()) + return; + BrowserThread::PostTaskAndReply( + BrowserThread::FILE, FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this), + base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this)); +} + +void DevToolsHttpHandlerImpl::SetRenderViewHostBinding( + RenderViewHostBinding* binding) { + if (binding) + binding_ = binding; + else + binding_ = default_binding_.get(); +} + +GURL DevToolsHttpHandlerImpl::GetFrontendURL(RenderViewHost* render_view_host) { + net::IPEndPoint ip_address; + if (server_->GetLocalAddress(&ip_address)) + return GURL(); + std::string host = ip_address.ToString(); + std::string id = binding_->GetIdentifier(render_view_host); + return GURL(std::string("http://") + + ip_address.ToString() + + GetFrontendURLInternal(id, host)); +} + +static std::string PathWithoutParams(const std::string& path) { + size_t query_position = path.find("?"); + if (query_position != std::string::npos) + return path.substr(0, query_position); + return path; +} + +static std::string GetMimeType(const std::string& filename) { + if (EndsWith(filename, ".html", false)) { + return "text/html"; + } else if (EndsWith(filename, ".css", false)) { + return "text/css"; + } else if (EndsWith(filename, ".js", false)) { + return "application/javascript"; + } else if (EndsWith(filename, ".png", false)) { + return "image/png"; + } else if (EndsWith(filename, ".gif", false)) { + return "image/gif"; + } + NOTREACHED(); + return "text/plain"; +} + +void DevToolsHttpHandlerImpl::Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) { + RenderProcessHost* process = Source<RenderProcessHost>(source).ptr(); + DevToolsManager* manager = DevToolsManager::GetInstance(); + for (ConnectionToClientHostMap::iterator it = + connection_to_client_host_ui_.begin(); + it != connection_to_client_host_ui_.end(); ++it) { + DevToolsAgentHost* agent = manager->GetDevToolsAgentHostFor(it->second); + if (!agent) + continue; + RenderViewHost* rvh = DevToolsAgentHostRegistry::GetRenderViewHost(agent); + if (rvh && rvh->GetProcess() == process) + it->second->InspectedContentsClosing(); + } +} + +void DevToolsHttpHandlerImpl::OnHttpRequest( + int connection_id, + const net::HttpServerRequestInfo& info) { + if (info.path.find("/json") == 0) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI, + this, + connection_id, + info)); + return; + } + + if (info.path.find("/thumb/") == 0) { + // Thumbnail request. + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI, + this, + connection_id, + info)); + return; + } + + if (info.path == "" || info.path == "/") { + // Discovery page request. + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI, + this, + connection_id)); + return; + } + + if (info.path.find("/devtools/") != 0) { + server_->Send404(connection_id); + return; + } + + std::string filename = PathWithoutParams(info.path.substr(10)); + std::string mime_type = GetMimeType(filename); + + FilePath frontend_dir = delegate_->GetDebugFrontendDir(); + if (!frontend_dir.empty()) { + FilePath path = frontend_dir.AppendASCII(filename); + std::string data; + file_util::ReadFileToString(path, &data); + server_->Send200(connection_id, data, mime_type); + return; + } + if (delegate_->BundlesFrontendResources()) { + int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename); + if (resource_id != -1) { + base::StringPiece data = GetContentClient()->GetDataResource( + resource_id, ui::SCALE_FACTOR_NONE); + server_->Send200(connection_id, data.as_string(), mime_type); + return; + } + } + server_->Send404(connection_id); +} + +void DevToolsHttpHandlerImpl::OnWebSocketRequest( + int connection_id, + const net::HttpServerRequestInfo& request) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &DevToolsHttpHandlerImpl::OnWebSocketRequestUI, + this, + connection_id, + request)); +} + +void DevToolsHttpHandlerImpl::OnWebSocketMessage( + int connection_id, + const std::string& data) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &DevToolsHttpHandlerImpl::OnWebSocketMessageUI, + this, + connection_id, + data)); +} + +void DevToolsHttpHandlerImpl::OnClose(int connection_id) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &DevToolsHttpHandlerImpl::OnCloseUI, + this, + connection_id)); +} + +struct DevToolsHttpHandlerImpl::PageInfo { + PageInfo() + : attached(false) { + } + + std::string id; + std::string url; + bool attached; + std::string title; + std::string thumbnail_url; + std::string favicon_url; + base::TimeTicks last_selected_time; +}; + +// static +bool DevToolsHttpHandlerImpl::SortPageListByTime(const PageInfo& info1, + const PageInfo& info2) { + return info1.last_selected_time > info2.last_selected_time; +} + +DevToolsHttpHandlerImpl::PageList DevToolsHttpHandlerImpl::GeneratePageList() { + PageList page_list; + for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); + !it.IsAtEnd(); it.Advance()) { + RenderProcessHost* render_process_host = it.GetCurrentValue(); + DCHECK(render_process_host); + + // Ignore processes that don't have a connection, such as crashed contents. + if (!render_process_host->HasConnection()) + continue; + + RenderProcessHost::RenderWidgetHostsIterator rwit( + render_process_host->GetRenderWidgetHostsIterator()); + for (; !rwit.IsAtEnd(); rwit.Advance()) { + const RenderWidgetHost* widget = rwit.GetCurrentValue(); + DCHECK(widget); + if (!widget || !widget->IsRenderView()) + continue; + + RenderViewHost* host = + RenderViewHost::From(const_cast<RenderWidgetHost*>(widget)); + page_list.push_back(CreatePageInfo(host)); + } + } + std::sort(page_list.begin(), page_list.end(), SortPageListByTime); + return page_list; +} + +std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal( + const std::string rvh_id, + const std::string& host) { + return base::StringPrintf( + "%s%sws=%s/devtools/page/%s", + overridden_frontend_url_.c_str(), + overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&", + host.c_str(), + rvh_id.c_str()); +} + +static bool ParseJsonPath( + const std::string& path, + std::string* command, + std::string* target_id) { + + // Fall back to list in case of empty query. + if (path.empty()) { + *command = "list"; + return true; + } + + if (path.find("/") != 0) { + // Malformed command. + return false; + } + *command = path.substr(1); + + size_t separator_pos = command->find("/"); + if (separator_pos != std::string::npos) { + *target_id = command->substr(separator_pos + 1); + *command = command->substr(0, separator_pos); + } + return true; +} + +void DevToolsHttpHandlerImpl::OnJsonRequestUI( + int connection_id, + const net::HttpServerRequestInfo& info) { + // Trim /json and ?jsonp=... + std::string path = info.path.substr(5); + std::string jsonp; + size_t jsonp_pos = path.find("?jsonp="); + if (jsonp_pos != std::string::npos) { + jsonp = path.substr(jsonp_pos + 7); + path = path.substr(0, jsonp_pos); + } + + // Trim fragment and query + size_t query_pos = path.find("?"); + if (query_pos != std::string::npos) + path = path.substr(0, query_pos); + + size_t fragment_pos = path.find("#"); + if (fragment_pos != std::string::npos) + path = path.substr(0, fragment_pos); + + std::string command; + std::string target_id; + if (!ParseJsonPath(path, &command, &target_id)) { + SendJson(connection_id, + net::HTTP_NOT_FOUND, + NULL, + "Malformed query: " + info.path, + jsonp); + return; + } + + if (command == "version") { + DictionaryValue version; + version.SetString("Protocol-Version", + WebKit::WebDevToolsAgent::inspectorProtocolVersion()); + version.SetString("WebKit-Version", + webkit_glue::GetWebKitVersion()); + version.SetString("User-Agent", + webkit_glue::GetUserAgent(GURL(chrome::kAboutBlankURL))); + SendJson(connection_id, net::HTTP_OK, &version, "", jsonp); + return; + } + + if (command == "list") { + PageList page_list = GeneratePageList(); + ListValue json_pages_list; + std::string host = info.headers["Host"]; + for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i) + json_pages_list.Append(SerializePageInfo(*i, host)); + SendJson(connection_id, net::HTTP_OK, &json_pages_list, "", jsonp); + return; + } + + if (command == "new") { + RenderViewHost* rvh = delegate_->CreateNewTarget(); + if (!rvh) { + SendJson(connection_id, + net::HTTP_INTERNAL_SERVER_ERROR, + NULL, + "Could not create new page", + jsonp); + return; + } + PageInfo page_info = CreatePageInfo(rvh); + std::string host = info.headers["Host"]; + scoped_ptr<DictionaryValue> dictionary(SerializePageInfo(page_info, host)); + SendJson(connection_id, net::HTTP_OK, dictionary.get(), "", jsonp); + return; + } + + if (command == "activate" || command == "close") { + RenderViewHost* rvh = binding_->ForIdentifier(target_id); + if (!rvh) { + SendJson(connection_id, + net::HTTP_NOT_FOUND, + NULL, + "No such target id: " + target_id, + jsonp); + return; + } + + if (command == "activate") { + rvh->GetDelegate()->Activate(); + SendJson(connection_id, net::HTTP_OK, NULL, "Target activated", jsonp); + return; + } + + if (command == "close") { + rvh->ClosePage(); + SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing", jsonp); + return; + } + } + SendJson(connection_id, + net::HTTP_NOT_FOUND, + NULL, + "Unknown command: " + command, + jsonp); + return; +} + +void DevToolsHttpHandlerImpl::OnThumbnailRequestUI( + int connection_id, + const net::HttpServerRequestInfo& info) { + std::string prefix = "/thumb/"; + size_t pos = info.path.find(prefix); + if (pos != 0) { + Send404(connection_id); + return; + } + + std::string page_url = info.path.substr(prefix.length()); + std::string data = delegate_->GetPageThumbnailData(GURL(page_url)); + if (!data.empty()) + Send200(connection_id, data, "image/png"); + else + Send404(connection_id); +} + +void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) { + std::string response = delegate_->GetDiscoveryPageHTML(); + Send200(connection_id, response, "text/html; charset=UTF-8"); +} + +void DevToolsHttpHandlerImpl::OnWebSocketRequestUI( + int connection_id, + const net::HttpServerRequestInfo& request) { + if (!thread_.get()) + return; + std::string browser_prefix = "/devtools/browser"; + size_t browser_pos = request.path.find(browser_prefix); + if (browser_pos == 0) { + if (browser_target_) { + Send500(connection_id, "Another client already attached"); + return; + } + browser_target_.reset(new DevToolsBrowserTarget(connection_id)); + browser_target_->RegisterHandler(new DevToolsTracingHandler()); + AcceptWebSocket(connection_id, request); + return; + } + + std::string page_prefix = "/devtools/page/"; + size_t pos = request.path.find(page_prefix); + if (pos != 0) { + Send404(connection_id); + return; + } + + std::string page_id = request.path.substr(page_prefix.length()); + RenderViewHost* rvh = binding_->ForIdentifier(page_id); + if (!rvh) { + Send500(connection_id, "No such target id: " + page_id); + return; + } + + DevToolsManager* manager = DevToolsManager::GetInstance(); + DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost( + rvh); + if (manager->GetDevToolsClientHostFor(agent)) { + Send500(connection_id, + "Target with given id is being inspected: " + page_id); + return; + } + + DevToolsClientHostImpl* client_host = + new DevToolsClientHostImpl(thread_->message_loop(), + server_, + connection_id); + connection_to_client_host_ui_[connection_id] = client_host; + + manager->RegisterDevToolsClientHostFor(agent, client_host); + + AcceptWebSocket(connection_id, request); +} + +void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( + int connection_id, + const std::string& data) { + if (browser_target_ && connection_id == browser_target_->connection_id()) { + std::string json_response = browser_target_->HandleMessage(data); + + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::SendOverWebSocket, + server_.get(), + connection_id, + json_response)); + return; + } + + ConnectionToClientHostMap::iterator it = + connection_to_client_host_ui_.find(connection_id); + if (it == connection_to_client_host_ui_.end()) + return; + + DevToolsManager* manager = DevToolsManager::GetInstance(); + manager->DispatchOnInspectorBackend(it->second, data); +} + +void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) { + ConnectionToClientHostMap::iterator it = + connection_to_client_host_ui_.find(connection_id); + if (it != connection_to_client_host_ui_.end()) { + DevToolsClientHostImpl* client_host = + static_cast<DevToolsClientHostImpl*>(it->second); + DevToolsManager::GetInstance()->ClientHostClosing(client_host); + delete client_host; + connection_to_client_host_ui_.erase(connection_id); + } + if (browser_target_ && browser_target_->connection_id() == connection_id) { + browser_target_.reset(); + return; + } +} + +DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( + const net::StreamListenSocketFactory* socket_factory, + const std::string& frontend_url, + DevToolsHttpHandlerDelegate* delegate) + : overridden_frontend_url_(frontend_url), + socket_factory_(socket_factory), + delegate_(delegate) { + if (overridden_frontend_url_.empty()) + overridden_frontend_url_ = "/devtools/devtools.html"; + + default_binding_.reset(new DevToolsDefaultBindingHandler); + binding_ = default_binding_.get(); + + registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, + NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, + NotificationService::AllBrowserContextsAndSources()); + + // Balanced in ResetHandlerThreadAndRelease(). + AddRef(); +} + +// Runs on the handler thread +void DevToolsHttpHandlerImpl::Init() { + server_ = new net::HttpServer(*socket_factory_.get(), this); +} + +// Runs on the handler thread +void DevToolsHttpHandlerImpl::Teardown() { + server_ = NULL; +} + +// Runs on FILE thread to make sure that it is serialized against +// {Start|Stop}HandlerThread and to allow calling pthread_join. +void DevToolsHttpHandlerImpl::StopHandlerThread() { + if (!thread_->message_loop()) + return; + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&DevToolsHttpHandlerImpl::Teardown, this)); + // Thread::Stop joins the thread. + thread_->Stop(); +} + +void DevToolsHttpHandlerImpl::SendJson(int connection_id, + net::HttpStatusCode status_code, + Value* value, + const std::string& message, + const std::string& jsonp) { + if (!thread_.get()) + return; + + // Serialize value and message. + std::string json_value; + if (value) { + base::JSONWriter::WriteWithOptions(value, + base::JSONWriter::OPTIONS_PRETTY_PRINT, + &json_value); + } + std::string json_message; + scoped_ptr<Value> message_object(Value::CreateStringValue(message)); + base::JSONWriter::Write(message_object.get(), &json_message); + + std::string response; + std::string mime_type = "application/json; charset=UTF-8"; + + // Wrap jsonp if necessary. + if (!jsonp.empty()) { + mime_type = "text/javascript; charset=UTF-8"; + response = StringPrintf("%s(%s, %d, %s);", + jsonp.c_str(), + json_value.empty() ? "undefined" + : json_value.c_str(), + status_code, + json_message.c_str()); + // JSONP always returns 200. + status_code = net::HTTP_OK; + } else { + response = StringPrintf("%s%s", json_value.c_str(), message.c_str()); + } + + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::Send, + server_.get(), + connection_id, + status_code, + response, + mime_type)); +} + +void DevToolsHttpHandlerImpl::Send200(int connection_id, + const std::string& data, + const std::string& mime_type) { + if (!thread_.get()) + return; + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::Send200, + server_.get(), + connection_id, + data, + mime_type)); +} + +void DevToolsHttpHandlerImpl::Send404(int connection_id) { + if (!thread_.get()) + return; + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::Send404, server_.get(), connection_id)); +} + +void DevToolsHttpHandlerImpl::Send500(int connection_id, + const std::string& message) { + if (!thread_.get()) + return; + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::Send500, server_.get(), connection_id, + message)); +} + +void DevToolsHttpHandlerImpl::AcceptWebSocket( + int connection_id, + const net::HttpServerRequestInfo& request) { + if (!thread_.get()) + return; + thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(), + connection_id, request)); +} + +DevToolsHttpHandlerImpl::PageInfo +DevToolsHttpHandlerImpl::CreatePageInfo(RenderViewHost* rvh) +{ + RenderViewHostDelegate* host_delegate = rvh->GetDelegate(); + DevToolsAgentHost* agent = + DevToolsAgentHostRegistry::GetDevToolsAgentHost(rvh); + DevToolsClientHost* client_host = DevToolsManager::GetInstance()-> + GetDevToolsClientHostFor(agent); + PageInfo page_info; + page_info.id = binding_->GetIdentifier(rvh); + page_info.attached = client_host != NULL; + page_info.url = host_delegate->GetURL().spec(); + + WebContents* web_contents = host_delegate->GetAsWebContents(); + if (web_contents) { + page_info.title = UTF16ToUTF8( + net::EscapeForHTML(web_contents->GetTitle())); + page_info.last_selected_time = web_contents->GetLastSelectedTime(); + + NavigationController& controller = web_contents->GetController(); + NavigationEntry* entry = controller.GetActiveEntry(); + if (entry != NULL && entry->GetURL().is_valid()) { + page_info.thumbnail_url = "/thumb/" + entry->GetURL().spec(); + page_info.favicon_url = entry->GetFavicon().url.spec(); + } + } + return page_info; +} + +DictionaryValue* DevToolsHttpHandlerImpl::SerializePageInfo( + const PageInfo& page_info, + const std::string& host) { + DictionaryValue* dictionary = new DictionaryValue; + dictionary->SetString("title", page_info.title); + dictionary->SetString("url", page_info.url); + dictionary->SetString("thumbnailUrl", page_info.thumbnail_url); + dictionary->SetString("faviconUrl", page_info.favicon_url); + if (!page_info.attached) { + dictionary->SetString("webSocketDebuggerUrl", + base::StringPrintf("ws://%s/devtools/page/%s", + host.c_str(), + page_info.id.c_str())); + std::string devtools_frontend_url = GetFrontendURLInternal( + page_info.id.c_str(), + host); + dictionary->SetString("devtoolsFrontendUrl", devtools_frontend_url); + } + return dictionary; +} + +} // namespace content |