- add sources.
[platform/framework/web/crosswalk.git] / src / content / child / websocket_bridge.cc
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/child/websocket_bridge.h"
6
7 #include <stdint.h>
8 #include <string>
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "content/child/child_thread.h"
14 #include "content/child/websocket_dispatcher.h"
15 #include "content/common/websocket.h"
16 #include "content/common/websocket_messages.h"
17 #include "ipc/ipc_message.h"
18 #include "ipc/ipc_message_macros.h"
19 #include "url/gurl.h"
20 #include "third_party/WebKit/public/platform/WebSocketHandle.h"
21 #include "third_party/WebKit/public/platform/WebSocketHandleClient.h"
22 #include "third_party/WebKit/public/platform/WebString.h"
23 #include "third_party/WebKit/public/platform/WebURL.h"
24 #include "third_party/WebKit/public/platform/WebVector.h"
25
26 using WebKit::WebSocketHandle;
27 using WebKit::WebSocketHandleClient;
28 using WebKit::WebString;
29 using WebKit::WebURL;
30 using WebKit::WebVector;
31
32 namespace content {
33
34 WebSocketBridge::WebSocketBridge()
35     : channel_id_(kInvalidChannelId), client_(NULL) {}
36
37 WebSocketBridge::~WebSocketBridge() {
38   Disconnect();
39 }
40
41 bool WebSocketBridge::OnMessageReceived(const IPC::Message& msg) {
42   bool handled = true;
43   IPC_BEGIN_MESSAGE_MAP(WebSocketBridge, msg)
44     IPC_MESSAGE_HANDLER(WebSocketMsg_AddChannelResponse, DidConnect)
45     IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, DidReceiveData)
46     IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, DidReceiveFlowControl)
47     IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, DidClose)
48     IPC_MESSAGE_UNHANDLED(handled = false)
49   IPC_END_MESSAGE_MAP()
50   return handled;
51 }
52
53 void WebSocketBridge::DidConnect(bool fail,
54                                  const std::string& selected_protocol,
55                                  const std::string& extensions) {
56   WebSocketHandleClient* client = client_;
57   DVLOG(1) << "WebSocketBridge::DidConnect("
58            << fail << ", "
59            << selected_protocol << ", "
60            << extensions << ")";
61   if (fail)
62     Disconnect();
63   if (!client)
64     return;
65
66   WebString protocol_to_pass = WebString::fromUTF8(selected_protocol);
67   WebString extensions_to_pass = WebString::fromUTF8(extensions);
68   client->didConnect(this, fail, protocol_to_pass, extensions_to_pass);
69   // |this| can be deleted here.
70 }
71
72 void WebSocketBridge::DidReceiveData(bool fin,
73                                      WebSocketMessageType type,
74                                      const std::vector<char>& data) {
75   DVLOG(1) << "WebSocketBridge::DidReceiveData("
76            << fin << ", "
77            << type << ", "
78            << "(data size = " << data.size() << "))";
79   if (!client_)
80     return;
81
82   WebSocketHandle::MessageType type_to_pass =
83       WebSocketHandle::MessageTypeContinuation;
84   switch (type) {
85     case WEB_SOCKET_MESSAGE_TYPE_CONTINUATION:
86       type_to_pass = WebSocketHandle::MessageTypeContinuation;
87       break;
88     case WEB_SOCKET_MESSAGE_TYPE_TEXT:
89       type_to_pass = WebSocketHandle::MessageTypeText;
90       break;
91     case WEB_SOCKET_MESSAGE_TYPE_BINARY:
92       type_to_pass = WebSocketHandle::MessageTypeBinary;
93       break;
94   }
95   const char* data_to_pass = data.empty() ? NULL : &data[0];
96   client_->didReceiveData(this, fin, type_to_pass, data_to_pass, data.size());
97   // |this| can be deleted here.
98 }
99
100 void WebSocketBridge::DidReceiveFlowControl(int64_t quota) {
101   DVLOG(1) << "WebSocketBridge::DidReceiveFlowControl(" << quota << ")";
102   if (!client_)
103     return;
104
105   client_->didReceiveFlowControl(this, quota);
106   // |this| can be deleted here.
107 }
108
109 void WebSocketBridge::DidClose(unsigned short code,
110                                const std::string& reason) {
111   DVLOG(1) << "WebSocketBridge::DidClose("
112            << code << ", "
113            << reason << ")";
114   WebSocketHandleClient* client = client_;
115   Disconnect();
116   if (!client)
117     return;
118
119   WebString reason_to_pass = WebString::fromUTF8(reason);
120   client->didClose(this, code, reason_to_pass);
121   // |this| can be deleted here.
122 }
123
124 void WebSocketBridge::connect(
125     const WebURL& url,
126     const WebVector<WebString>& protocols,
127     const WebString& origin,
128     WebSocketHandleClient* client) {
129   DCHECK_EQ(kInvalidChannelId, channel_id_);
130   WebSocketDispatcher* dispatcher =
131       ChildThread::current()->websocket_dispatcher();
132   channel_id_ = dispatcher->AddBridge(this);
133   client_ = client;
134
135   std::vector<std::string> protocols_to_pass;
136   for (size_t i = 0; i < protocols.size(); ++i)
137     protocols_to_pass.push_back(protocols[i].utf8());
138   GURL origin_to_pass(origin.utf8());
139
140   DVLOG(1) << "Bridge#" << channel_id_ << " Connect("
141            << url << ", (" << JoinString(protocols_to_pass, ", ") << "), "
142            << origin_to_pass << ")";
143
144   ChildThread::current()->Send(
145       new WebSocketHostMsg_AddChannelRequest(channel_id_,
146                                              url,
147                                              protocols_to_pass,
148                                              origin_to_pass));
149 }
150
151 void WebSocketBridge::send(bool fin,
152                            WebSocketHandle::MessageType type,
153                            const char* data,
154                            size_t size) {
155   if (channel_id_ == kInvalidChannelId)
156     return;
157
158   WebSocketMessageType type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION;
159   switch (type) {
160     case WebSocketHandle::MessageTypeContinuation:
161       type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION;
162       break;
163     case WebSocketHandle::MessageTypeText:
164       type_to_pass = WEB_SOCKET_MESSAGE_TYPE_TEXT;
165       break;
166     case WebSocketHandle::MessageTypeBinary:
167       type_to_pass = WEB_SOCKET_MESSAGE_TYPE_BINARY;
168       break;
169   }
170
171   DVLOG(1) << "Bridge #" << channel_id_ << " Send("
172            << fin << ", " << type_to_pass << ", "
173            << "(data size = "  << size << "))";
174
175   ChildThread::current()->Send(
176       new WebSocketMsg_SendFrame(channel_id_,
177                                  fin,
178                                  type_to_pass,
179                                  std::vector<char>(data, data + size)));
180 }
181
182 void WebSocketBridge::flowControl(int64_t quota) {
183   if (channel_id_ == kInvalidChannelId)
184     return;
185
186   DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")";
187
188   ChildThread::current()->Send(
189       new WebSocketMsg_FlowControl(channel_id_, quota));
190 }
191
192 void WebSocketBridge::close(unsigned short code,
193                             const WebString& reason) {
194   if (channel_id_ == kInvalidChannelId)
195     return;
196
197   std::string reason_to_pass = reason.utf8();
198   DVLOG(1) << "Bridge #" << channel_id_ << " Close("
199            << code << ", " << reason_to_pass << ")";
200   ChildThread::current()->Send(
201       new WebSocketMsg_DropChannel(channel_id_, code, reason_to_pass));
202 }
203
204 void WebSocketBridge::Disconnect() {
205   if (channel_id_ == kInvalidChannelId)
206     return;
207   WebSocketDispatcher* dispatcher =
208       ChildThread::current()->websocket_dispatcher();
209   dispatcher->RemoveBridge(channel_id_);
210
211   channel_id_ = kInvalidChannelId;
212   client_ = NULL;
213 }
214
215 }  // namespace content