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