Generate ax enums from idl.
[chromium-blink-merge.git] / content / browser / devtools / devtools_http_handler_impl.cc
blob1d0fca1e2824f007b7d5856b5be6e696d113b25c
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/threading/thread.h"
18 #include "base/values.h"
19 #include "content/browser/devtools/devtools_browser_target.h"
20 #include "content/browser/devtools/devtools_protocol.h"
21 #include "content/browser/devtools/devtools_protocol_constants.h"
22 #include "content/browser/devtools/devtools_system_info_handler.h"
23 #include "content/browser/devtools/devtools_tracing_handler.h"
24 #include "content/browser/devtools/tethering_handler.h"
25 #include "content/common/devtools_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/devtools_agent_host.h"
28 #include "content/public/browser/devtools_client_host.h"
29 #include "content/public/browser/devtools_http_handler_delegate.h"
30 #include "content/public/browser/devtools_manager.h"
31 #include "content/public/browser/devtools_target.h"
32 #include "content/public/common/content_client.h"
33 #include "content/public/common/url_constants.h"
34 #include "grit/devtools_resources_map.h"
35 #include "net/base/escape.h"
36 #include "net/base/io_buffer.h"
37 #include "net/base/ip_endpoint.h"
38 #include "net/server/http_server_request_info.h"
39 #include "net/server/http_server_response_info.h"
40 #include "webkit/common/user_agent/user_agent.h"
41 #include "webkit/common/user_agent/user_agent_util.h"
43 #if defined(OS_ANDROID)
44 #include "base/android/build_info.h"
45 #endif
47 namespace content {
49 namespace {
51 const char kProtocolVersion[] = "1.0";
53 const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
55 const char kThumbUrlPrefix[] = "/thumb/";
56 const char kPageUrlPrefix[] = "/devtools/page/";
58 const char kTargetIdField[] = "id";
59 const char kTargetTypeField[] = "type";
60 const char kTargetTitleField[] = "title";
61 const char kTargetDescriptionField[] = "description";
62 const char kTargetUrlField[] = "url";
63 const char kTargetThumbnailUrlField[] = "thumbnailUrl";
64 const char kTargetFaviconUrlField[] = "faviconUrl";
65 const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
66 const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
68 // An internal implementation of DevToolsClientHost that delegates
69 // messages sent for DevToolsClient to a DebuggerShell instance.
70 class DevToolsClientHostImpl : public DevToolsClientHost {
71 public:
72 DevToolsClientHostImpl(base::MessageLoop* message_loop,
73 net::HttpServer* server,
74 int connection_id)
75 : message_loop_(message_loop),
76 server_(server),
77 connection_id_(connection_id),
78 is_closed_(false),
79 detach_reason_("target_closed") {}
81 virtual ~DevToolsClientHostImpl() {}
83 // DevToolsClientHost interface
84 virtual void InspectedContentsClosing() OVERRIDE {
85 if (is_closed_)
86 return;
87 is_closed_ = true;
89 base::DictionaryValue notification;
90 notification.SetString(
91 devtools::Inspector::detached::kParamReason, detach_reason_);
92 std::string response = DevToolsProtocol::CreateNotification(
93 devtools::Inspector::detached::kName,
94 notification.DeepCopy())->Serialize();
95 message_loop_->PostTask(
96 FROM_HERE,
97 base::Bind(&net::HttpServer::SendOverWebSocket,
98 server_,
99 connection_id_,
100 response));
102 message_loop_->PostTask(
103 FROM_HERE,
104 base::Bind(&net::HttpServer::Close, server_, connection_id_));
107 virtual void DispatchOnInspectorFrontend(const std::string& data) OVERRIDE {
108 message_loop_->PostTask(
109 FROM_HERE,
110 base::Bind(&net::HttpServer::SendOverWebSocket,
111 server_,
112 connection_id_,
113 data));
116 virtual void ReplacedWithAnotherClient() OVERRIDE {
117 detach_reason_ = "replaced_with_devtools";
120 private:
121 base::MessageLoop* message_loop_;
122 net::HttpServer* server_;
123 int connection_id_;
124 bool is_closed_;
125 std::string detach_reason_;
128 static bool TimeComparator(const DevToolsTarget* target1,
129 const DevToolsTarget* target2) {
130 return target1->GetLastActivityTime() > target2->GetLastActivityTime();
133 } // namespace
135 // static
136 bool DevToolsHttpHandler::IsSupportedProtocolVersion(
137 const std::string& version) {
138 return version == kProtocolVersion;
141 // static
142 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
143 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
144 if (name == kDevtoolsResources[i].name)
145 return kDevtoolsResources[i].value;
147 return -1;
150 // static
151 DevToolsHttpHandler* DevToolsHttpHandler::Start(
152 const net::StreamListenSocketFactory* socket_factory,
153 const std::string& frontend_url,
154 DevToolsHttpHandlerDelegate* delegate) {
155 DevToolsHttpHandlerImpl* http_handler =
156 new DevToolsHttpHandlerImpl(socket_factory,
157 frontend_url,
158 delegate);
159 http_handler->Start();
160 return http_handler;
163 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
165 // Stop() must be called prior to destruction.
166 DCHECK(server_.get() == NULL);
167 DCHECK(thread_.get() == NULL);
168 STLDeleteValues(&target_map_);
171 void DevToolsHttpHandlerImpl::Start() {
172 if (thread_)
173 return;
174 thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
175 BrowserThread::PostTask(
176 BrowserThread::FILE, FROM_HERE,
177 base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
180 // Runs on FILE thread.
181 void DevToolsHttpHandlerImpl::StartHandlerThread() {
182 base::Thread::Options options;
183 options.message_loop_type = base::MessageLoop::TYPE_IO;
184 if (!thread_->StartWithOptions(options)) {
185 BrowserThread::PostTask(
186 BrowserThread::UI, FROM_HERE,
187 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
188 return;
191 thread_->message_loop()->PostTask(
192 FROM_HERE,
193 base::Bind(&DevToolsHttpHandlerImpl::Init, this));
196 void DevToolsHttpHandlerImpl::ResetHandlerThread() {
197 thread_.reset();
200 void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
201 ResetHandlerThread();
202 Release();
205 void DevToolsHttpHandlerImpl::Stop() {
206 if (!thread_)
207 return;
208 BrowserThread::PostTaskAndReply(
209 BrowserThread::FILE, FROM_HERE,
210 base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
211 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
214 GURL DevToolsHttpHandlerImpl::GetFrontendURL() {
215 net::IPEndPoint ip_address;
216 if (server_->GetLocalAddress(&ip_address))
217 return GURL();
218 return GURL(std::string("http://") + ip_address.ToString() +
219 overridden_frontend_url_);
222 static std::string PathWithoutParams(const std::string& path) {
223 size_t query_position = path.find("?");
224 if (query_position != std::string::npos)
225 return path.substr(0, query_position);
226 return path;
229 static std::string GetMimeType(const std::string& filename) {
230 if (EndsWith(filename, ".html", false)) {
231 return "text/html";
232 } else if (EndsWith(filename, ".css", false)) {
233 return "text/css";
234 } else if (EndsWith(filename, ".js", false)) {
235 return "application/javascript";
236 } else if (EndsWith(filename, ".png", false)) {
237 return "image/png";
238 } else if (EndsWith(filename, ".gif", false)) {
239 return "image/gif";
241 NOTREACHED();
242 return "text/plain";
245 void DevToolsHttpHandlerImpl::OnHttpRequest(
246 int connection_id,
247 const net::HttpServerRequestInfo& info) {
248 if (info.path.find("/json") == 0) {
249 BrowserThread::PostTask(
250 BrowserThread::UI,
251 FROM_HERE,
252 base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
253 this,
254 connection_id,
255 info));
256 return;
259 if (info.path.find(kThumbUrlPrefix) == 0) {
260 // Thumbnail request.
261 const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
262 DevToolsTarget* target = GetTarget(target_id);
263 GURL page_url;
264 if (target)
265 page_url = target->GetUrl();
266 BrowserThread::PostTask(
267 BrowserThread::UI,
268 FROM_HERE,
269 base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
270 this,
271 connection_id,
272 page_url));
273 return;
276 if (info.path == "" || info.path == "/") {
277 // Discovery page request.
278 BrowserThread::PostTask(
279 BrowserThread::UI,
280 FROM_HERE,
281 base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
282 this,
283 connection_id));
284 return;
287 if (info.path.find("/devtools/") != 0) {
288 server_->Send404(connection_id);
289 return;
292 std::string filename = PathWithoutParams(info.path.substr(10));
293 std::string mime_type = GetMimeType(filename);
295 base::FilePath frontend_dir = delegate_->GetDebugFrontendDir();
296 if (!frontend_dir.empty()) {
297 base::FilePath path = frontend_dir.AppendASCII(filename);
298 std::string data;
299 base::ReadFileToString(path, &data);
300 server_->Send200(connection_id, data, mime_type);
301 return;
303 if (delegate_->BundlesFrontendResources()) {
304 int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
305 if (resource_id != -1) {
306 base::StringPiece data = GetContentClient()->GetDataResource(
307 resource_id, ui::SCALE_FACTOR_NONE);
308 server_->Send200(connection_id, data.as_string(), mime_type);
309 return;
312 server_->Send404(connection_id);
315 void DevToolsHttpHandlerImpl::OnWebSocketRequest(
316 int connection_id,
317 const net::HttpServerRequestInfo& request) {
318 std::string browser_prefix = "/devtools/browser";
319 size_t browser_pos = request.path.find(browser_prefix);
320 if (browser_pos == 0) {
321 if (browser_target_) {
322 server_->Send500(connection_id, "Another client already attached");
323 return;
325 browser_target_ = new DevToolsBrowserTarget(
326 thread_->message_loop_proxy().get(), server_.get(), connection_id);
327 browser_target_->RegisterDomainHandler(
328 devtools::Tracing::kName,
329 new DevToolsTracingHandler(),
330 true /* handle on UI thread */);
331 browser_target_->RegisterDomainHandler(
332 TetheringHandler::kDomain,
333 new TetheringHandler(delegate_.get()),
334 false /* handle on this thread */);
335 browser_target_->RegisterDomainHandler(
336 devtools::SystemInfo::kName,
337 new DevToolsSystemInfoHandler(),
338 true /* handle on UI thread */);
340 server_->AcceptWebSocket(connection_id, request);
341 return;
344 BrowserThread::PostTask(
345 BrowserThread::UI,
346 FROM_HERE,
347 base::Bind(
348 &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
349 this,
350 connection_id,
351 request));
354 void DevToolsHttpHandlerImpl::OnWebSocketMessage(
355 int connection_id,
356 const std::string& data) {
357 if (browser_target_ && connection_id == browser_target_->connection_id()) {
358 browser_target_->HandleMessage(data);
359 return;
362 BrowserThread::PostTask(
363 BrowserThread::UI,
364 FROM_HERE,
365 base::Bind(
366 &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
367 this,
368 connection_id,
369 data));
372 void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
373 if (browser_target_ && browser_target_->connection_id() == connection_id) {
374 browser_target_->Detach();
375 browser_target_ = NULL;
376 return;
379 BrowserThread::PostTask(
380 BrowserThread::UI,
381 FROM_HERE,
382 base::Bind(
383 &DevToolsHttpHandlerImpl::OnCloseUI,
384 this,
385 connection_id));
388 std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
389 const std::string id,
390 const std::string& host) {
391 return base::StringPrintf(
392 "%s%sws=%s%s%s",
393 overridden_frontend_url_.c_str(),
394 overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&",
395 host.c_str(),
396 kPageUrlPrefix,
397 id.c_str());
400 static bool ParseJsonPath(
401 const std::string& path,
402 std::string* command,
403 std::string* target_id) {
405 // Fall back to list in case of empty query.
406 if (path.empty()) {
407 *command = "list";
408 return true;
411 if (path.find("/") != 0) {
412 // Malformed command.
413 return false;
415 *command = path.substr(1);
417 size_t separator_pos = command->find("/");
418 if (separator_pos != std::string::npos) {
419 *target_id = command->substr(separator_pos + 1);
420 *command = command->substr(0, separator_pos);
422 return true;
425 void DevToolsHttpHandlerImpl::OnJsonRequestUI(
426 int connection_id,
427 const net::HttpServerRequestInfo& info) {
428 // Trim /json
429 std::string path = info.path.substr(5);
431 // Trim fragment and query
432 std::string query;
433 size_t query_pos = path.find("?");
434 if (query_pos != std::string::npos) {
435 query = path.substr(query_pos + 1);
436 path = path.substr(0, query_pos);
439 size_t fragment_pos = path.find("#");
440 if (fragment_pos != std::string::npos)
441 path = path.substr(0, fragment_pos);
443 std::string command;
444 std::string target_id;
445 if (!ParseJsonPath(path, &command, &target_id)) {
446 SendJson(connection_id,
447 net::HTTP_NOT_FOUND,
448 NULL,
449 "Malformed query: " + info.path);
450 return;
453 if (command == "version") {
454 base::DictionaryValue version;
455 version.SetString("Protocol-Version", kProtocolVersion);
456 version.SetString("WebKit-Version", webkit_glue::GetWebKitVersion());
457 version.SetString("Browser", content::GetContentClient()->GetProduct());
458 version.SetString("User-Agent",
459 webkit_glue::GetUserAgent(GURL(kAboutBlankURL)));
460 #if defined(OS_ANDROID)
461 version.SetString("Android-Package",
462 base::android::BuildInfo::GetInstance()->package_name());
463 #endif
464 SendJson(connection_id, net::HTTP_OK, &version, std::string());
465 return;
468 if (command == "list") {
469 std::string host = info.headers["host"];
470 AddRef(); // Balanced in OnTargetListReceived.
471 delegate_->EnumerateTargets(
472 base::Bind(&DevToolsHttpHandlerImpl::OnTargetListReceived,
473 this, connection_id, host));
474 return;
477 if (command == "new") {
478 GURL url(net::UnescapeURLComponent(
479 query, net::UnescapeRule::URL_SPECIAL_CHARS));
480 if (!url.is_valid())
481 url = GURL(kAboutBlankURL);
482 scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget(url));
483 if (!target) {
484 SendJson(connection_id,
485 net::HTTP_INTERNAL_SERVER_ERROR,
486 NULL,
487 "Could not create new page");
488 return;
490 std::string host = info.headers["host"];
491 scoped_ptr<base::DictionaryValue> dictionary(
492 SerializeTarget(*target.get(), host));
493 SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
494 const std::string target_id = target->GetId();
495 target_map_[target_id] = target.release();
496 return;
499 if (command == "activate" || command == "close") {
500 DevToolsTarget* target = GetTarget(target_id);
501 if (!target) {
502 SendJson(connection_id,
503 net::HTTP_NOT_FOUND,
504 NULL,
505 "No such target id: " + target_id);
506 return;
509 if (command == "activate") {
510 if (target->Activate()) {
511 SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
512 } else {
513 SendJson(connection_id,
514 net::HTTP_INTERNAL_SERVER_ERROR,
515 NULL,
516 "Could not activate target id: " + target_id);
518 return;
521 if (command == "close") {
522 if (target->Close()) {
523 SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
524 } else {
525 SendJson(connection_id,
526 net::HTTP_INTERNAL_SERVER_ERROR,
527 NULL,
528 "Could not close target id: " + target_id);
530 return;
533 SendJson(connection_id,
534 net::HTTP_NOT_FOUND,
535 NULL,
536 "Unknown command: " + command);
537 return;
540 void DevToolsHttpHandlerImpl::OnTargetListReceived(
541 int connection_id,
542 const std::string& host,
543 const DevToolsHttpHandlerDelegate::TargetList& targets) {
544 DevToolsHttpHandlerDelegate::TargetList sorted_targets = targets;
545 std::sort(sorted_targets.begin(), sorted_targets.end(), TimeComparator);
547 STLDeleteValues(&target_map_);
548 base::ListValue list_value;
549 for (DevToolsHttpHandlerDelegate::TargetList::const_iterator it =
550 sorted_targets.begin(); it != sorted_targets.end(); ++it) {
551 DevToolsTarget* target = *it;
552 target_map_[target->GetId()] = target;
553 list_value.Append(SerializeTarget(*target, host));
555 SendJson(connection_id, net::HTTP_OK, &list_value, std::string());
556 Release(); // Balanced in OnJsonRequestUI.
559 DevToolsTarget* DevToolsHttpHandlerImpl::GetTarget(const std::string& id) {
560 TargetMap::const_iterator it = target_map_.find(id);
561 if (it == target_map_.end())
562 return NULL;
563 return it->second;
566 void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
567 int connection_id, const GURL& page_url) {
568 std::string data = delegate_->GetPageThumbnailData(page_url);
569 if (!data.empty())
570 Send200(connection_id, data, "image/png");
571 else
572 Send404(connection_id);
575 void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
576 std::string response = delegate_->GetDiscoveryPageHTML();
577 Send200(connection_id, response, "text/html; charset=UTF-8");
580 void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
581 int connection_id,
582 const net::HttpServerRequestInfo& request) {
583 if (!thread_)
584 return;
586 size_t pos = request.path.find(kPageUrlPrefix);
587 if (pos != 0) {
588 Send404(connection_id);
589 return;
592 std::string page_id = request.path.substr(strlen(kPageUrlPrefix));
593 DevToolsTarget* target = GetTarget(page_id);
594 scoped_refptr<DevToolsAgentHost> agent =
595 target ? target->GetAgentHost() : NULL;
596 if (!agent) {
597 Send500(connection_id, "No such target id: " + page_id);
598 return;
601 if (agent->IsAttached()) {
602 Send500(connection_id,
603 "Target with given id is being inspected: " + page_id);
604 return;
607 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(
608 thread_->message_loop(), server_.get(), connection_id);
609 connection_to_client_host_ui_[connection_id] = client_host;
611 DevToolsManager::GetInstance()->
612 RegisterDevToolsClientHostFor(agent, client_host);
614 AcceptWebSocket(connection_id, request);
617 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
618 int connection_id,
619 const std::string& data) {
620 ConnectionToClientHostMap::iterator it =
621 connection_to_client_host_ui_.find(connection_id);
622 if (it == connection_to_client_host_ui_.end())
623 return;
625 DevToolsManager* manager = DevToolsManager::GetInstance();
626 manager->DispatchOnInspectorBackend(it->second, data);
629 void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
630 ConnectionToClientHostMap::iterator it =
631 connection_to_client_host_ui_.find(connection_id);
632 if (it != connection_to_client_host_ui_.end()) {
633 DevToolsClientHostImpl* client_host =
634 static_cast<DevToolsClientHostImpl*>(it->second);
635 DevToolsManager::GetInstance()->ClientHostClosing(client_host);
636 delete client_host;
637 connection_to_client_host_ui_.erase(connection_id);
641 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
642 const net::StreamListenSocketFactory* socket_factory,
643 const std::string& frontend_url,
644 DevToolsHttpHandlerDelegate* delegate)
645 : overridden_frontend_url_(frontend_url),
646 socket_factory_(socket_factory),
647 delegate_(delegate) {
648 if (overridden_frontend_url_.empty())
649 overridden_frontend_url_ = "/devtools/devtools.html";
651 // Balanced in ResetHandlerThreadAndRelease().
652 AddRef();
655 // Runs on the handler thread
656 void DevToolsHttpHandlerImpl::Init() {
657 server_ = new net::HttpServer(*socket_factory_.get(), this);
660 // Runs on the handler thread
661 void DevToolsHttpHandlerImpl::Teardown() {
662 server_ = NULL;
665 // Runs on FILE thread to make sure that it is serialized against
666 // {Start|Stop}HandlerThread and to allow calling pthread_join.
667 void DevToolsHttpHandlerImpl::StopHandlerThread() {
668 if (!thread_->message_loop())
669 return;
670 thread_->message_loop()->PostTask(
671 FROM_HERE,
672 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
673 // Thread::Stop joins the thread.
674 thread_->Stop();
677 void DevToolsHttpHandlerImpl::SendJson(int connection_id,
678 net::HttpStatusCode status_code,
679 base::Value* value,
680 const std::string& message) {
681 if (!thread_)
682 return;
684 // Serialize value and message.
685 std::string json_value;
686 if (value) {
687 base::JSONWriter::WriteWithOptions(value,
688 base::JSONWriter::OPTIONS_PRETTY_PRINT,
689 &json_value);
691 std::string json_message;
692 scoped_ptr<base::Value> message_object(new base::StringValue(message));
693 base::JSONWriter::Write(message_object.get(), &json_message);
695 net::HttpServerResponseInfo response(status_code);
696 response.SetBody(json_value + message, "application/json; charset=UTF-8");
698 thread_->message_loop()->PostTask(
699 FROM_HERE,
700 base::Bind(&net::HttpServer::SendResponse,
701 server_.get(),
702 connection_id,
703 response));
706 void DevToolsHttpHandlerImpl::Send200(int connection_id,
707 const std::string& data,
708 const std::string& mime_type) {
709 if (!thread_)
710 return;
711 thread_->message_loop()->PostTask(
712 FROM_HERE,
713 base::Bind(&net::HttpServer::Send200,
714 server_.get(),
715 connection_id,
716 data,
717 mime_type));
720 void DevToolsHttpHandlerImpl::Send404(int connection_id) {
721 if (!thread_)
722 return;
723 thread_->message_loop()->PostTask(
724 FROM_HERE,
725 base::Bind(&net::HttpServer::Send404, server_.get(), connection_id));
728 void DevToolsHttpHandlerImpl::Send500(int connection_id,
729 const std::string& message) {
730 if (!thread_)
731 return;
732 thread_->message_loop()->PostTask(
733 FROM_HERE,
734 base::Bind(&net::HttpServer::Send500, server_.get(), connection_id,
735 message));
738 void DevToolsHttpHandlerImpl::AcceptWebSocket(
739 int connection_id,
740 const net::HttpServerRequestInfo& request) {
741 if (!thread_)
742 return;
743 thread_->message_loop()->PostTask(
744 FROM_HERE,
745 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(),
746 connection_id, request));
749 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget(
750 const DevToolsTarget& target,
751 const std::string& host) {
752 base::DictionaryValue* dictionary = new base::DictionaryValue;
754 std::string id = target.GetId();
755 dictionary->SetString(kTargetIdField, id);
756 dictionary->SetString(kTargetTypeField, target.GetType());
757 dictionary->SetString(kTargetTitleField,
758 net::EscapeForHTML(target.GetTitle()));
759 dictionary->SetString(kTargetDescriptionField, target.GetDescription());
761 GURL url = target.GetUrl();
762 dictionary->SetString(kTargetUrlField, url.spec());
764 GURL favicon_url = target.GetFaviconUrl();
765 if (favicon_url.is_valid())
766 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
768 if (!delegate_->GetPageThumbnailData(url).empty()) {
769 dictionary->SetString(kTargetThumbnailUrlField,
770 std::string(kThumbUrlPrefix) + id);
773 if (!target.IsAttached()) {
774 dictionary->SetString(kTargetWebSocketDebuggerUrlField,
775 base::StringPrintf("ws://%s%s%s",
776 host.c_str(),
777 kPageUrlPrefix,
778 id.c_str()));
779 std::string devtools_frontend_url = GetFrontendURLInternal(
780 id.c_str(),
781 host);
782 dictionary->SetString(
783 kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
786 return dictionary;
789 } // namespace content