Home | History | Annotate | Download | only in spy
      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