websocket_dispatcher_host.cc revision f2477e01787aa58f445919b809d89e252beef54f
14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/browser/renderer_host/websocket_dispatcher_host.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string> 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/callback.h" 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/stl_util.h" 124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/browser/renderer_host/websocket_host.h" 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/common/websocket_messages.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace content { 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace { 181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Many methods defined in this file return a WebSocketHostState enum 201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// value. Make WebSocketHostState visible at file scope so it doesn't have to be 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// fully-qualified every time. 221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState; 231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDispatcherHost::WebSocketDispatcherHost( 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const GetRequestContextCallback& get_context_callback) 288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) : get_context_callback_(get_context_callback), 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) websocket_host_factory_( 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Unretained(this))) {} 328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)WebSocketDispatcherHost::WebSocketDispatcherHost( 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const GetRequestContextCallback& get_context_callback, 358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const WebSocketHostFactory& websocket_host_factory) 368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) : get_context_callback_(get_context_callback), 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) websocket_host_factory_(websocket_host_factory) {} 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) { 408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return new WebSocketHost(routing_id, this, get_context_callback_.Run()); 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message, 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool* message_was_ok) { 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) switch (message.type()) { 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketHostMsg_AddChannelRequest::ID: 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_SendFrame::ID: 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_FlowControl::ID: 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_DropChannel::ID: 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) default: 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Every message that has not been handled by a previous filter passes 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // through here, so it is good to pass them on as efficiently as possible. 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int routing_id = message.routing_id(); 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHost* host = GetHost(routing_id); 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) { 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (host) { 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "routing_id=" << routing_id << " already in use."; 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The websocket multiplexing spec says to should drop the physical 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // connection in this case, but there isn't a real physical connection 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // to the renderer, and killing the renderer for this would seem to be a 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // little extreme. So for now just ignore the bogus request. 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; // We handled the message (by ignoring it). 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) host = websocket_host_factory_.Run(routing_id); 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!host) { 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "Received invalid routing ID " << routing_id 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << " from renderer."; 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; // We handled the message (by ignoring it). 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return host->OnMessageReceived(message, message_was_ok); 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const { 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHostTable::const_iterator it = hosts_.find(routing_id); 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return it == hosts_.end() ? NULL : it->second; 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) { 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!Send(message)) { 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "Sending of message type " << message->type() 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << " failed. Dropping channel."; 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DeleteWebSocketHost(message->routing_id()); 901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_ALIVE; 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse( 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int routing_id, 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool fail, 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& selected_protocol, 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& extensions) { 1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (SendOrDrop(new WebSocketMsg_AddChannelResponse( 1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) routing_id, fail, selected_protocol, extensions)) == 1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WEBSOCKET_HOST_DELETED) 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (fail) { 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DeleteWebSocketHost(routing_id); 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_ALIVE; 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendFrame( 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int routing_id, 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool fin, 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketMessageType type, 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::vector<char>& data) { 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data)); 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id, 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int64 quota) { 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota)); 1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendClosing(int routing_id) { 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(ricea): Implement the SendClosing IPC. 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_ALIVE; 1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendStartOpeningHandshake( 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int routing_id, const WebSocketHandshakeRequest& request) { 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake( 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) routing_id, request)); 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendFinishOpeningHandshake( 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int routing_id, const WebSocketHandshakeResponse& response) { 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake( 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) routing_id, response)); 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::DoDropChannel( 1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int routing_id, 1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint16 code, 1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::string& reason) { 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool was_clean = true; 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (SendOrDrop( 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) == 1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WEBSOCKET_HOST_DELETED) 1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DeleteWebSocketHost(routing_id); 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDispatcherHost::~WebSocketDispatcherHost() { 1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end()); 1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) { 1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHostTable::iterator it = hosts_.find(routing_id); 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(it != hosts_.end()); 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) delete it->second; 1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) hosts_.erase(it); 1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace content 166