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