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

Side by Side Diff: content/browser/websockets/websocket_impl.cc

Issue 2119973002: Port WebSockets to Mojo IPC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleanup 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
(Empty)
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/browser/websockets/websocket_impl.h"
6
7 #include <inttypes.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/threading/thread_task_runner_handle.h"
21 #include "content/browser/bad_message.h"
22 #include "content/browser/child_process_security_policy_impl.h"
23 #include "content/browser/ssl/ssl_error_handler.h"
24 #include "content/browser/ssl/ssl_manager.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "ipc/ipc_message.h"
27 #include "net/base/net_errors.h"
28 #include "net/http/http_request_headers.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/http/http_util.h"
31 #include "net/ssl/ssl_info.h"
32 #include "net/url_request/url_request_context_getter.h"
33 #include "net/websockets/websocket_channel.h"
34 #include "net/websockets/websocket_errors.h"
35 #include "net/websockets/websocket_event_interface.h"
36 #include "net/websockets/websocket_frame.h" // for WebSocketFrameHeader::OpCode
37 #include "net/websockets/websocket_handshake_request_info.h"
38 #include "net/websockets/websocket_handshake_response_info.h"
39 #include "url/origin.h"
40
41 namespace content {
42 namespace {
43
44 typedef net::WebSocketEventInterface::ChannelState ChannelState;
45
46 // Convert a mojom::WebSocketMessageType to a
47 // net::WebSocketFrameHeader::OpCode
48 net::WebSocketFrameHeader::OpCode MessageTypeToOpCode(
49 mojom::WebSocketMessageType type) {
50 DCHECK(type == mojom::WebSocketMessageType::CONTINUATION ||
51 type == mojom::WebSocketMessageType::TEXT ||
52 type == mojom::WebSocketMessageType::BINARY);
53 typedef net::WebSocketFrameHeader::OpCode OpCode;
54 // These compile asserts verify that the same underlying values are used for
55 // both types, so we can simply cast between them.
56 static_assert(
57 static_cast<OpCode>(mojom::WebSocketMessageType::CONTINUATION) ==
58 net::WebSocketFrameHeader::kOpCodeContinuation,
59 "enum values must match for opcode continuation");
60 static_assert(
61 static_cast<OpCode>(mojom::WebSocketMessageType::TEXT) ==
62 net::WebSocketFrameHeader::kOpCodeText,
63 "enum values must match for opcode text");
64 static_assert(
65 static_cast<OpCode>(mojom::WebSocketMessageType::BINARY) ==
66 net::WebSocketFrameHeader::kOpCodeBinary,
67 "enum values must match for opcode binary");
68 return static_cast<OpCode>(type);
69 }
70
71 mojom::WebSocketMessageType OpCodeToMessageType(
72 net::WebSocketFrameHeader::OpCode opCode) {
73 DCHECK(opCode == net::WebSocketFrameHeader::kOpCodeContinuation ||
74 opCode == net::WebSocketFrameHeader::kOpCodeText ||
75 opCode == net::WebSocketFrameHeader::kOpCodeBinary);
76 // This cast is guaranteed valid by the static_assert() statements above.
77 return static_cast<mojom::WebSocketMessageType>(opCode);
78 }
79
80 } // namespace
81
82 // Implementation of net::WebSocketEventInterface. Receives events from our
83 // WebSocketChannel object.
84 class WebSocketImpl::WebSocketEventHandler final
85 : public net::WebSocketEventInterface {
86 public:
87 WebSocketEventHandler(WebSocketImpl* impl, int32_t render_frame_id);
88 ~WebSocketEventHandler() override;
89
90 // net::WebSocketEventInterface implementation
91
92 ChannelState OnAddChannelResponse(const std::string& selected_subprotocol,
93 const std::string& extensions) override;
94 ChannelState OnDataFrame(bool fin,
95 WebSocketMessageType type,
96 const std::vector<char>& data) override;
97 ChannelState OnClosingHandshake() override;
98 ChannelState OnFlowControl(int64_t quota) override;
99 ChannelState OnDropChannel(bool was_clean,
100 uint16_t code,
101 const std::string& reason) override;
102 ChannelState OnFailChannel(const std::string& message) override;
103 ChannelState OnStartOpeningHandshake(
104 std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) override;
105 ChannelState OnFinishOpeningHandshake(
106 std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) override;
107 ChannelState OnSSLCertificateError(
108 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
109 callbacks,
110 const GURL& url,
111 const net::SSLInfo& ssl_info,
112 bool fatal) override;
113
114 private:
115 class SSLErrorHandlerDelegate final : public SSLErrorHandler::Delegate {
116 public:
117 SSLErrorHandlerDelegate(
118 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
119 callbacks);
120 ~SSLErrorHandlerDelegate() override;
121
122 base::WeakPtr<SSLErrorHandler::Delegate> GetWeakPtr();
123
124 // SSLErrorHandler::Delegate methods
125 void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override;
126 void ContinueSSLRequest() override;
127
128 private:
129 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks_;
130 base::WeakPtrFactory<SSLErrorHandlerDelegate> weak_ptr_factory_;
131
132 DISALLOW_COPY_AND_ASSIGN(SSLErrorHandlerDelegate);
133 };
134
135 WebSocketImpl* const impl_;
136 std::unique_ptr<SSLErrorHandlerDelegate> ssl_error_handler_delegate_;
137 int32_t render_frame_id_;
138
139 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
140 };
141
142 WebSocketImpl::WebSocketEventHandler::WebSocketEventHandler(
143 WebSocketImpl* impl,
144 int32_t render_frame_id)
145 : impl_(impl),
146 render_frame_id_(render_frame_id) {
147 DVLOG(1) << "WebSocketEventHandler created @"
148 << reinterpret_cast<void*>(this);
149 }
150
151 WebSocketImpl::WebSocketEventHandler::~WebSocketEventHandler() {
152 DVLOG(1) << "WebSocketEventHandler destroyed @"
153 << reinterpret_cast<void*>(this);
154 }
155
156 ChannelState WebSocketImpl::WebSocketEventHandler::OnAddChannelResponse(
157 const std::string& selected_protocol,
158 const std::string& extensions) {
159 DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse @"
160 << reinterpret_cast<void*>(this)
161 << " selected_protocol=\"" << selected_protocol << "\""
162 << " extensions=\"" << extensions << "\"";
163
164 impl_->delegate_->OnReceivedResponseFromServer(impl_);
165
166 impl_->client_->OnAddChannelResponse(selected_protocol, extensions);
167
168 return net::WebSocketEventInterface::CHANNEL_ALIVE;
169 }
170
171 ChannelState WebSocketImpl::WebSocketEventHandler::OnDataFrame(
172 bool fin,
173 net::WebSocketFrameHeader::OpCode type,
174 const std::vector<char>& data) {
175 DVLOG(3) << "WebSocketEventHandler::OnDataFrame @"
176 << reinterpret_cast<void*>(this)
177 << " fin=" << fin
178 << " type=" << type << " data is " << data.size() << " bytes";
179
180 // TODO(darin): Avoid this copy.
181 mojo::Array<uint8_t> data_to_pass(data.size());
182 std::copy(data.begin(), data.end(), data_to_pass.begin());
183
184 impl_->client_->OnDataFrame(fin, OpCodeToMessageType(type),
185 std::move(data_to_pass));
186
187 return net::WebSocketEventInterface::CHANNEL_ALIVE;
188 }
189
190 ChannelState WebSocketImpl::WebSocketEventHandler::OnClosingHandshake() {
191 DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake @"
192 << reinterpret_cast<void*>(this);
193
194 impl_->client_->OnClosingHandshake();
195
196 return net::WebSocketEventInterface::CHANNEL_ALIVE;
197 }
198
199 ChannelState WebSocketImpl::WebSocketEventHandler::OnFlowControl(
200 int64_t quota) {
201 DVLOG(3) << "WebSocketEventHandler::OnFlowControl @"
202 << reinterpret_cast<void*>(this)
203 << " quota=" << quota;
204
205 impl_->client_->OnFlowControl(quota);
206
207 return net::WebSocketEventInterface::CHANNEL_ALIVE;
208 }
209
210 ChannelState WebSocketImpl::WebSocketEventHandler::OnDropChannel(
211 bool was_clean,
212 uint16_t code,
213 const std::string& reason) {
214 DVLOG(3) << "WebSocketEventHandler::OnDropChannel @"
215 << reinterpret_cast<void*>(this)
216 << " was_clean=" << was_clean << " code=" << code
217 << " reason=\"" << reason << "\"";
218
219 impl_->client_->OnDropChannel(was_clean, code, reason);
220
221 // net::WebSocketChannel requires that we delete it at this point.
222 impl_->channel_.reset();
223
224 return net::WebSocketEventInterface::CHANNEL_DELETED;
225 }
226
227 ChannelState WebSocketImpl::WebSocketEventHandler::OnFailChannel(
228 const std::string& message) {
229 DVLOG(3) << "WebSocketEventHandler::OnFailChannel @"
230 << reinterpret_cast<void*>(this) << " message=\"" << message << "\"";
231
232 impl_->client_->OnFailChannel(message);
233
234 // net::WebSocketChannel requires that we delete it at this point.
235 impl_->channel_.reset();
236
237 return net::WebSocketEventInterface::CHANNEL_DELETED;
238 }
239
240 ChannelState WebSocketImpl::WebSocketEventHandler::OnStartOpeningHandshake(
241 std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) {
242 bool should_send =
243 ChildProcessSecurityPolicyImpl::GetInstance()->CanReadRawCookies(
244 impl_->delegate_->GetClientProcessId());
245
246 DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake @"
247 << reinterpret_cast<void*>(this) << " should_send=" << should_send;
248
249 if (!should_send)
250 return WebSocketEventInterface::CHANNEL_ALIVE;
251
252 mojom::WebSocketHandshakeRequestPtr request_to_pass(
253 mojom::WebSocketHandshakeRequest::New());
254 request_to_pass->url.Swap(&request->url);
255 net::HttpRequestHeaders::Iterator it(request->headers);
256 while (it.GetNext()) {
257 mojom::HttpHeaderPtr header(mojom::HttpHeader::New());
258 header->name = it.name();
259 header->value = it.value();
260 request_to_pass->headers.push_back(std::move(header));
261 }
262 request_to_pass->headers_text =
263 base::StringPrintf("GET %s HTTP/1.1\r\n",
264 request_to_pass->url.spec().c_str()) +
265 request->headers.ToString();
266
267 impl_->client_->OnStartOpeningHandshake(std::move(request_to_pass));
268
269 return WebSocketEventInterface::CHANNEL_ALIVE;
270 }
271
272 ChannelState WebSocketImpl::WebSocketEventHandler::OnFinishOpeningHandshake(
273 std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) {
274 bool should_send =
275 ChildProcessSecurityPolicyImpl::GetInstance()->CanReadRawCookies(
276 impl_->delegate_->GetClientProcessId());
277
278 DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
279 << reinterpret_cast<void*>(this) << " should_send=" << should_send;
280
281 if (!should_send)
282 return WebSocketEventInterface::CHANNEL_ALIVE;
283
284 mojom::WebSocketHandshakeResponsePtr response_to_pass(
285 mojom::WebSocketHandshakeResponse::New());
286 response_to_pass->url.Swap(&response->url);
287 response_to_pass->status_code = response->status_code;
288 response_to_pass->status_text = response->status_text;
289 size_t iter = 0;
290 std::string name, value;
291 while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) {
292 mojom::HttpHeaderPtr header(mojom::HttpHeader::New());
293 header->name = name;
294 header->value = value;
295 response_to_pass->headers.push_back(std::move(header));
296 }
297 response_to_pass->headers_text =
298 net::HttpUtil::ConvertHeadersBackToHTTPResponse(
299 response->headers->raw_headers());
300
301 impl_->client_->OnFinishOpeningHandshake(std::move(response_to_pass));
302
303 return WebSocketEventInterface::CHANNEL_ALIVE;
304 }
305
306 ChannelState WebSocketImpl::WebSocketEventHandler::OnSSLCertificateError(
307 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
308 const GURL& url,
309 const net::SSLInfo& ssl_info,
310 bool fatal) {
311 DVLOG(3) << "WebSocketEventHandler::OnSSLCertificateError"
312 << reinterpret_cast<void*>(this) << " url=" << url.spec()
313 << " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
314 ssl_error_handler_delegate_.reset(
315 new SSLErrorHandlerDelegate(std::move(callbacks)));
316 SSLManager::OnSSLCertificateSubresourceError(
317 ssl_error_handler_delegate_->GetWeakPtr(),
318 url,
319 impl_->delegate_->GetClientProcessId(),
320 render_frame_id_,
321 ssl_info,
322 fatal);
323 // The above method is always asynchronous.
324 return WebSocketEventInterface::CHANNEL_ALIVE;
325 }
326
327 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
328 SSLErrorHandlerDelegate(
329 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
330 callbacks)
331 : callbacks_(std::move(callbacks)), weak_ptr_factory_(this) {}
332
333 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
334 ~SSLErrorHandlerDelegate() {}
335
336 base::WeakPtr<SSLErrorHandler::Delegate>
337 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
338 return weak_ptr_factory_.GetWeakPtr();
339 }
340
341 void WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
342 CancelSSLRequest(int error, const net::SSLInfo* ssl_info) {
343 DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest"
344 << " error=" << error
345 << " cert_status=" << (ssl_info ? ssl_info->cert_status
346 : static_cast<net::CertStatus>(-1));
347 callbacks_->CancelSSLRequest(error, ssl_info);
348 }
349
350 void WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
351 ContinueSSLRequest() {
352 DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest";
353 callbacks_->ContinueSSLRequest();
354 }
355
356 WebSocketImpl::WebSocketImpl(
357 Delegate* delegate,
358 mojom::WebSocketRequest request,
359 base::TimeDelta delay)
360 : delegate_(delegate),
361 binding_(this, std::move(request)),
362 delay_(delay),
363 pending_flow_control_quota_(0),
364 handshake_succeeded_(false),
365 weak_ptr_factory_(this) {
366 binding_.set_connection_error_handler(
367 base::Bind(&WebSocketImpl::OnConnectionError, base::Unretained(this)));
368 }
369
370 WebSocketImpl::~WebSocketImpl() {}
371
372 void WebSocketImpl::GoAway() {
373 StartClosingHandshake(static_cast<uint16_t>(net::kWebSocketErrorGoingAway),
374 "");
375 }
376
377 void WebSocketImpl::AddChannelRequest(
378 const GURL& socket_url,
379 mojo::Array<mojo::String> requested_protocols_mojo,
380 const url::Origin& origin,
381 const GURL& first_party_for_cookies,
382 const mojo::String& user_agent_override,
383 int32_t render_frame_id,
384 mojom::WebSocketClientPtr client) {
385 // Convert to STL types.
386 std::vector<std::string> requested_protocols(
387 requested_protocols_mojo.begin(),
388 requested_protocols_mojo.end());
389
390 DVLOG(3) << "WebSocketImpl::AddChannelRequest @"
391 << reinterpret_cast<void*>(this)
392 << " socket_url=\"" << socket_url << "\" requested_protocols=\""
393 << base::JoinString(requested_protocols, ", ")
394 << "\" origin=\"" << origin
395 << "\" first_party_for_cookies=\"" << first_party_for_cookies
396 << "\" user_agent_override=\"" << user_agent_override
397 << "\" render_frame_id=\"" << render_frame_id
398 << "\"";
399
400 if (client_ || !client) {
401 bad_message::ReceivedBadMessage(
402 delegate_->GetClientProcessId(),
403 bad_message::WSI_UNEXPECTED_ADD_CHANNEL_REQUEST);
404 return;
405 }
406
407 client_ = std::move(client);
408
409 DCHECK(!channel_);
410 if (delay_ > base::TimeDelta()) {
411 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
412 FROM_HERE,
413 base::Bind(&WebSocketImpl::AddChannel,
414 weak_ptr_factory_.GetWeakPtr(),
415 socket_url,
416 requested_protocols,
417 origin,
418 first_party_for_cookies,
419 user_agent_override,
420 render_frame_id),
421 delay_);
422 } else {
423 AddChannel(socket_url, requested_protocols, origin, first_party_for_cookies,
424 user_agent_override, render_frame_id);
425 }
426 }
427
428 void WebSocketImpl::SendFrame(bool fin, mojom::WebSocketMessageType type,
429 mojo::Array<uint8_t> data) {
430 DVLOG(3) << "WebSocketImpl::SendFrame @"
431 << reinterpret_cast<void*>(this) << " fin=" << fin
432 << " type=" << type << " data is " << data.size() << " bytes";
433
434 if (!channel_) {
435 // The client should not be sending us frames until after we've informed
436 // it that the channel has been opened (OnAddChannelResponse).
437 if (handshake_succeeded_) {
438 DVLOG(1) << "Dropping frame sent to closed websocket";
439 } else {
440 bad_message::ReceivedBadMessage(
441 delegate_->GetClientProcessId(),
442 bad_message::WSI_UNEXPECTED_SEND_FRAME);
443 }
444 return;
445 }
446
447 // TODO(darin): Avoid this copy.
448 std::vector<char> data_to_pass(data.size());
449 std::copy(data.begin(), data.end(), data_to_pass.begin());
450
451 channel_->SendFrame(fin, MessageTypeToOpCode(type), data_to_pass);
452 }
453
454 void WebSocketImpl::SendFlowControl(int64_t quota) {
455 DVLOG(3) << "WebSocketImpl::OnFlowControl @"
456 << reinterpret_cast<void*>(this) << " quota=" << quota;
457
458 if (!channel_) {
459 // WebSocketChannel is not yet created due to the delay introduced by
460 // per-renderer WebSocket throttling.
461 // SendFlowControl() is called after WebSocketChannel is created.
462 pending_flow_control_quota_ += quota;
463 return;
464 }
465
466 ignore_result(channel_->SendFlowControl(quota));
467 }
468
469 void WebSocketImpl::StartClosingHandshake(uint16_t code,
470 const mojo::String& reason) {
471 DVLOG(3) << "WebSocketImpl::StartClosingHandshake @"
472 << reinterpret_cast<void*>(this)
473 << " code=" << code << " reason=\"" << reason << "\"";
474
475 if (!channel_) {
476 // WebSocketChannel is not yet created due to the delay introduced by
477 // per-renderer WebSocket throttling.
478 if (client_)
479 client_->OnDropChannel(false, net::kWebSocketErrorAbnormalClosure, "");
480 return;
481 }
482
483 ignore_result(channel_->StartClosingHandshake(code, reason));
484 }
485
486 void WebSocketImpl::OnConnectionError() {
487 DVLOG(3) << "WebSocketImpl::OnConnectionError @"
488 << reinterpret_cast<void*>(this);
489
490 delegate_->OnLostConnectionToClient(this);
491 }
492
493 void WebSocketImpl::AddChannel(
494 const GURL& socket_url,
495 const std::vector<std::string>& requested_protocols,
496 const url::Origin& origin,
497 const GURL& first_party_for_cookies,
498 const std::string& user_agent_override,
499 int32_t render_frame_id) {
500 DVLOG(3) << "WebSocketImpl::AddChannel @"
501 << reinterpret_cast<void*>(this)
502 << " socket_url=\"" << socket_url
503 << "\" requested_protocols=\""
504 << base::JoinString(requested_protocols, ", ")
505 << "\" origin=\"" << origin
506 << "\" first_party_for_cookies=\"" << first_party_for_cookies
507 << "\" user_agent_override=\"" << user_agent_override
508 << "\" render_frame_id=\"" << render_frame_id
509 << "\"";
510
511 DCHECK(!channel_);
512
513 StoragePartition* partition = delegate_->GetStoragePartition();
514
515 std::unique_ptr<net::WebSocketEventInterface> event_interface(
516 new WebSocketEventHandler(this, render_frame_id));
517 channel_.reset(
518 new net::WebSocketChannel(
519 std::move(event_interface),
520 partition->GetURLRequestContext()->GetURLRequestContext()));
521
522 int64_t quota = pending_flow_control_quota_;
523 pending_flow_control_quota_ = 0;
524
525 std::string additional_headers;
526 if (!user_agent_override.empty()) {
527 if (!net::HttpUtil::IsValidHeaderValue(user_agent_override)) {
528 bad_message::ReceivedBadMessage(
529 delegate_->GetClientProcessId(),
530 bad_message::WSI_INVALID_HEADER_VALUE);
531 return;
532 }
533 additional_headers = base::StringPrintf("%s:%s",
534 net::HttpRequestHeaders::kUserAgent,
535 user_agent_override.c_str());
536 }
537 channel_->SendAddChannelRequest(socket_url, requested_protocols, origin,
538 first_party_for_cookies, additional_headers);
539 if (quota > 0)
540 SendFlowControl(quota);
541 }
542
543 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698