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/http/http_request_headers.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_util.h"
15 #include "net/websockets/websocket_channel.h"
16 #include "net/websockets/websocket_event_interface.h"
17 #include "net/websockets/websocket_frame.h" // for WebSocketFrameHeader::OpCode
18 #include "net/websockets/websocket_handshake_request_info.h"
19 #include "net/websockets/websocket_handshake_response_info.h"
25 typedef net::WebSocketEventInterface::ChannelState ChannelState
;
27 // Convert a content::WebSocketMessageType to a
28 // net::WebSocketFrameHeader::OpCode
29 net::WebSocketFrameHeader::OpCode
MessageTypeToOpCode(
30 WebSocketMessageType type
) {
31 DCHECK(type
== WEB_SOCKET_MESSAGE_TYPE_CONTINUATION
||
32 type
== WEB_SOCKET_MESSAGE_TYPE_TEXT
||
33 type
== WEB_SOCKET_MESSAGE_TYPE_BINARY
);
34 typedef net::WebSocketFrameHeader::OpCode OpCode
;
35 // These compile asserts verify that the same underlying values are used for
36 // both types, so we can simply cast between them.
37 COMPILE_ASSERT(static_cast<OpCode
>(WEB_SOCKET_MESSAGE_TYPE_CONTINUATION
) ==
38 net::WebSocketFrameHeader::kOpCodeContinuation
,
39 enum_values_must_match_for_opcode_continuation
);
40 COMPILE_ASSERT(static_cast<OpCode
>(WEB_SOCKET_MESSAGE_TYPE_TEXT
) ==
41 net::WebSocketFrameHeader::kOpCodeText
,
42 enum_values_must_match_for_opcode_text
);
43 COMPILE_ASSERT(static_cast<OpCode
>(WEB_SOCKET_MESSAGE_TYPE_BINARY
) ==
44 net::WebSocketFrameHeader::kOpCodeBinary
,
45 enum_values_must_match_for_opcode_binary
);
46 return static_cast<OpCode
>(type
);
49 WebSocketMessageType
OpCodeToMessageType(
50 net::WebSocketFrameHeader::OpCode opCode
) {
51 DCHECK(opCode
== net::WebSocketFrameHeader::kOpCodeContinuation
||
52 opCode
== net::WebSocketFrameHeader::kOpCodeText
||
53 opCode
== net::WebSocketFrameHeader::kOpCodeBinary
);
54 // This cast is guaranteed valid by the COMPILE_ASSERT() statements above.
55 return static_cast<WebSocketMessageType
>(opCode
);
58 ChannelState
StateCast(WebSocketDispatcherHost::WebSocketHostState host_state
) {
59 const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_ALIVE
=
60 WebSocketDispatcherHost::WEBSOCKET_HOST_ALIVE
;
61 const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_DELETED
=
62 WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED
;
64 DCHECK(host_state
== WEBSOCKET_HOST_ALIVE
||
65 host_state
== WEBSOCKET_HOST_DELETED
);
66 // These compile asserts verify that we can get away with using static_cast<>
67 // for the conversion.
68 COMPILE_ASSERT(static_cast<ChannelState
>(WEBSOCKET_HOST_ALIVE
) ==
69 net::WebSocketEventInterface::CHANNEL_ALIVE
,
70 enum_values_must_match_for_state_alive
);
71 COMPILE_ASSERT(static_cast<ChannelState
>(WEBSOCKET_HOST_DELETED
) ==
72 net::WebSocketEventInterface::CHANNEL_DELETED
,
73 enum_values_must_match_for_state_deleted
);
74 return static_cast<ChannelState
>(host_state
);
77 // Implementation of net::WebSocketEventInterface. Receives events from our
78 // WebSocketChannel object. Each event is translated to an IPC and sent to the
79 // renderer or child process via WebSocketDispatcherHost.
80 class WebSocketEventHandler
: public net::WebSocketEventInterface
{
82 WebSocketEventHandler(WebSocketDispatcherHost
* dispatcher
, int routing_id
);
83 virtual ~WebSocketEventHandler();
85 // net::WebSocketEventInterface implementation
87 virtual ChannelState
OnAddChannelResponse(
89 const std::string
& selected_subprotocol
,
90 const std::string
& extensions
) OVERRIDE
;
91 virtual ChannelState
OnDataFrame(bool fin
,
92 WebSocketMessageType type
,
93 const std::vector
<char>& data
) OVERRIDE
;
94 virtual ChannelState
OnClosingHandshake() OVERRIDE
;
95 virtual ChannelState
OnFlowControl(int64 quota
) OVERRIDE
;
96 virtual ChannelState
OnDropChannel(bool was_clean
,
98 const std::string
& reason
) OVERRIDE
;
99 virtual ChannelState
OnFailChannel(const std::string
& message
) OVERRIDE
;
100 virtual ChannelState
OnStartOpeningHandshake(
101 scoped_ptr
<net::WebSocketHandshakeRequestInfo
> request
) OVERRIDE
;
102 virtual ChannelState
OnFinishOpeningHandshake(
103 scoped_ptr
<net::WebSocketHandshakeResponseInfo
> response
) OVERRIDE
;
106 WebSocketDispatcherHost
* const dispatcher_
;
107 const int routing_id_
;
109 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler
);
112 WebSocketEventHandler::WebSocketEventHandler(
113 WebSocketDispatcherHost
* dispatcher
,
115 : dispatcher_(dispatcher
), routing_id_(routing_id
) {}
117 WebSocketEventHandler::~WebSocketEventHandler() {
118 DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_
;
121 ChannelState
WebSocketEventHandler::OnAddChannelResponse(
123 const std::string
& selected_protocol
,
124 const std::string
& extensions
) {
125 DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
126 << " routing_id=" << routing_id_
<< " fail=" << fail
127 << " selected_protocol=\"" << selected_protocol
<< "\""
128 << " extensions=\"" << extensions
<< "\"";
129 return StateCast(dispatcher_
->SendAddChannelResponse(
130 routing_id_
, fail
, selected_protocol
, extensions
));
133 ChannelState
WebSocketEventHandler::OnDataFrame(
135 net::WebSocketFrameHeader::OpCode type
,
136 const std::vector
<char>& data
) {
137 DVLOG(3) << "WebSocketEventHandler::OnDataFrame"
138 << " routing_id=" << routing_id_
<< " fin=" << fin
139 << " type=" << type
<< " data is " << data
.size() << " bytes";
140 return StateCast(dispatcher_
->SendFrame(
141 routing_id_
, fin
, OpCodeToMessageType(type
), data
));
144 ChannelState
WebSocketEventHandler::OnClosingHandshake() {
145 DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake"
146 << " routing_id=" << routing_id_
;
147 return StateCast(dispatcher_
->SendClosing(routing_id_
));
150 ChannelState
WebSocketEventHandler::OnFlowControl(int64 quota
) {
151 DVLOG(3) << "WebSocketEventHandler::OnFlowControl"
152 << " routing_id=" << routing_id_
<< " quota=" << quota
;
153 return StateCast(dispatcher_
->SendFlowControl(routing_id_
, quota
));
156 ChannelState
WebSocketEventHandler::OnDropChannel(bool was_clean
,
158 const std::string
& reason
) {
159 DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
160 << " routing_id=" << routing_id_
<< " was_clean=" << was_clean
161 << " code=" << code
<< " reason=\"" << reason
<< "\"";
163 dispatcher_
->DoDropChannel(routing_id_
, was_clean
, code
, reason
));
166 ChannelState
WebSocketEventHandler::OnFailChannel(const std::string
& message
) {
167 DVLOG(3) << "WebSocketEventHandler::OnFailChannel"
168 << " routing_id=" << routing_id_
169 << " message=\"" << message
<< "\"";
170 return StateCast(dispatcher_
->NotifyFailure(routing_id_
, message
));
173 ChannelState
WebSocketEventHandler::OnStartOpeningHandshake(
174 scoped_ptr
<net::WebSocketHandshakeRequestInfo
> request
) {
175 // TODO(yhirano) Do nothing if the inspector is not attached.
176 DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake";
177 WebSocketHandshakeRequest request_to_pass
;
178 request_to_pass
.url
.Swap(&request
->url
);
179 net::HttpRequestHeaders::Iterator
it(request
->headers
);
181 request_to_pass
.headers
.push_back(std::make_pair(it
.name(), it
.value()));
182 request_to_pass
.headers_text
=
183 base::StringPrintf("GET %s HTTP/1.1\r\n",
184 request_to_pass
.url
.spec().c_str()) +
185 request
->headers
.ToString();
187 request_to_pass
.request_time
= request
->request_time
;
188 return StateCast(dispatcher_
->SendStartOpeningHandshake(routing_id_
,
192 ChannelState
WebSocketEventHandler::OnFinishOpeningHandshake(
193 scoped_ptr
<net::WebSocketHandshakeResponseInfo
> response
) {
194 // TODO(yhirano) Do nothing if the inspector is not attached.
195 DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake";
196 WebSocketHandshakeResponse response_to_pass
;
197 response_to_pass
.url
.Swap(&response
->url
);
198 response_to_pass
.status_code
= response
->status_code
;
199 response_to_pass
.status_text
.swap(response
->status_text
);
201 std::string name
, value
;
202 while (response
->headers
->EnumerateHeaderLines(&iter
, &name
, &value
))
203 response_to_pass
.headers
.push_back(std::make_pair(name
, value
));
204 response_to_pass
.headers_text
=
205 net::HttpUtil::ConvertHeadersBackToHTTPResponse(
206 response
->headers
->raw_headers());
207 response_to_pass
.response_time
= response
->response_time
;
208 return StateCast(dispatcher_
->SendFinishOpeningHandshake(routing_id_
,
214 WebSocketHost::WebSocketHost(int routing_id
,
215 WebSocketDispatcherHost
* dispatcher
,
216 net::URLRequestContext
* url_request_context
)
217 : routing_id_(routing_id
) {
218 DVLOG(1) << "WebSocketHost: created routing_id=" << routing_id
;
219 scoped_ptr
<net::WebSocketEventInterface
> event_interface(
220 new WebSocketEventHandler(dispatcher
, routing_id
));
222 new net::WebSocketChannel(event_interface
.Pass(), url_request_context
));
225 WebSocketHost::~WebSocketHost() {}
227 bool WebSocketHost::OnMessageReceived(const IPC::Message
& message
,
228 bool* message_was_ok
) {
230 IPC_BEGIN_MESSAGE_MAP_EX(WebSocketHost
, message
, *message_was_ok
)
231 IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest
, OnAddChannelRequest
)
232 IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame
, OnSendFrame
)
233 IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl
, OnFlowControl
)
234 IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel
, OnDropChannel
)
235 IPC_MESSAGE_UNHANDLED(handled
= false)
236 IPC_END_MESSAGE_MAP_EX()
240 void WebSocketHost::OnAddChannelRequest(
241 const GURL
& socket_url
,
242 const std::vector
<std::string
>& requested_protocols
,
243 const GURL
& origin
) {
244 DVLOG(3) << "WebSocketHost::OnAddChannelRequest"
245 << " routing_id=" << routing_id_
<< " socket_url=\"" << socket_url
246 << "\" requested_protocols=\""
247 << JoinString(requested_protocols
, ", ") << "\" origin=\"" << origin
250 channel_
->SendAddChannelRequest(socket_url
, requested_protocols
, origin
);
253 void WebSocketHost::OnSendFrame(bool fin
,
254 WebSocketMessageType type
,
255 const std::vector
<char>& data
) {
256 DVLOG(3) << "WebSocketHost::OnSendFrame"
257 << " routing_id=" << routing_id_
<< " fin=" << fin
258 << " type=" << type
<< " data is " << data
.size() << " bytes";
260 channel_
->SendFrame(fin
, MessageTypeToOpCode(type
), data
);
263 void WebSocketHost::OnFlowControl(int64 quota
) {
264 DVLOG(3) << "WebSocketHost::OnFlowControl"
265 << " routing_id=" << routing_id_
<< " quota=" << quota
;
267 channel_
->SendFlowControl(quota
);
270 void WebSocketHost::OnDropChannel(bool was_clean
,
272 const std::string
& reason
) {
273 DVLOG(3) << "WebSocketHost::OnDropChannel"
274 << " routing_id=" << routing_id_
<< " was_clean=" << was_clean
275 << " code=" << code
<< " reason=\"" << reason
<< "\"";
277 // TODO(yhirano): Handle |was_clean| appropriately.
278 channel_
->StartClosingHandshake(code
, reason
);
281 } // namespace content