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