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_dispatcher_host.h"
10 #include "base/callback.h"
11 #include "base/logging.h"
12 #include "base/stl_util.h"
13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/renderer_host/websocket_host.h"
15 #include "content/common/websocket_messages.h"
21 // Many methods defined in this file return a WebSocketHostState enum
22 // value. Make WebSocketHostState visible at file scope so it doesn't have to be
23 // fully-qualified every time.
24 typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState
;
28 WebSocketDispatcherHost::WebSocketDispatcherHost(
30 const GetRequestContextCallback
& get_context_callback
)
31 : BrowserMessageFilter(WebSocketMsgStart
),
32 process_id_(process_id
),
33 get_context_callback_(get_context_callback
),
34 websocket_host_factory_(
35 base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost
,
36 base::Unretained(this))) {}
38 WebSocketDispatcherHost::WebSocketDispatcherHost(
40 const GetRequestContextCallback
& get_context_callback
,
41 const WebSocketHostFactory
& websocket_host_factory
)
42 : BrowserMessageFilter(WebSocketMsgStart
),
43 process_id_(process_id
),
44 get_context_callback_(get_context_callback
),
45 websocket_host_factory_(websocket_host_factory
) {}
47 WebSocketHost
* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id
) {
48 return new WebSocketHost(routing_id
, this, get_context_callback_
.Run());
51 bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message
& message
) {
52 switch (message
.type()) {
53 case WebSocketHostMsg_AddChannelRequest::ID
:
54 case WebSocketMsg_SendFrame::ID
:
55 case WebSocketMsg_FlowControl::ID
:
56 case WebSocketMsg_DropChannel::ID
:
60 // Every message that has not been handled by a previous filter passes
61 // through here, so it is good to pass them on as efficiently as possible.
65 int routing_id
= message
.routing_id();
66 WebSocketHost
* host
= GetHost(routing_id
);
67 if (message
.type() == WebSocketHostMsg_AddChannelRequest::ID
) {
69 DVLOG(1) << "routing_id=" << routing_id
<< " already in use.";
70 // The websocket multiplexing spec says to should drop the physical
71 // connection in this case, but there isn't a real physical connection
72 // to the renderer, and killing the renderer for this would seem to be a
73 // little extreme. So for now just ignore the bogus request.
74 return true; // We handled the message (by ignoring it).
76 host
= websocket_host_factory_
.Run(routing_id
);
77 hosts_
.insert(WebSocketHostTable::value_type(routing_id
, host
));
80 DVLOG(1) << "Received invalid routing ID " << routing_id
82 return true; // We handled the message (by ignoring it).
84 return host
->OnMessageReceived(message
);
87 bool WebSocketDispatcherHost::CanReadRawCookies() const {
88 ChildProcessSecurityPolicyImpl
* policy
=
89 ChildProcessSecurityPolicyImpl::GetInstance();
90 return policy
->CanReadRawCookies(process_id_
);
93 WebSocketHost
* WebSocketDispatcherHost::GetHost(int routing_id
) const {
94 WebSocketHostTable::const_iterator it
= hosts_
.find(routing_id
);
95 return it
== hosts_
.end() ? NULL
: it
->second
;
98 WebSocketHostState
WebSocketDispatcherHost::SendOrDrop(IPC::Message
* message
) {
99 const uint32 message_type
= message
->type();
100 const int32 message_routing_id
= message
->routing_id();
101 if (!Send(message
)) {
103 DVLOG(1) << "Sending of message type " << message_type
104 << " failed. Dropping channel.";
105 DeleteWebSocketHost(message_routing_id
);
106 return WEBSOCKET_HOST_DELETED
;
108 return WEBSOCKET_HOST_ALIVE
;
111 WebSocketHostState
WebSocketDispatcherHost::SendAddChannelResponse(
114 const std::string
& selected_protocol
,
115 const std::string
& extensions
) {
116 if (SendOrDrop(new WebSocketMsg_AddChannelResponse(
117 routing_id
, fail
, selected_protocol
, extensions
)) ==
118 WEBSOCKET_HOST_DELETED
)
119 return WEBSOCKET_HOST_DELETED
;
121 DeleteWebSocketHost(routing_id
);
122 return WEBSOCKET_HOST_DELETED
;
124 return WEBSOCKET_HOST_ALIVE
;
127 WebSocketHostState
WebSocketDispatcherHost::SendFrame(
130 WebSocketMessageType type
,
131 const std::vector
<char>& data
) {
132 return SendOrDrop(new WebSocketMsg_SendFrame(routing_id
, fin
, type
, data
));
135 WebSocketHostState
WebSocketDispatcherHost::SendFlowControl(int routing_id
,
137 return SendOrDrop(new WebSocketMsg_FlowControl(routing_id
, quota
));
140 WebSocketHostState
WebSocketDispatcherHost::NotifyClosingHandshake(
142 return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id
));
145 WebSocketHostState
WebSocketDispatcherHost::NotifyStartOpeningHandshake(
146 int routing_id
, const WebSocketHandshakeRequest
& request
) {
147 return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake(
148 routing_id
, request
));
151 WebSocketHostState
WebSocketDispatcherHost::NotifyFinishOpeningHandshake(
152 int routing_id
, const WebSocketHandshakeResponse
& response
) {
153 return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake(
154 routing_id
, response
));
157 WebSocketHostState
WebSocketDispatcherHost::NotifyFailure(
159 const std::string
& message
) {
160 if (SendOrDrop(new WebSocketMsg_NotifyFailure(
161 routing_id
, message
)) == WEBSOCKET_HOST_DELETED
) {
162 return WEBSOCKET_HOST_DELETED
;
164 DeleteWebSocketHost(routing_id
);
165 return WEBSOCKET_HOST_DELETED
;
168 WebSocketHostState
WebSocketDispatcherHost::DoDropChannel(
172 const std::string
& reason
) {
174 new WebSocketMsg_DropChannel(routing_id
, was_clean
, code
, reason
)) ==
175 WEBSOCKET_HOST_DELETED
)
176 return WEBSOCKET_HOST_DELETED
;
177 DeleteWebSocketHost(routing_id
);
178 return WEBSOCKET_HOST_DELETED
;
181 WebSocketDispatcherHost::~WebSocketDispatcherHost() {
182 std::vector
<WebSocketHost
*> hosts
;
183 for (base::hash_map
<int, WebSocketHost
*>::const_iterator i
= hosts_
.begin();
184 i
!= hosts_
.end(); ++i
) {
185 // In order to avoid changing the container while iterating, we copy
187 hosts
.push_back(i
->second
);
190 for (size_t i
= 0; i
< hosts
.size(); ++i
) {
191 // Note that some calls to GoAway could fail. In that case hosts[i] will be
192 // deleted and removed from |hosts_| in |DoDropChannel|.
197 STLDeleteContainerPairSecondPointers(hosts_
.begin(), hosts_
.end());
200 void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id
) {
201 WebSocketHostTable::iterator it
= hosts_
.find(routing_id
);
202 DCHECK(it
!= hosts_
.end());
207 } // namespace content