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.
5 #include "mojo/spy/websocket_server.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_listen_socket.h"
22 const int kNotConnected = -1;
24 #define MOJO_DEBUGGER_MESSAGE_FORMAT "\"url: %s\n," \
25 "time: %02d:%02d:%02d\n,"\
33 WebSocketServer::WebSocketServer(int port,
34 mojo::ScopedMessagePipeHandle server_pipe)
36 connection_id_(kNotConnected),
37 spy_server_(MakeProxy<spy_api::SpyServer>(server_pipe.Pass())) {
38 spy_server_.set_client(this);
41 WebSocketServer::~WebSocketServer() {
44 bool WebSocketServer::Start() {
45 net::TCPListenSocketFactory factory("0.0.0.0", port_);
46 web_server_ = new net::HttpServer(factory, this);
47 net::IPEndPoint address;
48 int error = web_server_->GetLocalAddress(&address);
49 port_ = address.port();
50 return (error == net::OK);
53 void WebSocketServer::LogMessageInfo(
54 const mojo::MojoRequestHeader& message_header,
56 const base::Time& message_time) {
57 base::Time::Exploded exploded;
58 message_time.LocalExplode(&exploded);
60 std::string output_message = base::StringPrintf(
61 MOJO_DEBUGGER_MESSAGE_FORMAT,
66 static_cast<unsigned>(message_header.num_bytes),
67 static_cast<unsigned>(message_header.num_fields),
68 static_cast<unsigned>(message_header.name),
69 static_cast<unsigned long long>(
70 message_header.num_fields == 3 ? message_header.request_id
72 message_header.flags != 0 ?
73 (message_header.flags & mojo::kMessageExpectsResponse ?
74 "Expects response" : "Response message")
75 : "Not a request or response message");
77 web_server_->SendOverWebSocket(connection_id_, output_message.c_str());
79 DVLOG(1) << output_message;
83 void WebSocketServer::OnHttpRequest(
85 const net::HttpServerRequestInfo& info) {
86 web_server_->Send500(connection_id, "websockets protocol only");
89 void WebSocketServer::OnWebSocketRequest(
91 const net::HttpServerRequestInfo& info) {
92 if (connection_id_ != kNotConnected) {
93 // Reject connection since we already have our client.
94 base::MessageLoop::current()->PostTask(
96 base::Bind(&net::HttpServer::Close, web_server_, connection_id));
99 // Accept the connection.
100 web_server_->AcceptWebSocket(connection_id, info);
101 connection_id_ = connection_id;
104 void WebSocketServer::OnWebSocketMessage(
106 const std::string& data) {
108 if (data == "\"start\"") {
109 spy_api::VersionPtr ver = spy_api::Version::New();
112 spy_server_->StartSession(
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)));
121 void WebSocketServer::OnFatalError(spy_api::Result result) {
122 web_server_->SendOverWebSocket(connection_id_, "\"fatal error\"");
125 void WebSocketServer::OnClose(
127 if (connection_id != connection_id_)
129 connection_id_ = kNotConnected;
131 spy_server_->StopSession(
132 base::Bind(&WebSocketServer::OnSessionEnd, base::Unretained(this)));
135 void WebSocketServer::OnSessionEnd(spy_api::Result result) {
136 // Called when the spy session (not the websocket) ends.
139 void WebSocketServer::OnClientConnection(
140 const mojo::String& name,
142 spy_api::ConnectionOptions options) {
143 std::string cc("\"");
144 cc += name.To<std::string>() + "\"";
145 web_server_->SendOverWebSocket(connection_id_, cc);
148 void WebSocketServer::OnMessage(spy_api::MessagePtr message) {
151 void WebSocketServer::OnStartSession(spy_api::Result, mojo::String) {
152 web_server_->SendOverWebSocket(connection_id_, "\"ok start\"");
155 bool WebSocketServer::Connected() const {
156 return connection_id_ != kNotConnected;