Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: content/child/websocket_bridge.cc

Issue 2119973002: Port WebSockets to Mojo IPC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/websocket_bridge.h" 5 #include "content/child/websocket_bridge.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <string.h>
9
8 #include <string> 10 #include <string>
9 #include <utility> 11 #include <utility>
10 #include <vector> 12 #include <vector>
11 13
12 #include "base/logging.h" 14 #include "base/logging.h"
13 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
14 #include "content/child/child_thread_impl.h" 16 #include "content/public/common/service_registry.h"
15 #include "content/child/websocket_dispatcher.h"
16 #include "content/common/websocket.h"
17 #include "content/common/websocket_messages.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_message_macros.h"
20 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" 17 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
21 #include "third_party/WebKit/public/platform/WebString.h" 18 #include "third_party/WebKit/public/platform/WebString.h"
22 #include "third_party/WebKit/public/platform/WebURL.h" 19 #include "third_party/WebKit/public/platform/WebURL.h"
23 #include "third_party/WebKit/public/platform/WebVector.h" 20 #include "third_party/WebKit/public/platform/WebVector.h"
24 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandle. h" 21 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandle. h"
25 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandleC lient.h" 22 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandleC lient.h"
26 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keRequestInfo.h" 23 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keRequestInfo.h"
27 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keResponseInfo.h" 24 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keResponseInfo.h"
28 #include "url/gurl.h" 25 #include "url/gurl.h"
29 #include "url/origin.h" 26 #include "url/origin.h"
30 27
31 using blink::WebSecurityOrigin; 28 using blink::WebSecurityOrigin;
32 using blink::WebSocketHandle; 29 using blink::WebSocketHandle;
33 using blink::WebSocketHandleClient; 30 using blink::WebSocketHandleClient;
34 using blink::WebString; 31 using blink::WebString;
35 using blink::WebURL; 32 using blink::WebURL;
36 using blink::WebVector; 33 using blink::WebVector;
37 34
38 namespace content { 35 namespace content {
39 36
40 namespace { 37 namespace {
41 38
42 const unsigned short kAbnormalShutdownOpCode = 1006; 39 // XXX const unsigned short kAbnormalShutdownOpCode = 1006;
43 40
44 } // namespace 41 } // namespace
45 42
46 WebSocketBridge::WebSocketBridge() 43 WebSocketBridge::WebSocketBridge()
47 : channel_id_(kInvalidChannelId), 44 : client_(nullptr),
48 render_frame_id_(MSG_ROUTING_NONE), 45 client_binding_(this) {}
49 client_(NULL) {} 46
47 void WebSocketBridge::Initialize(ServiceRegistry* registry) {
48 registry->ConnectToRemoteService(mojo::GetProxy(&websocket_));
49
50 mojom::WebSocketClientPtr client;
Ben Goodger (Google) 2016/07/01 21:19:51 delete these two lines and then...
darin (slow to review) 2016/07/06 16:57:21 Done.
51 client_binding_.Bind(&client);
52
53 websocket_->Initialize(std::move(client));
Ben Goodger (Google) 2016/07/01 21:19:51 websocket_->Initialize(client_binding_.CreateInter
darin (slow to review) 2016/07/06 16:57:21 Done.
54 }
50 55
51 WebSocketBridge::~WebSocketBridge() { 56 WebSocketBridge::~WebSocketBridge() {
52 if (channel_id_ != kInvalidChannelId) {
53 // The connection is abruptly disconnected by the renderer without
54 // closing handshake.
55 ChildThreadImpl::current()->Send(
56 new WebSocketMsg_DropChannel(channel_id_,
57 false,
58 kAbnormalShutdownOpCode,
59 std::string()));
60 }
61 Disconnect();
62 } 57 }
63 58
64 bool WebSocketBridge::OnMessageReceived(const IPC::Message& msg) { 59 void WebSocketBridge::OnFailChannel(const mojo::String& message) {
65 bool handled = true; 60 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
66 IPC_BEGIN_MESSAGE_MAP(WebSocketBridge, msg) 61 << " OnFailChannel(" << message << ")";
67 IPC_MESSAGE_HANDLER(WebSocketMsg_AddChannelResponse, DidConnect)
68 IPC_MESSAGE_HANDLER(WebSocketMsg_NotifyStartOpeningHandshake,
69 DidStartOpeningHandshake)
70 IPC_MESSAGE_HANDLER(WebSocketMsg_NotifyFinishOpeningHandshake,
71 DidFinishOpeningHandshake)
72 IPC_MESSAGE_HANDLER(WebSocketMsg_NotifyFailure, DidFail)
73 IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, DidReceiveData)
74 IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, DidReceiveFlowControl)
75 IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, DidClose)
76 IPC_MESSAGE_HANDLER(WebSocketMsg_NotifyClosing,
77 DidStartClosingHandshake)
78 IPC_MESSAGE_UNHANDLED(handled = false)
79 IPC_END_MESSAGE_MAP()
80 return handled;
81 }
82 62
83 void WebSocketBridge::DidConnect(const std::string& selected_protocol,
84 const std::string& extensions) {
85 WebSocketHandleClient* client = client_;
86 DVLOG(1) << "WebSocketBridge::DidConnect("
87 << selected_protocol << ", "
88 << extensions << ")";
89 if (!client)
90 return;
91
92 WebString protocol_to_pass = WebString::fromUTF8(selected_protocol);
93 WebString extensions_to_pass = WebString::fromUTF8(extensions);
94 client->didConnect(this, protocol_to_pass, extensions_to_pass);
95 // |this| can be deleted here.
96 }
97
98 void WebSocketBridge::DidStartOpeningHandshake(
99 const WebSocketHandshakeRequest& request) {
100 DVLOG(1) << "WebSocketBridge::DidStartOpeningHandshake("
101 << request.url << ")";
102 // All strings are already encoded to ASCII in the browser.
103 blink::WebSocketHandshakeRequestInfo request_to_pass;
104 request_to_pass.setURL(WebURL(request.url));
105 for (size_t i = 0; i < request.headers.size(); ++i) {
106 const std::pair<std::string, std::string>& header = request.headers[i];
107 request_to_pass.addHeaderField(WebString::fromLatin1(header.first),
108 WebString::fromLatin1(header.second));
109 }
110 request_to_pass.setHeadersText(WebString::fromLatin1(request.headers_text));
111 client_->didStartOpeningHandshake(this, request_to_pass);
112 }
113
114 void WebSocketBridge::DidFinishOpeningHandshake(
115 const WebSocketHandshakeResponse& response) {
116 DVLOG(1) << "WebSocketBridge::DidFinishOpeningHandshake("
117 << response.url << ")";
118 // All strings are already encoded to ASCII in the browser.
119 blink::WebSocketHandshakeResponseInfo response_to_pass;
120 response_to_pass.setStatusCode(response.status_code);
121 response_to_pass.setStatusText(WebString::fromLatin1(response.status_text));
122 for (size_t i = 0; i < response.headers.size(); ++i) {
123 const std::pair<std::string, std::string>& header = response.headers[i];
124 response_to_pass.addHeaderField(WebString::fromLatin1(header.first),
125 WebString::fromLatin1(header.second));
126 }
127 response_to_pass.setHeadersText(WebString::fromLatin1(response.headers_text));
128 client_->didFinishOpeningHandshake(this, response_to_pass);
129 }
130
131 void WebSocketBridge::DidFail(const std::string& message) {
132 DVLOG(1) << "WebSocketBridge::DidFail(" << message << ")";
133 WebSocketHandleClient* client = client_; 63 WebSocketHandleClient* client = client_;
134 Disconnect(); 64 Disconnect();
135 if (!client) 65 if (!client)
136 return; 66 return;
137 67
138 WebString message_to_pass = WebString::fromUTF8(message); 68 client->didFail(this, WebString::fromUTF8(message));
139 client->didFail(this, message_to_pass);
140 // |this| can be deleted here. 69 // |this| can be deleted here.
141 } 70 }
142 71
143 void WebSocketBridge::DidReceiveData(bool fin, 72 void WebSocketBridge::OnStartOpeningHandshake(
144 WebSocketMessageType type, 73 mojom::WebSocketHandshakeRequestPtr request) {
145 const std::vector<char>& data) { 74 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
146 DVLOG(1) << "WebSocketBridge::DidReceiveData(" 75 << " OnStartOpeningHandshake(" << request->url << ")";
147 << fin << ", " 76 // All strings are already encoded to ASCII in the browser.
148 << type << ", " 77 blink::WebSocketHandshakeRequestInfo request_to_pass;
78 request_to_pass.setURL(WebURL(request->url));
79 for (size_t i = 0; i < request->headers.size(); ++i) {
80 const mojom::HttpHeaderPtr& header = request->headers[i];
81 request_to_pass.addHeaderField(WebString::fromLatin1(header->name),
82 WebString::fromLatin1(header->value));
83 }
84 request_to_pass.setHeadersText(WebString::fromLatin1(request->headers_text));
85 client_->didStartOpeningHandshake(this, request_to_pass);
86 }
87
88 void WebSocketBridge::OnFinishOpeningHandshake(
89 mojom::WebSocketHandshakeResponsePtr response) {
90 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
91 << " OnFinishOpeningHandshake(" << response->url << ")";
92
93 // All strings are already encoded to ASCII in the browser.
94 blink::WebSocketHandshakeResponseInfo response_to_pass;
95 response_to_pass.setStatusCode(response->status_code);
96 response_to_pass.setStatusText(WebString::fromLatin1(response->status_text));
97 for (size_t i = 0; i < response->headers.size(); ++i) {
98 const mojom::HttpHeaderPtr& header = response->headers[i];
99 response_to_pass.addHeaderField(WebString::fromLatin1(header->name),
100 WebString::fromLatin1(header->value));
101 }
102 response_to_pass.setHeadersText(
103 WebString::fromLatin1(response->headers_text));
104 client_->didFinishOpeningHandshake(this, response_to_pass);
105 }
106
107 void WebSocketBridge::OnAddChannelResponse(
108 const mojo::String& protocol,
109 const mojo::String& extensions) {
110 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
111 << " OnAddChannelResponse("
112 << protocol << ", " << extensions << ")";
113
114 if (!client_)
115 return;
116
117 client_->didConnect(this,
118 WebString::fromUTF8(protocol),
119 WebString::fromUTF8(extensions));
120 // |this| can be deleted here.
121 }
122
123 void WebSocketBridge::OnBlobSent() {
124 }
125
126 void WebSocketBridge::OnDataFrame(bool fin, mojom::WebSocketMessageType type,
127 mojo::Array<uint8_t> data) {
128 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
129 << " OnDataFrame(" << fin << ", " << type << ", "
149 << "(data size = " << data.size() << "))"; 130 << "(data size = " << data.size() << "))";
150 if (!client_) 131 if (!client_)
151 return; 132 return;
152 133
153 WebSocketHandle::MessageType type_to_pass = 134 WebSocketHandle::MessageType type_to_pass =
154 WebSocketHandle::MessageTypeContinuation; 135 WebSocketHandle::MessageTypeContinuation;
155 switch (type) { 136 switch (type) {
156 case WEB_SOCKET_MESSAGE_TYPE_CONTINUATION: 137 case mojom::WebSocketMessageType::CONTINUATION:
157 type_to_pass = WebSocketHandle::MessageTypeContinuation; 138 type_to_pass = WebSocketHandle::MessageTypeContinuation;
158 break; 139 break;
159 case WEB_SOCKET_MESSAGE_TYPE_TEXT: 140 case mojom::WebSocketMessageType::TEXT:
160 type_to_pass = WebSocketHandle::MessageTypeText; 141 type_to_pass = WebSocketHandle::MessageTypeText;
161 break; 142 break;
162 case WEB_SOCKET_MESSAGE_TYPE_BINARY: 143 case mojom::WebSocketMessageType::BINARY:
163 type_to_pass = WebSocketHandle::MessageTypeBinary; 144 type_to_pass = WebSocketHandle::MessageTypeBinary;
164 break; 145 break;
165 } 146 }
166 const char* data_to_pass = data.empty() ? NULL : &data[0]; 147 const char* data_to_pass =
148 reinterpret_cast<const char*>(data.empty() ? nullptr : &data[0]);
167 client_->didReceiveData(this, fin, type_to_pass, data_to_pass, data.size()); 149 client_->didReceiveData(this, fin, type_to_pass, data_to_pass, data.size());
168 // |this| can be deleted here. 150 // |this| can be deleted here.
169 } 151 }
170 152
171 void WebSocketBridge::DidReceiveFlowControl(int64_t quota) { 153 void WebSocketBridge::OnFlowControl(int64_t quota) {
172 DVLOG(1) << "WebSocketBridge::DidReceiveFlowControl(" << quota << ")"; 154 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
155 << " OnFlowControl(" << quota << ")";
173 if (!client_) 156 if (!client_)
174 return; 157 return;
175 158
176 client_->didReceiveFlowControl(this, quota); 159 client_->didReceiveFlowControl(this, quota);
177 // |this| can be deleted here. 160 // |this| can be deleted here.
178 } 161 }
179 162
180 void WebSocketBridge::DidClose(bool was_clean, 163 void WebSocketBridge::OnDropChannel(bool was_clean, uint16_t code,
181 unsigned short code, 164 const mojo::String& reason) {
182 const std::string& reason) { 165 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
183 DVLOG(1) << "WebSocketBridge::DidClose(" 166 << " OnDropChannel(" << was_clean << ", " << code << ", "
184 << was_clean << ", "
185 << code << ", "
186 << reason << ")"; 167 << reason << ")";
168
187 WebSocketHandleClient* client = client_; 169 WebSocketHandleClient* client = client_;
188 Disconnect(); 170 Disconnect();
189 if (!client) 171 if (!client)
190 return; 172 return;
191 173
192 WebString reason_to_pass = WebString::fromUTF8(reason); 174 client->didClose(this, was_clean, code, WebString::fromUTF8(reason));
193 client->didClose(this, was_clean, code, reason_to_pass);
194 // |this| can be deleted here. 175 // |this| can be deleted here.
195 } 176 }
196 177
197 void WebSocketBridge::DidStartClosingHandshake() { 178 void WebSocketBridge::OnClosingHandshake() {
198 DVLOG(1) << "WebSocketBridge::DidStartClosingHandshake()"; 179 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
180 << " OnClosingHandshake()";
199 if (!client_) 181 if (!client_)
200 return; 182 return;
201 183
202 client_->didStartClosingHandshake(this); 184 client_->didStartClosingHandshake(this);
203 // |this| can be deleted here. 185 // |this| can be deleted here.
204 } 186 }
205 187
206 void WebSocketBridge::connect(const WebURL& url, 188 void WebSocketBridge::connect(const WebURL& url,
207 const WebVector<WebString>& protocols, 189 const WebVector<WebString>& protocols,
208 const WebSecurityOrigin& origin, 190 const WebSecurityOrigin& origin,
209 WebSocketHandleClient* client) { 191 WebSocketHandleClient* client) {
210 DCHECK_EQ(kInvalidChannelId, channel_id_); 192 DCHECK(websocket_);
211 WebSocketDispatcher* dispatcher = 193
212 ChildThreadImpl::current()->websocket_dispatcher(); 194 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
213 channel_id_ = dispatcher->AddBridge(this); 195 << " Connect(" << url << ", " << origin.toString().utf8() << ")";
196
197 DCHECK(!client_);
214 client_ = client; 198 client_ = client;
215 199
216 std::vector<std::string> protocols_to_pass; 200 mojo::Array<mojo::String> protocols_to_pass;
217 for (size_t i = 0; i < protocols.size(); ++i) 201 for (size_t i = 0; i < protocols.size(); ++i)
218 protocols_to_pass.push_back(protocols[i].utf8()); 202 protocols_to_pass[i] = protocols[i].utf8();
219 203
220 DVLOG(1) << "Bridge#" << channel_id_ << " Connect(" << url << ", (" 204 websocket_->AddChannelRequest(url, std::move(protocols_to_pass), origin);
221 << base::JoinString(protocols_to_pass, ", ") << "), "
222 << origin.toString().utf8() << ")";
223
224 ChildThreadImpl::current()->Send(new WebSocketHostMsg_AddChannelRequest(
225 channel_id_, url, protocols_to_pass, origin, render_frame_id_));
226 } 205 }
227 206
228 void WebSocketBridge::send(bool fin, 207 void WebSocketBridge::send(bool fin,
229 WebSocketHandle::MessageType type, 208 WebSocketHandle::MessageType type,
230 const char* data, 209 const char* data,
231 size_t size) { 210 size_t size) {
232 if (channel_id_ == kInvalidChannelId) 211 DCHECK(websocket_);
233 return;
234 212
235 WebSocketMessageType type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION; 213 mojom::WebSocketMessageType type_to_pass;
236 switch (type) { 214 switch (type) {
237 case WebSocketHandle::MessageTypeContinuation: 215 case WebSocketHandle::MessageTypeContinuation:
238 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_CONTINUATION; 216 type_to_pass = mojom::WebSocketMessageType::CONTINUATION;
239 break; 217 break;
240 case WebSocketHandle::MessageTypeText: 218 case WebSocketHandle::MessageTypeText:
241 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_TEXT; 219 type_to_pass = mojom::WebSocketMessageType::TEXT;
242 break; 220 break;
243 case WebSocketHandle::MessageTypeBinary: 221 case WebSocketHandle::MessageTypeBinary:
244 type_to_pass = WEB_SOCKET_MESSAGE_TYPE_BINARY; 222 type_to_pass = mojom::WebSocketMessageType::BINARY;
245 break; 223 break;
224 default:
225 NOTREACHED();
226 return;
246 } 227 }
247 228
248 DVLOG(1) << "Bridge #" << channel_id_ << " Send(" 229 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
249 << fin << ", " << type_to_pass << ", " 230 << " Send(" << fin << ", " << type_to_pass << ", "
250 << "(data size = " << size << "))"; 231 << "(data size = " << size << "))";
251 232
252 ChildThreadImpl::current()->Send( 233 mojo::Array<uint8_t> data_to_pass(size);
253 new WebSocketMsg_SendFrame(channel_id_, 234 memcpy(&data_to_pass[0], data, size);
254 fin, 235
255 type_to_pass, 236 websocket_->SendFrame(fin, type_to_pass, std::move(data_to_pass));
256 std::vector<char>(data, data + size)));
257 } 237 }
258 238
259 void WebSocketBridge::flowControl(int64_t quota) { 239 void WebSocketBridge::flowControl(int64_t quota) {
260 if (channel_id_ == kInvalidChannelId) 240 DCHECK(websocket_);
261 return;
262 241
263 DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")"; 242 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
243 << " FlowControl(" << quota << ")";
264 244
265 ChildThreadImpl::current()->Send( 245 websocket_->SendFlowControl(quota);
266 new WebSocketMsg_FlowControl(channel_id_, quota));
267 } 246 }
268 247
269 void WebSocketBridge::close(unsigned short code, 248 void WebSocketBridge::close(unsigned short code,
270 const WebString& reason) { 249 const WebString& reason) {
271 if (channel_id_ == kInvalidChannelId) 250 DCHECK(websocket_);
272 return;
273 251
274 std::string reason_to_pass = reason.utf8(); 252 std::string reason_to_pass = reason.utf8();
275 DVLOG(1) << "Bridge #" << channel_id_ << " Close(" 253
276 << code << ", " << reason_to_pass << ")"; 254 DVLOG(1) << "Bridge @" << reinterpret_cast<void*>(this)
277 // This method is for closing handshake and hence |was_clean| shall be true. 255 << " Close(" << code << ", " << reason_to_pass << ")";
278 ChildThreadImpl::current()->Send( 256
279 new WebSocketMsg_DropChannel(channel_id_, true, code, reason_to_pass)); 257 websocket_->StartClosingHandshake(code, reason_to_pass);
280 } 258 }
281 259
282 void WebSocketBridge::Disconnect() { 260 void WebSocketBridge::Disconnect() {
283 if (channel_id_ == kInvalidChannelId) 261 websocket_.reset();
284 return; 262 client_ = nullptr;
285 WebSocketDispatcher* dispatcher =
286 ChildThreadImpl::current()->websocket_dispatcher();
287 dispatcher->RemoveBridge(channel_id_);
288
289 channel_id_ = kInvalidChannelId;
290 client_ = NULL;
291 } 263 }
292 264
293 } // namespace content 265 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698