OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/devtools/devtools_http_handler_impl.h" | 5 #include "content/browser/devtools/devtools_http_handler_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
13 #include "base/json/json_writer.h" | 13 #include "base/json/json_writer.h" |
14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/message_loop_proxy.h" | 16 #include "base/message_loop_proxy.h" |
17 #include "base/string_number_conversions.h" | 17 #include "base/string_number_conversions.h" |
18 #include "base/stringprintf.h" | |
19 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
20 #include "base/utf_string_conversions.h" | |
21 #include "base/values.h" | |
22 #include "content/browser/devtools/devtools_agent_host_impl.h" | |
23 #include "content/browser/devtools/devtools_browser_target.h" | 19 #include "content/browser/devtools/devtools_browser_target.h" |
24 #include "content/browser/devtools/devtools_tracing_handler.h" | 20 #include "content/browser/devtools/devtools_tracing_handler.h" |
25 #include "content/browser/web_contents/web_contents_impl.h" | 21 #include "content/browser/web_contents/web_contents_impl.h" |
26 #include "content/common/devtools_messages.h" | 22 #include "content/common/devtools_messages.h" |
27 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
28 #include "content/public/browser/devtools_agent_host.h" | 24 #include "content/public/browser/devtools_agent_host.h" |
29 #include "content/public/browser/devtools_client_host.h" | 25 #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" | 26 #include "content/public/browser/devtools_manager.h" |
32 #include "content/public/browser/favicon_status.h" | 27 #include "content/public/browser/devtools_target_list.h" |
33 #include "content/public/browser/navigation_entry.h" | |
34 #include "content/public/browser/notification_service.h" | 28 #include "content/public/browser/notification_service.h" |
35 #include "content/public/browser/notification_types.h" | 29 #include "content/public/browser/notification_types.h" |
36 #include "content/public/browser/render_process_host.h" | |
37 #include "content/public/browser/render_view_host.h" | 30 #include "content/public/browser/render_view_host.h" |
38 #include "content/public/browser/render_widget_host.h" | |
39 #include "content/public/common/content_client.h" | 31 #include "content/public/common/content_client.h" |
40 #include "content/public/common/url_constants.h" | 32 #include "content/public/common/url_constants.h" |
41 #include "googleurl/src/gurl.h" | 33 #include "googleurl/src/gurl.h" |
42 #include "grit/devtools_resources_map.h" | 34 #include "grit/devtools_resources_map.h" |
43 #include "net/base/escape.h" | |
44 #include "net/base/io_buffer.h" | 35 #include "net/base/io_buffer.h" |
45 #include "net/base/ip_endpoint.h" | 36 #include "net/base/ip_endpoint.h" |
46 #include "net/server/http_server_request_info.h" | 37 #include "net/server/http_server_request_info.h" |
47 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" | 38 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" |
48 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h" | 39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h" |
49 #include "ui/base/layout.h" | 40 #include "ui/base/layout.h" |
50 #include "webkit/user_agent/user_agent.h" | 41 #include "webkit/user_agent/user_agent.h" |
51 #include "webkit/user_agent/user_agent_util.h" | 42 #include "webkit/user_agent/user_agent_util.h" |
52 | 43 |
53 namespace content { | 44 namespace content { |
54 | 45 |
55 const int kBufferSize = 16 * 1024; | 46 const int kBufferSize = 16 * 1024; |
56 | 47 |
57 namespace { | 48 namespace { |
58 | 49 |
59 static const char* kDevToolsHandlerThreadName = "Chrome_DevToolsHandlerThread"; | 50 static const char* kDevToolsHandlerThreadName = "Chrome_DevToolsHandlerThread"; |
60 | 51 |
61 class DevToolsDefaultBindingHandler | 52 class DevToolsDefaultBindingHandler |
62 : public DevToolsHttpHandler::DevToolsAgentHostBinding { | 53 : public DevToolsHttpHandler::DevToolsAgentHostBinding { |
63 public: | 54 public: |
64 DevToolsDefaultBindingHandler() { | 55 DevToolsDefaultBindingHandler() { |
65 } | 56 } |
66 | 57 |
67 void GarbageCollect() { | |
68 AgentsMap::iterator it = agents_map_.begin(); | |
69 while (it != agents_map_.end()) { | |
70 if (!it->second->GetRenderViewHost()) | |
71 agents_map_.erase(it++); | |
72 else | |
73 ++it; | |
74 } | |
75 } | |
76 | |
77 virtual std::string GetIdentifier(DevToolsAgentHost* agent_host) OVERRIDE { | 58 virtual std::string GetIdentifier(DevToolsAgentHost* agent_host) OVERRIDE { |
78 GarbageCollect(); | 59 return DevToolsTargetList::GetInstance()->GetIdentifier(agent_host); |
79 DevToolsAgentHostImpl* agent_host_impl = | |
80 static_cast<DevToolsAgentHostImpl*>(agent_host); | |
81 std::string id = base::StringPrintf("%d", agent_host_impl->id()); | |
82 agents_map_[id] = agent_host; | |
83 return id; | |
84 } | 60 } |
85 | 61 |
86 virtual DevToolsAgentHost* ForIdentifier( | 62 virtual DevToolsAgentHost* ForIdentifier( |
87 const std::string& identifier) OVERRIDE { | 63 const std::string& identifier) OVERRIDE { |
88 GarbageCollect(); | 64 return DevToolsTargetList::GetInstance()->ForIdentifier(identifier); |
89 AgentsMap::iterator it = agents_map_.find(identifier); | |
90 if (it != agents_map_.end()) | |
91 return it->second; | |
92 return NULL; | |
93 } | 65 } |
94 | |
95 private: | |
96 typedef std::map<std::string, scoped_refptr<DevToolsAgentHost> > AgentsMap; | |
97 AgentsMap agents_map_; | |
98 }; | 66 }; |
99 | 67 |
100 // An internal implementation of DevToolsClientHost that delegates | 68 // An internal implementation of DevToolsClientHost that delegates |
101 // messages sent for DevToolsClient to a DebuggerShell instance. | 69 // messages sent for DevToolsClient to a DebuggerShell instance. |
102 class DevToolsClientHostImpl : public DevToolsClientHost { | 70 class DevToolsClientHostImpl : public DevToolsClientHost { |
103 public: | 71 public: |
104 DevToolsClientHostImpl( | 72 DevToolsClientHostImpl( |
105 MessageLoop* message_loop, | 73 MessageLoop* message_loop, |
106 net::HttpServer* server, | 74 net::HttpServer* server, |
107 int connection_id) | 75 int connection_id) |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 void DevToolsHttpHandlerImpl::OnClose(int connection_id) { | 355 void DevToolsHttpHandlerImpl::OnClose(int connection_id) { |
388 BrowserThread::PostTask( | 356 BrowserThread::PostTask( |
389 BrowserThread::UI, | 357 BrowserThread::UI, |
390 FROM_HERE, | 358 FROM_HERE, |
391 base::Bind( | 359 base::Bind( |
392 &DevToolsHttpHandlerImpl::OnCloseUI, | 360 &DevToolsHttpHandlerImpl::OnCloseUI, |
393 this, | 361 this, |
394 connection_id)); | 362 connection_id)); |
395 } | 363 } |
396 | 364 |
397 struct DevToolsHttpHandlerImpl::PageInfo { | 365 static base::TimeTicks GetLastSelectedTime(DevToolsAgentHost* agent) { |
398 PageInfo() | 366 WebContents* web_contents = |
399 : attached(false) { | 367 agent->GetRenderViewHost()->GetDelegate()->GetAsWebContents(); |
pfeldman
2013/03/01 14:28:17
You did not address this one: Boom! GetRenderViewH
Vladislav Kaznacheev
2013/03/01 16:16:38
Done.
| |
400 } | 368 return web_contents ? web_contents->GetLastSelectedTime() : base::TimeTicks(); |
401 | 369 } |
402 std::string id; | |
403 std::string url; | |
404 std::string type; | |
405 bool attached; | |
406 std::string title; | |
407 std::string thumbnail_url; | |
408 std::string favicon_url; | |
409 base::TimeTicks last_selected_time; | |
410 }; | |
411 | 370 |
412 // static | 371 // static |
413 bool DevToolsHttpHandlerImpl::SortPageListByTime(const PageInfo& info1, | 372 bool DevToolsHttpHandlerImpl::TimeComparator(DevToolsAgentHost* agent1, |
414 const PageInfo& info2) { | 373 DevToolsAgentHost* agent2) { |
415 return info1.last_selected_time > info2.last_selected_time; | 374 return GetLastSelectedTime(agent1) > GetLastSelectedTime(agent2); |
pfeldman
2013/03/01 14:28:17
Also did not address this one - you can't compare
Vladislav Kaznacheev
2013/03/01 16:16:38
Done.
| |
416 } | |
417 | |
418 DevToolsHttpHandlerImpl::PageList DevToolsHttpHandlerImpl::GeneratePageList() { | |
419 PageList page_list; | |
420 for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); | |
421 !it.IsAtEnd(); it.Advance()) { | |
422 RenderProcessHost* render_process_host = it.GetCurrentValue(); | |
423 DCHECK(render_process_host); | |
424 | |
425 // Ignore processes that don't have a connection, such as crashed contents. | |
426 if (!render_process_host->HasConnection()) | |
427 continue; | |
428 | |
429 RenderProcessHost::RenderWidgetHostsIterator rwit( | |
430 render_process_host->GetRenderWidgetHostsIterator()); | |
431 for (; !rwit.IsAtEnd(); rwit.Advance()) { | |
432 const RenderWidgetHost* widget = rwit.GetCurrentValue(); | |
433 DCHECK(widget); | |
434 if (!widget || !widget->IsRenderView()) | |
435 continue; | |
436 | |
437 RenderViewHost* host = | |
438 RenderViewHost::From(const_cast<RenderWidgetHost*>(widget)); | |
439 page_list.push_back(CreatePageInfo(host, delegate_->GetTargetType(host))); | |
440 } | |
441 } | |
442 std::sort(page_list.begin(), page_list.end(), SortPageListByTime); | |
443 return page_list; | |
444 } | 375 } |
445 | 376 |
446 std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal( | 377 std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal( |
447 const std::string rvh_id, | 378 const std::string rvh_id, |
448 const std::string& host) { | 379 const std::string& host) { |
449 return base::StringPrintf( | 380 return base::StringPrintf( |
450 "%s%sws=%s/devtools/page/%s", | 381 "%s%sws=%s/devtools/page/%s", |
451 overridden_frontend_url_.c_str(), | 382 overridden_frontend_url_.c_str(), |
452 overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&", | 383 overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&", |
453 host.c_str(), | 384 host.c_str(), |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 webkit_glue::GetWebKitVersion()); | 450 webkit_glue::GetWebKitVersion()); |
520 version.SetString("Browser", | 451 version.SetString("Browser", |
521 content::GetContentClient()->GetProduct()); | 452 content::GetContentClient()->GetProduct()); |
522 version.SetString("User-Agent", | 453 version.SetString("User-Agent", |
523 webkit_glue::GetUserAgent(GURL(chrome::kAboutBlankURL))); | 454 webkit_glue::GetUserAgent(GURL(chrome::kAboutBlankURL))); |
524 SendJson(connection_id, net::HTTP_OK, &version, "", jsonp); | 455 SendJson(connection_id, net::HTTP_OK, &version, "", jsonp); |
525 return; | 456 return; |
526 } | 457 } |
527 | 458 |
528 if (command == "list") { | 459 if (command == "list") { |
529 PageList page_list = GeneratePageList(); | 460 typedef std::vector<DevToolsAgentHost*> PageList; |
461 PageList page_list; | |
462 DevToolsTargetList::AgentsMap& agents_map = | |
463 DevToolsTargetList::GetInstance()->GetAgentsMap(); | |
464 for (DevToolsTargetList::iterator i = agents_map.begin(); | |
465 i != agents_map.end(); ++i) | |
pfeldman
2013/03/01 14:28:17
one extra space before i and { }
Vladislav Kaznacheev
2013/03/01 16:16:38
By { } you mean the loop body, right? If so done a
| |
466 page_list.push_back(i->second); | |
467 std::sort(page_list.begin(), page_list.end(), TimeComparator); | |
530 base::ListValue json_pages_list; | 468 base::ListValue json_pages_list; |
531 std::string host = info.headers["Host"]; | 469 std::string host = info.headers["Host"]; |
532 for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i) | 470 for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i) |
533 json_pages_list.Append(SerializePageInfo(*i, host)); | 471 json_pages_list.Append(SerializePageInfo(*i, host)); |
534 SendJson(connection_id, net::HTTP_OK, &json_pages_list, "", jsonp); | 472 SendJson(connection_id, net::HTTP_OK, &json_pages_list, "", jsonp); |
535 return; | 473 return; |
536 } | 474 } |
537 | 475 |
538 if (command == "new") { | 476 if (command == "new") { |
539 RenderViewHost* rvh = delegate_->CreateNewTarget(); | 477 RenderViewHost* rvh = delegate_->CreateNewTarget(); |
540 if (!rvh) { | 478 if (!rvh) { |
541 SendJson(connection_id, | 479 SendJson(connection_id, |
542 net::HTTP_INTERNAL_SERVER_ERROR, | 480 net::HTTP_INTERNAL_SERVER_ERROR, |
543 NULL, | 481 NULL, |
544 "Could not create new page", | 482 "Could not create new page", |
545 jsonp); | 483 jsonp); |
546 return; | 484 return; |
547 } | 485 } |
548 PageInfo page_info = | |
549 CreatePageInfo(rvh, DevToolsHttpHandlerDelegate::kTargetTypeTab); | |
550 std::string host = info.headers["Host"]; | 486 std::string host = info.headers["Host"]; |
551 scoped_ptr<base::DictionaryValue> dictionary( | 487 scoped_ptr<base::DictionaryValue> dictionary( |
552 SerializePageInfo(page_info, host)); | 488 SerializePageInfo(DevToolsAgentHost::GetFor(rvh), host)); |
553 SendJson(connection_id, net::HTTP_OK, dictionary.get(), "", jsonp); | 489 SendJson(connection_id, net::HTTP_OK, dictionary.get(), "", jsonp); |
554 return; | 490 return; |
555 } | 491 } |
556 | 492 |
557 if (command == "activate" || command == "close") { | 493 if (command == "activate" || command == "close") { |
558 DevToolsAgentHost* agent_host = binding_->ForIdentifier(target_id); | 494 DevToolsAgentHost* agent_host = binding_->ForIdentifier(target_id); |
559 RenderViewHost* rvh = agent_host ? agent_host->GetRenderViewHost() : NULL; | 495 RenderViewHost* rvh = agent_host ? agent_host->GetRenderViewHost() : NULL; |
560 if (!rvh) { | 496 if (!rvh) { |
561 SendJson(connection_id, | 497 SendJson(connection_id, |
562 net::HTTP_NOT_FOUND, | 498 net::HTTP_NOT_FOUND, |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
830 int connection_id, | 766 int connection_id, |
831 const net::HttpServerRequestInfo& request) { | 767 const net::HttpServerRequestInfo& request) { |
832 if (!thread_.get()) | 768 if (!thread_.get()) |
833 return; | 769 return; |
834 thread_->message_loop()->PostTask( | 770 thread_->message_loop()->PostTask( |
835 FROM_HERE, | 771 FROM_HERE, |
836 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(), | 772 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(), |
837 connection_id, request)); | 773 connection_id, request)); |
838 } | 774 } |
839 | 775 |
840 DevToolsHttpHandlerImpl::PageInfo | 776 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializePageInfo( |
841 DevToolsHttpHandlerImpl::CreatePageInfo(RenderViewHost* rvh, | 777 DevToolsAgentHost* agent_host, |
842 DevToolsHttpHandlerDelegate::TargetType type) { | 778 const std::string& host) { |
843 RenderViewHostDelegate* host_delegate = rvh->GetDelegate(); | 779 base::DictionaryValue* dictionary = new base::DictionaryValue; |
844 scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetFor(rvh)); | 780 dictionary->SetString("title", agent_host->title()); |
845 DevToolsClientHost* client_host = DevToolsManager::GetInstance()-> | 781 dictionary->SetString("url", agent_host->url().spec()); |
846 GetDevToolsClientHostFor(agent); | 782 switch (delegate_->GetTargetType(agent_host->GetRenderViewHost())) { |
847 PageInfo page_info; | |
848 page_info.id = binding_->GetIdentifier(agent); | |
849 page_info.attached = client_host != NULL; | |
850 page_info.url = host_delegate->GetURL().spec(); | |
851 | |
852 switch (type) { | |
853 case DevToolsHttpHandlerDelegate::kTargetTypeTab: | 783 case DevToolsHttpHandlerDelegate::kTargetTypeTab: |
854 page_info.type = "page"; | 784 dictionary->SetString("type", "page"); |
855 break; | 785 break; |
856 default: | 786 default: |
857 page_info.type = "other"; | 787 dictionary->SetString("type", "other"); |
858 } | 788 } |
859 | 789 std::string id = binding_->GetIdentifier(agent_host); |
860 WebContents* web_contents = host_delegate->GetAsWebContents(); | 790 dictionary->SetString("id", id); |
861 if (web_contents) { | 791 dictionary->SetString("thumbnailUrl", agent_host->thumbnail_url().spec()); |
862 page_info.title = UTF16ToUTF8( | 792 dictionary->SetString("faviconUrl", agent_host->favicon_url().spec()); |
863 net::EscapeForHTML(web_contents->GetTitle())); | 793 if (!agent_host->attached()) { |
864 page_info.last_selected_time = web_contents->GetLastSelectedTime(); | |
865 | |
866 NavigationController& controller = web_contents->GetController(); | |
867 NavigationEntry* entry = controller.GetActiveEntry(); | |
868 if (entry != NULL && entry->GetURL().is_valid()) { | |
869 page_info.thumbnail_url = "/thumb/" + entry->GetURL().spec(); | |
870 page_info.favicon_url = entry->GetFavicon().url.spec(); | |
871 } | |
872 } | |
873 return page_info; | |
874 } | |
875 | |
876 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializePageInfo( | |
877 const PageInfo& page_info, | |
878 const std::string& host) { | |
879 base::DictionaryValue* dictionary = new base::DictionaryValue; | |
880 dictionary->SetString("title", page_info.title); | |
881 dictionary->SetString("url", page_info.url); | |
882 dictionary->SetString("type", page_info.type); | |
883 dictionary->SetString("id", page_info.id); | |
884 dictionary->SetString("thumbnailUrl", page_info.thumbnail_url); | |
885 dictionary->SetString("faviconUrl", page_info.favicon_url); | |
886 if (!page_info.attached) { | |
887 dictionary->SetString("webSocketDebuggerUrl", | 794 dictionary->SetString("webSocketDebuggerUrl", |
888 base::StringPrintf("ws://%s/devtools/page/%s", | 795 base::StringPrintf("ws://%s/devtools/page/%s", |
889 host.c_str(), | 796 host.c_str(), |
890 page_info.id.c_str())); | 797 id.c_str())); |
891 std::string devtools_frontend_url = GetFrontendURLInternal( | 798 std::string devtools_frontend_url = GetFrontendURLInternal( |
892 page_info.id.c_str(), | 799 id.c_str(), |
893 host); | 800 host); |
894 dictionary->SetString("devtoolsFrontendUrl", devtools_frontend_url); | 801 dictionary->SetString("devtoolsFrontendUrl", devtools_frontend_url); |
895 } | 802 } |
896 return dictionary; | 803 return dictionary; |
897 } | 804 } |
898 | 805 |
899 } // namespace content | 806 } // namespace content |
OLD | NEW |