• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WebSocketDispatcherHost(const GetRequestContextCallback & get_context_callback)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 
WebSocketDispatcherHost(const GetRequestContextCallback & get_context_callback,const WebSocketHostFactory & websocket_host_factory)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 
CreateWebSocketHost(int routing_id)39 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) {
40   return new WebSocketHost(routing_id, this, get_context_callback_.Run());
41 }
42 
OnMessageReceived(const IPC::Message & message,bool * message_was_ok)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 
GetHost(int routing_id) const80 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 
SendOrDrop(IPC::Message * message)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 
SendAddChannelResponse(int routing_id,bool fail,const std::string & selected_protocol,const std::string & extensions)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 
SendFrame(int routing_id,bool fin,WebSocketMessageType type,const std::vector<char> & data)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 
SendFlowControl(int routing_id,int64 quota)122 WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id,
123                                                             int64 quota) {
124   return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota));
125 }
126 
SendClosing(int routing_id)127 WebSocketHostState WebSocketDispatcherHost::SendClosing(int routing_id) {
128   // TODO(ricea): Implement the SendClosing IPC.
129   return WEBSOCKET_HOST_ALIVE;
130 }
131 
SendStartOpeningHandshake(int routing_id,const WebSocketHandshakeRequest & request)132 WebSocketHostState WebSocketDispatcherHost::SendStartOpeningHandshake(
133     int routing_id, const WebSocketHandshakeRequest& request) {
134   return SendOrDrop(new WebSocketMsg_NotifyStartOpeningHandshake(
135       routing_id, request));
136 }
137 
SendFinishOpeningHandshake(int routing_id,const WebSocketHandshakeResponse & response)138 WebSocketHostState WebSocketDispatcherHost::SendFinishOpeningHandshake(
139     int routing_id, const WebSocketHandshakeResponse& response) {
140   return SendOrDrop(new WebSocketMsg_NotifyFinishOpeningHandshake(
141       routing_id, response));
142 }
143 
DoDropChannel(int routing_id,uint16 code,const std::string & reason)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 
~WebSocketDispatcherHost()157 WebSocketDispatcherHost::~WebSocketDispatcherHost() {
158   STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end());
159 }
160 
DeleteWebSocketHost(int routing_id)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