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 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 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 47 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) { 48 return new WebSocketHost(routing_id, this, get_context_callback_.Run()); 49 } 50 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 87 bool WebSocketDispatcherHost::CanReadRawCookies() const { 88 ChildProcessSecurityPolicyImpl* policy = 89 ChildProcessSecurityPolicyImpl::GetInstance(); 90 return policy->CanReadRawCookies(process_id_); 91 } 92 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; 96 } 97 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 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 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 135 WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id, 136 int64 quota) { 137 return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota)); 138 } 139 140 WebSocketHostState WebSocketDispatcherHost::NotifyClosingHandshake( 141 int routing_id) { 142 return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id)); 143 } 144 145 WebSocketHostState WebSocketDispatcherHost::NotifyStartOpeningHandshake( 146 int routing_id, const WebSocketHandshakeRequest& request) { 147 return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake( 148 routing_id, request)); 149 } 150 151 WebSocketHostState WebSocketDispatcherHost::NotifyFinishOpeningHandshake( 152 int routing_id, const WebSocketHandshakeResponse& response) { 153 return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake( 154 routing_id, response)); 155 } 156 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 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 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 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