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