Chromium Code Reviews| 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" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 #include "content/public/common/content_client.h" | 32 #include "content/public/common/content_client.h" |
| 33 #include "content/public/common/url_constants.h" | 33 #include "content/public/common/url_constants.h" |
| 34 #include "content/public/common/user_agent.h" | 34 #include "content/public/common/user_agent.h" |
| 35 #include "content/public/common/user_agent.h" | 35 #include "content/public/common/user_agent.h" |
| 36 #include "grit/devtools_resources_map.h" | 36 #include "grit/devtools_resources_map.h" |
| 37 #include "net/base/escape.h" | 37 #include "net/base/escape.h" |
| 38 #include "net/base/io_buffer.h" | 38 #include "net/base/io_buffer.h" |
| 39 #include "net/base/ip_endpoint.h" | 39 #include "net/base/ip_endpoint.h" |
| 40 #include "net/server/http_server_request_info.h" | 40 #include "net/server/http_server_request_info.h" |
| 41 #include "net/server/http_server_response_info.h" | 41 #include "net/server/http_server_response_info.h" |
| 42 #include "net/socket/server_socket.h" | |
| 42 | 43 |
| 43 #if defined(OS_ANDROID) | 44 #if defined(OS_ANDROID) |
| 44 #include "base/android/build_info.h" | 45 #include "base/android/build_info.h" |
| 45 #endif | 46 #endif |
| 46 | 47 |
| 47 namespace content { | 48 namespace content { |
| 48 | 49 |
| 49 namespace { | 50 namespace { |
| 50 | 51 |
| 51 const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread"; | 52 const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread"; |
| 52 | 53 |
| 53 const char kThumbUrlPrefix[] = "/thumb/"; | 54 const char kThumbUrlPrefix[] = "/thumb/"; |
| 54 const char kPageUrlPrefix[] = "/devtools/page/"; | 55 const char kPageUrlPrefix[] = "/devtools/page/"; |
| 55 | 56 |
| 56 const char kTargetIdField[] = "id"; | 57 const char kTargetIdField[] = "id"; |
| 57 const char kTargetTypeField[] = "type"; | 58 const char kTargetTypeField[] = "type"; |
| 58 const char kTargetTitleField[] = "title"; | 59 const char kTargetTitleField[] = "title"; |
| 59 const char kTargetDescriptionField[] = "description"; | 60 const char kTargetDescriptionField[] = "description"; |
| 60 const char kTargetUrlField[] = "url"; | 61 const char kTargetUrlField[] = "url"; |
| 61 const char kTargetThumbnailUrlField[] = "thumbnailUrl"; | 62 const char kTargetThumbnailUrlField[] = "thumbnailUrl"; |
| 62 const char kTargetFaviconUrlField[] = "faviconUrl"; | 63 const char kTargetFaviconUrlField[] = "faviconUrl"; |
| 63 const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl"; | 64 const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl"; |
| 64 const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl"; | 65 const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl"; |
| 65 | 66 |
| 66 // An internal implementation of DevToolsClientHost that delegates | 67 // An internal implementation of DevToolsClientHost that delegates |
| 67 // messages sent for DevToolsClient to a DebuggerShell instance. | 68 // messages sent for DevToolsClient to a DebuggerShell instance. |
| 68 class DevToolsClientHostImpl : public DevToolsClientHost { | 69 class DevToolsClientHostImpl : public DevToolsClientHost { |
| 69 public: | 70 public: |
| 70 DevToolsClientHostImpl(base::MessageLoop* message_loop, | 71 DevToolsClientHostImpl(base::MessageLoop* message_loop, |
| 71 net::HttpServer* server, | 72 base::WeakPtr<net::HttpServer> server, |
| 72 int connection_id) | 73 int connection_id) |
| 73 : message_loop_(message_loop), | 74 : message_loop_(message_loop), |
| 74 server_(server), | 75 server_(server), |
| 75 connection_id_(connection_id), | 76 connection_id_(connection_id), |
| 76 is_closed_(false), | 77 is_closed_(false), |
| 77 detach_reason_("target_closed") {} | 78 detach_reason_("target_closed") {} |
| 78 | 79 |
| 79 virtual ~DevToolsClientHostImpl() {} | 80 virtual ~DevToolsClientHostImpl() {} |
| 80 | 81 |
| 81 // DevToolsClientHost interface | 82 // DevToolsClientHost interface |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 110 connection_id_, | 111 connection_id_, |
| 111 data)); | 112 data)); |
| 112 } | 113 } |
| 113 | 114 |
| 114 virtual void ReplacedWithAnotherClient() OVERRIDE { | 115 virtual void ReplacedWithAnotherClient() OVERRIDE { |
| 115 detach_reason_ = "replaced_with_devtools"; | 116 detach_reason_ = "replaced_with_devtools"; |
| 116 } | 117 } |
| 117 | 118 |
| 118 private: | 119 private: |
| 119 base::MessageLoop* message_loop_; | 120 base::MessageLoop* message_loop_; |
| 120 net::HttpServer* server_; | 121 base::WeakPtr<net::HttpServer> server_; |
|
pfeldman
2014/05/22 06:01:05
It was not refcounting it, so you should be fine w
byungchul
2014/05/28 01:19:35
It is used in base::Bind() not to call when server
Ryan Sleevi
2014/05/28 01:36:26
Are you sure it's necessary? We may be able to get
byungchul
2014/05/30 00:19:02
It's challenging to make HttpServer callback-drive
| |
| 121 int connection_id_; | 122 int connection_id_; |
| 122 bool is_closed_; | 123 bool is_closed_; |
| 123 std::string detach_reason_; | 124 std::string detach_reason_; |
| 124 }; | 125 }; |
| 125 | 126 |
| 126 static bool TimeComparator(const DevToolsTarget* target1, | 127 static bool TimeComparator(const DevToolsTarget* target1, |
| 127 const DevToolsTarget* target2) { | 128 const DevToolsTarget* target2) { |
| 128 return target1->GetLastActivityTime() > target2->GetLastActivityTime(); | 129 return target1->GetLastActivityTime() > target2->GetLastActivityTime(); |
| 129 } | 130 } |
| 130 | 131 |
| 131 } // namespace | 132 } // namespace |
| 132 | 133 |
| 133 // static | 134 // static |
| 134 bool DevToolsHttpHandler::IsSupportedProtocolVersion( | 135 bool DevToolsHttpHandler::IsSupportedProtocolVersion( |
| 135 const std::string& version) { | 136 const std::string& version) { |
| 136 return devtools::IsSupportedProtocolVersion(version); | 137 return devtools::IsSupportedProtocolVersion(version); |
| 137 } | 138 } |
| 138 | 139 |
| 139 // static | 140 // static |
| 140 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { | 141 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { |
| 141 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) { | 142 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) { |
| 142 if (name == kDevtoolsResources[i].name) | 143 if (name == kDevtoolsResources[i].name) |
| 143 return kDevtoolsResources[i].value; | 144 return kDevtoolsResources[i].value; |
| 144 } | 145 } |
| 145 return -1; | 146 return -1; |
| 146 } | 147 } |
| 147 | 148 |
| 148 // static | 149 // static |
| 149 DevToolsHttpHandler* DevToolsHttpHandler::Start( | 150 DevToolsHttpHandler* DevToolsHttpHandler::Start( |
| 150 const net::StreamListenSocketFactory* socket_factory, | 151 scoped_ptr<net::ServerSocket> server_socket, |
| 151 const std::string& frontend_url, | 152 const std::string& frontend_url, |
| 152 DevToolsHttpHandlerDelegate* delegate) { | 153 DevToolsHttpHandlerDelegate* delegate) { |
| 153 DevToolsHttpHandlerImpl* http_handler = | 154 DevToolsHttpHandlerImpl* http_handler = |
| 154 new DevToolsHttpHandlerImpl(socket_factory, | 155 new DevToolsHttpHandlerImpl(server_socket.Pass(), |
| 155 frontend_url, | 156 frontend_url, |
| 156 delegate); | 157 delegate); |
| 157 http_handler->Start(); | 158 http_handler->Start(); |
| 158 return http_handler; | 159 return http_handler; |
| 159 } | 160 } |
| 160 | 161 |
| 161 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { | 162 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { |
| 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 163 // Stop() must be called prior to destruction. | 164 // Stop() must be called prior to destruction. |
| 164 DCHECK(server_.get() == NULL); | 165 DCHECK(server_.get() == NULL); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 void DevToolsHttpHandlerImpl::OnWebSocketRequest( | 318 void DevToolsHttpHandlerImpl::OnWebSocketRequest( |
| 318 int connection_id, | 319 int connection_id, |
| 319 const net::HttpServerRequestInfo& request) { | 320 const net::HttpServerRequestInfo& request) { |
| 320 std::string browser_prefix = "/devtools/browser"; | 321 std::string browser_prefix = "/devtools/browser"; |
| 321 size_t browser_pos = request.path.find(browser_prefix); | 322 size_t browser_pos = request.path.find(browser_prefix); |
| 322 if (browser_pos == 0) { | 323 if (browser_pos == 0) { |
| 323 if (browser_target_) { | 324 if (browser_target_) { |
| 324 server_->Send500(connection_id, "Another client already attached"); | 325 server_->Send500(connection_id, "Another client already attached"); |
| 325 return; | 326 return; |
| 326 } | 327 } |
| 327 browser_target_ = new DevToolsBrowserTarget(server_.get(), connection_id); | 328 browser_target_ = new DevToolsBrowserTarget(server_->AsWeakPtr(), |
| 329 connection_id); | |
| 328 browser_target_->RegisterDomainHandler( | 330 browser_target_->RegisterDomainHandler( |
| 329 devtools::Tracing::kName, | 331 devtools::Tracing::kName, |
| 330 new DevToolsTracingHandler(DevToolsTracingHandler::Browser), | 332 new DevToolsTracingHandler(DevToolsTracingHandler::Browser), |
| 331 true /* handle on UI thread */); | 333 true /* handle on UI thread */); |
| 332 browser_target_->RegisterDomainHandler( | 334 browser_target_->RegisterDomainHandler( |
| 333 TetheringHandler::kDomain, | 335 TetheringHandler::kDomain, |
| 334 new TetheringHandler(delegate_.get()), | 336 new TetheringHandler(delegate_.get()), |
| 335 false /* handle on this thread */); | 337 false /* handle on this thread */); |
| 336 browser_target_->RegisterDomainHandler( | 338 browser_target_->RegisterDomainHandler( |
| 337 devtools::SystemInfo::kName, | 339 devtools::SystemInfo::kName, |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 return; | 600 return; |
| 599 } | 601 } |
| 600 | 602 |
| 601 if (agent->IsAttached()) { | 603 if (agent->IsAttached()) { |
| 602 Send500(connection_id, | 604 Send500(connection_id, |
| 603 "Target with given id is being inspected: " + page_id); | 605 "Target with given id is being inspected: " + page_id); |
| 604 return; | 606 return; |
| 605 } | 607 } |
| 606 | 608 |
| 607 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl( | 609 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl( |
| 608 thread_->message_loop(), server_.get(), connection_id); | 610 thread_->message_loop(), server_->AsWeakPtr(), connection_id); |
| 609 connection_to_client_host_ui_[connection_id] = client_host; | 611 connection_to_client_host_ui_[connection_id] = client_host; |
| 610 | 612 |
| 611 DevToolsManager::GetInstance()-> | 613 DevToolsManager::GetInstance()-> |
| 612 RegisterDevToolsClientHostFor(agent, client_host); | 614 RegisterDevToolsClientHostFor(agent, client_host); |
| 613 | 615 |
| 614 AcceptWebSocket(connection_id, request); | 616 AcceptWebSocket(connection_id, request); |
| 615 } | 617 } |
| 616 | 618 |
| 617 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( | 619 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( |
| 618 int connection_id, | 620 int connection_id, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 632 if (it != connection_to_client_host_ui_.end()) { | 634 if (it != connection_to_client_host_ui_.end()) { |
| 633 DevToolsClientHostImpl* client_host = | 635 DevToolsClientHostImpl* client_host = |
| 634 static_cast<DevToolsClientHostImpl*>(it->second); | 636 static_cast<DevToolsClientHostImpl*>(it->second); |
| 635 DevToolsManager::GetInstance()->ClientHostClosing(client_host); | 637 DevToolsManager::GetInstance()->ClientHostClosing(client_host); |
| 636 delete client_host; | 638 delete client_host; |
| 637 connection_to_client_host_ui_.erase(connection_id); | 639 connection_to_client_host_ui_.erase(connection_id); |
| 638 } | 640 } |
| 639 } | 641 } |
| 640 | 642 |
| 641 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( | 643 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( |
| 642 const net::StreamListenSocketFactory* socket_factory, | 644 scoped_ptr<net::ServerSocket> server_socket, |
| 643 const std::string& frontend_url, | 645 const std::string& frontend_url, |
| 644 DevToolsHttpHandlerDelegate* delegate) | 646 DevToolsHttpHandlerDelegate* delegate) |
| 645 : frontend_url_(frontend_url), | 647 : frontend_url_(frontend_url), |
| 646 socket_factory_(socket_factory), | 648 server_socket_(server_socket.Pass()), |
| 647 delegate_(delegate) { | 649 delegate_(delegate) { |
| 648 if (frontend_url_.empty()) | 650 if (frontend_url_.empty()) |
| 649 frontend_url_ = "/devtools/devtools.html"; | 651 frontend_url_ = "/devtools/devtools.html"; |
| 650 | 652 |
| 651 // Balanced in ResetHandlerThreadAndRelease(). | 653 // Balanced in ResetHandlerThreadAndRelease(). |
| 652 AddRef(); | 654 AddRef(); |
| 653 } | 655 } |
| 654 | 656 |
| 655 // Runs on the handler thread | 657 // Runs on the handler thread |
| 656 void DevToolsHttpHandlerImpl::Init() { | 658 void DevToolsHttpHandlerImpl::Init() { |
| 657 server_ = new net::HttpServer(*socket_factory_.get(), this); | 659 server_.reset(new net::HttpServer(server_socket_.Pass(), this)); |
| 658 } | 660 } |
| 659 | 661 |
| 660 // Runs on the handler thread | 662 // Runs on the handler thread |
| 661 void DevToolsHttpHandlerImpl::Teardown() { | 663 void DevToolsHttpHandlerImpl::Teardown() { |
| 662 server_ = NULL; | 664 server_.reset(NULL); |
| 663 } | 665 } |
| 664 | 666 |
| 665 // Runs on FILE thread to make sure that it is serialized against | 667 // Runs on FILE thread to make sure that it is serialized against |
| 666 // {Start|Stop}HandlerThread and to allow calling pthread_join. | 668 // {Start|Stop}HandlerThread and to allow calling pthread_join. |
| 667 void DevToolsHttpHandlerImpl::StopHandlerThread() { | 669 void DevToolsHttpHandlerImpl::StopHandlerThread() { |
| 668 if (!thread_->message_loop()) | 670 if (!thread_->message_loop()) |
| 669 return; | 671 return; |
| 670 thread_->message_loop()->PostTask( | 672 thread_->message_loop()->PostTask( |
| 671 FROM_HERE, | 673 FROM_HERE, |
| 672 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this)); | 674 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this)); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 691 std::string json_message; | 693 std::string json_message; |
| 692 scoped_ptr<base::Value> message_object(new base::StringValue(message)); | 694 scoped_ptr<base::Value> message_object(new base::StringValue(message)); |
| 693 base::JSONWriter::Write(message_object.get(), &json_message); | 695 base::JSONWriter::Write(message_object.get(), &json_message); |
| 694 | 696 |
| 695 net::HttpServerResponseInfo response(status_code); | 697 net::HttpServerResponseInfo response(status_code); |
| 696 response.SetBody(json_value + message, "application/json; charset=UTF-8"); | 698 response.SetBody(json_value + message, "application/json; charset=UTF-8"); |
| 697 | 699 |
| 698 thread_->message_loop()->PostTask( | 700 thread_->message_loop()->PostTask( |
| 699 FROM_HERE, | 701 FROM_HERE, |
| 700 base::Bind(&net::HttpServer::SendResponse, | 702 base::Bind(&net::HttpServer::SendResponse, |
| 701 server_.get(), | 703 server_->AsWeakPtr(), |
| 702 connection_id, | 704 connection_id, |
| 703 response)); | 705 response)); |
| 704 } | 706 } |
| 705 | 707 |
| 706 void DevToolsHttpHandlerImpl::Send200(int connection_id, | 708 void DevToolsHttpHandlerImpl::Send200(int connection_id, |
| 707 const std::string& data, | 709 const std::string& data, |
| 708 const std::string& mime_type) { | 710 const std::string& mime_type) { |
| 709 if (!thread_) | 711 if (!thread_) |
| 710 return; | 712 return; |
| 711 thread_->message_loop()->PostTask( | 713 thread_->message_loop()->PostTask( |
| 712 FROM_HERE, | 714 FROM_HERE, |
| 713 base::Bind(&net::HttpServer::Send200, | 715 base::Bind(&net::HttpServer::Send200, |
| 714 server_.get(), | 716 server_->AsWeakPtr(), |
| 715 connection_id, | 717 connection_id, |
| 716 data, | 718 data, |
| 717 mime_type)); | 719 mime_type)); |
| 718 } | 720 } |
| 719 | 721 |
| 720 void DevToolsHttpHandlerImpl::Send404(int connection_id) { | 722 void DevToolsHttpHandlerImpl::Send404(int connection_id) { |
| 721 if (!thread_) | 723 if (!thread_) |
| 722 return; | 724 return; |
| 723 thread_->message_loop()->PostTask( | 725 thread_->message_loop()->PostTask( |
| 724 FROM_HERE, | 726 FROM_HERE, |
| 725 base::Bind(&net::HttpServer::Send404, server_.get(), connection_id)); | 727 base::Bind(&net::HttpServer::Send404, |
| 728 server_->AsWeakPtr(), | |
| 729 connection_id)); | |
| 726 } | 730 } |
| 727 | 731 |
| 728 void DevToolsHttpHandlerImpl::Send500(int connection_id, | 732 void DevToolsHttpHandlerImpl::Send500(int connection_id, |
| 729 const std::string& message) { | 733 const std::string& message) { |
| 730 if (!thread_) | 734 if (!thread_) |
| 731 return; | 735 return; |
| 732 thread_->message_loop()->PostTask( | 736 thread_->message_loop()->PostTask( |
| 733 FROM_HERE, | 737 FROM_HERE, |
| 734 base::Bind(&net::HttpServer::Send500, server_.get(), connection_id, | 738 base::Bind(&net::HttpServer::Send500, |
| 739 server_->AsWeakPtr(), | |
| 740 connection_id, | |
| 735 message)); | 741 message)); |
| 736 } | 742 } |
| 737 | 743 |
| 738 void DevToolsHttpHandlerImpl::AcceptWebSocket( | 744 void DevToolsHttpHandlerImpl::AcceptWebSocket( |
| 739 int connection_id, | 745 int connection_id, |
| 740 const net::HttpServerRequestInfo& request) { | 746 const net::HttpServerRequestInfo& request) { |
| 741 if (!thread_) | 747 if (!thread_) |
| 742 return; | 748 return; |
| 743 thread_->message_loop()->PostTask( | 749 thread_->message_loop()->PostTask( |
| 744 FROM_HERE, | 750 FROM_HERE, |
| 745 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(), | 751 base::Bind(&net::HttpServer::AcceptWebSocket, |
| 746 connection_id, request)); | 752 server_->AsWeakPtr(), |
| 753 connection_id, | |
| 754 request)); | |
| 747 } | 755 } |
| 748 | 756 |
| 749 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget( | 757 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget( |
| 750 const DevToolsTarget& target, | 758 const DevToolsTarget& target, |
| 751 const std::string& host) { | 759 const std::string& host) { |
| 752 base::DictionaryValue* dictionary = new base::DictionaryValue; | 760 base::DictionaryValue* dictionary = new base::DictionaryValue; |
| 753 | 761 |
| 754 std::string id = target.GetId(); | 762 std::string id = target.GetId(); |
| 755 dictionary->SetString(kTargetIdField, id); | 763 dictionary->SetString(kTargetIdField, id); |
| 756 dictionary->SetString(kTargetTypeField, target.GetType()); | 764 dictionary->SetString(kTargetTypeField, target.GetType()); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 780 id.c_str(), | 788 id.c_str(), |
| 781 host); | 789 host); |
| 782 dictionary->SetString( | 790 dictionary->SetString( |
| 783 kTargetDevtoolsFrontendUrlField, devtools_frontend_url); | 791 kTargetDevtoolsFrontendUrlField, devtools_frontend_url); |
| 784 } | 792 } |
| 785 | 793 |
| 786 return dictionary; | 794 return dictionary; |
| 787 } | 795 } |
| 788 | 796 |
| 789 } // namespace content | 797 } // namespace content |
| OLD | NEW |