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> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <vector> 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/callback.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h" 124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/stl_util.h" 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/browser/child_process_security_policy_impl.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/browser/renderer_host/websocket_host.h" 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/common/websocket_messages.h" 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace content { 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace { 201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Many methods defined in this file return a WebSocketHostState enum 221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// value. Make WebSocketHostState visible at file scope so it doesn't have to be 231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// fully-qualified every time. 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState; 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDispatcherHost::WebSocketDispatcherHost( 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch int process_id, 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const GetRequestContextCallback& get_context_callback) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : BrowserMessageFilter(WebSocketMsgStart), 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch process_id_(process_id), 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) get_context_callback_(get_context_callback), 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) websocket_host_factory_( 358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, 368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Unretained(this))) {} 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)WebSocketDispatcherHost::WebSocketDispatcherHost( 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch int process_id, 408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const GetRequestContextCallback& get_context_callback, 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const WebSocketHostFactory& websocket_host_factory) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : BrowserMessageFilter(WebSocketMsgStart), 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch process_id_(process_id), 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) get_context_callback_(get_context_callback), 458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) websocket_host_factory_(websocket_host_factory) {} 468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) { 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return new WebSocketHost(routing_id, this, get_context_callback_.Run()); 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) switch (message.type()) { 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketHostMsg_AddChannelRequest::ID: 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_SendFrame::ID: 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_FlowControl::ID: 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case WebSocketMsg_DropChannel::ID: 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) default: 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Every message that has not been handled by a previous filter passes 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // through here, so it is good to pass them on as efficiently as possible. 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int routing_id = message.routing_id(); 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHost* host = GetHost(routing_id); 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) { 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (host) { 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "routing_id=" << routing_id << " already in use."; 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The websocket multiplexing spec says to should drop the physical 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // connection in this case, but there isn't a real physical connection 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // to the renderer, and killing the renderer for this would seem to be a 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // little extreme. So for now just ignore the bogus request. 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; // We handled the message (by ignoring it). 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) host = websocket_host_factory_.Run(routing_id); 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!host) { 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "Received invalid routing ID " << routing_id 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << " from renderer."; 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; // We handled the message (by ignoring it). 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return host->OnMessageReceived(message); 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool WebSocketDispatcherHost::CanReadRawCookies() const { 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ChildProcessSecurityPolicyImpl* policy = 89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ChildProcessSecurityPolicyImpl::GetInstance(); 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return policy->CanReadRawCookies(process_id_); 91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const { 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHostTable::const_iterator it = hosts_.find(routing_id); 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return it == hosts_.end() ? NULL : it->second; 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) { 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const uint32 message_type = message->type(); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int32 message_routing_id = message->routing_id(); 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!Send(message)) { 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) message = NULL; 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(1) << "Sending of message type " << message_type 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << " failed. Dropping channel."; 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeleteWebSocketHost(message_routing_id); 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_ALIVE; 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse( 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int routing_id, 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool fail, 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& selected_protocol, 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& extensions) { 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (SendOrDrop(new WebSocketMsg_AddChannelResponse( 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) routing_id, fail, selected_protocol, extensions)) == 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WEBSOCKET_HOST_DELETED) 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (fail) { 1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DeleteWebSocketHost(routing_id); 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_ALIVE; 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendFrame( 1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int routing_id, 1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool fin, 1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketMessageType type, 1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::vector<char>& data) { 1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data)); 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id, 1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int64 quota) { 1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota)); 1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::NotifyClosingHandshake( 14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int routing_id) { 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id)); 1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::NotifyStartOpeningHandshake( 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int routing_id, const WebSocketHandshakeRequest& request) { 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake( 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) routing_id, request)); 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 15123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::NotifyFinishOpeningHandshake( 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int routing_id, const WebSocketHandshakeResponse& response) { 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake( 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) routing_id, response)); 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::NotifyFailure( 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int routing_id, 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& message) { 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (SendOrDrop(new WebSocketMsg_NotifyFailure( 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) routing_id, message)) == WEBSOCKET_HOST_DELETED) { 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeleteWebSocketHost(routing_id); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebSocketHostState WebSocketDispatcherHost::DoDropChannel( 1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int routing_id, 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool was_clean, 1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint16 code, 1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::string& reason) { 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (SendOrDrop( 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) == 1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WEBSOCKET_HOST_DELETED) 1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DeleteWebSocketHost(routing_id); 1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WEBSOCKET_HOST_DELETED; 1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDispatcherHost::~WebSocketDispatcherHost() { 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<WebSocketHost*> hosts; 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (base::hash_map<int, WebSocketHost*>::const_iterator i = hosts_.begin(); 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) i != hosts_.end(); ++i) { 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // In order to avoid changing the container while iterating, we copy 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // the hosts. 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hosts.push_back(i->second); 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < hosts.size(); ++i) { 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Note that some calls to GoAway could fail. In that case hosts[i] will be 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // deleted and removed from |hosts_| in |DoDropChannel|. 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hosts[i]->GoAway(); 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hosts[i] = NULL; 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end()); 1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) { 2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WebSocketHostTable::iterator it = hosts_.find(routing_id); 2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(it != hosts_.end()); 2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) delete it->second; 2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) hosts_.erase(it); 2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace content 208