OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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_dispatcher.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/id_map.h" | |
11 #include "base/lazy_instance.h" | |
12 #include "base/memory/ref_counted.h" | |
13 #include "content/child/child_thread.h" | |
14 #include "content/common/websocket_messages.h" | |
15 #include "ipc/ipc_message.h" | |
16 #include "ipc/ipc_message_macros.h" | |
17 #include "url/gurl.h" | |
18 #include "webkit/child/websocket_handle_bridge.h" | |
19 #include "webkit/child/websocket_handle_delegate.h" | |
20 | |
21 using webkit_glue::WebSocketHandleBridge; | |
22 using webkit_glue::WebSocketHandleDelegate; | |
23 | |
24 namespace content { | |
25 | |
26 class IPCWebSocketHandleBridge : public WebSocketHandleBridge { | |
27 public: | |
28 explicit IPCWebSocketHandleBridge(WebSocketHandleDelegate* delegate); | |
29 | |
tyoshino (SeeGerritForStatus)
2013/09/03 08:46:47
// Methods called by WebSocketDispatcher
yhirano
2013/09/03 09:12:08
Done.
| |
30 void DidConnect(bool fail, | |
31 const std::string& selected_protocol, | |
32 const std::string& extensions); | |
33 void DidReceiveData(bool fin, | |
34 WebSocketHandleBridge::MessageType type, | |
35 const char* data, | |
36 size_t size); | |
37 void DidReceiveFlowControl(int64_t quota); | |
38 void DidClose(unsigned short code, const std::string& reason); | |
39 | |
40 // WebSocketHandleBridge functions. | |
41 virtual void Connect(const GURL& url, | |
42 const std::vector<std::string>& protocols, | |
43 const GURL& origin, | |
44 WebSocketHandleDelegate* delegate) OVERRIDE; | |
45 virtual void Send(bool fin, | |
46 WebSocketHandleBridge::MessageType type, | |
47 const char* data, | |
48 size_t size) OVERRIDE; | |
49 virtual void FlowControl(int64_t quota) OVERRIDE; | |
50 virtual void Close(unsigned short code, const std::string& reason) OVERRIDE; | |
51 virtual void Disconnect() OVERRIDE; | |
52 | |
53 static IPCWebSocketHandleBridge* Get(int channel_id); | |
54 | |
55 private: | |
56 virtual ~IPCWebSocketHandleBridge(); | |
57 int channel_id_; | |
58 WebSocketHandleDelegate* delegate_; | |
59 | |
60 // Map from ID to bridge instance. | |
61 static base::LazyInstance<IDMap<IPCWebSocketHandleBridge> >::Leaky bridges_; | |
62 const int INVALID_CHANNEL_ID = -1; | |
63 }; | |
64 | |
65 base::LazyInstance<IDMap<IPCWebSocketHandleBridge> >::Leaky | |
66 IPCWebSocketHandleBridge::bridges_ = LAZY_INSTANCE_INITIALIZER;; | |
67 | |
68 IPCWebSocketHandleBridge::IPCWebSocketHandleBridge( | |
69 WebSocketHandleDelegate* delegate) | |
70 : channel_id_(INVALID_CHANNEL_ID), | |
71 delegate_(delegate) { | |
72 channel_id_ = bridges_.Get().Add(this); | |
73 DCHECK(delegate_); | |
74 | |
75 // To be released in Disconnect. | |
76 AddRef(); | |
77 } | |
78 | |
79 IPCWebSocketHandleBridge::~IPCWebSocketHandleBridge() { | |
80 DCHECK_EQ(INVALID_CHANNEL_ID, channel_id_); | |
81 DCHECK(!delegate_); | |
82 } | |
83 | |
84 void IPCWebSocketHandleBridge::DidConnect(bool fail, | |
85 const std::string& selected_protocol, | |
86 const std::string& extensions) { | |
87 if (delegate_) { | |
88 delegate_->DidConnect(fail, selected_protocol, extensions); | |
89 } | |
90 } | |
91 | |
92 void IPCWebSocketHandleBridge::DidReceiveData( | |
93 bool fin, | |
94 WebSocketHandleBridge::MessageType type, | |
95 const char* data, | |
96 size_t size) { | |
97 if (delegate_) | |
98 delegate_->DidReceiveData(fin, type, data, size); | |
99 } | |
100 | |
101 void IPCWebSocketHandleBridge::DidReceiveFlowControl(int64_t quota) { | |
102 if (delegate_) | |
103 delegate_->DidReceiveFlowControl(quota); | |
104 } | |
105 | |
106 void IPCWebSocketHandleBridge::DidClose(unsigned short code, | |
107 const std::string& reason) { | |
108 if (delegate_) | |
109 delegate_->DidClose(code, reason); | |
110 Disconnect(); | |
111 // Disconnect() may delete this object. | |
112 } | |
113 | |
114 void IPCWebSocketHandleBridge::Connect( | |
115 const GURL& url, | |
116 const std::vector<std::string>& protocols, | |
117 const GURL& origin, | |
118 WebSocketHandleDelegate* delegate) { | |
119 if (channel_id_ == INVALID_CHANNEL_ID) | |
120 return; | |
121 | |
122 DVLOG(1) << "Bridge#" << channel_id_ << " Connect(" | |
123 << url << ", " << "(" << JoinString(protocols, ", ") << ")" | |
124 << ", " << origin << ")"; | |
125 | |
126 ChildThread::current()->Send( | |
127 new WebSocketHostMsg_AddChannelRequest(channel_id_, | |
128 url, | |
129 protocols, | |
130 origin)); | |
131 } | |
132 | |
133 void IPCWebSocketHandleBridge::Send(bool fin, | |
134 WebSocketHandleBridge::MessageType type, | |
135 const char* data, | |
136 size_t size) { | |
137 if (channel_id_ == INVALID_CHANNEL_ID) | |
138 return; | |
139 | |
140 WebSocketMessageType type_to_pass; | |
141 switch (type) { | |
142 case WebSocketHandleBridge::MESSAGE_TYPE_CONTINUATION: | |
143 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION; | |
144 break; | |
145 case WebSocketHandleBridge::MESSAGE_TYPE_TEXT: | |
146 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_TEXT; | |
147 break; | |
148 case WebSocketHandleBridge::MESSAGE_TYPE_BINARY: | |
149 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_BINARY; | |
150 break; | |
151 default: | |
152 NOTREACHED(); | |
153 break; | |
154 } | |
155 | |
156 DVLOG(1) << "Bridge #" << channel_id_ << " Send(" | |
157 << fin << ", " << type_to_pass << ", " | |
158 << "(data size = " << size << "))"; | |
159 | |
160 ChildThread::current()->Send( | |
161 new WebSocketMsg_SendFrame(channel_id_, | |
162 fin, | |
163 type_to_pass, | |
164 std::vector<char>(&data[0], &data[size]))); | |
165 } | |
166 | |
167 void IPCWebSocketHandleBridge::FlowControl(int64_t quota) { | |
168 if (channel_id_ == INVALID_CHANNEL_ID) | |
169 return; | |
170 | |
171 DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")"; | |
172 | |
173 ChildThread::current()->Send( | |
174 new WebSocketMsg_FlowControl(channel_id_, quota)); | |
175 } | |
176 | |
177 void IPCWebSocketHandleBridge::Close(unsigned short code, | |
178 const std::string& reason) { | |
179 if (channel_id_ == INVALID_CHANNEL_ID) | |
180 return; | |
181 | |
182 DVLOG(1) << "Bridge #" << channel_id_ << " Close(" | |
183 << code << ", " << reason << ")"; | |
184 ChildThread::current()->Send( | |
185 new WebSocketMsg_DropChannel(channel_id_, code, reason)); | |
186 } | |
187 | |
188 void IPCWebSocketHandleBridge::Disconnect() { | |
189 if (channel_id_ != INVALID_CHANNEL_ID) { | |
190 DCHECK(Get(channel_id_)); | |
191 bridges_.Get().Remove(channel_id_); | |
192 } | |
193 | |
194 channel_id_ = INVALID_CHANNEL_ID; | |
195 delegate_ = NULL; | |
196 Release(); | |
197 // Release() may delete this object. | |
198 } | |
199 | |
200 // static | |
201 IPCWebSocketHandleBridge* IPCWebSocketHandleBridge::Get(int channel_id) { | |
202 return bridges_.Get().Lookup(channel_id); | |
203 } | |
204 | |
205 WebSocketDispatcher::WebSocketDispatcher() {} | |
206 | |
207 WebSocketHandleBridge* WebSocketDispatcher::CreateBridge( | |
208 WebSocketHandleDelegate* delegate) { | |
209 return new IPCWebSocketHandleBridge(delegate); | |
210 } | |
211 | |
212 bool WebSocketDispatcher::OnMessageReceived(const IPC::Message& msg) { | |
213 bool handled = true; | |
214 IPC_BEGIN_MESSAGE_MAP(WebSocketDispatcher, msg) | |
215 IPC_MESSAGE_HANDLER(WebSocketMsg_AddChannelResponse, OnConnected) | |
216 IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnReceivedData) | |
217 IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnReceivedFlowControl) | |
218 IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnClosed) | |
219 IPC_MESSAGE_UNHANDLED(handled = false) | |
220 IPC_END_MESSAGE_MAP() | |
221 return handled; | |
222 } | |
223 | |
224 void WebSocketDispatcher::OnConnected(int channel_id, | |
225 bool fail, | |
226 std::string selected_protocol, | |
227 std::string extensions) { | |
228 DVLOG(1) << "WebSocketDispathcer::OnConnected(" | |
229 << channel_id << ", " | |
230 << fail << ", " | |
231 << selected_protocol << ", " | |
232 << extensions << ")"; | |
233 IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id); | |
234 if (!bridge) { | |
235 DVLOG(1) << "No bridge for channel_id=" << channel_id; | |
236 return; | |
237 } | |
238 bridge->DidConnect(fail, selected_protocol, extensions); | |
239 } | |
240 | |
241 void WebSocketDispatcher::OnReceivedData(int channel_id, | |
242 bool fin, | |
243 WebSocketMessageType type, | |
244 std::vector<char> data) { | |
245 DVLOG(1) << "WebSocketDispathcer::OnReceivedData(" | |
246 << channel_id << ", " | |
247 << fin << ", " | |
248 << type << ", " | |
249 << "(data size = " << data.size() << "))"; | |
250 IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id); | |
251 if (!bridge) { | |
252 DVLOG(1) << "No bridge for channel_id=" << channel_id; | |
253 return; | |
254 } | |
255 WebSocketHandleBridge::MessageType type_to_pass; | |
256 switch (type) { | |
257 case WEB_SOCKET_MESSAGE_TYPE_CONTINUATION: | |
258 type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_CONTINUATION; | |
259 break; | |
260 case WEB_SOCKET_MESSAGE_TYPE_TEXT: | |
261 type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_TEXT; | |
262 break; | |
263 case WEB_SOCKET_MESSAGE_TYPE_BINARY: | |
264 type_to_pass = WebSocketHandleBridge::MESSAGE_TYPE_BINARY; | |
265 break; | |
266 default: | |
267 NOTREACHED(); | |
268 break; | |
269 } | |
270 bridge->DidReceiveData(fin, type_to_pass, data.data(), data.size()); | |
271 } | |
272 | |
273 void WebSocketDispatcher::OnReceivedFlowControl(int channel_id, int64 quota) { | |
274 DVLOG(1) << "WebSocketDispathcer::OnReceivedFlowControl(" | |
275 << channel_id << ", " | |
276 << quota << ")"; | |
277 IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id); | |
278 if (!bridge) { | |
279 DVLOG(1) << "No bridge for channel_id=" << channel_id; | |
280 return; | |
281 } | |
282 bridge->DidReceiveFlowControl(quota); | |
283 } | |
284 | |
285 void WebSocketDispatcher::OnClosed(int channel_id, | |
286 unsigned short code, | |
287 std::string reason) { | |
288 DVLOG(1) << "WebSocketDispathcer::OnClosed(" | |
289 << channel_id << ", " | |
290 << code << ", " | |
291 << reason << ")"; | |
292 IPCWebSocketHandleBridge* bridge = IPCWebSocketHandleBridge::Get(channel_id); | |
293 if (!bridge) { | |
294 DVLOG(1) << "No bridge for channel_id=" << channel_id; | |
295 return; | |
296 } | |
297 bridge->DidClose(code, reason); | |
298 } | |
299 | |
300 } // namespace content | |
OLD | NEW |