• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_dispatcher_host.h"
6 
7 #include <string>
8 #include <vector>
9 
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"
16 
17 namespace content {
18 
19 namespace {
20 
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;
25 
26 }  // namespace
27 
WebSocketDispatcherHost(int process_id,const GetRequestContextCallback & get_context_callback)28 WebSocketDispatcherHost::WebSocketDispatcherHost(
29     int process_id,
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))) {}
37 
WebSocketDispatcherHost(int process_id,const GetRequestContextCallback & get_context_callback,const WebSocketHostFactory & websocket_host_factory)38 WebSocketDispatcherHost::WebSocketDispatcherHost(
39     int process_id,
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) {}
46 
CreateWebSocketHost(int routing_id)47 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) {
48   return new WebSocketHost(routing_id, this, get_context_callback_.Run());
49 }
50 
OnMessageReceived(const IPC::Message & message)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:
57       break;
58 
59     default:
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.
62       return false;
63   }
64 
65   int routing_id = message.routing_id();
66   WebSocketHost* host = GetHost(routing_id);
67   if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) {
68     if (host) {
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).
75     }
76     host = websocket_host_factory_.Run(routing_id);
77     hosts_.insert(WebSocketHostTable::value_type(routing_id, host));
78   }
79   if (!host) {
80     DVLOG(1) << "Received invalid routing ID " << routing_id
81              << " from renderer.";
82     return true;  // We handled the message (by ignoring it).
83   }
84   return host->OnMessageReceived(message);
85 }
86 
CanReadRawCookies() const87 bool WebSocketDispatcherHost::CanReadRawCookies() const {
88   ChildProcessSecurityPolicyImpl* policy =
89       ChildProcessSecurityPolicyImpl::GetInstance();
90   return policy->CanReadRawCookies(process_id_);
91 }
92 
GetHost(int routing_id) const93 WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const {
94   WebSocketHostTable::const_iterator it = hosts_.find(routing_id);
95   return it == hosts_.end() ? NULL : it->second;
96 }
97 
SendOrDrop(IPC::Message * message)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)) {
102     message = NULL;
103     DVLOG(1) << "Sending of message type " << message_type
104              << " failed. Dropping channel.";
105     DeleteWebSocketHost(message_routing_id);
106     return WEBSOCKET_HOST_DELETED;
107   }
108   return WEBSOCKET_HOST_ALIVE;
109 }
110 
SendAddChannelResponse(int routing_id,bool fail,const std::string & selected_protocol,const std::string & extensions)111 WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse(
112     int routing_id,
113     bool fail,
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;
120   if (fail) {
121     DeleteWebSocketHost(routing_id);
122     return WEBSOCKET_HOST_DELETED;
123   }
124   return WEBSOCKET_HOST_ALIVE;
125 }
126 
SendFrame(int routing_id,bool fin,WebSocketMessageType type,const std::vector<char> & data)127 WebSocketHostState WebSocketDispatcherHost::SendFrame(
128     int routing_id,
129     bool fin,
130     WebSocketMessageType type,
131     const std::vector<char>& data) {
132   return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data));
133 }
134 
SendFlowControl(int routing_id,int64 quota)135 WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id,
136                                                             int64 quota) {
137   return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota));
138 }
139 
NotifyClosingHandshake(int routing_id)140 WebSocketHostState WebSocketDispatcherHost::NotifyClosingHandshake(
141     int routing_id) {
142   return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id));
143 }
144 
NotifyStartOpeningHandshake(int routing_id,const WebSocketHandshakeRequest & request)145 WebSocketHostState WebSocketDispatcherHost::NotifyStartOpeningHandshake(
146     int routing_id, const WebSocketHandshakeRequest& request) {
147   return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake(
148       routing_id, request));
149 }
150 
NotifyFinishOpeningHandshake(int routing_id,const WebSocketHandshakeResponse & response)151 WebSocketHostState WebSocketDispatcherHost::NotifyFinishOpeningHandshake(
152     int routing_id, const WebSocketHandshakeResponse& response) {
153   return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake(
154       routing_id, response));
155 }
156 
NotifyFailure(int routing_id,const std::string & message)157 WebSocketHostState WebSocketDispatcherHost::NotifyFailure(
158     int routing_id,
159     const std::string& message) {
160   if (SendOrDrop(new WebSocketMsg_NotifyFailure(
161           routing_id, message)) == WEBSOCKET_HOST_DELETED) {
162     return WEBSOCKET_HOST_DELETED;
163   }
164   DeleteWebSocketHost(routing_id);
165   return WEBSOCKET_HOST_DELETED;
166 }
167 
DoDropChannel(int routing_id,bool was_clean,uint16 code,const std::string & reason)168 WebSocketHostState WebSocketDispatcherHost::DoDropChannel(
169     int routing_id,
170     bool was_clean,
171     uint16 code,
172     const std::string& reason) {
173   if (SendOrDrop(
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;
179 }
180 
~WebSocketDispatcherHost()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
186     // the hosts.
187     hosts.push_back(i->second);
188   }
189 
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|.
193     hosts[i]->GoAway();
194     hosts[i] = NULL;
195   }
196 
197   STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end());
198 }
199 
DeleteWebSocketHost(int routing_id)200 void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) {
201   WebSocketHostTable::iterator it = hosts_.find(routing_id);
202   DCHECK(it != hosts_.end());
203   delete it->second;
204   hosts_.erase(it);
205 }
206 
207 }  // namespace content
208