12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_http_handler_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_writer.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_browser_target.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/devtools_protocol.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/devtools_protocol_constants.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_tracing_handler.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/tethering_handler.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/web_contents/web_contents_impl.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/devtools_messages.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_agent_host.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_client_host.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_http_handler_delegate.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_manager.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/favicon_status.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/navigation_entry.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_service.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_types.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/render_view_host.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/content_client.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/url_constants.h"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/devtools_resources_map.h"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/escape.h"
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/ip_endpoint.h"
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/server/http_server_request_info.h"
46a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "net/server/http_server_response_info.h"
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/layout.h"
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/user_agent/user_agent.h"
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/user_agent/user_agent_util.h"
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kBufferSize = 16 * 1024;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic const char* kProtocolVersion = "1.0";
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kDevToolsHandlerThreadName = "Chrome_DevToolsHandlerThread";
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kThumbUrlPrefix = "/thumb/";
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kPageUrlPrefix = "/devtools/page/";
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetIdField = "id";
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetTypeField = "type";
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetTitleField = "title";
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetDescriptionField = "description";
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetUrlField = "url";
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetThumbnailUrlField = "thumbnailUrl";
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetFaviconUrlField = "faviconUrl";
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetWebSocketDebuggerUrlField = "webSocketDebuggerUrl";
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetDevtoolsFrontendUrlField = "devtoolsFrontendUrl";
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetTypePage = "page";
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char* kTargetTypeOther = "other";
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DevToolsDefaultBindingHandler
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public DevToolsHttpHandler::DevToolsAgentHostBinding {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsDefaultBindingHandler() {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual std::string GetIdentifier(DevToolsAgentHost* agent_host) OVERRIDE {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return agent_host->GetId();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual DevToolsAgentHost* ForIdentifier(const std::string& id) OVERRIDE {
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return DevToolsAgentHost::GetForId(id).get();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// An internal implementation of DevToolsClientHost that delegates
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// messages sent for DevToolsClient to a DebuggerShell instance.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DevToolsClientHostImpl : public DevToolsClientHost {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientHostImpl(base::MessageLoop* message_loop,
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         net::HttpServer* server,
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         int connection_id)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : message_loop_(message_loop),
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        server_(server),
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        connection_id_(connection_id),
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        is_closed_(false),
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        detach_reason_("target_closed") {}
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~DevToolsClientHostImpl() {}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DevToolsClientHost interface
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void InspectedContentsClosing() OVERRIDE {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (is_closed_)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    is_closed_ = true;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue notification;
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    notification.SetString(
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        devtools::Inspector::detached::kParamReason, detach_reason_);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string response = DevToolsProtocol::CreateNotification(
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        devtools::Inspector::detached::kName,
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        notification.DeepCopy())->Serialize();
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&net::HttpServer::SendOverWebSocket,
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   server_,
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id_,
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   response));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&net::HttpServer::Close, server_, connection_id_));
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void DispatchOnInspectorFrontend(const std::string& data) OVERRIDE {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&net::HttpServer::SendOverWebSocket,
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   server_,
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id_,
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   data));
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ReplacedWithAnotherClient() OVERRIDE {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    detach_reason_ = "replaced_with_devtools";
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop* message_loop_;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::HttpServer* server_;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int connection_id_;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_closed_;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string detach_reason_;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static base::TimeTicks GetLastSelectedTime(RenderViewHost* rvh) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* web_contents = rvh->GetDelegate()->GetAsWebContents();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!web_contents)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::TimeTicks();
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return web_contents->GetLastSelectedTime();
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef std::pair<RenderViewHost*, base::TimeTicks> PageInfo;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static bool TimeComparator(const PageInfo& info1, const PageInfo& info2) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return info1.second > info2.second;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DevToolsHttpHandler::IsSupportedProtocolVersion(
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& version) {
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return version == kProtocolVersion;
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == kDevtoolsResources[i].name)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return kDevtoolsResources[i].value;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return -1;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandler* DevToolsHttpHandler::Start(
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::StreamListenSocketFactory* socket_factory,
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& frontend_url,
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsHttpHandlerDelegate* delegate) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsHttpHandlerImpl* http_handler =
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new DevToolsHttpHandlerImpl(socket_factory,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  frontend_url,
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  delegate);
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_handler->Start();
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return http_handler;
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop() must be called prior to destruction.
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(server_.get() == NULL);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_.get() == NULL);
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Start() {
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (thread_)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on FILE thread.
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::StartHandlerThread() {
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Thread::Options options;
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  options.message_loop_type = base::MessageLoop::TYPE_IO;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!thread_->StartWithOptions(options)) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::Init, this));
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::ResetHandlerThread() {
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_.reset();
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResetHandlerThread();
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Release();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Stop() {
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTaskAndReply(
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::SetDevToolsAgentHostBinding(
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsAgentHostBinding* binding) {
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (binding)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    binding_ = binding;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    binding_ = default_binding_.get();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GURL DevToolsHttpHandlerImpl::GetFrontendURL(DevToolsAgentHost* agent_host) {
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::IPEndPoint ip_address;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (server_->GetLocalAddress(&ip_address))
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return GURL();
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!agent_host) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return GURL(std::string("http://") + ip_address.ToString() +
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        overridden_frontend_url_);
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string host = ip_address.ToString();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string id = binding_->GetIdentifier(agent_host);
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GURL(std::string("http://") +
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              ip_address.ToString() +
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              GetFrontendURLInternal(id, host));
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string PathWithoutParams(const std::string& path) {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t query_position = path.find("?");
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (query_position != std::string::npos)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return path.substr(0, query_position);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path;
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string GetMimeType(const std::string& filename) {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (EndsWith(filename, ".html", false)) {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "text/html";
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".css", false)) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "text/css";
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".js", false)) {
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "application/javascript";
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".png", false)) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "image/png";
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".gif", false)) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "image/gif";
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "text/plain";
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnHttpRequest(
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& info) {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find("/json") == 0) {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id,
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   info));
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find(kThumbUrlPrefix) == 0) {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Thumbnail request.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsAgentHost* agent_host = binding_->ForIdentifier(target_id);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GURL page_url;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (agent_host) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RenderViewHost* rvh = agent_host->GetRenderViewHost();
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (rvh)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        page_url = rvh->GetDelegate()->GetURL();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id,
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   page_url));
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path == "" || info.path == "/") {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Discovery page request.
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id));
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find("/devtools/") != 0) {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    server_->Send404(connection_id);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string filename = PathWithoutParams(info.path.substr(10));
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string mime_type = GetMimeType(filename);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath frontend_dir = delegate_->GetDebugFrontendDir();
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!frontend_dir.empty()) {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path = frontend_dir.AppendASCII(filename);
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string data;
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    file_util::ReadFileToString(path, &data);
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    server_->Send200(connection_id, data, mime_type);
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delegate_->BundlesFrontendResources()) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resource_id != -1) {
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringPiece data = GetContentClient()->GetDataResource(
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              resource_id, ui::SCALE_FACTOR_NONE);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      server_->Send200(connection_id, data.as_string(), mime_type);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  server_->Send404(connection_id);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketRequest(
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
3697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string browser_prefix = "/devtools/browser";
3707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t browser_pos = request.path.find(browser_prefix);
3717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (browser_pos == 0) {
3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (browser_target_) {
3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      server_->Send500(connection_id, "Another client already attached");
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return;
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    browser_target_ = new DevToolsBrowserTarget(
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        thread_->message_loop_proxy().get(), server_.get(), connection_id);
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    browser_target_->RegisterDomainHandler(
3792385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        devtools::Tracing::kName,
3802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        new DevToolsTracingHandler(),
3812385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        true /* handle on UI thread */);
3822385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    browser_target_->RegisterDomainHandler(
3832385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        TetheringHandler::kDomain,
3842385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        new TetheringHandler(delegate_.get()),
3852385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        false /* handle on this thread */);
3867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    server_->AcceptWebSocket(connection_id, request);
3887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id,
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          request));
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketMessage(
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& data) {
4047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (browser_target_ && connection_id == browser_target_->connection_id()) {
4057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    browser_target_->HandleMessage(data);
4067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id,
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          data));
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (browser_target_ && browser_target_->connection_id() == connection_id) {
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    browser_target_->Detach();
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    browser_target_ = NULL;
4237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnCloseUI,
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id));
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string id,
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "%s%sws=%s%s%s",
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      overridden_frontend_url_.c_str(),
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&",
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      host.c_str(),
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kPageUrlPrefix,
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id.c_str());
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static bool ParseJsonPath(
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& path,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* command,
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* target_id) {
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fall back to list in case of empty query.
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path.empty()) {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *command = "list";
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path.find("/") != 0) {
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Malformed command.
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *command = path.substr(1);
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t separator_pos = command->find("/");
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (separator_pos != std::string::npos) {
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *target_id = command->substr(separator_pos + 1);
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *command = command->substr(0, separator_pos);
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnJsonRequestUI(
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& info) {
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Trim /json
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string path = info.path.substr(5);
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Trim fragment and query
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t query_pos = path.find("?");
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (query_pos != std::string::npos)
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path = path.substr(0, query_pos);
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t fragment_pos = path.find("#");
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (fragment_pos != std::string::npos)
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path = path.substr(0, fragment_pos);
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string command;
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string target_id;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ParseJsonPath(path, &command, &target_id)) {
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendJson(connection_id,
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             net::HTTP_NOT_FOUND,
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             NULL,
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             "Malformed query: " + info.path);
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "version") {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue version;
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    version.SetString("Protocol-Version", kProtocolVersion);
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    version.SetString("WebKit-Version", webkit_glue::GetWebKitVersion());
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    version.SetString("Browser", content::GetContentClient()->GetProduct());
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    version.SetString("User-Agent",
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      webkit_glue::GetUserAgent(GURL(kAboutBlankURL)));
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendJson(connection_id, net::HTTP_OK, &version, std::string());
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "list") {
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    typedef std::vector<PageInfo> PageList;
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PageList page_list;
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<RenderViewHost*> rvh_list =
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DevToolsAgentHost::GetValidRenderViewHosts();
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != rvh_list.end(); ++it)
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      page_list.push_back(PageInfo(*it, GetLastSelectedTime(*it)));
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::sort(page_list.begin(), page_list.end(), TimeComparator);
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* target_list = new base::ListValue();
521a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string host = info.headers["host"];
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i)
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      target_list->Append(SerializePageInfo(i->first, host));
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddRef();  // Balanced in SendTargetList.
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTaskAndReply(
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::IO,
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::CollectWorkerInfo,
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this),
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   target_list,
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   host),
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::SendTargetList,
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this),
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id,
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   target_list));
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "new") {
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderViewHost* rvh = delegate_->CreateNewTarget();
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!rvh) {
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id,
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               net::HTTP_INTERNAL_SERVER_ERROR,
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               NULL,
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               "Could not create new page");
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
549a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string host = info.headers["host"];
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::DictionaryValue> dictionary(SerializePageInfo(rvh, host));
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "activate" || command == "close") {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsAgentHost* agent_host = binding_->ForIdentifier(target_id);
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderViewHost* rvh = agent_host ? agent_host->GetRenderViewHost() : NULL;
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!rvh) {
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               net::HTTP_NOT_FOUND,
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               NULL,
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               "No such target id: " + target_id);
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command == "activate") {
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rvh->GetDelegate()->Activate();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command == "close") {
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rvh->ClosePage();
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendJson(connection_id,
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           net::HTTP_NOT_FOUND,
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           NULL,
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           "Unknown command: " + command);
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return;
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DevToolsHttpHandlerImpl::CollectWorkerInfo(base::ListValue* target_list,
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                std::string host) {
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<WorkerService::WorkerInfo> worker_info =
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WorkerService::GetInstance()->GetWorkers();
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < worker_info.size(); ++i)
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    target_list->Append(SerializeWorkerInfo(worker_info[i], host));
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::SendTargetList(int connection_id,
5967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             base::ListValue* target_list) {
597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SendJson(connection_id, net::HTTP_OK, target_list, std::string());
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete target_list;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Release();  // Balanced OnJsonRequestUI.
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id, const GURL& page_url) {
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string data = delegate_->GetPageThumbnailData(page_url);
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!data.empty())
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send200(connection_id, data, "image/png");
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send404(connection_id);
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string response = delegate_->GetDiscoveryPageHTML();
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Send200(connection_id, response, "text/html; charset=UTF-8");
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t pos = request.path.find(kPageUrlPrefix);
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pos != 0) {
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send404(connection_id);
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string page_id = request.path.substr(strlen(kPageUrlPrefix));
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsAgentHost* agent = binding_->ForIdentifier(page_id);
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!agent) {
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send500(connection_id, "No such target id: " + page_id);
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (agent->IsAttached()) {
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send500(connection_id,
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "Target with given id is being inspected: " + page_id);
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
641868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      thread_->message_loop(), server_.get(), connection_id);
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connection_to_client_host_ui_[connection_id] = client_host;
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsManager::GetInstance()->
646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      RegisterDevToolsClientHostFor(agent, client_host);
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AcceptWebSocket(connection_id, request);
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& data) {
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ConnectionToClientHostMap::iterator it =
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection_to_client_host_ui_.find(connection_id);
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == connection_to_client_host_ui_.end())
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsManager* manager = DevToolsManager::GetInstance();
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  manager->DispatchOnInspectorBackend(it->second, data);
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ConnectionToClientHostMap::iterator it =
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection_to_client_host_ui_.find(connection_id);
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != connection_to_client_host_ui_.end()) {
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsClientHostImpl* client_host =
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<DevToolsClientHostImpl*>(it->second);
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsManager::GetInstance()->ClientHostClosing(client_host);
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete client_host;
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connection_to_client_host_ui_.erase(connection_id);
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::StreamListenSocketFactory* socket_factory,
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& frontend_url,
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsHttpHandlerDelegate* delegate)
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : overridden_frontend_url_(frontend_url),
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      socket_factory_(socket_factory),
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate_(delegate) {
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (overridden_frontend_url_.empty())
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      overridden_frontend_url_ = "/devtools/devtools.html";
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  default_binding_.reset(new DevToolsDefaultBindingHandler);
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  binding_ = default_binding_.get();
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Balanced in ResetHandlerThreadAndRelease().
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddRef();
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on the handler thread
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Init() {
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  server_ = new net::HttpServer(*socket_factory_.get(), this);
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on the handler thread
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Teardown() {
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  server_ = NULL;
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on FILE thread to make sure that it is serialized against
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// {Start|Stop}HandlerThread and to allow calling pthread_join.
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::StopHandlerThread() {
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!thread_->message_loop())
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Thread::Stop joins the thread.
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->Stop();
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::SendJson(int connection_id,
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       net::HttpStatusCode status_code,
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::Value* value,
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       const std::string& message) {
718c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Serialize value and message.
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json_value;
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value) {
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONWriter::WriteWithOptions(value,
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::JSONWriter::OPTIONS_PRETTY_PRINT,
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       &json_value);
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json_message;
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> message_object(new base::StringValue(message));
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::JSONWriter::Write(message_object.get(), &json_message);
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  net::HttpServerResponseInfo response(status_code);
733a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  response.SetBody(json_value + message, "application/json; charset=UTF-8");
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
737a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      base::Bind(&net::HttpServer::SendResponse,
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 server_.get(),
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 connection_id,
740a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch                 response));
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send200(int connection_id,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& data,
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& mime_type) {
746c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&net::HttpServer::Send200,
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 server_.get(),
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 connection_id,
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 data,
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 mime_type));
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send404(int connection_id) {
758c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&net::HttpServer::Send404, server_.get(), connection_id));
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send500(int connection_id,
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& message) {
767c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&net::HttpServer::Send500, server_.get(), connection_id,
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 message));
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::AcceptWebSocket(
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(),
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 connection_id, request));
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* DevToolsHttpHandlerImpl::SerializePageInfo(
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderViewHost* rvh,
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dictionary = new base::DictionaryValue;
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<DevToolsAgentHost> agent(
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DevToolsAgentHost::GetOrCreateFor(rvh));
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
794868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string id = binding_->GetIdentifier(agent.get());
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetIdField, id);
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (delegate_->GetTargetType(rvh)) {
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case DevToolsHttpHandlerDelegate::kTargetTypeTab:
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dictionary->SetString(kTargetTypeField, kTargetTypePage);
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dictionary->SetString(kTargetTypeField, kTargetTypeOther);
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* web_contents = rvh->GetDelegate()->GetAsWebContents();
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (web_contents) {
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dictionary->SetString(kTargetTitleField, UTF16ToUTF8(
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        net::EscapeForHTML(web_contents->GetTitle())));
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dictionary->SetString(kTargetUrlField, web_contents->GetURL().spec());
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dictionary->SetString(kTargetThumbnailUrlField,
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string(kThumbUrlPrefix) + id);
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NavigationController& controller = web_contents->GetController();
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NavigationEntry* entry = controller.GetActiveEntry();
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry != NULL && entry->GetURL().is_valid()) {
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dictionary->SetString(kTargetFaviconUrlField,
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetFavicon().url.spec());
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetDescriptionField,
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate_->GetViewDescription(rvh));
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
823c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!agent->IsAttached())
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SerializeDebuggerURLs(dictionary, id, host);
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return dictionary;
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeWorkerInfo(
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const WorkerService::WorkerInfo& worker,
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dictionary = new base::DictionaryValue;
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetForWorker(
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      worker.process_id, worker.route_id));
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
836868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string id = binding_->GetIdentifier(agent.get());
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetIdField, id);
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetTypeField, kTargetTypeOther);
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetTitleField,
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UTF16ToUTF8(net::EscapeForHTML(worker.name)));
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetUrlField, worker.url.spec());
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetDescriptionField,
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle)));
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
846c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!agent->IsAttached())
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SerializeDebuggerURLs(dictionary, id, host);
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return dictionary;
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::SerializeDebuggerURLs(
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* dictionary,
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetWebSocketDebuggerUrlField,
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        base::StringPrintf("ws://%s%s%s",
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           host.c_str(),
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           kPageUrlPrefix,
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           id.c_str()));
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string devtools_frontend_url = GetFrontendURLInternal(
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id.c_str(),
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      host);
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
867