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