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