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 9 #include "base/callback.h" 10 #include "base/logging.h" 11 #include "base/stl_util.h" 12 #include "content/browser/child_process_security_policy_impl.h" 13 #include "content/browser/renderer_host/websocket_host.h" 14 #include "content/common/websocket_messages.h" 15 16 namespace content { 17 18 namespace { 19 20 // Many methods defined in this file return a WebSocketHostState enum 21 // value. Make WebSocketHostState visible at file scope so it doesn't have to be 22 // fully-qualified every time. 23 typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState; 24 25 } // namespace 26 27 WebSocketDispatcherHost::WebSocketDispatcherHost( 28 int process_id, 29 const GetRequestContextCallback& get_context_callback) 30 : BrowserMessageFilter(WebSocketMsgStart), 31 process_id_(process_id), 32 get_context_callback_(get_context_callback), 33 websocket_host_factory_( 34 base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, 35 base::Unretained(this))) {} 36 37 WebSocketDispatcherHost::WebSocketDispatcherHost( 38 int process_id, 39 const GetRequestContextCallback& get_context_callback, 40 const WebSocketHostFactory& websocket_host_factory) 41 : BrowserMessageFilter(WebSocketMsgStart), 42 process_id_(process_id), 43 get_context_callback_(get_context_callback), 44 websocket_host_factory_(websocket_host_factory) {} 45 46 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) { 47 return new WebSocketHost(routing_id, this, get_context_callback_.Run()); 48 } 49 50 bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { 51 switch (message.type()) { 52 case WebSocketHostMsg_AddChannelRequest::ID: 53 case WebSocketMsg_SendFrame::ID: 54 case WebSocketMsg_FlowControl::ID: 55 case WebSocketMsg_DropChannel::ID: 56 break; 57 58 default: 59 // Every message that has not been handled by a previous filter passes 60 // through here, so it is good to pass them on as efficiently as possible. 61 return false; 62 } 63 64 int routing_id = message.routing_id(); 65 WebSocketHost* host = GetHost(routing_id); 66 if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) { 67 if (host) { 68 DVLOG(1) << "routing_id=" << routing_id << " already in use."; 69 // The websocket multiplexing spec says to should drop the physical 70 // connection in this case, but there isn't a real physical connection 71 // to the renderer, and killing the renderer for this would seem to be a 72 // little extreme. So for now just ignore the bogus request. 73 return true; // We handled the message (by ignoring it). 74 } 75 host = websocket_host_factory_.Run(routing_id); 76 hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); 77 } 78 if (!host) { 79 DVLOG(1) << "Received invalid routing ID " << routing_id 80 << " from renderer."; 81 return true; // We handled the message (by ignoring it). 82 } 83 return host->OnMessageReceived(message); 84 } 85 86 bool WebSocketDispatcherHost::CanReadRawCookies() const { 87 ChildProcessSecurityPolicyImpl* policy = 88 ChildProcessSecurityPolicyImpl::GetInstance(); 89 return policy->CanReadRawCookies(process_id_); 90 } 91 92 WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const { 93 WebSocketHostTable::const_iterator it = hosts_.find(routing_id); 94 return it == hosts_.end() ? NULL : it->second; 95 } 96 97 WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) { 98 const uint32 message_type = message->type(); 99 const int32 message_routing_id = message->routing_id(); 100 if (!Send(message)) { 101 message = NULL; 102 DVLOG(1) << "Sending of message type " << message_type 103 << " failed. Dropping channel."; 104 DeleteWebSocketHost(message_routing_id); 105 return WEBSOCKET_HOST_DELETED; 106 } 107 return WEBSOCKET_HOST_ALIVE; 108 } 109 110 WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse( 111 int routing_id, 112 bool fail, 113 const std::string& selected_protocol, 114 const std::string& extensions) { 115 if (SendOrDrop(new WebSocketMsg_AddChannelResponse( 116 routing_id, fail, selected_protocol, extensions)) == 117 WEBSOCKET_HOST_DELETED) 118 return WEBSOCKET_HOST_DELETED; 119 if (fail) { 120 DeleteWebSocketHost(routing_id); 121 return WEBSOCKET_HOST_DELETED; 122 } 123 return WEBSOCKET_HOST_ALIVE; 124 } 125 126 WebSocketHostState WebSocketDispatcherHost::SendFrame( 127 int routing_id, 128 bool fin, 129 WebSocketMessageType type, 130 const std::vector<char>& data) { 131 return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data)); 132 } 133 134 WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id, 135 int64 quota) { 136 return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota)); 137 } 138 139 WebSocketHostState WebSocketDispatcherHost::NotifyClosingHandshake( 140 int routing_id) { 141 return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id)); 142 } 143 144 WebSocketHostState WebSocketDispatcherHost::NotifyStartOpeningHandshake( 145 int routing_id, const WebSocketHandshakeRequest& request) { 146 return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake( 147 routing_id, request)); 148 } 149 150 WebSocketHostState WebSocketDispatcherHost::NotifyFinishOpeningHandshake( 151 int routing_id, const WebSocketHandshakeResponse& response) { 152 return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake( 153 routing_id, response)); 154 } 155 156 WebSocketHostState WebSocketDispatcherHost::NotifyFailure( 157 int routing_id, 158 const std::string& message) { 159 if (SendOrDrop(new WebSocketMsg_NotifyFailure( 160 routing_id, message)) == WEBSOCKET_HOST_DELETED) { 161 return WEBSOCKET_HOST_DELETED; 162 } 163 DeleteWebSocketHost(routing_id); 164 return WEBSOCKET_HOST_DELETED; 165 } 166 167 WebSocketHostState WebSocketDispatcherHost::DoDropChannel( 168 int routing_id, 169 bool was_clean, 170 uint16 code, 171 const std::string& reason) { 172 if (SendOrDrop( 173 new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) == 174 WEBSOCKET_HOST_DELETED) 175 return WEBSOCKET_HOST_DELETED; 176 DeleteWebSocketHost(routing_id); 177 return WEBSOCKET_HOST_DELETED; 178 } 179 180 WebSocketDispatcherHost::~WebSocketDispatcherHost() { 181 STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end()); 182 } 183 184 void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) { 185 WebSocketHostTable::iterator it = hosts_.find(routing_id); 186 DCHECK(it != hosts_.end()); 187 delete it->second; 188 hosts_.erase(it); 189 } 190 191 } // namespace content 192