1 // Copyright 2014 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 "mojo/spy/websocket_server.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/strings/stringprintf.h" 12 #include "mojo/public/cpp/bindings/message.h" 13 #include "net/base/ip_endpoint.h" 14 #include "net/base/net_errors.h" 15 #include "net/server/http_server_request_info.h" 16 #include "net/server/http_server_response_info.h" 17 #include "net/socket/tcp_server_socket.h" 18 #include "url/gurl.h" 19 20 namespace mojo { 21 22 const int kNotConnected = -1; 23 24 #define MOJO_DEBUGGER_MESSAGE_FORMAT "\"url: %s\n," \ 25 "time: %02d:%02d:%02d\n,"\ 26 "bytes: %u\n,"\ 27 "fields: %u\n,"\ 28 "name: %u\n,"\ 29 "requestId: %llu\n,"\ 30 "type: %s\n,"\ 31 "end:\n\"" 32 33 WebSocketServer::WebSocketServer(int port, 34 mojo::ScopedMessagePipeHandle server_pipe) 35 : port_(port), 36 connection_id_(kNotConnected), 37 spy_server_(MakeProxy<spy_api::SpyServer>(server_pipe.Pass())) { 38 spy_server_.set_client(this); 39 } 40 41 WebSocketServer::~WebSocketServer() { 42 } 43 44 bool WebSocketServer::Start() { 45 scoped_ptr<net::ServerSocket> server_socket( 46 new net::TCPServerSocket(NULL, net::NetLog::Source())); 47 server_socket->ListenWithAddressAndPort("0.0.0.0", port_, 1); 48 web_server_.reset(new net::HttpServer(server_socket.Pass(), this)); 49 net::IPEndPoint address; 50 int error = web_server_->GetLocalAddress(&address); 51 port_ = address.port(); 52 return (error == net::OK); 53 } 54 55 void WebSocketServer::LogMessageInfo( 56 const mojo::MojoRequestHeader& message_header, 57 const GURL& url, 58 const base::Time& message_time) { 59 base::Time::Exploded exploded; 60 message_time.LocalExplode(&exploded); 61 62 std::string output_message = base::StringPrintf( 63 MOJO_DEBUGGER_MESSAGE_FORMAT, 64 url.spec().c_str(), 65 exploded.hour, 66 exploded.minute, 67 exploded.second, 68 static_cast<unsigned>(message_header.num_bytes), 69 static_cast<unsigned>(message_header.num_fields), 70 static_cast<unsigned>(message_header.name), 71 static_cast<unsigned long long>( 72 message_header.num_fields == 3 ? message_header.request_id 73 : 0), 74 message_header.flags != 0 ? 75 (message_header.flags & mojo::kMessageExpectsResponse ? 76 "Expects response" : "Response message") 77 : "Not a request or response message"); 78 if (Connected()) { 79 web_server_->SendOverWebSocket(connection_id_, output_message.c_str()); 80 } else { 81 DVLOG(1) << output_message; 82 } 83 } 84 85 void WebSocketServer::OnHttpRequest( 86 int connection_id, 87 const net::HttpServerRequestInfo& info) { 88 web_server_->Send500(connection_id, "websockets protocol only"); 89 } 90 91 void WebSocketServer::OnWebSocketRequest( 92 int connection_id, 93 const net::HttpServerRequestInfo& info) { 94 if (connection_id_ != kNotConnected) { 95 // Reject connection since we already have our client. 96 web_server_->Close(connection_id); 97 return; 98 } 99 // Accept the connection. 100 web_server_->AcceptWebSocket(connection_id, info); 101 connection_id_ = connection_id; 102 } 103 104 void WebSocketServer::OnWebSocketMessage( 105 int connection_id, 106 const std::string& data) { 107 108 if (data == "\"start\"") { 109 spy_api::VersionPtr ver = spy_api::Version::New(); 110 ver->v_major = 0; 111 ver->v_minor = 1; 112 spy_server_->StartSession( 113 ver.Pass(), 114 base::Bind(&WebSocketServer::OnStartSession, base::Unretained(this))); 115 } else if (data == "\"stop\"") { 116 spy_server_->StopSession( 117 base::Bind(&WebSocketServer::OnSessionEnd, base::Unretained(this))); 118 } 119 } 120 121 void WebSocketServer::OnFatalError(spy_api::Result result) { 122 web_server_->SendOverWebSocket(connection_id_, "\"fatal error\""); 123 } 124 125 void WebSocketServer::OnClose( 126 int connection_id) { 127 if (connection_id != connection_id_) 128 return; 129 connection_id_ = kNotConnected; 130 131 spy_server_->StopSession( 132 base::Bind(&WebSocketServer::OnSessionEnd, base::Unretained(this))); 133 } 134 135 void WebSocketServer::OnSessionEnd(spy_api::Result result) { 136 // Called when the spy session (not the websocket) ends. 137 } 138 139 void WebSocketServer::OnClientConnection( 140 const mojo::String& name, 141 uint32_t id, 142 spy_api::ConnectionOptions options) { 143 std::string cc("\""); 144 cc += name.To<std::string>() + "\""; 145 web_server_->SendOverWebSocket(connection_id_, cc); 146 } 147 148 void WebSocketServer::OnMessage(spy_api::MessagePtr message) { 149 } 150 151 void WebSocketServer::OnStartSession(spy_api::Result, mojo::String) { 152 web_server_->SendOverWebSocket(connection_id_, "\"ok start\""); 153 } 154 155 bool WebSocketServer::Connected() const { 156 return connection_id_ != kNotConnected; 157 } 158 159 } // namespace mojo 160