[WebSocket] Send (request|response)_headers_text to the inspector.
[chromium-blink-merge.git] / content / browser / renderer_host / websocket_host.cc
blobb4a7cee43f2520ee51e69b811db88ffb3c6f908d
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"
21 namespace content {
23 namespace {
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 {
81 public:
82 WebSocketEventHandler(WebSocketDispatcherHost* dispatcher, int routing_id);
83 virtual ~WebSocketEventHandler();
85 // net::WebSocketEventInterface implementation
87 virtual ChannelState OnAddChannelResponse(
88 bool fail,
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,
97 uint16 code,
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;
105 private:
106 WebSocketDispatcherHost* const dispatcher_;
107 const int routing_id_;
109 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
112 WebSocketEventHandler::WebSocketEventHandler(
113 WebSocketDispatcherHost* dispatcher,
114 int routing_id)
115 : dispatcher_(dispatcher), routing_id_(routing_id) {}
117 WebSocketEventHandler::~WebSocketEventHandler() {
118 DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_;
121 ChannelState WebSocketEventHandler::OnAddChannelResponse(
122 bool fail,
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(
134 bool fin,
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,
157 uint16 code,
158 const std::string& reason) {
159 DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
160 << " routing_id=" << routing_id_ << " was_clean=" << was_clean
161 << " code=" << code << " reason=\"" << reason << "\"";
162 return StateCast(
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);
180 while (it.GetNext())
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_,
189 request_to_pass));
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);
200 void* iter = NULL;
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_,
209 response_to_pass));
212 } // namespace
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));
221 channel_.reset(
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) {
229 bool handled = true;
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()
237 return handled;
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
248 << "\"";
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,
271 uint16 code,
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