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 #include <vector>
      9 
     10 #include "base/callback.h"
     11 #include "base/logging.h"
     12 #include "base/stl_util.h"
     13 #include "content/browser/child_process_security_policy_impl.h"
     14 #include "content/browser/renderer_host/websocket_host.h"
     15 #include "content/common/websocket_messages.h"
     16 
     17 namespace content {
     18 
     19 namespace {
     20 
     21 // Many methods defined in this file return a WebSocketHostState enum
     22 // value. Make WebSocketHostState visible at file scope so it doesn't have to be
     23 // fully-qualified every time.
     24 typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState;
     25 
     26 }  // namespace
     27 
     28 WebSocketDispatcherHost::WebSocketDispatcherHost(
     29     int process_id,
     30     const GetRequestContextCallback& get_context_callback)
     31     : BrowserMessageFilter(WebSocketMsgStart),
     32       process_id_(process_id),
     33       get_context_callback_(get_context_callback),
     34       websocket_host_factory_(
     35           base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost,
     36                      base::Unretained(this))) {}
     37 
     38 WebSocketDispatcherHost::WebSocketDispatcherHost(
     39     int process_id,
     40     const GetRequestContextCallback& get_context_callback,
     41     const WebSocketHostFactory& websocket_host_factory)
     42     : BrowserMessageFilter(WebSocketMsgStart),
     43       process_id_(process_id),
     44       get_context_callback_(get_context_callback),
     45       websocket_host_factory_(websocket_host_factory) {}
     46 
     47 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) {
     48   return new WebSocketHost(routing_id, this, get_context_callback_.Run());
     49 }
     50 
     51 bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
     52   switch (message.type()) {
     53     case WebSocketHostMsg_AddChannelRequest::ID:
     54     case WebSocketMsg_SendFrame::ID:
     55     case WebSocketMsg_FlowControl::ID:
     56     case WebSocketMsg_DropChannel::ID:
     57       break;
     58 
     59     default:
     60       // Every message that has not been handled by a previous filter passes
     61       // through here, so it is good to pass them on as efficiently as possible.
     62       return false;
     63   }
     64 
     65   int routing_id = message.routing_id();
     66   WebSocketHost* host = GetHost(routing_id);
     67   if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) {
     68     if (host) {
     69       DVLOG(1) << "routing_id=" << routing_id << " already in use.";
     70       // The websocket multiplexing spec says to should drop the physical
     71       // connection in this case, but there isn't a real physical connection
     72       // to the renderer, and killing the renderer for this would seem to be a
     73       // little extreme. So for now just ignore the bogus request.
     74       return true;  // We handled the message (by ignoring it).
     75     }
     76     host = websocket_host_factory_.Run(routing_id);
     77     hosts_.insert(WebSocketHostTable::value_type(routing_id, host));
     78   }
     79   if (!host) {
     80     DVLOG(1) << "Received invalid routing ID " << routing_id
     81              << " from renderer.";
     82     return true;  // We handled the message (by ignoring it).
     83   }
     84   return host->OnMessageReceived(message);
     85 }
     86 
     87 bool WebSocketDispatcherHost::CanReadRawCookies() const {
     88   ChildProcessSecurityPolicyImpl* policy =
     89       ChildProcessSecurityPolicyImpl::GetInstance();
     90   return policy->CanReadRawCookies(process_id_);
     91 }
     92 
     93 WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const {
     94   WebSocketHostTable::const_iterator it = hosts_.find(routing_id);
     95   return it == hosts_.end() ? NULL : it->second;
     96 }
     97 
     98 WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) {
     99   const uint32 message_type = message->type();
    100   const int32 message_routing_id = message->routing_id();
    101   if (!Send(message)) {
    102     message = NULL;
    103     DVLOG(1) << "Sending of message type " << message_type
    104              << " failed. Dropping channel.";
    105     DeleteWebSocketHost(message_routing_id);
    106     return WEBSOCKET_HOST_DELETED;
    107   }
    108   return WEBSOCKET_HOST_ALIVE;
    109 }
    110 
    111 WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse(
    112     int routing_id,
    113     bool fail,
    114     const std::string& selected_protocol,
    115     const std::string& extensions) {
    116   if (SendOrDrop(new WebSocketMsg_AddChannelResponse(
    117           routing_id, fail, selected_protocol, extensions)) ==
    118       WEBSOCKET_HOST_DELETED)
    119     return WEBSOCKET_HOST_DELETED;
    120   if (fail) {
    121     DeleteWebSocketHost(routing_id);
    122     return WEBSOCKET_HOST_DELETED;
    123   }
    124   return WEBSOCKET_HOST_ALIVE;
    125 }
    126 
    127 WebSocketHostState WebSocketDispatcherHost::SendFrame(
    128     int routing_id,
    129     bool fin,
    130     WebSocketMessageType type,
    131     const std::vector<char>& data) {
    132   return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data));
    133 }
    134 
    135 WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id,
    136                                                             int64 quota) {
    137   return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota));
    138 }
    139 
    140 WebSocketHostState WebSocketDispatcherHost::NotifyClosingHandshake(
    141     int routing_id) {
    142   return SendOrDrop(new WebSocketMsg_NotifyClosing(routing_id));
    143 }
    144 
    145 WebSocketHostState WebSocketDispatcherHost::NotifyStartOpeningHandshake(
    146     int routing_id, const WebSocketHandshakeRequest& request) {
    147   return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake(
    148       routing_id, request));
    149 }
    150 
    151 WebSocketHostState WebSocketDispatcherHost::NotifyFinishOpeningHandshake(
    152     int routing_id, const WebSocketHandshakeResponse& response) {
    153   return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake(
    154       routing_id, response));
    155 }
    156 
    157 WebSocketHostState WebSocketDispatcherHost::NotifyFailure(
    158     int routing_id,
    159     const std::string& message) {
    160   if (SendOrDrop(new WebSocketMsg_NotifyFailure(
    161           routing_id, message)) == WEBSOCKET_HOST_DELETED) {
    162     return WEBSOCKET_HOST_DELETED;
    163   }
    164   DeleteWebSocketHost(routing_id);
    165   return WEBSOCKET_HOST_DELETED;
    166 }
    167 
    168 WebSocketHostState WebSocketDispatcherHost::DoDropChannel(
    169     int routing_id,
    170     bool was_clean,
    171     uint16 code,
    172     const std::string& reason) {
    173   if (SendOrDrop(
    174           new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) ==
    175       WEBSOCKET_HOST_DELETED)
    176     return WEBSOCKET_HOST_DELETED;
    177   DeleteWebSocketHost(routing_id);
    178   return WEBSOCKET_HOST_DELETED;
    179 }
    180 
    181 WebSocketDispatcherHost::~WebSocketDispatcherHost() {
    182   std::vector<WebSocketHost*> hosts;
    183   for (base::hash_map<int, WebSocketHost*>::const_iterator i = hosts_.begin();
    184        i != hosts_.end(); ++i) {
    185     // In order to avoid changing the container while iterating, we copy
    186     // the hosts.
    187     hosts.push_back(i->second);
    188   }
    189 
    190   for (size_t i = 0; i < hosts.size(); ++i) {
    191     // Note that some calls to GoAway could fail. In that case hosts[i] will be
    192     // deleted and removed from |hosts_| in |DoDropChannel|.
    193     hosts[i]->GoAway();
    194     hosts[i] = NULL;
    195   }
    196 
    197   STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end());
    198 }
    199 
    200 void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) {
    201   WebSocketHostTable::iterator it = hosts_.find(routing_id);
    202   DCHECK(it != hosts_.end());
    203   delete it->second;
    204   hosts_.erase(it);
    205 }
    206 
    207 }  // namespace content
    208