1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_http_protocol_handler.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <utility>
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/json/json_writer.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop_proxy.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/values.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_client_host.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_manager.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/webui/devtools_ui.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/devtools_messages.h"
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/io_buffer.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/server/http_server_request_info.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h"
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBufferSize = 16 * 1024;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// An internal implementation of DevToolsClientHost that delegates
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// messages sent for DevToolsClient to a DebuggerShell instance.
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DevToolsClientHostImpl : public DevToolsClientHost {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DevToolsClientHostImpl(
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      net::HttpServer* server,
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int connection_id)
4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      : server_(server),
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        connection_id_(connection_id) {
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~DevToolsClientHostImpl() {}
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DevToolsClientHost interface
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void InspectedTabClosing() {
49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::IO,
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        FROM_HERE,
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        NewRunnableMethod(server_,
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &net::HttpServer::Close,
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          connection_id_));
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SendMessageToClient(const IPC::Message& msg) {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          OnDispatchOnInspectorFrontend);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IPC_MESSAGE_UNHANDLED_ERROR()
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IPC_END_MESSAGE_MAP()
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual void TabReplaced(TabContentsWrapper* new_tab) {
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void NotifyCloseListener() {
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DevToolsClientHost::NotifyCloseListener();
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Message handling routines
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void OnDispatchOnInspectorFrontend(const std::string& data) {
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    BrowserThread::PostTask(
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        BrowserThread::IO,
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        FROM_HERE,
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        NewRunnableMethod(server_,
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &net::HttpServer::SendOverWebSocket,
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          connection_id_,
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          data));
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual void FrameNavigating(const std::string& url) {}
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  net::HttpServer* server_;
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int connection_id_;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}  // namespace
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenscoped_refptr<DevToolsHttpProtocolHandler> DevToolsHttpProtocolHandler::Start(
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& ip,
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int port,
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& frontend_url,
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabContentsProvider* provider) {
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  scoped_refptr<DevToolsHttpProtocolHandler> http_handler =
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      new DevToolsHttpProtocolHandler(ip, port, frontend_url, provider);
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  http_handler->Start();
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return http_handler;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDevToolsHttpProtocolHandler::~DevToolsHttpProtocolHandler() {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Stop() must be called prior to this being called
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(server_.get() == NULL);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DevToolsHttpProtocolHandler::Start() {
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Init));
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DevToolsHttpProtocolHandler::Stop() {
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Teardown));
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DevToolsHttpProtocolHandler::OnHttpRequest(
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& info) {
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (info.path == "" || info.path == "/") {
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Pages discovery request.
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::UI,
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        FROM_HERE,
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NewRunnableMethod(this,
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &DevToolsHttpProtocolHandler::OnRootRequestUI,
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          connection_id,
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          info));
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (info.path == "/json") {
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Pages discovery json request.
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        BrowserThread::UI,
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FROM_HERE,
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        NewRunnableMethod(this,
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &DevToolsHttpProtocolHandler::OnJsonRequestUI,
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          connection_id,
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          info));
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  size_t pos = info.path.find("/devtools/");
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (pos != 0) {
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    server_->Send404(connection_id);
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Proxy static files from chrome-devtools://devtools/*.
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!Profile::GetDefaultRequestContext()) {
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_->Send404(connection_id);
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make sure DevTools data source is registered.
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DevToolsUI::RegisterDevToolsDataSource();
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
16221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  net::URLRequest* request = new net::URLRequest(
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GURL("chrome-devtools:/" + info.path), this);
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Bind(request, connection_id);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->set_context(
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Profile::GetDefaultRequestContext()->GetURLRequestContext());
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->Start();
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DevToolsHttpProtocolHandler::OnWebSocketRequest(
17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& request) {
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI,
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FROM_HERE,
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          this,
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          &DevToolsHttpProtocolHandler::OnWebSocketRequestUI,
17972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          connection_id,
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          request));
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::OnWebSocketMessage(
18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& data) {
186731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE,
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this,
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &DevToolsHttpProtocolHandler::OnWebSocketMessageUI,
19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          connection_id,
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          data));
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::OnClose(int connection_id) {
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ConnectionToRequestsMap::iterator it =
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      connection_to_requests_io_.find(connection_id);
19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it != connection_to_requests_io_.end()) {
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Dispose delegating socket.
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (std::set<net::URLRequest*>::iterator it2 = it->second.begin();
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick         it2 != it->second.end(); ++it2) {
20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      net::URLRequest* request = *it2;
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      request->Cancel();
20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      request_to_connection_io_.erase(request);
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      request_to_buffer_io_.erase(request);
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      delete request;
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    connection_to_requests_io_.erase(connection_id);
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
213731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI,
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FROM_HERE,
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          this,
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          &DevToolsHttpProtocolHandler::OnCloseUI,
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          connection_id));
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct PageInfo
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen{
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int id;
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string url;
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool attached;
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string title;
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string favicon_url;
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentypedef std::vector<PageInfo> PageList;
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic PageList GeneratePageList(
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DevToolsHttpProtocolHandler::TabContentsProvider* tab_contents_provider,
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int connection_id,
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& info) {
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  typedef DevToolsHttpProtocolHandler::InspectableTabs Tabs;
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Tabs inspectable_tabs = tab_contents_provider->GetInspectableTabs();
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PageList page_list;
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (Tabs::iterator it = inspectable_tabs.begin();
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       it != inspectable_tabs.end(); ++it) {
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabContentsWrapper* tab_contents = *it;
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NavigationController& controller = tab_contents->controller();
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NavigationEntry* entry = controller.GetActiveEntry();
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (entry == NULL || !entry->url().is_valid())
24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      continue;
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        GetDevToolsClientHostFor(tab_contents->tab_contents()->
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                      render_view_host());
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PageInfo page_info;
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info.id = controller.session_id().id();
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info.attached = client_host != NULL;
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info.url = entry->url().spec();
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info.title = UTF16ToUTF8(entry->title());
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info.favicon_url = entry->favicon().url().spec();
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_list.push_back(page_info);
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return page_list;
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DevToolsHttpProtocolHandler::OnRootRequestUI(
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int connection_id,
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& info) {
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string host = info.headers["Host"];
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string response = "<html><body>";
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PageList page_list = GeneratePageList(tab_contents_provider_.get(),
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        connection_id, info);
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (PageList::iterator i = page_list.begin();
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       i != page_list.end(); ++i) {
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::string frontendURL = StringPrintf("%s?host=%s&page=%d",
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           overriden_frontend_url_.c_str(),
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           host.c_str(),
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           i->id);
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    response += "<div>";
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    response += StringPrintf(
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        "<img style=\"margin-right:5px;width:16px;height:16px\" src=\"%s\">",
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        i->favicon_url.c_str());
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (i->attached) {
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      response += i->url.c_str();
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      response += StringPrintf("<a href=\"%s\">%s</a><br>",
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               frontendURL.c_str(),
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               i->url.c_str());
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    response += "</div>";
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  response += "</body></html>";
29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Send200(connection_id, response, "text/html; charset=UTF-8");
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DevToolsHttpProtocolHandler::OnJsonRequestUI(
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int connection_id,
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& info) {
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PageList page_list = GeneratePageList(tab_contents_provider_.get(),
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        connection_id, info);
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue json_pages_list;
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string host = info.headers["Host"];
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (PageList::iterator i = page_list.begin();
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       i != page_list.end(); ++i) {
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* page_info = new DictionaryValue;
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    json_pages_list.Append(page_info);
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info->SetString("title", i->title);
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info->SetString("url", i->url);
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    page_info->SetString("faviconUrl", i->favicon_url);
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!i->attached) {
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      page_info->SetString("webSocketDebuggerUrl",
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           StringPrintf("ws://%s/devtools/page/%d",
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        host.c_str(),
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        i->id));
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      page_info->SetString(
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          "devtoolsFrontendUrl",
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          StringPrintf("http://%s/devtools/devtools.html?page=%d",
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       host.c_str(),
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       i->id));
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string response;
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::JSONWriter::Write(&json_pages_list, true, &response);
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Send200(connection_id, response, "application/json; charset=UTF-8");
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DevToolsHttpProtocolHandler::OnWebSocketRequestUI(
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& request) {
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string prefix = "/devtools/page/";
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  size_t pos = request.path.find(prefix);
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (pos != 0) {
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Send404(connection_id);
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string page_id = request.path.substr(prefix.length());
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int id = 0;
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!base::StringToInt(page_id, &id)) {
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Send500(connection_id, "Invalid page id: " + page_id);
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TabContents* tab_contents = GetTabContents(id);
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (tab_contents == NULL) {
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Send500(connection_id, "No such page id: " + page_id);
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DevToolsManager* manager = DevToolsManager::GetInstance();
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (manager->GetDevToolsClientHostFor(tab_contents->render_view_host())) {
35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Send500(connection_id, "Page with given id is being inspected: " + page_id);
3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DevToolsClientHostImpl* client_host =
35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      new DevToolsClientHostImpl(server_, connection_id);
35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  connection_to_client_host_ui_[connection_id] = client_host;
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  manager->RegisterDevToolsClientHostFor(
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      tab_contents->render_view_host(),
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      client_host);
36372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  manager->ForwardToDevToolsAgent(
36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      client_host,
36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DevToolsAgentMsg_FrontendLoaded());
36672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  AcceptWebSocket(connection_id, request);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& data) {
37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ConnectionToClientHostMap::iterator it =
37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      connection_to_client_host_ui_.find(connection_id);
37572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it == connection_to_client_host_ui_.end())
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DevToolsManager* manager = DevToolsManager::GetInstance();
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  manager->ForwardToDevToolsAgent(
3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      it->second,
3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DevToolsAgentMsg_DispatchOnInspectorBackend(data));
3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::OnCloseUI(int connection_id) {
38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ConnectionToClientHostMap::iterator it =
38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      connection_to_client_host_ui_.find(connection_id);
38772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it != connection_to_client_host_ui_.end()) {
38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DevToolsClientHostImpl* client_host =
38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        static_cast<DevToolsClientHostImpl*>(it->second);
39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    client_host->NotifyCloseListener();
39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete client_host;
39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    connection_to_client_host_ui_.erase(connection_id);
39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid DevToolsHttpProtocolHandler::OnResponseStarted(net::URLRequest* request) {
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  RequestToSocketMap::iterator it = request_to_connection_io_.find(request);
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it == request_to_connection_io_.end())
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int connection_id = it->second;
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string content_type;
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->GetMimeType(&content_type);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->status().is_success()) {
40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    server_->Send(connection_id, StringPrintf("HTTP/1.1 200 OK\r\n"
40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                              "Content-Type:%s\r\n"
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              "Transfer-Encoding: chunked\r\n"
41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                              "\r\n",
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              content_type.c_str()));
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    server_->Send404(connection_id);
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bytes_read = 0;
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Some servers may treat HEAD requests as GET requests.  To free up the
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // network connection as soon as possible, signal that the request has
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // completed immediately, without trying to read any data back (all we care
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // about is the response code and headers, which we already have).
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request->status().is_success())
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->Read(buffer, kBufferSize, &bytes_read);
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OnReadCompleted(request, bytes_read);
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid DevToolsHttpProtocolHandler::OnReadCompleted(net::URLRequest* request,
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  int bytes_read) {
42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  RequestToSocketMap::iterator it = request_to_connection_io_.find(request);
43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it == request_to_connection_io_.end())
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int connection_id = it->second;
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!request->status().is_success() || bytes_read <= 0)
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::string chunk_size = StringPrintf("%X\r\n", bytes_read);
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_->Send(connection_id, chunk_size);
44172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    server_->Send(connection_id, buffer->data(), bytes_read);
442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_->Send(connection_id, "\r\n");
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } while (request->Read(buffer, kBufferSize, &bytes_read));
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See comments re: HEAD requests in OnResponseStarted().
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!request->status().is_io_pending()) {
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_->Send(connection_id, "0\r\n\r\n");
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RequestCompleted(request);
450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDevToolsHttpProtocolHandler::DevToolsHttpProtocolHandler(
45472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& ip,
45572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int port,
45672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& frontend_host,
45772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabContentsProvider* provider)
45872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : ip_(ip),
45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      port_(port),
46072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      overriden_frontend_url_(frontend_host),
46172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      tab_contents_provider_(provider) {
46272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (overriden_frontend_url_.empty())
46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      overriden_frontend_url_ = "/devtools/devtools.html";
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DevToolsHttpProtocolHandler::Init() {
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  server_ = new net::HttpServer(ip_, port_, this);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Run on I/O thread
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DevToolsHttpProtocolHandler::Teardown() {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  server_ = NULL;
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid DevToolsHttpProtocolHandler::Bind(net::URLRequest* request,
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                       int connection_id) {
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_to_connection_io_[request] = connection_id;
47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ConnectionToRequestsMap::iterator it =
47972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      connection_to_requests_io_.find(connection_id);
48072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it == connection_to_requests_io_.end()) {
48172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    std::pair<int, std::set<net::URLRequest*> > value(
48272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        connection_id,
48321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        std::set<net::URLRequest*>());
48472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    it = connection_to_requests_io_.insert(value).first;
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  it->second.insert(request);
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize);
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid DevToolsHttpProtocolHandler::RequestCompleted(net::URLRequest* request) {
49172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  RequestToSocketMap::iterator it = request_to_connection_io_.find(request);
49272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (it == request_to_connection_io_.end())
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int connection_id = it->second;
49672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  request_to_connection_io_.erase(request);
49772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ConnectionToRequestsMap::iterator it2 =
49872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      connection_to_requests_io_.find(connection_id);
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  it2->second.erase(request);
5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  request_to_buffer_io_.erase(request);
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete request;
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
50472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::Send200(int connection_id,
5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          const std::string& data,
5063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          const std::string& mime_type) {
507731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
508731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
50972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NewRunnableMethod(server_.get(),
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &net::HttpServer::Send200,
51172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        connection_id,
5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        data,
5133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        mime_type));
5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
51672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::Send404(int connection_id) {
517731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
51972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NewRunnableMethod(server_.get(),
520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &net::HttpServer::Send404,
52172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        connection_id));
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
52472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DevToolsHttpProtocolHandler::Send500(int connection_id,
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          const std::string& message) {
526731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
527731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
52872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NewRunnableMethod(server_.get(),
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &net::HttpServer::Send500,
53072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        connection_id,
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        message));
5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DevToolsHttpProtocolHandler::AcceptWebSocket(
53572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int connection_id,
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const net::HttpServerRequestInfo& request) {
537731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
538731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
53972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NewRunnableMethod(server_.get(),
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &net::HttpServer::AcceptWebSocket,
54172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        connection_id,
5423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        request));
5433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5453345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) {
54672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  InspectableTabs inspectable_tabs =
54772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      tab_contents_provider_->GetInspectableTabs();
54872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
54972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (InspectableTabs::iterator it = inspectable_tabs.begin();
55072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       it != inspectable_tabs.end(); ++it) {
55172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabContentsWrapper* tab_contents = *it;
55272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NavigationController& controller =
55372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        tab_contents->controller();
55472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (controller.session_id().id() == session_id)
55572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return controller.tab_contents();
5563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return NULL;
5583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
559