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