Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / devtools / devtools_http_handler_impl.cc
blobd1b5b1e67245588bb2cf4c35cc6e0ccf5523d50e
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/devtools_http_handler_impl.h"
7 #include <algorithm>
8 #include <utility>
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_util.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/threading/thread.h"
19 #include "base/values.h"
20 #include "content/browser/devtools/devtools_browser_target.h"
21 #include "content/browser/devtools/devtools_protocol.h"
22 #include "content/browser/devtools/devtools_protocol_constants.h"
23 #include "content/browser/devtools/devtools_system_info_handler.h"
24 #include "content/browser/devtools/devtools_tracing_handler.h"
25 #include "content/browser/devtools/tethering_handler.h"
26 #include "content/common/devtools_messages.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/devtools_agent_host.h"
29 #include "content/public/browser/devtools_client_host.h"
30 #include "content/public/browser/devtools_http_handler_delegate.h"
31 #include "content/public/browser/devtools_manager.h"
32 #include "content/public/browser/devtools_target.h"
33 #include "content/public/common/content_client.h"
34 #include "content/public/common/url_constants.h"
35 #include "content/public/common/user_agent.h"
36 #include "content/public/common/user_agent.h"
37 #include "grit/devtools_resources_map.h"
38 #include "net/base/escape.h"
39 #include "net/base/io_buffer.h"
40 #include "net/base/ip_endpoint.h"
41 #include "net/base/net_errors.h"
42 #include "net/server/http_server_request_info.h"
43 #include "net/server/http_server_response_info.h"
45 #if defined(OS_ANDROID)
46 #include "base/android/build_info.h"
47 #endif
49 namespace content {
51 namespace {
53 const base::FilePath::CharType kDevToolsActivePortFileName[] =
54 FILE_PATH_LITERAL("DevToolsActivePort");
56 const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
58 const char kThumbUrlPrefix[] = "/thumb/";
59 const char kPageUrlPrefix[] = "/devtools/page/";
61 const char kTargetIdField[] = "id";
62 const char kTargetParentIdField[] = "parentId";
63 const char kTargetTypeField[] = "type";
64 const char kTargetTitleField[] = "title";
65 const char kTargetDescriptionField[] = "description";
66 const char kTargetUrlField[] = "url";
67 const char kTargetThumbnailUrlField[] = "thumbnailUrl";
68 const char kTargetFaviconUrlField[] = "faviconUrl";
69 const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
70 const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
72 // An internal implementation of DevToolsClientHost that delegates
73 // messages sent for DevToolsClient to a DebuggerShell instance.
74 class DevToolsClientHostImpl : public DevToolsClientHost {
75 public:
76 DevToolsClientHostImpl(base::MessageLoop* message_loop,
77 net::HttpServer* server,
78 int connection_id)
79 : message_loop_(message_loop),
80 server_(server),
81 connection_id_(connection_id),
82 is_closed_(false),
83 detach_reason_("target_closed") {}
85 virtual ~DevToolsClientHostImpl() {}
87 // DevToolsClientHost interface
88 virtual void InspectedContentsClosing() OVERRIDE {
89 if (is_closed_)
90 return;
91 is_closed_ = true;
93 base::DictionaryValue notification;
94 notification.SetString(
95 devtools::Inspector::detached::kParamReason, detach_reason_);
96 std::string response = DevToolsProtocol::CreateNotification(
97 devtools::Inspector::detached::kName,
98 notification.DeepCopy())->Serialize();
99 message_loop_->PostTask(
100 FROM_HERE,
101 base::Bind(&net::HttpServer::SendOverWebSocket,
102 server_,
103 connection_id_,
104 response));
106 message_loop_->PostTask(
107 FROM_HERE,
108 base::Bind(&net::HttpServer::Close, server_, connection_id_));
111 virtual void DispatchOnInspectorFrontend(const std::string& data) OVERRIDE {
112 message_loop_->PostTask(
113 FROM_HERE,
114 base::Bind(&net::HttpServer::SendOverWebSocket,
115 server_,
116 connection_id_,
117 data));
120 virtual void ReplacedWithAnotherClient() OVERRIDE {
121 detach_reason_ = "replaced_with_devtools";
124 private:
125 base::MessageLoop* message_loop_;
126 net::HttpServer* server_;
127 int connection_id_;
128 bool is_closed_;
129 std::string detach_reason_;
132 static bool TimeComparator(const DevToolsTarget* target1,
133 const DevToolsTarget* target2) {
134 return target1->GetLastActivityTime() > target2->GetLastActivityTime();
137 } // namespace
139 // static
140 bool DevToolsHttpHandler::IsSupportedProtocolVersion(
141 const std::string& version) {
142 return devtools::IsSupportedProtocolVersion(version);
145 // static
146 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
147 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
148 if (name == kDevtoolsResources[i].name)
149 return kDevtoolsResources[i].value;
151 return -1;
154 // static
155 DevToolsHttpHandler* DevToolsHttpHandler::Start(
156 const net::StreamListenSocketFactory* socket_factory,
157 const std::string& frontend_url,
158 DevToolsHttpHandlerDelegate* delegate,
159 const base::FilePath& active_port_output_directory) {
160 DevToolsHttpHandlerImpl* http_handler =
161 new DevToolsHttpHandlerImpl(socket_factory,
162 frontend_url,
163 delegate,
164 active_port_output_directory);
165 http_handler->Start();
166 return http_handler;
169 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
171 // Stop() must be called prior to destruction.
172 DCHECK(server_.get() == NULL);
173 DCHECK(thread_.get() == NULL);
174 STLDeleteValues(&target_map_);
177 void DevToolsHttpHandlerImpl::Start() {
178 if (thread_)
179 return;
180 thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
181 BrowserThread::PostTask(
182 BrowserThread::FILE, FROM_HERE,
183 base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
186 // Runs on FILE thread.
187 void DevToolsHttpHandlerImpl::StartHandlerThread() {
188 base::Thread::Options options;
189 options.message_loop_type = base::MessageLoop::TYPE_IO;
190 if (!thread_->StartWithOptions(options)) {
191 BrowserThread::PostTask(
192 BrowserThread::UI, FROM_HERE,
193 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
194 return;
197 thread_->message_loop()->PostTask(
198 FROM_HERE,
199 base::Bind(&DevToolsHttpHandlerImpl::Init, this));
202 void DevToolsHttpHandlerImpl::ResetHandlerThread() {
203 thread_.reset();
206 void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
207 ResetHandlerThread();
208 Release();
211 void DevToolsHttpHandlerImpl::Stop() {
212 if (!thread_)
213 return;
214 BrowserThread::PostTaskAndReply(
215 BrowserThread::FILE, FROM_HERE,
216 base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
217 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
220 GURL DevToolsHttpHandlerImpl::GetFrontendURL() {
221 net::IPEndPoint ip_address;
222 if (server_->GetLocalAddress(&ip_address))
223 return GURL();
224 return GURL(std::string("http://") + ip_address.ToString() + frontend_url_);
227 static std::string PathWithoutParams(const std::string& path) {
228 size_t query_position = path.find("?");
229 if (query_position != std::string::npos)
230 return path.substr(0, query_position);
231 return path;
234 static std::string GetMimeType(const std::string& filename) {
235 if (EndsWith(filename, ".html", false)) {
236 return "text/html";
237 } else if (EndsWith(filename, ".css", false)) {
238 return "text/css";
239 } else if (EndsWith(filename, ".js", false)) {
240 return "application/javascript";
241 } else if (EndsWith(filename, ".png", false)) {
242 return "image/png";
243 } else if (EndsWith(filename, ".gif", false)) {
244 return "image/gif";
245 } else if (EndsWith(filename, ".json", false)) {
246 return "application/json";
248 LOG(ERROR) << "GetMimeType doesn't know mime type for: "
249 << filename
250 << " text/plain will be returned";
251 NOTREACHED();
252 return "text/plain";
255 void DevToolsHttpHandlerImpl::OnHttpRequest(
256 int connection_id,
257 const net::HttpServerRequestInfo& info) {
258 if (info.path.find("/json") == 0) {
259 BrowserThread::PostTask(
260 BrowserThread::UI,
261 FROM_HERE,
262 base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
263 this,
264 connection_id,
265 info));
266 return;
269 if (info.path.find(kThumbUrlPrefix) == 0) {
270 // Thumbnail request.
271 const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
272 DevToolsTarget* target = GetTarget(target_id);
273 GURL page_url;
274 if (target)
275 page_url = target->GetURL();
276 BrowserThread::PostTask(
277 BrowserThread::UI,
278 FROM_HERE,
279 base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
280 this,
281 connection_id,
282 page_url));
283 return;
286 if (info.path == "" || info.path == "/") {
287 // Discovery page request.
288 BrowserThread::PostTask(
289 BrowserThread::UI,
290 FROM_HERE,
291 base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
292 this,
293 connection_id));
294 return;
297 if (info.path.find("/devtools/") != 0) {
298 server_->Send404(connection_id);
299 return;
302 std::string filename = PathWithoutParams(info.path.substr(10));
303 std::string mime_type = GetMimeType(filename);
305 base::FilePath frontend_dir = delegate_->GetDebugFrontendDir();
306 if (!frontend_dir.empty()) {
307 base::FilePath path = frontend_dir.AppendASCII(filename);
308 std::string data;
309 base::ReadFileToString(path, &data);
310 server_->Send200(connection_id, data, mime_type);
311 return;
313 if (delegate_->BundlesFrontendResources()) {
314 int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
315 if (resource_id != -1) {
316 base::StringPiece data = GetContentClient()->GetDataResource(
317 resource_id, ui::SCALE_FACTOR_NONE);
318 server_->Send200(connection_id, data.as_string(), mime_type);
319 return;
322 server_->Send404(connection_id);
325 void DevToolsHttpHandlerImpl::OnWebSocketRequest(
326 int connection_id,
327 const net::HttpServerRequestInfo& request) {
328 std::string browser_prefix = "/devtools/browser";
329 size_t browser_pos = request.path.find(browser_prefix);
330 if (browser_pos == 0) {
331 scoped_refptr<DevToolsBrowserTarget> browser_target =
332 new DevToolsBrowserTarget(server_.get(), connection_id);
333 browser_target->RegisterDomainHandler(
334 devtools::Tracing::kName,
335 new DevToolsTracingHandler(DevToolsTracingHandler::Browser),
336 true /* handle on UI thread */);
337 browser_target->RegisterDomainHandler(
338 TetheringHandler::kDomain,
339 new TetheringHandler(delegate_.get()),
340 false /* handle on this thread */);
341 browser_target->RegisterDomainHandler(
342 devtools::SystemInfo::kName,
343 new DevToolsSystemInfoHandler(),
344 true /* handle on UI thread */);
345 browser_targets_[connection_id] = browser_target;
347 server_->AcceptWebSocket(connection_id, request);
348 return;
351 BrowserThread::PostTask(
352 BrowserThread::UI,
353 FROM_HERE,
354 base::Bind(
355 &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
356 this,
357 connection_id,
358 request));
361 void DevToolsHttpHandlerImpl::OnWebSocketMessage(
362 int connection_id,
363 const std::string& data) {
364 BrowserTargets::iterator it = browser_targets_.find(connection_id);
365 if (it != browser_targets_.end()) {
366 it->second->HandleMessage(data);
367 return;
370 BrowserThread::PostTask(
371 BrowserThread::UI,
372 FROM_HERE,
373 base::Bind(
374 &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
375 this,
376 connection_id,
377 data));
380 void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
381 BrowserTargets::iterator it = browser_targets_.find(connection_id);
382 if (it != browser_targets_.end()) {
383 it->second->Detach();
384 browser_targets_.erase(it);
385 return;
388 BrowserThread::PostTask(
389 BrowserThread::UI,
390 FROM_HERE,
391 base::Bind(
392 &DevToolsHttpHandlerImpl::OnCloseUI,
393 this,
394 connection_id));
397 std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
398 const std::string id,
399 const std::string& host) {
400 return base::StringPrintf(
401 "%s%sws=%s%s%s",
402 frontend_url_.c_str(),
403 frontend_url_.find("?") == std::string::npos ? "?" : "&",
404 host.c_str(),
405 kPageUrlPrefix,
406 id.c_str());
409 static bool ParseJsonPath(
410 const std::string& path,
411 std::string* command,
412 std::string* target_id) {
414 // Fall back to list in case of empty query.
415 if (path.empty()) {
416 *command = "list";
417 return true;
420 if (path.find("/") != 0) {
421 // Malformed command.
422 return false;
424 *command = path.substr(1);
426 size_t separator_pos = command->find("/");
427 if (separator_pos != std::string::npos) {
428 *target_id = command->substr(separator_pos + 1);
429 *command = command->substr(0, separator_pos);
431 return true;
434 void DevToolsHttpHandlerImpl::OnJsonRequestUI(
435 int connection_id,
436 const net::HttpServerRequestInfo& info) {
437 // Trim /json
438 std::string path = info.path.substr(5);
440 // Trim fragment and query
441 std::string query;
442 size_t query_pos = path.find("?");
443 if (query_pos != std::string::npos) {
444 query = path.substr(query_pos + 1);
445 path = path.substr(0, query_pos);
448 size_t fragment_pos = path.find("#");
449 if (fragment_pos != std::string::npos)
450 path = path.substr(0, fragment_pos);
452 std::string command;
453 std::string target_id;
454 if (!ParseJsonPath(path, &command, &target_id)) {
455 SendJson(connection_id,
456 net::HTTP_NOT_FOUND,
457 NULL,
458 "Malformed query: " + info.path);
459 return;
462 if (command == "version") {
463 base::DictionaryValue version;
464 version.SetString("Protocol-Version", devtools::kProtocolVersion);
465 version.SetString("WebKit-Version", GetWebKitVersion());
466 version.SetString("Browser", GetContentClient()->GetProduct());
467 version.SetString("User-Agent", GetContentClient()->GetUserAgent());
468 #if defined(OS_ANDROID)
469 version.SetString("Android-Package",
470 base::android::BuildInfo::GetInstance()->package_name());
471 #endif
472 SendJson(connection_id, net::HTTP_OK, &version, std::string());
473 return;
476 if (command == "list") {
477 std::string host = info.headers["host"];
478 AddRef(); // Balanced in OnTargetListReceived.
479 delegate_->EnumerateTargets(
480 base::Bind(&DevToolsHttpHandlerImpl::OnTargetListReceived,
481 this, connection_id, host));
482 return;
485 if (command == "new") {
486 GURL url(net::UnescapeURLComponent(
487 query, net::UnescapeRule::URL_SPECIAL_CHARS));
488 if (!url.is_valid())
489 url = GURL(url::kAboutBlankURL);
490 scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget(url));
491 if (!target) {
492 SendJson(connection_id,
493 net::HTTP_INTERNAL_SERVER_ERROR,
494 NULL,
495 "Could not create new page");
496 return;
498 std::string host = info.headers["host"];
499 scoped_ptr<base::DictionaryValue> dictionary(
500 SerializeTarget(*target.get(), host));
501 SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
502 const std::string target_id = target->GetId();
503 target_map_[target_id] = target.release();
504 return;
507 if (command == "activate" || command == "close") {
508 DevToolsTarget* target = GetTarget(target_id);
509 if (!target) {
510 SendJson(connection_id,
511 net::HTTP_NOT_FOUND,
512 NULL,
513 "No such target id: " + target_id);
514 return;
517 if (command == "activate") {
518 if (target->Activate()) {
519 SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
520 } else {
521 SendJson(connection_id,
522 net::HTTP_INTERNAL_SERVER_ERROR,
523 NULL,
524 "Could not activate target id: " + target_id);
526 return;
529 if (command == "close") {
530 if (target->Close()) {
531 SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
532 } else {
533 SendJson(connection_id,
534 net::HTTP_INTERNAL_SERVER_ERROR,
535 NULL,
536 "Could not close target id: " + target_id);
538 return;
541 SendJson(connection_id,
542 net::HTTP_NOT_FOUND,
543 NULL,
544 "Unknown command: " + command);
545 return;
548 void DevToolsHttpHandlerImpl::OnTargetListReceived(
549 int connection_id,
550 const std::string& host,
551 const DevToolsHttpHandlerDelegate::TargetList& targets) {
552 DevToolsHttpHandlerDelegate::TargetList sorted_targets = targets;
553 std::sort(sorted_targets.begin(), sorted_targets.end(), TimeComparator);
555 STLDeleteValues(&target_map_);
556 base::ListValue list_value;
557 for (DevToolsHttpHandlerDelegate::TargetList::const_iterator it =
558 sorted_targets.begin(); it != sorted_targets.end(); ++it) {
559 DevToolsTarget* target = *it;
560 target_map_[target->GetId()] = target;
561 list_value.Append(SerializeTarget(*target, host));
563 SendJson(connection_id, net::HTTP_OK, &list_value, std::string());
564 Release(); // Balanced in OnJsonRequestUI.
567 DevToolsTarget* DevToolsHttpHandlerImpl::GetTarget(const std::string& id) {
568 TargetMap::const_iterator it = target_map_.find(id);
569 if (it == target_map_.end())
570 return NULL;
571 return it->second;
574 void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
575 int connection_id, const GURL& page_url) {
576 std::string data = delegate_->GetPageThumbnailData(page_url);
577 if (!data.empty())
578 Send200(connection_id, data, "image/png");
579 else
580 Send404(connection_id);
583 void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
584 std::string response = delegate_->GetDiscoveryPageHTML();
585 Send200(connection_id, response, "text/html; charset=UTF-8");
588 void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
589 int connection_id,
590 const net::HttpServerRequestInfo& request) {
591 if (!thread_)
592 return;
594 size_t pos = request.path.find(kPageUrlPrefix);
595 if (pos != 0) {
596 Send404(connection_id);
597 return;
600 std::string page_id = request.path.substr(strlen(kPageUrlPrefix));
601 DevToolsTarget* target = GetTarget(page_id);
602 scoped_refptr<DevToolsAgentHost> agent =
603 target ? target->GetAgentHost() : NULL;
604 if (!agent) {
605 Send500(connection_id, "No such target id: " + page_id);
606 return;
609 if (agent->IsAttached()) {
610 Send500(connection_id,
611 "Target with given id is being inspected: " + page_id);
612 return;
615 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(
616 thread_->message_loop(), server_.get(), connection_id);
617 connection_to_client_host_ui_[connection_id] = client_host;
619 DevToolsManager::GetInstance()->
620 RegisterDevToolsClientHostFor(agent, client_host);
622 AcceptWebSocket(connection_id, request);
625 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
626 int connection_id,
627 const std::string& data) {
628 ConnectionToClientHostMap::iterator it =
629 connection_to_client_host_ui_.find(connection_id);
630 if (it == connection_to_client_host_ui_.end())
631 return;
633 DevToolsManager* manager = DevToolsManager::GetInstance();
634 manager->DispatchOnInspectorBackend(it->second, data);
637 void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
638 ConnectionToClientHostMap::iterator it =
639 connection_to_client_host_ui_.find(connection_id);
640 if (it != connection_to_client_host_ui_.end()) {
641 DevToolsClientHostImpl* client_host =
642 static_cast<DevToolsClientHostImpl*>(it->second);
643 DevToolsManager::GetInstance()->ClientHostClosing(client_host);
644 delete client_host;
645 connection_to_client_host_ui_.erase(connection_id);
649 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
650 const net::StreamListenSocketFactory* socket_factory,
651 const std::string& frontend_url,
652 DevToolsHttpHandlerDelegate* delegate,
653 const base::FilePath& active_port_output_directory)
654 : frontend_url_(frontend_url),
655 socket_factory_(socket_factory),
656 delegate_(delegate),
657 active_port_output_directory_(active_port_output_directory) {
658 if (frontend_url_.empty())
659 frontend_url_ = "/devtools/devtools.html";
661 // Balanced in ResetHandlerThreadAndRelease().
662 AddRef();
665 // Runs on the handler thread
666 void DevToolsHttpHandlerImpl::Init() {
667 server_ = new net::HttpServer(*socket_factory_.get(), this);
668 if (!active_port_output_directory_.empty())
669 WriteActivePortToUserProfile();
672 // Runs on the handler thread
673 void DevToolsHttpHandlerImpl::Teardown() {
674 server_ = NULL;
677 // Runs on FILE thread to make sure that it is serialized against
678 // {Start|Stop}HandlerThread and to allow calling pthread_join.
679 void DevToolsHttpHandlerImpl::StopHandlerThread() {
680 if (!thread_->message_loop())
681 return;
682 thread_->message_loop()->PostTask(
683 FROM_HERE,
684 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
685 // Thread::Stop joins the thread.
686 thread_->Stop();
689 void DevToolsHttpHandlerImpl::WriteActivePortToUserProfile() {
690 DCHECK(!active_port_output_directory_.empty());
691 net::IPEndPoint endpoint;
692 int err;
693 if ((err = server_->GetLocalAddress(&endpoint)) != net::OK) {
694 LOG(ERROR) << "Error " << err << " getting local address";
695 return;
698 // Write this port to a well-known file in the profile directory
699 // so Telemetry can pick it up.
700 base::FilePath path = active_port_output_directory_.Append(
701 kDevToolsActivePortFileName);
702 std::string port_string = base::IntToString(endpoint.port());
703 if (base::WriteFile(path, port_string.c_str(), port_string.length()) < 0) {
704 LOG(ERROR) << "Error writing DevTools active port to file";
708 void DevToolsHttpHandlerImpl::SendJson(int connection_id,
709 net::HttpStatusCode status_code,
710 base::Value* value,
711 const std::string& message) {
712 if (!thread_)
713 return;
715 // Serialize value and message.
716 std::string json_value;
717 if (value) {
718 base::JSONWriter::WriteWithOptions(value,
719 base::JSONWriter::OPTIONS_PRETTY_PRINT,
720 &json_value);
722 std::string json_message;
723 scoped_ptr<base::Value> message_object(new base::StringValue(message));
724 base::JSONWriter::Write(message_object.get(), &json_message);
726 net::HttpServerResponseInfo response(status_code);
727 response.SetBody(json_value + message, "application/json; charset=UTF-8");
729 thread_->message_loop()->PostTask(
730 FROM_HERE,
731 base::Bind(&net::HttpServer::SendResponse,
732 server_.get(),
733 connection_id,
734 response));
737 void DevToolsHttpHandlerImpl::Send200(int connection_id,
738 const std::string& data,
739 const std::string& mime_type) {
740 if (!thread_)
741 return;
742 thread_->message_loop()->PostTask(
743 FROM_HERE,
744 base::Bind(&net::HttpServer::Send200,
745 server_.get(),
746 connection_id,
747 data,
748 mime_type));
751 void DevToolsHttpHandlerImpl::Send404(int connection_id) {
752 if (!thread_)
753 return;
754 thread_->message_loop()->PostTask(
755 FROM_HERE,
756 base::Bind(&net::HttpServer::Send404, server_.get(), connection_id));
759 void DevToolsHttpHandlerImpl::Send500(int connection_id,
760 const std::string& message) {
761 if (!thread_)
762 return;
763 thread_->message_loop()->PostTask(
764 FROM_HERE,
765 base::Bind(&net::HttpServer::Send500, server_.get(), connection_id,
766 message));
769 void DevToolsHttpHandlerImpl::AcceptWebSocket(
770 int connection_id,
771 const net::HttpServerRequestInfo& request) {
772 if (!thread_)
773 return;
774 thread_->message_loop()->PostTask(
775 FROM_HERE,
776 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(),
777 connection_id, request));
780 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget(
781 const DevToolsTarget& target,
782 const std::string& host) {
783 base::DictionaryValue* dictionary = new base::DictionaryValue;
785 std::string id = target.GetId();
786 dictionary->SetString(kTargetIdField, id);
787 std::string parent_id = target.GetParentId();
788 if (!parent_id.empty())
789 dictionary->SetString(kTargetParentIdField, parent_id);
790 dictionary->SetString(kTargetTypeField, target.GetType());
791 dictionary->SetString(kTargetTitleField,
792 net::EscapeForHTML(target.GetTitle()));
793 dictionary->SetString(kTargetDescriptionField, target.GetDescription());
795 GURL url = target.GetURL();
796 dictionary->SetString(kTargetUrlField, url.spec());
798 GURL favicon_url = target.GetFaviconURL();
799 if (favicon_url.is_valid())
800 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
802 if (!delegate_->GetPageThumbnailData(url).empty()) {
803 dictionary->SetString(kTargetThumbnailUrlField,
804 std::string(kThumbUrlPrefix) + id);
807 if (!target.IsAttached()) {
808 dictionary->SetString(kTargetWebSocketDebuggerUrlField,
809 base::StringPrintf("ws://%s%s%s",
810 host.c_str(),
811 kPageUrlPrefix,
812 id.c_str()));
813 std::string devtools_frontend_url = GetFrontendURLInternal(
814 id.c_str(),
815 host);
816 dictionary->SetString(
817 kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
820 return dictionary;
823 } // namespace content