Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: content/browser/debugger/devtools_http_handler_impl.cc

Issue 11630004: DevTools: rename debugger/ to devtools/, move DevTools files into content/renderer/devtools. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: For landing Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "content/browser/debugger/devtools_http_handler_impl.h"
6
7 #include <algorithm>
8 #include <utility>
9
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/lazy_instance.h"
15 #include "base/logging.h"
16 #include "base/message_loop_proxy.h"
17 #include "base/string_number_conversions.h"
18 #include "base/stringprintf.h"
19 #include "base/threading/thread.h"
20 #include "base/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "content/browser/debugger/devtools_browser_target.h"
23 #include "content/browser/debugger/devtools_tracing_handler.h"
24 #include "content/browser/web_contents/web_contents_impl.h"
25 #include "content/common/devtools_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/devtools_agent_host_registry.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/favicon_status.h"
32 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_types.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/render_view_host.h"
37 #include "content/public/browser/render_widget_host.h"
38 #include "content/public/common/content_client.h"
39 #include "content/public/common/url_constants.h"
40 #include "googleurl/src/gurl.h"
41 #include "grit/devtools_resources_map.h"
42 #include "net/base/escape.h"
43 #include "net/base/io_buffer.h"
44 #include "net/base/ip_endpoint.h"
45 #include "net/server/http_server_request_info.h"
46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h"
47 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
48 #include "ui/base/layout.h"
49 #include "webkit/user_agent/user_agent.h"
50 #include "webkit/user_agent/user_agent_util.h"
51
52 namespace content {
53
54 const int kBufferSize = 16 * 1024;
55
56 namespace {
57
58 static const char* kDevToolsHandlerThreadName = "Chrome_DevToolsHandlerThread";
59
60 class DevToolsDefaultBindingHandler
61 : public DevToolsHttpHandler::RenderViewHostBinding {
62 public:
63 DevToolsDefaultBindingHandler() {
64 }
65
66 virtual std::string GetIdentifier(RenderViewHost* rvh) OVERRIDE {
67 int process_id = rvh->GetProcess()->GetID();
68 int routing_id = rvh->GetRoutingID();
69 return base::StringPrintf("%d_%d", process_id, routing_id);
70 }
71
72 virtual RenderViewHost* ForIdentifier(
73 const std::string& identifier) OVERRIDE {
74 size_t pos = identifier.find("_");
75 if (pos == std::string::npos)
76 return NULL;
77
78 int process_id;
79 if (!base::StringToInt(identifier.substr(0, pos), &process_id))
80 return NULL;
81
82 int routing_id;
83 if (!base::StringToInt(identifier.substr(pos+1), &routing_id))
84 return NULL;
85
86 return RenderViewHost::FromID(process_id, routing_id);
87 }
88 };
89
90
91 // An internal implementation of DevToolsClientHost that delegates
92 // messages sent for DevToolsClient to a DebuggerShell instance.
93 class DevToolsClientHostImpl : public DevToolsClientHost {
94 public:
95 DevToolsClientHostImpl(
96 MessageLoop* message_loop,
97 net::HttpServer* server,
98 int connection_id)
99 : message_loop_(message_loop),
100 server_(server),
101 connection_id_(connection_id),
102 is_closed_(false),
103 detach_reason_("target_closed") {
104 }
105
106 ~DevToolsClientHostImpl() {}
107
108 // DevToolsClientHost interface
109 virtual void InspectedContentsClosing() {
110 if (is_closed_)
111 return;
112 is_closed_ = true;
113
114 std::string response =
115 WebKit::WebDevToolsAgent::inspectorDetachedEvent(
116 WebKit::WebString::fromUTF8(detach_reason_)).utf8();
117 message_loop_->PostTask(
118 FROM_HERE,
119 base::Bind(&net::HttpServer::SendOverWebSocket,
120 server_,
121 connection_id_,
122 response));
123
124 message_loop_->PostTask(
125 FROM_HERE,
126 base::Bind(&net::HttpServer::Close, server_, connection_id_));
127 }
128
129 virtual void DispatchOnInspectorFrontend(const std::string& data) {
130 message_loop_->PostTask(
131 FROM_HERE,
132 base::Bind(&net::HttpServer::SendOverWebSocket,
133 server_,
134 connection_id_,
135 data));
136 }
137
138 virtual void ContentsReplaced(WebContents* new_contents) {
139 }
140
141 virtual void ReplacedWithAnotherClient() {
142 detach_reason_ = "replaced_with_devtools";
143 }
144
145 private:
146 virtual void FrameNavigating(const std::string& url) {}
147 MessageLoop* message_loop_;
148 net::HttpServer* server_;
149 int connection_id_;
150 bool is_closed_;
151 std::string detach_reason_;
152 };
153
154 } // namespace
155
156 // static
157 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
158 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
159 if (name == kDevtoolsResources[i].name)
160 return kDevtoolsResources[i].value;
161 }
162 return -1;
163 }
164
165 // static
166 DevToolsHttpHandler* DevToolsHttpHandler::Start(
167 const net::StreamListenSocketFactory* socket_factory,
168 const std::string& frontend_url,
169 DevToolsHttpHandlerDelegate* delegate) {
170 DevToolsHttpHandlerImpl* http_handler =
171 new DevToolsHttpHandlerImpl(socket_factory,
172 frontend_url,
173 delegate);
174 http_handler->Start();
175 return http_handler;
176 }
177
178 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
180 // Stop() must be called prior to destruction.
181 DCHECK(server_.get() == NULL);
182 DCHECK(thread_.get() == NULL);
183 }
184
185 void DevToolsHttpHandlerImpl::Start() {
186 if (thread_.get())
187 return;
188 thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
189 BrowserThread::PostTask(
190 BrowserThread::FILE, FROM_HERE,
191 base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
192 }
193
194 // Runs on FILE thread.
195 void DevToolsHttpHandlerImpl::StartHandlerThread() {
196 base::Thread::Options options;
197 options.message_loop_type = MessageLoop::TYPE_IO;
198 if (!thread_->StartWithOptions(options)) {
199 BrowserThread::PostTask(
200 BrowserThread::UI, FROM_HERE,
201 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
202 return;
203 }
204
205 thread_->message_loop()->PostTask(
206 FROM_HERE,
207 base::Bind(&DevToolsHttpHandlerImpl::Init, this));
208 }
209
210 void DevToolsHttpHandlerImpl::ResetHandlerThread() {
211 thread_.reset();
212 }
213
214 void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
215 ResetHandlerThread();
216 Release();
217 }
218
219 void DevToolsHttpHandlerImpl::Stop() {
220 if (!thread_.get())
221 return;
222 BrowserThread::PostTaskAndReply(
223 BrowserThread::FILE, FROM_HERE,
224 base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
225 base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
226 }
227
228 void DevToolsHttpHandlerImpl::SetRenderViewHostBinding(
229 RenderViewHostBinding* binding) {
230 if (binding)
231 binding_ = binding;
232 else
233 binding_ = default_binding_.get();
234 }
235
236 GURL DevToolsHttpHandlerImpl::GetFrontendURL(RenderViewHost* render_view_host) {
237 net::IPEndPoint ip_address;
238 if (server_->GetLocalAddress(&ip_address))
239 return GURL();
240 std::string host = ip_address.ToString();
241 std::string id = binding_->GetIdentifier(render_view_host);
242 return GURL(std::string("http://") +
243 ip_address.ToString() +
244 GetFrontendURLInternal(id, host));
245 }
246
247 static std::string PathWithoutParams(const std::string& path) {
248 size_t query_position = path.find("?");
249 if (query_position != std::string::npos)
250 return path.substr(0, query_position);
251 return path;
252 }
253
254 static std::string GetMimeType(const std::string& filename) {
255 if (EndsWith(filename, ".html", false)) {
256 return "text/html";
257 } else if (EndsWith(filename, ".css", false)) {
258 return "text/css";
259 } else if (EndsWith(filename, ".js", false)) {
260 return "application/javascript";
261 } else if (EndsWith(filename, ".png", false)) {
262 return "image/png";
263 } else if (EndsWith(filename, ".gif", false)) {
264 return "image/gif";
265 }
266 NOTREACHED();
267 return "text/plain";
268 }
269
270 void DevToolsHttpHandlerImpl::Observe(int type,
271 const NotificationSource& source,
272 const NotificationDetails& details) {
273 RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
274 DevToolsManager* manager = DevToolsManager::GetInstance();
275 for (ConnectionToClientHostMap::iterator it =
276 connection_to_client_host_ui_.begin();
277 it != connection_to_client_host_ui_.end(); ++it) {
278 DevToolsAgentHost* agent = manager->GetDevToolsAgentHostFor(it->second);
279 if (!agent)
280 continue;
281 RenderViewHost* rvh = DevToolsAgentHostRegistry::GetRenderViewHost(agent);
282 if (rvh && rvh->GetProcess() == process)
283 it->second->InspectedContentsClosing();
284 }
285 }
286
287 void DevToolsHttpHandlerImpl::OnHttpRequest(
288 int connection_id,
289 const net::HttpServerRequestInfo& info) {
290 if (info.path.find("/json") == 0) {
291 BrowserThread::PostTask(
292 BrowserThread::UI,
293 FROM_HERE,
294 base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
295 this,
296 connection_id,
297 info));
298 return;
299 }
300
301 if (info.path.find("/thumb/") == 0) {
302 // Thumbnail request.
303 BrowserThread::PostTask(
304 BrowserThread::UI,
305 FROM_HERE,
306 base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
307 this,
308 connection_id,
309 info));
310 return;
311 }
312
313 if (info.path == "" || info.path == "/") {
314 // Discovery page request.
315 BrowserThread::PostTask(
316 BrowserThread::UI,
317 FROM_HERE,
318 base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
319 this,
320 connection_id));
321 return;
322 }
323
324 if (info.path.find("/devtools/") != 0) {
325 server_->Send404(connection_id);
326 return;
327 }
328
329 std::string filename = PathWithoutParams(info.path.substr(10));
330 std::string mime_type = GetMimeType(filename);
331
332 FilePath frontend_dir = delegate_->GetDebugFrontendDir();
333 if (!frontend_dir.empty()) {
334 FilePath path = frontend_dir.AppendASCII(filename);
335 std::string data;
336 file_util::ReadFileToString(path, &data);
337 server_->Send200(connection_id, data, mime_type);
338 return;
339 }
340 if (delegate_->BundlesFrontendResources()) {
341 int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
342 if (resource_id != -1) {
343 base::StringPiece data = GetContentClient()->GetDataResource(
344 resource_id, ui::SCALE_FACTOR_NONE);
345 server_->Send200(connection_id, data.as_string(), mime_type);
346 return;
347 }
348 }
349 server_->Send404(connection_id);
350 }
351
352 void DevToolsHttpHandlerImpl::OnWebSocketRequest(
353 int connection_id,
354 const net::HttpServerRequestInfo& request) {
355 BrowserThread::PostTask(
356 BrowserThread::UI,
357 FROM_HERE,
358 base::Bind(
359 &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
360 this,
361 connection_id,
362 request));
363 }
364
365 void DevToolsHttpHandlerImpl::OnWebSocketMessage(
366 int connection_id,
367 const std::string& data) {
368 BrowserThread::PostTask(
369 BrowserThread::UI,
370 FROM_HERE,
371 base::Bind(
372 &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
373 this,
374 connection_id,
375 data));
376 }
377
378 void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
379 BrowserThread::PostTask(
380 BrowserThread::UI,
381 FROM_HERE,
382 base::Bind(
383 &DevToolsHttpHandlerImpl::OnCloseUI,
384 this,
385 connection_id));
386 }
387
388 struct DevToolsHttpHandlerImpl::PageInfo {
389 PageInfo()
390 : attached(false) {
391 }
392
393 std::string id;
394 std::string url;
395 bool attached;
396 std::string title;
397 std::string thumbnail_url;
398 std::string favicon_url;
399 base::TimeTicks last_selected_time;
400 };
401
402 // static
403 bool DevToolsHttpHandlerImpl::SortPageListByTime(const PageInfo& info1,
404 const PageInfo& info2) {
405 return info1.last_selected_time > info2.last_selected_time;
406 }
407
408 DevToolsHttpHandlerImpl::PageList DevToolsHttpHandlerImpl::GeneratePageList() {
409 PageList page_list;
410 for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
411 !it.IsAtEnd(); it.Advance()) {
412 RenderProcessHost* render_process_host = it.GetCurrentValue();
413 DCHECK(render_process_host);
414
415 // Ignore processes that don't have a connection, such as crashed contents.
416 if (!render_process_host->HasConnection())
417 continue;
418
419 RenderProcessHost::RenderWidgetHostsIterator rwit(
420 render_process_host->GetRenderWidgetHostsIterator());
421 for (; !rwit.IsAtEnd(); rwit.Advance()) {
422 const RenderWidgetHost* widget = rwit.GetCurrentValue();
423 DCHECK(widget);
424 if (!widget || !widget->IsRenderView())
425 continue;
426
427 RenderViewHost* host =
428 RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
429 page_list.push_back(CreatePageInfo(host));
430 }
431 }
432 std::sort(page_list.begin(), page_list.end(), SortPageListByTime);
433 return page_list;
434 }
435
436 std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
437 const std::string rvh_id,
438 const std::string& host) {
439 return base::StringPrintf(
440 "%s%sws=%s/devtools/page/%s",
441 overridden_frontend_url_.c_str(),
442 overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&",
443 host.c_str(),
444 rvh_id.c_str());
445 }
446
447 static bool ParseJsonPath(
448 const std::string& path,
449 std::string* command,
450 std::string* target_id) {
451
452 // Fall back to list in case of empty query.
453 if (path.empty()) {
454 *command = "list";
455 return true;
456 }
457
458 if (path.find("/") != 0) {
459 // Malformed command.
460 return false;
461 }
462 *command = path.substr(1);
463
464 size_t separator_pos = command->find("/");
465 if (separator_pos != std::string::npos) {
466 *target_id = command->substr(separator_pos + 1);
467 *command = command->substr(0, separator_pos);
468 }
469 return true;
470 }
471
472 void DevToolsHttpHandlerImpl::OnJsonRequestUI(
473 int connection_id,
474 const net::HttpServerRequestInfo& info) {
475 // Trim /json and ?jsonp=...
476 std::string path = info.path.substr(5);
477 std::string jsonp;
478 size_t jsonp_pos = path.find("?jsonp=");
479 if (jsonp_pos != std::string::npos) {
480 jsonp = path.substr(jsonp_pos + 7);
481 path = path.substr(0, jsonp_pos);
482 }
483
484 // Trim fragment and query
485 size_t query_pos = path.find("?");
486 if (query_pos != std::string::npos)
487 path = path.substr(0, query_pos);
488
489 size_t fragment_pos = path.find("#");
490 if (fragment_pos != std::string::npos)
491 path = path.substr(0, fragment_pos);
492
493 std::string command;
494 std::string target_id;
495 if (!ParseJsonPath(path, &command, &target_id)) {
496 SendJson(connection_id,
497 net::HTTP_NOT_FOUND,
498 NULL,
499 "Malformed query: " + info.path,
500 jsonp);
501 return;
502 }
503
504 if (command == "version") {
505 DictionaryValue version;
506 version.SetString("Protocol-Version",
507 WebKit::WebDevToolsAgent::inspectorProtocolVersion());
508 version.SetString("WebKit-Version",
509 webkit_glue::GetWebKitVersion());
510 version.SetString("User-Agent",
511 webkit_glue::GetUserAgent(GURL(chrome::kAboutBlankURL)));
512 SendJson(connection_id, net::HTTP_OK, &version, "", jsonp);
513 return;
514 }
515
516 if (command == "list") {
517 PageList page_list = GeneratePageList();
518 ListValue json_pages_list;
519 std::string host = info.headers["Host"];
520 for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i)
521 json_pages_list.Append(SerializePageInfo(*i, host));
522 SendJson(connection_id, net::HTTP_OK, &json_pages_list, "", jsonp);
523 return;
524 }
525
526 if (command == "new") {
527 RenderViewHost* rvh = delegate_->CreateNewTarget();
528 if (!rvh) {
529 SendJson(connection_id,
530 net::HTTP_INTERNAL_SERVER_ERROR,
531 NULL,
532 "Could not create new page",
533 jsonp);
534 return;
535 }
536 PageInfo page_info = CreatePageInfo(rvh);
537 std::string host = info.headers["Host"];
538 scoped_ptr<DictionaryValue> dictionary(SerializePageInfo(page_info, host));
539 SendJson(connection_id, net::HTTP_OK, dictionary.get(), "", jsonp);
540 return;
541 }
542
543 if (command == "activate" || command == "close") {
544 RenderViewHost* rvh = binding_->ForIdentifier(target_id);
545 if (!rvh) {
546 SendJson(connection_id,
547 net::HTTP_NOT_FOUND,
548 NULL,
549 "No such target id: " + target_id,
550 jsonp);
551 return;
552 }
553
554 if (command == "activate") {
555 rvh->GetDelegate()->Activate();
556 SendJson(connection_id, net::HTTP_OK, NULL, "Target activated", jsonp);
557 return;
558 }
559
560 if (command == "close") {
561 rvh->ClosePage();
562 SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing", jsonp);
563 return;
564 }
565 }
566 SendJson(connection_id,
567 net::HTTP_NOT_FOUND,
568 NULL,
569 "Unknown command: " + command,
570 jsonp);
571 return;
572 }
573
574 void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
575 int connection_id,
576 const net::HttpServerRequestInfo& info) {
577 std::string prefix = "/thumb/";
578 size_t pos = info.path.find(prefix);
579 if (pos != 0) {
580 Send404(connection_id);
581 return;
582 }
583
584 std::string page_url = info.path.substr(prefix.length());
585 std::string data = delegate_->GetPageThumbnailData(GURL(page_url));
586 if (!data.empty())
587 Send200(connection_id, data, "image/png");
588 else
589 Send404(connection_id);
590 }
591
592 void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
593 std::string response = delegate_->GetDiscoveryPageHTML();
594 Send200(connection_id, response, "text/html; charset=UTF-8");
595 }
596
597 void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
598 int connection_id,
599 const net::HttpServerRequestInfo& request) {
600 if (!thread_.get())
601 return;
602 std::string browser_prefix = "/devtools/browser";
603 size_t browser_pos = request.path.find(browser_prefix);
604 if (browser_pos == 0) {
605 if (browser_target_) {
606 Send500(connection_id, "Another client already attached");
607 return;
608 }
609 browser_target_.reset(new DevToolsBrowserTarget(connection_id));
610 browser_target_->RegisterHandler(new DevToolsTracingHandler());
611 AcceptWebSocket(connection_id, request);
612 return;
613 }
614
615 std::string page_prefix = "/devtools/page/";
616 size_t pos = request.path.find(page_prefix);
617 if (pos != 0) {
618 Send404(connection_id);
619 return;
620 }
621
622 std::string page_id = request.path.substr(page_prefix.length());
623 RenderViewHost* rvh = binding_->ForIdentifier(page_id);
624 if (!rvh) {
625 Send500(connection_id, "No such target id: " + page_id);
626 return;
627 }
628
629 DevToolsManager* manager = DevToolsManager::GetInstance();
630 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
631 rvh);
632 if (manager->GetDevToolsClientHostFor(agent)) {
633 Send500(connection_id,
634 "Target with given id is being inspected: " + page_id);
635 return;
636 }
637
638 DevToolsClientHostImpl* client_host =
639 new DevToolsClientHostImpl(thread_->message_loop(),
640 server_,
641 connection_id);
642 connection_to_client_host_ui_[connection_id] = client_host;
643
644 manager->RegisterDevToolsClientHostFor(agent, client_host);
645
646 AcceptWebSocket(connection_id, request);
647 }
648
649 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
650 int connection_id,
651 const std::string& data) {
652 if (browser_target_ && connection_id == browser_target_->connection_id()) {
653 std::string json_response = browser_target_->HandleMessage(data);
654
655 thread_->message_loop()->PostTask(
656 FROM_HERE,
657 base::Bind(&net::HttpServer::SendOverWebSocket,
658 server_.get(),
659 connection_id,
660 json_response));
661 return;
662 }
663
664 ConnectionToClientHostMap::iterator it =
665 connection_to_client_host_ui_.find(connection_id);
666 if (it == connection_to_client_host_ui_.end())
667 return;
668
669 DevToolsManager* manager = DevToolsManager::GetInstance();
670 manager->DispatchOnInspectorBackend(it->second, data);
671 }
672
673 void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
674 ConnectionToClientHostMap::iterator it =
675 connection_to_client_host_ui_.find(connection_id);
676 if (it != connection_to_client_host_ui_.end()) {
677 DevToolsClientHostImpl* client_host =
678 static_cast<DevToolsClientHostImpl*>(it->second);
679 DevToolsManager::GetInstance()->ClientHostClosing(client_host);
680 delete client_host;
681 connection_to_client_host_ui_.erase(connection_id);
682 }
683 if (browser_target_ && browser_target_->connection_id() == connection_id) {
684 browser_target_.reset();
685 return;
686 }
687 }
688
689 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
690 const net::StreamListenSocketFactory* socket_factory,
691 const std::string& frontend_url,
692 DevToolsHttpHandlerDelegate* delegate)
693 : overridden_frontend_url_(frontend_url),
694 socket_factory_(socket_factory),
695 delegate_(delegate) {
696 if (overridden_frontend_url_.empty())
697 overridden_frontend_url_ = "/devtools/devtools.html";
698
699 default_binding_.reset(new DevToolsDefaultBindingHandler);
700 binding_ = default_binding_.get();
701
702 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
703 NotificationService::AllBrowserContextsAndSources());
704 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
705 NotificationService::AllBrowserContextsAndSources());
706
707 // Balanced in ResetHandlerThreadAndRelease().
708 AddRef();
709 }
710
711 // Runs on the handler thread
712 void DevToolsHttpHandlerImpl::Init() {
713 server_ = new net::HttpServer(*socket_factory_.get(), this);
714 }
715
716 // Runs on the handler thread
717 void DevToolsHttpHandlerImpl::Teardown() {
718 server_ = NULL;
719 }
720
721 // Runs on FILE thread to make sure that it is serialized against
722 // {Start|Stop}HandlerThread and to allow calling pthread_join.
723 void DevToolsHttpHandlerImpl::StopHandlerThread() {
724 if (!thread_->message_loop())
725 return;
726 thread_->message_loop()->PostTask(
727 FROM_HERE,
728 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
729 // Thread::Stop joins the thread.
730 thread_->Stop();
731 }
732
733 void DevToolsHttpHandlerImpl::SendJson(int connection_id,
734 net::HttpStatusCode status_code,
735 Value* value,
736 const std::string& message,
737 const std::string& jsonp) {
738 if (!thread_.get())
739 return;
740
741 // Serialize value and message.
742 std::string json_value;
743 if (value) {
744 base::JSONWriter::WriteWithOptions(value,
745 base::JSONWriter::OPTIONS_PRETTY_PRINT,
746 &json_value);
747 }
748 std::string json_message;
749 scoped_ptr<Value> message_object(Value::CreateStringValue(message));
750 base::JSONWriter::Write(message_object.get(), &json_message);
751
752 std::string response;
753 std::string mime_type = "application/json; charset=UTF-8";
754
755 // Wrap jsonp if necessary.
756 if (!jsonp.empty()) {
757 mime_type = "text/javascript; charset=UTF-8";
758 response = StringPrintf("%s(%s, %d, %s);",
759 jsonp.c_str(),
760 json_value.empty() ? "undefined"
761 : json_value.c_str(),
762 status_code,
763 json_message.c_str());
764 // JSONP always returns 200.
765 status_code = net::HTTP_OK;
766 } else {
767 response = StringPrintf("%s%s", json_value.c_str(), message.c_str());
768 }
769
770 thread_->message_loop()->PostTask(
771 FROM_HERE,
772 base::Bind(&net::HttpServer::Send,
773 server_.get(),
774 connection_id,
775 status_code,
776 response,
777 mime_type));
778 }
779
780 void DevToolsHttpHandlerImpl::Send200(int connection_id,
781 const std::string& data,
782 const std::string& mime_type) {
783 if (!thread_.get())
784 return;
785 thread_->message_loop()->PostTask(
786 FROM_HERE,
787 base::Bind(&net::HttpServer::Send200,
788 server_.get(),
789 connection_id,
790 data,
791 mime_type));
792 }
793
794 void DevToolsHttpHandlerImpl::Send404(int connection_id) {
795 if (!thread_.get())
796 return;
797 thread_->message_loop()->PostTask(
798 FROM_HERE,
799 base::Bind(&net::HttpServer::Send404, server_.get(), connection_id));
800 }
801
802 void DevToolsHttpHandlerImpl::Send500(int connection_id,
803 const std::string& message) {
804 if (!thread_.get())
805 return;
806 thread_->message_loop()->PostTask(
807 FROM_HERE,
808 base::Bind(&net::HttpServer::Send500, server_.get(), connection_id,
809 message));
810 }
811
812 void DevToolsHttpHandlerImpl::AcceptWebSocket(
813 int connection_id,
814 const net::HttpServerRequestInfo& request) {
815 if (!thread_.get())
816 return;
817 thread_->message_loop()->PostTask(
818 FROM_HERE,
819 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(),
820 connection_id, request));
821 }
822
823 DevToolsHttpHandlerImpl::PageInfo
824 DevToolsHttpHandlerImpl::CreatePageInfo(RenderViewHost* rvh)
825 {
826 RenderViewHostDelegate* host_delegate = rvh->GetDelegate();
827 DevToolsAgentHost* agent =
828 DevToolsAgentHostRegistry::GetDevToolsAgentHost(rvh);
829 DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
830 GetDevToolsClientHostFor(agent);
831 PageInfo page_info;
832 page_info.id = binding_->GetIdentifier(rvh);
833 page_info.attached = client_host != NULL;
834 page_info.url = host_delegate->GetURL().spec();
835
836 WebContents* web_contents = host_delegate->GetAsWebContents();
837 if (web_contents) {
838 page_info.title = UTF16ToUTF8(
839 net::EscapeForHTML(web_contents->GetTitle()));
840 page_info.last_selected_time = web_contents->GetLastSelectedTime();
841
842 NavigationController& controller = web_contents->GetController();
843 NavigationEntry* entry = controller.GetActiveEntry();
844 if (entry != NULL && entry->GetURL().is_valid()) {
845 page_info.thumbnail_url = "/thumb/" + entry->GetURL().spec();
846 page_info.favicon_url = entry->GetFavicon().url.spec();
847 }
848 }
849 return page_info;
850 }
851
852 DictionaryValue* DevToolsHttpHandlerImpl::SerializePageInfo(
853 const PageInfo& page_info,
854 const std::string& host) {
855 DictionaryValue* dictionary = new DictionaryValue;
856 dictionary->SetString("title", page_info.title);
857 dictionary->SetString("url", page_info.url);
858 dictionary->SetString("thumbnailUrl", page_info.thumbnail_url);
859 dictionary->SetString("faviconUrl", page_info.favicon_url);
860 if (!page_info.attached) {
861 dictionary->SetString("webSocketDebuggerUrl",
862 base::StringPrintf("ws://%s/devtools/page/%s",
863 host.c_str(),
864 page_info.id.c_str()));
865 std::string devtools_frontend_url = GetFrontendURLInternal(
866 page_info.id.c_str(),
867 host);
868 dictionary->SetString("devtoolsFrontendUrl", devtools_frontend_url);
869 }
870 return dictionary;
871 }
872
873 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/debugger/devtools_http_handler_impl.h ('k') | content/browser/debugger/devtools_http_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698