Home | History | Annotate | Download | only in renderer_host
      1 // Copyright 2013 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 "content/browser/renderer_host/websocket_host.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/strings/string_util.h"
      9 #include "content/browser/renderer_host/websocket_dispatcher_host.h"
     10 #include "content/common/websocket_messages.h"
     11 #include "ipc/ipc_message_macros.h"
     12 #include "net/websockets/websocket_channel.h"
     13 #include "net/websockets/websocket_event_interface.h"
     14 #include "net/websockets/websocket_frame.h"  // for WebSocketFrameHeader::OpCode
     15 
     16 namespace content {
     17 
     18 namespace {
     19 
     20 typedef net::WebSocketEventInterface::ChannelState ChannelState;
     21 
     22 // Convert a content::WebSocketMessageType to a
     23 // net::WebSocketFrameHeader::OpCode
     24 net::WebSocketFrameHeader::OpCode MessageTypeToOpCode(
     25     WebSocketMessageType type) {
     26   DCHECK(type == WEB_SOCKET_MESSAGE_TYPE_CONTINUATION ||
     27          type == WEB_SOCKET_MESSAGE_TYPE_TEXT ||
     28          type == WEB_SOCKET_MESSAGE_TYPE_BINARY);
     29   typedef net::WebSocketFrameHeader::OpCode OpCode;
     30   // These compile asserts verify that the same underlying values are used for
     31   // both types, so we can simply cast between them.
     32   COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_CONTINUATION) ==
     33                      net::WebSocketFrameHeader::kOpCodeContinuation,
     34                  enum_values_must_match_for_opcode_continuation);
     35   COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_TEXT) ==
     36                      net::WebSocketFrameHeader::kOpCodeText,
     37                  enum_values_must_match_for_opcode_text);
     38   COMPILE_ASSERT(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_BINARY) ==
     39                      net::WebSocketFrameHeader::kOpCodeBinary,
     40                  enum_values_must_match_for_opcode_binary);
     41   return static_cast<OpCode>(type);
     42 }
     43 
     44 WebSocketMessageType OpCodeToMessageType(
     45     net::WebSocketFrameHeader::OpCode opCode) {
     46   DCHECK(opCode == net::WebSocketFrameHeader::kOpCodeContinuation ||
     47          opCode == net::WebSocketFrameHeader::kOpCodeText ||
     48          opCode == net::WebSocketFrameHeader::kOpCodeBinary);
     49   // This cast is guaranteed valid by the COMPILE_ASSERT() statements above.
     50   return static_cast<WebSocketMessageType>(opCode);
     51 }
     52 
     53 ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) {
     54   const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_ALIVE =
     55       WebSocketDispatcherHost::WEBSOCKET_HOST_ALIVE;
     56   const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_DELETED =
     57       WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED;
     58 
     59   DCHECK(host_state == WEBSOCKET_HOST_ALIVE ||
     60          host_state == WEBSOCKET_HOST_DELETED);
     61   // These compile asserts verify that we can get away with using static_cast<>
     62   // for the conversion.
     63   COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_ALIVE) ==
     64                      net::WebSocketEventInterface::CHANNEL_ALIVE,
     65                  enum_values_must_match_for_state_alive);
     66   COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_DELETED) ==
     67                      net::WebSocketEventInterface::CHANNEL_DELETED,
     68                  enum_values_must_match_for_state_deleted);
     69   return static_cast<ChannelState>(host_state);
     70 }
     71 
     72 // Implementation of net::WebSocketEventInterface. Receives events from our
     73 // WebSocketChannel object. Each event is translated to an IPC and sent to the
     74 // renderer or child process via WebSocketDispatcherHost.
     75 class WebSocketEventHandler : public net::WebSocketEventInterface {
     76  public:
     77   WebSocketEventHandler(WebSocketDispatcherHost* dispatcher, int routing_id);
     78   virtual ~WebSocketEventHandler();
     79 
     80   // net::WebSocketEventInterface implementation
     81 
     82   // TODO(ricea): Add |extensions| parameter to pass the list of enabled
     83   // WebSocket extensions through to the renderer to make it visible to
     84   // Javascript.
     85   virtual ChannelState OnAddChannelResponse(
     86       bool fail,
     87       const std::string& selected_subprotocol) OVERRIDE;
     88   virtual ChannelState OnDataFrame(bool fin,
     89                                    WebSocketMessageType type,
     90                                    const std::vector<char>& data) OVERRIDE;
     91   virtual ChannelState OnClosingHandshake() OVERRIDE;
     92   virtual ChannelState OnFlowControl(int64 quota) OVERRIDE;
     93   virtual ChannelState OnDropChannel(uint16 code,
     94                                      const std::string& reason) OVERRIDE;
     95 
     96  private:
     97   WebSocketDispatcherHost* const dispatcher_;
     98   const int routing_id_;
     99 
    100   DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
    101 };
    102 
    103 WebSocketEventHandler::WebSocketEventHandler(
    104     WebSocketDispatcherHost* dispatcher,
    105     int routing_id)
    106     : dispatcher_(dispatcher), routing_id_(routing_id) {}
    107 
    108 WebSocketEventHandler::~WebSocketEventHandler() {
    109   DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_;
    110 }
    111 
    112 ChannelState WebSocketEventHandler::OnAddChannelResponse(
    113     bool fail,
    114     const std::string& selected_protocol) {
    115   DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
    116            << " routing_id=" << routing_id_ << " fail=" << fail
    117            << " selected_protocol=\"" << selected_protocol << "\"";
    118   return StateCast(dispatcher_->SendAddChannelResponse(
    119       routing_id_, fail, selected_protocol, std::string()));
    120 }
    121 
    122 ChannelState WebSocketEventHandler::OnDataFrame(
    123     bool fin,
    124     net::WebSocketFrameHeader::OpCode type,
    125     const std::vector<char>& data) {
    126   DVLOG(3) << "WebSocketEventHandler::OnDataFrame"
    127            << " routing_id=" << routing_id_ << " fin=" << fin
    128            << " type=" << type << " data is " << data.size() << " bytes";
    129   return StateCast(dispatcher_->SendFrame(
    130       routing_id_, fin, OpCodeToMessageType(type), data));
    131 }
    132 
    133 ChannelState WebSocketEventHandler::OnClosingHandshake() {
    134   DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake"
    135            << " routing_id=" << routing_id_;
    136   return StateCast(dispatcher_->SendClosing(routing_id_));
    137 }
    138 
    139 ChannelState WebSocketEventHandler::OnFlowControl(int64 quota) {
    140   DVLOG(3) << "WebSocketEventHandler::OnFlowControl"
    141            << " routing_id=" << routing_id_ << " quota=" << quota;
    142   return StateCast(dispatcher_->SendFlowControl(routing_id_, quota));
    143 }
    144 
    145 ChannelState WebSocketEventHandler::OnDropChannel(uint16 code,
    146                                                   const std::string& reason) {
    147   DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
    148            << " routing_id=" << routing_id_ << " code=" << code
    149            << " reason=\"" << reason << "\"";
    150   return StateCast(dispatcher_->DoDropChannel(routing_id_, code, reason));
    151 }
    152 
    153 }  // namespace
    154 
    155 WebSocketHost::WebSocketHost(int routing_id,
    156                              WebSocketDispatcherHost* dispatcher,
    157                              net::URLRequestContext* url_request_context)
    158     : routing_id_(routing_id) {
    159   DVLOG(1) << "WebSocketHost: created routing_id=" << routing_id;
    160   scoped_ptr<net::WebSocketEventInterface> event_interface(
    161       new WebSocketEventHandler(dispatcher, routing_id));
    162   channel_.reset(
    163       new net::WebSocketChannel(event_interface.Pass(), url_request_context));
    164 }
    165 
    166 WebSocketHost::~WebSocketHost() {}
    167 
    168 bool WebSocketHost::OnMessageReceived(const IPC::Message& message,
    169                                       bool* message_was_ok) {
    170   bool handled = true;
    171   IPC_BEGIN_MESSAGE_MAP_EX(WebSocketHost, message, *message_was_ok)
    172     IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest, OnAddChannelRequest)
    173     IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnSendFrame)
    174     IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnFlowControl)
    175     IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnDropChannel)
    176     IPC_MESSAGE_UNHANDLED(handled = false)
    177   IPC_END_MESSAGE_MAP_EX()
    178   return handled;
    179 }
    180 
    181 void WebSocketHost::OnAddChannelRequest(
    182     const GURL& socket_url,
    183     const std::vector<std::string>& requested_protocols,
    184     const GURL& origin) {
    185   DVLOG(3) << "WebSocketHost::OnAddChannelRequest"
    186            << " routing_id=" << routing_id_ << " socket_url=\"" << socket_url
    187            << "\" requested_protocols=\""
    188            << JoinString(requested_protocols, ", ") << "\" origin=\"" << origin
    189            << "\"";
    190 
    191   channel_->SendAddChannelRequest(socket_url, requested_protocols, origin);
    192 }
    193 
    194 void WebSocketHost::OnSendFrame(bool fin,
    195                                 WebSocketMessageType type,
    196                                 const std::vector<char>& data) {
    197   DVLOG(3) << "WebSocketHost::OnSendFrame"
    198            << " routing_id=" << routing_id_ << " fin=" << fin
    199            << " type=" << type << " data is " << data.size() << " bytes";
    200 
    201   channel_->SendFrame(fin, MessageTypeToOpCode(type), data);
    202 }
    203 
    204 void WebSocketHost::OnFlowControl(int64 quota) {
    205   DVLOG(3) << "WebSocketHost::OnFlowControl"
    206            << " routing_id=" << routing_id_ << " quota=" << quota;
    207 
    208   channel_->SendFlowControl(quota);
    209 }
    210 
    211 void WebSocketHost::OnDropChannel(bool was_clean,
    212                                   uint16 code,
    213                                   const std::string& reason) {
    214   DVLOG(3) << "WebSocketHost::OnDropChannel"
    215            << " routing_id=" << routing_id_ << " was_clean=" << was_clean
    216            << " code=" << code << " reason=\"" << reason << "\"";
    217 
    218   // TODO(yhirano): Handle |was_clean| appropriately.
    219   channel_->StartClosingHandshake(code, reason);
    220 }
    221 
    222 
    223 }  // namespace content
    224