Home | History | Annotate | Download | only in renderer_host
      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