blob: bf4c96a298b2987f3bf3fe912ee493915a06dc53 [file] [log] [blame]
cpu@chromium.org8b63c642014-04-30 17:07:50 +09001// 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
cpu@chromium.orga9997562014-07-09 18:07:39 +09007#include <string>
8
cpu@chromium.org8b63c642014-04-30 17:07:50 +09009#include "base/bind.h"
ananta@chromium.org146a9722014-07-11 05:27:40 +090010#include "base/logging.h"
cpu@chromium.org8b63c642014-04-30 17:07:50 +090011#include "base/strings/stringprintf.h"
cpu@chromium.orga9997562014-07-09 18:07:39 +090012#include "mojo/public/cpp/bindings/message.h"
cpu@chromium.org8b63c642014-04-30 17:07:50 +090013#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"
ananta@chromium.org146a9722014-07-11 05:27:40 +090018#include "url/gurl.h"
cpu@chromium.org8b63c642014-04-30 17:07:50 +090019
cpu@chromium.orga9997562014-07-09 18:07:39 +090020namespace mojo {
cpu@chromium.org8b63c642014-04-30 17:07:50 +090021
22const int kNotConnected = -1;
23
ananta@chromium.org146a9722014-07-11 05:27:40 +090024#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
cpu@chromium.orga9997562014-07-09 18:07:39 +090033WebSocketServer::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);
cpu@chromium.org8b63c642014-04-30 17:07:50 +090039}
40
41WebSocketServer::~WebSocketServer() {
42}
43
44bool WebSocketServer::Start() {
45 net::TCPListenSocketFactory factory("0.0.0.0", port_);
cpu@chromium.orga9997562014-07-09 18:07:39 +090046 web_server_ = new net::HttpServer(factory, this);
cpu@chromium.org8b63c642014-04-30 17:07:50 +090047 net::IPEndPoint address;
cpu@chromium.orga9997562014-07-09 18:07:39 +090048 int error = web_server_->GetLocalAddress(&address);
cpu@chromium.org8b63c642014-04-30 17:07:50 +090049 port_ = address.port();
50 return (error == net::OK);
51}
52
ananta@chromium.org146a9722014-07-11 05:27:40 +090053void WebSocketServer::LogMessageInfo(
54 const mojo::MojoRequestHeader& message_header,
55 const GURL& url,
56 const base::Time& message_time) {
57 base::Time::Exploded exploded;
58 message_time.LocalExplode(&exploded);
59
60 std::string output_message = base::StringPrintf(
61 MOJO_DEBUGGER_MESSAGE_FORMAT,
62 url.spec().c_str(),
63 exploded.hour,
64 exploded.minute,
65 exploded.second,
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
71 : 0),
72 message_header.flags != 0 ?
73 (message_header.flags & mojo::kMessageExpectsResponse ?
74 "Expects response" : "Response message")
75 : "Not a request or response message");
76 if (Connected()) {
77 web_server_->SendOverWebSocket(connection_id_, output_message.c_str());
78 } else {
79 DVLOG(1) << output_message;
80 }
81}
82
cpu@chromium.org8b63c642014-04-30 17:07:50 +090083void WebSocketServer::OnHttpRequest(
84 int connection_id,
85 const net::HttpServerRequestInfo& info) {
cpu@chromium.orga9997562014-07-09 18:07:39 +090086 web_server_->Send500(connection_id, "websockets protocol only");
cpu@chromium.org8b63c642014-04-30 17:07:50 +090087}
88
89void WebSocketServer::OnWebSocketRequest(
90 int connection_id,
91 const net::HttpServerRequestInfo& info) {
92 if (connection_id_ != kNotConnected) {
93 // Reject connection since we already have our client.
94 base::MessageLoop::current()->PostTask(
95 FROM_HERE,
cpu@chromium.orga9997562014-07-09 18:07:39 +090096 base::Bind(&net::HttpServer::Close, web_server_, connection_id));
cpu@chromium.org8b63c642014-04-30 17:07:50 +090097 return;
98 }
99 // Accept the connection.
cpu@chromium.orga9997562014-07-09 18:07:39 +0900100 web_server_->AcceptWebSocket(connection_id, info);
cpu@chromium.org8b63c642014-04-30 17:07:50 +0900101 connection_id_ = connection_id;
102}
103
104void WebSocketServer::OnWebSocketMessage(
105 int connection_id,
106 const std::string& data) {
cpu@chromium.orga9997562014-07-09 18:07:39 +0900107
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
121void WebSocketServer::OnFatalError(spy_api::Result result) {
122 web_server_->SendOverWebSocket(connection_id_, "\"fatal error\"");
cpu@chromium.org8b63c642014-04-30 17:07:50 +0900123}
124
125void WebSocketServer::OnClose(
126 int connection_id) {
cpu@chromium.orga9997562014-07-09 18:07:39 +0900127 if (connection_id != connection_id_)
128 return;
129 connection_id_ = kNotConnected;
130
131 spy_server_->StopSession(
132 base::Bind(&WebSocketServer::OnSessionEnd, base::Unretained(this)));
cpu@chromium.org8b63c642014-04-30 17:07:50 +0900133}
134
cpu@chromium.orga9997562014-07-09 18:07:39 +0900135void WebSocketServer::OnSessionEnd(spy_api::Result result) {
136 // Called when the spy session (not the websocket) ends.
137}
138
139void 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
148void WebSocketServer::OnMessage(spy_api::MessagePtr message) {
149}
150
151void WebSocketServer::OnStartSession(spy_api::Result, mojo::String) {
152 web_server_->SendOverWebSocket(connection_id_, "\"ok start\"");
153}
154
ananta@chromium.org146a9722014-07-11 05:27:40 +0900155bool WebSocketServer::Connected() const {
156 return connection_id_ != kNotConnected;
157}
158
cpu@chromium.orga9997562014-07-09 18:07:39 +0900159} // namespace mojo
ananta@chromium.org146a9722014-07-11 05:27:40 +0900160