| 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 |
| 67 // Maximum write buffer size of devtools websocket. |
| 68 const int32 kSendBufferSizeForDevToolsWebSocket = 100 * 1024 * 1024; // 100Mb |
| 69 |
| 66 // An internal implementation of DevToolsClientHost that delegates | 70 // An internal implementation of DevToolsClientHost that delegates |
| 67 // messages sent for DevToolsClient to a DebuggerShell instance. | 71 // messages sent for DevToolsClient to a DebuggerShell instance. |
| 68 class DevToolsClientHostImpl : public DevToolsClientHost { | 72 class DevToolsClientHostImpl : public DevToolsClientHost { |
| 69 public: | 73 public: |
| 70 DevToolsClientHostImpl(base::MessageLoop* message_loop, | 74 DevToolsClientHostImpl(base::MessageLoop* message_loop, |
| 71 net::HttpServer* server, | 75 base::WeakPtr<net::HttpServer> server, |
| 72 int connection_id) | 76 int connection_id) |
| 73 : message_loop_(message_loop), | 77 : message_loop_(message_loop), |
| 74 server_(server), | 78 server_(server), |
| 75 connection_id_(connection_id), | 79 connection_id_(connection_id), |
| 76 is_closed_(false), | 80 is_closed_(false), |
| 77 detach_reason_("target_closed") {} | 81 detach_reason_("target_closed") {} |
| 78 | 82 |
| 79 virtual ~DevToolsClientHostImpl() {} | 83 virtual ~DevToolsClientHostImpl() {} |
| 80 | 84 |
| 81 // DevToolsClientHost interface | 85 // DevToolsClientHost interface |
| (...skipping 28 matching lines...) Expand all Loading... |
| 110 connection_id_, | 114 connection_id_, |
| 111 data)); | 115 data)); |
| 112 } | 116 } |
| 113 | 117 |
| 114 virtual void ReplacedWithAnotherClient() OVERRIDE { | 118 virtual void ReplacedWithAnotherClient() OVERRIDE { |
| 115 detach_reason_ = "replaced_with_devtools"; | 119 detach_reason_ = "replaced_with_devtools"; |
| 116 } | 120 } |
| 117 | 121 |
| 118 private: | 122 private: |
| 119 base::MessageLoop* message_loop_; | 123 base::MessageLoop* message_loop_; |
| 120 net::HttpServer* server_; | 124 base::WeakPtr<net::HttpServer> server_; |
| 121 int connection_id_; | 125 int connection_id_; |
| 122 bool is_closed_; | 126 bool is_closed_; |
| 123 std::string detach_reason_; | 127 std::string detach_reason_; |
| 124 }; | 128 }; |
| 125 | 129 |
| 126 static bool TimeComparator(const DevToolsTarget* target1, | 130 static bool TimeComparator(const DevToolsTarget* target1, |
| 127 const DevToolsTarget* target2) { | 131 const DevToolsTarget* target2) { |
| 128 return target1->GetLastActivityTime() > target2->GetLastActivityTime(); | 132 return target1->GetLastActivityTime() > target2->GetLastActivityTime(); |
| 129 } | 133 } |
| 130 | 134 |
| 131 } // namespace | 135 } // namespace |
| 132 | 136 |
| 133 // static | 137 // static |
| 134 bool DevToolsHttpHandler::IsSupportedProtocolVersion( | 138 bool DevToolsHttpHandler::IsSupportedProtocolVersion( |
| 135 const std::string& version) { | 139 const std::string& version) { |
| 136 return devtools::IsSupportedProtocolVersion(version); | 140 return devtools::IsSupportedProtocolVersion(version); |
| 137 } | 141 } |
| 138 | 142 |
| 139 // static | 143 // static |
| 140 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { | 144 int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { |
| 141 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) { | 145 for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) { |
| 142 if (name == kDevtoolsResources[i].name) | 146 if (name == kDevtoolsResources[i].name) |
| 143 return kDevtoolsResources[i].value; | 147 return kDevtoolsResources[i].value; |
| 144 } | 148 } |
| 145 return -1; | 149 return -1; |
| 146 } | 150 } |
| 147 | 151 |
| 148 // static | 152 // static |
| 149 DevToolsHttpHandler* DevToolsHttpHandler::Start( | 153 DevToolsHttpHandler* DevToolsHttpHandler::Start( |
| 150 const net::StreamListenSocketFactory* socket_factory, | 154 scoped_ptr<net::ServerSocketFactory> server_socket_factory, |
| 151 const std::string& frontend_url, | 155 const std::string& frontend_url, |
| 152 DevToolsHttpHandlerDelegate* delegate) { | 156 DevToolsHttpHandlerDelegate* delegate) { |
| 153 DevToolsHttpHandlerImpl* http_handler = | 157 DevToolsHttpHandlerImpl* http_handler = |
| 154 new DevToolsHttpHandlerImpl(socket_factory, | 158 new DevToolsHttpHandlerImpl(server_socket_factory.Pass(), |
| 155 frontend_url, | 159 frontend_url, |
| 156 delegate); | 160 delegate); |
| 157 http_handler->Start(); | 161 http_handler->Start(); |
| 158 return http_handler; | 162 return http_handler; |
| 159 } | 163 } |
| 160 | 164 |
| 161 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { | 165 DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { |
| 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 163 // Stop() must be called prior to destruction. | 167 // Stop() must be called prior to destruction. |
| 164 DCHECK(server_.get() == NULL); | 168 DCHECK(server_.get() == NULL); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 void DevToolsHttpHandlerImpl::OnWebSocketRequest( | 321 void DevToolsHttpHandlerImpl::OnWebSocketRequest( |
| 318 int connection_id, | 322 int connection_id, |
| 319 const net::HttpServerRequestInfo& request) { | 323 const net::HttpServerRequestInfo& request) { |
| 320 std::string browser_prefix = "/devtools/browser"; | 324 std::string browser_prefix = "/devtools/browser"; |
| 321 size_t browser_pos = request.path.find(browser_prefix); | 325 size_t browser_pos = request.path.find(browser_prefix); |
| 322 if (browser_pos == 0) { | 326 if (browser_pos == 0) { |
| 323 if (browser_target_) { | 327 if (browser_target_) { |
| 324 server_->Send500(connection_id, "Another client already attached"); | 328 server_->Send500(connection_id, "Another client already attached"); |
| 325 return; | 329 return; |
| 326 } | 330 } |
| 327 browser_target_ = new DevToolsBrowserTarget(server_.get(), connection_id); | 331 browser_target_ = new DevToolsBrowserTarget(server_->GetWeakPtr(), |
| 332 connection_id); |
| 328 browser_target_->RegisterDomainHandler( | 333 browser_target_->RegisterDomainHandler( |
| 329 devtools::Tracing::kName, | 334 devtools::Tracing::kName, |
| 330 new DevToolsTracingHandler(DevToolsTracingHandler::Browser), | 335 new DevToolsTracingHandler(DevToolsTracingHandler::Browser), |
| 331 true /* handle on UI thread */); | 336 true /* handle on UI thread */); |
| 332 browser_target_->RegisterDomainHandler( | 337 browser_target_->RegisterDomainHandler( |
| 333 TetheringHandler::kDomain, | 338 TetheringHandler::kDomain, |
| 334 new TetheringHandler(delegate_.get()), | 339 new TetheringHandler(delegate_.get()), |
| 335 false /* handle on this thread */); | 340 false /* handle on this thread */); |
| 336 browser_target_->RegisterDomainHandler( | 341 browser_target_->RegisterDomainHandler( |
| 337 devtools::SystemInfo::kName, | 342 devtools::SystemInfo::kName, |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 return; | 603 return; |
| 599 } | 604 } |
| 600 | 605 |
| 601 if (agent->IsAttached()) { | 606 if (agent->IsAttached()) { |
| 602 Send500(connection_id, | 607 Send500(connection_id, |
| 603 "Target with given id is being inspected: " + page_id); | 608 "Target with given id is being inspected: " + page_id); |
| 604 return; | 609 return; |
| 605 } | 610 } |
| 606 | 611 |
| 607 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl( | 612 DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl( |
| 608 thread_->message_loop(), server_.get(), connection_id); | 613 thread_->message_loop(), server_->GetWeakPtr(), connection_id); |
| 609 connection_to_client_host_ui_[connection_id] = client_host; | 614 connection_to_client_host_ui_[connection_id] = client_host; |
| 610 | 615 |
| 611 DevToolsManager::GetInstance()-> | 616 DevToolsManager::GetInstance()-> |
| 612 RegisterDevToolsClientHostFor(agent, client_host); | 617 RegisterDevToolsClientHostFor(agent, client_host); |
| 613 | 618 |
| 614 AcceptWebSocket(connection_id, request); | 619 AcceptWebSocket(connection_id, request); |
| 615 } | 620 } |
| 616 | 621 |
| 617 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( | 622 void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( |
| 618 int connection_id, | 623 int connection_id, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 632 if (it != connection_to_client_host_ui_.end()) { | 637 if (it != connection_to_client_host_ui_.end()) { |
| 633 DevToolsClientHostImpl* client_host = | 638 DevToolsClientHostImpl* client_host = |
| 634 static_cast<DevToolsClientHostImpl*>(it->second); | 639 static_cast<DevToolsClientHostImpl*>(it->second); |
| 635 DevToolsManager::GetInstance()->ClientHostClosing(client_host); | 640 DevToolsManager::GetInstance()->ClientHostClosing(client_host); |
| 636 delete client_host; | 641 delete client_host; |
| 637 connection_to_client_host_ui_.erase(connection_id); | 642 connection_to_client_host_ui_.erase(connection_id); |
| 638 } | 643 } |
| 639 } | 644 } |
| 640 | 645 |
| 641 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( | 646 DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( |
| 642 const net::StreamListenSocketFactory* socket_factory, | 647 scoped_ptr<net::ServerSocketFactory> server_socket_factory, |
| 643 const std::string& frontend_url, | 648 const std::string& frontend_url, |
| 644 DevToolsHttpHandlerDelegate* delegate) | 649 DevToolsHttpHandlerDelegate* delegate) |
| 645 : frontend_url_(frontend_url), | 650 : frontend_url_(frontend_url), |
| 646 socket_factory_(socket_factory), | 651 server_socket_factory_(server_socket_factory.Pass()), |
| 647 delegate_(delegate) { | 652 delegate_(delegate) { |
| 648 if (frontend_url_.empty()) | 653 if (frontend_url_.empty()) |
| 649 frontend_url_ = "/devtools/devtools.html"; | 654 frontend_url_ = "/devtools/devtools.html"; |
| 650 | 655 |
| 651 // Balanced in ResetHandlerThreadAndRelease(). | 656 // Balanced in ResetHandlerThreadAndRelease(). |
| 652 AddRef(); | 657 AddRef(); |
| 653 } | 658 } |
| 654 | 659 |
| 655 // Runs on the handler thread | 660 // Runs on the handler thread |
| 656 void DevToolsHttpHandlerImpl::Init() { | 661 void DevToolsHttpHandlerImpl::Init() { |
| 657 server_ = new net::HttpServer(*socket_factory_.get(), this); | 662 server_.reset(new net::HttpServer(server_socket_factory_->CreateAndListen(), |
| 663 this)); |
| 658 } | 664 } |
| 659 | 665 |
| 660 // Runs on the handler thread | 666 // Runs on the handler thread |
| 661 void DevToolsHttpHandlerImpl::Teardown() { | 667 void DevToolsHttpHandlerImpl::Teardown() { |
| 662 server_ = NULL; | 668 server_.reset(NULL); |
| 663 } | 669 } |
| 664 | 670 |
| 665 // Runs on FILE thread to make sure that it is serialized against | 671 // Runs on FILE thread to make sure that it is serialized against |
| 666 // {Start|Stop}HandlerThread and to allow calling pthread_join. | 672 // {Start|Stop}HandlerThread and to allow calling pthread_join. |
| 667 void DevToolsHttpHandlerImpl::StopHandlerThread() { | 673 void DevToolsHttpHandlerImpl::StopHandlerThread() { |
| 668 if (!thread_->message_loop()) | 674 if (!thread_->message_loop()) |
| 669 return; | 675 return; |
| 670 thread_->message_loop()->PostTask( | 676 thread_->message_loop()->PostTask( |
| 671 FROM_HERE, | 677 FROM_HERE, |
| 672 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this)); | 678 base::Bind(&DevToolsHttpHandlerImpl::Teardown, this)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 691 std::string json_message; | 697 std::string json_message; |
| 692 scoped_ptr<base::Value> message_object(new base::StringValue(message)); | 698 scoped_ptr<base::Value> message_object(new base::StringValue(message)); |
| 693 base::JSONWriter::Write(message_object.get(), &json_message); | 699 base::JSONWriter::Write(message_object.get(), &json_message); |
| 694 | 700 |
| 695 net::HttpServerResponseInfo response(status_code); | 701 net::HttpServerResponseInfo response(status_code); |
| 696 response.SetBody(json_value + message, "application/json; charset=UTF-8"); | 702 response.SetBody(json_value + message, "application/json; charset=UTF-8"); |
| 697 | 703 |
| 698 thread_->message_loop()->PostTask( | 704 thread_->message_loop()->PostTask( |
| 699 FROM_HERE, | 705 FROM_HERE, |
| 700 base::Bind(&net::HttpServer::SendResponse, | 706 base::Bind(&net::HttpServer::SendResponse, |
| 701 server_.get(), | 707 server_->GetWeakPtr(), |
| 702 connection_id, | 708 connection_id, |
| 703 response)); | 709 response)); |
| 704 } | 710 } |
| 705 | 711 |
| 706 void DevToolsHttpHandlerImpl::Send200(int connection_id, | 712 void DevToolsHttpHandlerImpl::Send200(int connection_id, |
| 707 const std::string& data, | 713 const std::string& data, |
| 708 const std::string& mime_type) { | 714 const std::string& mime_type) { |
| 709 if (!thread_) | 715 if (!thread_) |
| 710 return; | 716 return; |
| 711 thread_->message_loop()->PostTask( | 717 thread_->message_loop()->PostTask( |
| 712 FROM_HERE, | 718 FROM_HERE, |
| 713 base::Bind(&net::HttpServer::Send200, | 719 base::Bind(&net::HttpServer::Send200, |
| 714 server_.get(), | 720 server_->GetWeakPtr(), |
| 715 connection_id, | 721 connection_id, |
| 716 data, | 722 data, |
| 717 mime_type)); | 723 mime_type)); |
| 718 } | 724 } |
| 719 | 725 |
| 720 void DevToolsHttpHandlerImpl::Send404(int connection_id) { | 726 void DevToolsHttpHandlerImpl::Send404(int connection_id) { |
| 721 if (!thread_) | 727 if (!thread_) |
| 722 return; | 728 return; |
| 723 thread_->message_loop()->PostTask( | 729 thread_->message_loop()->PostTask( |
| 724 FROM_HERE, | 730 FROM_HERE, |
| 725 base::Bind(&net::HttpServer::Send404, server_.get(), connection_id)); | 731 base::Bind(&net::HttpServer::Send404, |
| 732 server_->GetWeakPtr(), |
| 733 connection_id)); |
| 726 } | 734 } |
| 727 | 735 |
| 728 void DevToolsHttpHandlerImpl::Send500(int connection_id, | 736 void DevToolsHttpHandlerImpl::Send500(int connection_id, |
| 729 const std::string& message) { | 737 const std::string& message) { |
| 730 if (!thread_) | 738 if (!thread_) |
| 731 return; | 739 return; |
| 732 thread_->message_loop()->PostTask( | 740 thread_->message_loop()->PostTask( |
| 733 FROM_HERE, | 741 FROM_HERE, |
| 734 base::Bind(&net::HttpServer::Send500, server_.get(), connection_id, | 742 base::Bind(&net::HttpServer::Send500, |
| 743 server_->GetWeakPtr(), |
| 744 connection_id, |
| 735 message)); | 745 message)); |
| 736 } | 746 } |
| 737 | 747 |
| 738 void DevToolsHttpHandlerImpl::AcceptWebSocket( | 748 void DevToolsHttpHandlerImpl::AcceptWebSocket( |
| 739 int connection_id, | 749 int connection_id, |
| 740 const net::HttpServerRequestInfo& request) { | 750 const net::HttpServerRequestInfo& request) { |
| 741 if (!thread_) | 751 if (!thread_) |
| 742 return; | 752 return; |
| 743 thread_->message_loop()->PostTask( | 753 thread_->message_loop()->PostTask( |
| 744 FROM_HERE, | 754 FROM_HERE, |
| 745 base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(), | 755 base::Bind(&net::HttpServer::SetSendBufferSize, |
| 746 connection_id, request)); | 756 server_->GetWeakPtr(), |
| 757 connection_id, |
| 758 kSendBufferSizeForDevToolsWebSocket)); |
| 759 thread_->message_loop()->PostTask( |
| 760 FROM_HERE, |
| 761 base::Bind(&net::HttpServer::AcceptWebSocket, |
| 762 server_->GetWeakPtr(), |
| 763 connection_id, |
| 764 request)); |
| 747 } | 765 } |
| 748 | 766 |
| 749 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget( | 767 base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget( |
| 750 const DevToolsTarget& target, | 768 const DevToolsTarget& target, |
| 751 const std::string& host) { | 769 const std::string& host) { |
| 752 base::DictionaryValue* dictionary = new base::DictionaryValue; | 770 base::DictionaryValue* dictionary = new base::DictionaryValue; |
| 753 | 771 |
| 754 std::string id = target.GetId(); | 772 std::string id = target.GetId(); |
| 755 dictionary->SetString(kTargetIdField, id); | 773 dictionary->SetString(kTargetIdField, id); |
| 756 dictionary->SetString(kTargetTypeField, target.GetType()); | 774 dictionary->SetString(kTargetTypeField, target.GetType()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 780 id.c_str(), | 798 id.c_str(), |
| 781 host); | 799 host); |
| 782 dictionary->SetString( | 800 dictionary->SetString( |
| 783 kTargetDevtoolsFrontendUrlField, devtools_frontend_url); | 801 kTargetDevtoolsFrontendUrlField, devtools_frontend_url); |
| 784 } | 802 } |
| 785 | 803 |
| 786 return dictionary; | 804 return dictionary; |
| 787 } | 805 } |
| 788 | 806 |
| 789 } // namespace content | 807 } // namespace content |
| OLD | NEW |