| Index: content/child/websocket_dispatcher.cc
|
| diff --git a/content/child/websocket_dispatcher.cc b/content/child/websocket_dispatcher.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bea7e01e3fe0e1db41ecf673285ab60d594031a0
|
| --- /dev/null
|
| +++ b/content/child/websocket_dispatcher.cc
|
| @@ -0,0 +1,302 @@
|
| +// Copyright (c) 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/child/websocket_dispatcher.h"
|
| +
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/id_map.h"
|
| +#include "base/lazy_instance.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "content/child/child_thread.h"
|
| +#include "content/common/websocket_messages.h"
|
| +#include "ipc/ipc_message.h"
|
| +#include "ipc/ipc_message_macros.h"
|
| +#include "url/gurl.h"
|
| +#include "webkit/child/websocket_handle_bridge.h"
|
| +#include "webkit/child/websocket_handle_delegate.h"
|
| +
|
| +using webkit_glue::WebSocketHandleBridge;
|
| +using webkit_glue::WebSocketHandleDelegate;
|
| +
|
| +namespace content {
|
| +
|
| +class IPCWebSocketHandleBridge : public WebSocketHandleBridge {
|
| + public:
|
| + explicit IPCWebSocketHandleBridge(WebSocketHandleDelegate* delegate);
|
| +
|
| + void DidConnect(bool succeed,
|
| + const std::string& selected_protocol,
|
| + const std::string& extensions);
|
| + void DidReceiveData(WebSocketHandleBridge::MessageType type,
|
| + const char* data,
|
| + size_t size,
|
| + bool fin);
|
| + void DidReceiveFlowControl(int64_t quota);
|
| + void DidClose(unsigned short code, const std::string& reason);
|
| +
|
| + // WebSocketHandleBridge functions.
|
| + virtual void Connect(const GURL& url,
|
| + const std::vector<std::string>& protocols,
|
| + const GURL& origin,
|
| + WebSocketHandleDelegate* delegate) OVERRIDE;
|
| + virtual void Send(WebSocketHandleBridge::MessageType type,
|
| + const char* data,
|
| + size_t size,
|
| + bool fin) OVERRIDE;
|
| + virtual void FlowControl(int64_t quota) OVERRIDE;
|
| + virtual void Close(unsigned short code, const std::string& reason) OVERRIDE;
|
| + virtual void Disconnect() OVERRIDE;
|
| +
|
| + static IPCWebSocketHandleBridge* Get(int channel_id);
|
| +
|
| + private:
|
| + virtual ~IPCWebSocketHandleBridge();
|
| + int channel_id_;
|
| + WebSocketHandleDelegate* delegate_;
|
| +
|
| + // Map from ID to bridge instance.
|
| + static base::LazyInstance<IDMap<IPCWebSocketHandleBridge> >::Leaky bridges;
|
| + const int INVALID_CHANNEL_ID = -1;
|
| +};
|
| +
|
| +base::LazyInstance<IDMap<IPCWebSocketHandleBridge> >::Leaky
|
| + IPCWebSocketHandleBridge::bridges = LAZY_INSTANCE_INITIALIZER;;
|
| +
|
| +IPCWebSocketHandleBridge::IPCWebSocketHandleBridge(
|
| + WebSocketHandleDelegate* delegate)
|
| + : channel_id_(INVALID_CHANNEL_ID)
|
| + , delegate_(delegate) {
|
| + channel_id_ = bridges.Get().Add(this);
|
| + DCHECK(delegate_);
|
| +
|
| + // To be released in Disconnect.
|
| + AddRef();
|
| +}
|
| +
|
| +IPCWebSocketHandleBridge::~IPCWebSocketHandleBridge() {
|
| + DCHECK_EQ(INVALID_CHANNEL_ID, channel_id_);
|
| + DCHECK(!delegate_);
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::DidConnect(bool succeed,
|
| + const std::string& selected_protocol,
|
| + const std::string& extensions) {
|
| + if (delegate_) {
|
| + delegate_->DidConnect(succeed, selected_protocol, extensions);
|
| + }
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::DidReceiveData(
|
| + WebSocketHandleBridge::MessageType type,
|
| + const char* data,
|
| + size_t size,
|
| + bool fin) {
|
| + if (delegate_) {
|
| + delegate_->DidReceiveData(type, data, size, fin);
|
| + }
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::DidReceiveFlowControl(int64_t quota) {
|
| + if (delegate_) {
|
| + delegate_->DidReceiveFlowControl(quota);
|
| + }
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::DidClose(unsigned short code,
|
| + const std::string& reason) {
|
| + if (delegate_) {
|
| + delegate_->DidClose(code, reason);
|
| + }
|
| + Disconnect();
|
| + // Disconnect() may delete this object.
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::Connect(
|
| + const GURL& url,
|
| + const std::vector<std::string>& protocols,
|
| + const GURL& origin,
|
| + WebSocketHandleDelegate* delegate) {
|
| + if (channel_id_ == INVALID_CHANNEL_ID) {
|
| + return;
|
| + }
|
| + DVLOG(1) << "Bridge#" << channel_id_ << " Connect("
|
| + << url << ", " << "(protocols)" << ", " << origin << ")";
|
| +
|
| + ChildThread::current()->Send(
|
| + new WebSocketHostMsg_AddChannelRequest(channel_id_,
|
| + url,
|
| + protocols,
|
| + origin));
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::Send(WebSocketHandleBridge::MessageType type,
|
| + const char* data,
|
| + size_t size,
|
| + bool fin) {
|
| + if (channel_id_ == INVALID_CHANNEL_ID) {
|
| + return;
|
| + }
|
| +
|
| + WebSocketMessageType type_to_pass;
|
| + switch (type) {
|
| + case WebSocketHandleBridge::MESSAGE_TYPE_CONTINUATION:
|
| + type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION;
|
| + break;
|
| + case WebSocketHandleBridge::MESSAGE_TYPE_TEXT:
|
| + type_to_pass = WEB_SOCKET_MESSAGE_TYPE_TEXT;
|
| + break;
|
| + case WebSocketHandleBridge::MESSAGE_TYPE_BINARY:
|
| + type_to_pass = WEB_SOCKET_MESSAGE_TYPE_BINARY;
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + DVLOG(1) << "Bridge #" << channel_id_ << " Send("
|
| + << fin << ", " << type_to_pass << ", "
|
| + << "(data size = " << size << "))";
|
| +
|
| + ChildThread::current()->Send(
|
| + new WebSocketMsg_SendFrame(channel_id_,
|
| + fin,
|
| + type_to_pass,
|
| + std::vector<char>(&data[0], &data[size])));
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::FlowControl(int64_t quota) {
|
| + if (channel_id_ == INVALID_CHANNEL_ID) {
|
| + return;
|
| + }
|
| + DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")";
|
| +
|
| + ChildThread::current()->Send(
|
| + new WebSocketMsg_FlowControl(channel_id_, quota));
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::Close(unsigned short code,
|
| + const std::string& reason) {
|
| + if (channel_id_ == INVALID_CHANNEL_ID) {
|
| + return;
|
| + }
|
| + DVLOG(1) << "Bridge #" << channel_id_ << " Close("
|
| + << code << ", " << reason << ")";
|
| + ChildThread::current()->Send(
|
| + new WebSocketMsg_DropChannel(channel_id_, code, reason));
|
| +}
|
| +
|
| +void IPCWebSocketHandleBridge::Disconnect() {
|
| + if (channel_id_ != INVALID_CHANNEL_ID) {
|
| + DCHECK(Get(channel_id_));
|
| + bridges.Get().Remove(channel_id_);
|
| + }
|
| +
|
| + channel_id_ = INVALID_CHANNEL_ID;
|
| + delegate_ = NULL;
|
| + Release();
|
| + // Release() may delete this object.
|
| +}
|
| +
|
| +IPCWebSocketHandleBridge* IPCWebSocketHandleBridge::Get(int channel_id) {
|
| + return bridges.Get().Lookup(channel_id);
|
| +}
|
| +
|
| +WebSocketDispatcher::WebSocketDispatcher() {}
|
| +
|
| +WebSocketHandleBridge* WebSocketDispatcher::CreateBridge(
|
| + WebSocketHandleDelegate* delegate) {
|
| + return new IPCWebSocketHandleBridge(delegate);
|
| +}
|
| +
|
| +bool WebSocketDispatcher::OnMessageReceived(const IPC::Message& msg) {
|
| + bool handled = true;
|
| + IPC_BEGIN_MESSAGE_MAP(WebSocketDispatcher, msg)
|
| + IPC_MESSAGE_HANDLER(WebSocketMsg_AddChannelResponse, OnConnected)
|
| + IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnReceivedData)
|
| + IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnReceivedFlowControl)
|
| + IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnClosed)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP()
|
| + return handled;
|
| +}
|
| +
|
| +void WebSocketDispatcher::OnConnected(int channel_id,
|
| + bool fail,
|
| + std::string selected_protocol,
|
| + std::string extensions) {
|
| + DVLOG(1) << "WebSocketDispathcer::OnConnected("
|
| + << channel_id << ", "
|
| + << fail << ", "
|
| + << selected_protocol << ", "
|
| + << extensions << ")";
|
| + IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id);
|
| + if (!bridge) {
|
| + DVLOG(1) << "No bridge for channel_id=" << channel_id;
|
| + return;
|
| + }
|
| + bridge->DidConnect(!fail, selected_protocol, extensions);
|
| +}
|
| +
|
| +void WebSocketDispatcher::OnReceivedData(int channel_id,
|
| + bool fin,
|
| + WebSocketMessageType type,
|
| + std::vector<char> data) {
|
| + DVLOG(1) << "WebSocketDispathcer::OnReceivedData("
|
| + << channel_id << ", "
|
| + << fin << ", "
|
| + << type << ", "
|
| + << "(data size = " << data.size() << "))";
|
| + IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id);
|
| + if (!bridge) {
|
| + DVLOG(1) << "No bridge for channel_id=" << channel_id;
|
| + return;
|
| + }
|
| + WebSocketHandleBridge::MessageType type_to_pass;
|
| + switch (type) {
|
| + case WEB_SOCKET_MESSAGE_TYPE_CONTINUATION:
|
| + type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_CONTINUATION;
|
| + break;
|
| + case WEB_SOCKET_MESSAGE_TYPE_TEXT:
|
| + type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_TEXT;
|
| + break;
|
| + case WEB_SOCKET_MESSAGE_TYPE_BINARY:
|
| + type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_BINARY;
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + bridge->DidReceiveData(type_to_pass, data.data(), data.size(), fin);
|
| +}
|
| +
|
| +void WebSocketDispatcher::OnReceivedFlowControl(int channel_id, int64 quota) {
|
| + DVLOG(1) << "WebSocketDispathcer::OnReceivedFlowControl("
|
| + << channel_id << ", "
|
| + << quota << ")";
|
| + IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id);
|
| + if (!bridge) {
|
| + DVLOG(1) << "No bridge for channel_id=" << channel_id;
|
| + return;
|
| + }
|
| + bridge->DidReceiveFlowControl(quota);
|
| +}
|
| +
|
| +void WebSocketDispatcher::OnClosed(int channel_id,
|
| + unsigned short code,
|
| + std::string reason) {
|
| + DVLOG(1) << "WebSocketDispathcer::OnClosed("
|
| + << channel_id << ", "
|
| + << code << ", "
|
| + << reason << ")";
|
| + IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id);
|
| + if (!bridge) {
|
| + DVLOG(1) << "No bridge for channel_id=" << channel_id;
|
| + return;
|
| + }
|
| + bridge->DidClose(code, reason);
|
| +}
|
| +
|
| +} // namespace content
|
|
|