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.
5 #include "content/browser/renderer_host/websocket_host.h"
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
20 typedef net::WebSocketEventInterface::ChannelState ChannelState
;
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
);
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
);
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
;
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
);
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
{
77 WebSocketEventHandler(WebSocketDispatcherHost
* dispatcher
, int routing_id
);
78 virtual ~WebSocketEventHandler();
80 // net::WebSocketEventInterface implementation
82 // TODO(ricea): Add |extensions| parameter to pass the list of enabled
83 // WebSocket extensions through to the renderer to make it visible to
85 virtual ChannelState
OnAddChannelResponse(
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 virtual ChannelState
OnFailChannel(const std::string
& message
) OVERRIDE
;
98 WebSocketDispatcherHost
* const dispatcher_
;
99 const int routing_id_
;
101 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler
);
104 WebSocketEventHandler::WebSocketEventHandler(
105 WebSocketDispatcherHost
* dispatcher
,
107 : dispatcher_(dispatcher
), routing_id_(routing_id
) {}
109 WebSocketEventHandler::~WebSocketEventHandler() {
110 DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_
;
113 ChannelState
WebSocketEventHandler::OnAddChannelResponse(
115 const std::string
& selected_protocol
) {
116 DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
117 << " routing_id=" << routing_id_
<< " fail=" << fail
118 << " selected_protocol=\"" << selected_protocol
<< "\"";
119 return StateCast(dispatcher_
->SendAddChannelResponse(
120 routing_id_
, fail
, selected_protocol
, std::string()));
123 ChannelState
WebSocketEventHandler::OnDataFrame(
125 net::WebSocketFrameHeader::OpCode type
,
126 const std::vector
<char>& data
) {
127 DVLOG(3) << "WebSocketEventHandler::OnDataFrame"
128 << " routing_id=" << routing_id_
<< " fin=" << fin
129 << " type=" << type
<< " data is " << data
.size() << " bytes";
130 return StateCast(dispatcher_
->SendFrame(
131 routing_id_
, fin
, OpCodeToMessageType(type
), data
));
134 ChannelState
WebSocketEventHandler::OnClosingHandshake() {
135 DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake"
136 << " routing_id=" << routing_id_
;
137 return StateCast(dispatcher_
->SendClosing(routing_id_
));
140 ChannelState
WebSocketEventHandler::OnFlowControl(int64 quota
) {
141 DVLOG(3) << "WebSocketEventHandler::OnFlowControl"
142 << " routing_id=" << routing_id_
<< " quota=" << quota
;
143 return StateCast(dispatcher_
->SendFlowControl(routing_id_
, quota
));
146 ChannelState
WebSocketEventHandler::OnDropChannel(uint16 code
,
147 const std::string
& reason
) {
148 DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
149 << " routing_id=" << routing_id_
<< " code=" << code
150 << " reason=\"" << reason
<< "\"";
151 return StateCast(dispatcher_
->DoDropChannel(routing_id_
, code
, reason
));
154 ChannelState
WebSocketEventHandler::OnFailChannel(const std::string
& message
) {
155 DVLOG(3) << "WebSocketEventHandler::OnFailChannel"
156 << " routing_id=" << routing_id_
157 << " message=\"" << message
<< "\"";
158 return StateCast(dispatcher_
->NotifyFailure(routing_id_
, message
));
163 WebSocketHost::WebSocketHost(int routing_id
,
164 WebSocketDispatcherHost
* dispatcher
,
165 net::URLRequestContext
* url_request_context
)
166 : routing_id_(routing_id
) {
167 DVLOG(1) << "WebSocketHost: created routing_id=" << routing_id
;
168 scoped_ptr
<net::WebSocketEventInterface
> event_interface(
169 new WebSocketEventHandler(dispatcher
, routing_id
));
171 new net::WebSocketChannel(event_interface
.Pass(), url_request_context
));
174 WebSocketHost::~WebSocketHost() {}
176 bool WebSocketHost::OnMessageReceived(const IPC::Message
& message
,
177 bool* message_was_ok
) {
179 IPC_BEGIN_MESSAGE_MAP_EX(WebSocketHost
, message
, *message_was_ok
)
180 IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest
, OnAddChannelRequest
)
181 IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame
, OnSendFrame
)
182 IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl
, OnFlowControl
)
183 IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel
, OnDropChannel
)
184 IPC_MESSAGE_UNHANDLED(handled
= false)
185 IPC_END_MESSAGE_MAP_EX()
189 void WebSocketHost::OnAddChannelRequest(
190 const GURL
& socket_url
,
191 const std::vector
<std::string
>& requested_protocols
,
192 const GURL
& origin
) {
193 DVLOG(3) << "WebSocketHost::OnAddChannelRequest"
194 << " routing_id=" << routing_id_
<< " socket_url=\"" << socket_url
195 << "\" requested_protocols=\""
196 << JoinString(requested_protocols
, ", ") << "\" origin=\"" << origin
199 channel_
->SendAddChannelRequest(socket_url
, requested_protocols
, origin
);
202 void WebSocketHost::OnSendFrame(bool fin
,
203 WebSocketMessageType type
,
204 const std::vector
<char>& data
) {
205 DVLOG(3) << "WebSocketHost::OnSendFrame"
206 << " routing_id=" << routing_id_
<< " fin=" << fin
207 << " type=" << type
<< " data is " << data
.size() << " bytes";
209 channel_
->SendFrame(fin
, MessageTypeToOpCode(type
), data
);
212 void WebSocketHost::OnFlowControl(int64 quota
) {
213 DVLOG(3) << "WebSocketHost::OnFlowControl"
214 << " routing_id=" << routing_id_
<< " quota=" << quota
;
216 channel_
->SendFlowControl(quota
);
219 void WebSocketHost::OnDropChannel(bool was_clean
,
221 const std::string
& reason
) {
222 DVLOG(3) << "WebSocketHost::OnDropChannel"
223 << " routing_id=" << routing_id_
<< " was_clean=" << was_clean
224 << " code=" << code
<< " reason=\"" << reason
<< "\"";
226 // TODO(yhirano): Handle |was_clean| appropriately.
227 channel_
->StartClosingHandshake(code
, reason
);
231 } // namespace content