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

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: Fix compile error Created 4 years, 4 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 explicit WebSocketEventHandler(WebSocketImpl* impl);
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
138 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
139 };
140
141 WebSocketImpl::WebSocketEventHandler::WebSocketEventHandler(WebSocketImpl* impl)
142 : impl_(impl) {
143 DVLOG(1) << "WebSocketEventHandler created @"
144 << reinterpret_cast<void*>(this);
145 }
146
147 WebSocketImpl::WebSocketEventHandler::~WebSocketEventHandler() {
148 DVLOG(1) << "WebSocketEventHandler destroyed @"
149 << reinterpret_cast<void*>(this);
150 }
151
152 ChannelState WebSocketImpl::WebSocketEventHandler::OnAddChannelResponse(
153 const std::string& selected_protocol,
154 const std::string& extensions) {
155 DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse @"
156 << reinterpret_cast<void*>(this)
157 << " selected_protocol=\"" << selected_protocol << "\""
158 << " extensions=\"" << extensions << "\"";
159
160 impl_->delegate_->OnReceivedResponseFromServer(impl_);
161
162 impl_->client_->OnAddChannelResponse(selected_protocol, extensions);
163
164 return net::WebSocketEventInterface::CHANNEL_ALIVE;
165 }
166
167 ChannelState WebSocketImpl::WebSocketEventHandler::OnDataFrame(
168 bool fin,
169 net::WebSocketFrameHeader::OpCode type,
170 const std::vector<char>& data) {
171 DVLOG(3) << "WebSocketEventHandler::OnDataFrame @"
172 << reinterpret_cast<void*>(this)
173 << " fin=" << fin
174 << " type=" << type << " data is " << data.size() << " bytes";
175
176 // TODO(darin): Avoid this copy.
177 mojo::Array<uint8_t> data_to_pass(data.size());
178 std::copy(data.begin(), data.end(), data_to_pass.begin());
179
180 impl_->client_->OnDataFrame(fin, OpCodeToMessageType(type),
181 std::move(data_to_pass));
182
183 return net::WebSocketEventInterface::CHANNEL_ALIVE;
184 }
185
186 ChannelState WebSocketImpl::WebSocketEventHandler::OnClosingHandshake() {
187 DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake @"
188 << reinterpret_cast<void*>(this);
189
190 impl_->client_->OnClosingHandshake();
191
192 return net::WebSocketEventInterface::CHANNEL_ALIVE;
193 }
194
195 ChannelState WebSocketImpl::WebSocketEventHandler::OnFlowControl(
196 int64_t quota) {
197 DVLOG(3) << "WebSocketEventHandler::OnFlowControl @"
198 << reinterpret_cast<void*>(this)
199 << " quota=" << quota;
200
201 impl_->client_->OnFlowControl(quota);
202
203 return net::WebSocketEventInterface::CHANNEL_ALIVE;
204 }
205
206 ChannelState WebSocketImpl::WebSocketEventHandler::OnDropChannel(
207 bool was_clean,
208 uint16_t code,
209 const std::string& reason) {
210 DVLOG(3) << "WebSocketEventHandler::OnDropChannel @"
211 << reinterpret_cast<void*>(this)
212 << " was_clean=" << was_clean << " code=" << code
213 << " reason=\"" << reason << "\"";
214
215 impl_->client_->OnDropChannel(was_clean, code, reason);
216
217 // net::WebSocketChannel requires that we delete it at this point.
218 impl_->channel_.reset();
219
220 return net::WebSocketEventInterface::CHANNEL_DELETED;
221 }
222
223 ChannelState WebSocketImpl::WebSocketEventHandler::OnFailChannel(
224 const std::string& message) {
225 DVLOG(3) << "WebSocketEventHandler::OnFailChannel @"
226 << reinterpret_cast<void*>(this) << " message=\"" << message << "\"";
227
228 impl_->client_->OnFailChannel(message);
229
230 // net::WebSocketChannel requires that we delete it at this point.
231 impl_->channel_.reset();
232
233 return net::WebSocketEventInterface::CHANNEL_DELETED;
234 }
235
236 ChannelState WebSocketImpl::WebSocketEventHandler::OnStartOpeningHandshake(
237 std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) {
238 bool should_send =
239 ChildProcessSecurityPolicyImpl::GetInstance()->CanReadRawCookies(
240 impl_->delegate_->GetClientProcessId());
241
242 DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake @"
243 << reinterpret_cast<void*>(this) << " should_send=" << should_send;
244
245 if (!should_send)
246 return WebSocketEventInterface::CHANNEL_ALIVE;
247
248 mojom::WebSocketHandshakeRequestPtr request_to_pass(
249 mojom::WebSocketHandshakeRequest::New());
250 request_to_pass->url.Swap(&request->url);
251 net::HttpRequestHeaders::Iterator it(request->headers);
252 while (it.GetNext()) {
253 mojom::HttpHeaderPtr header(mojom::HttpHeader::New());
254 header->name = it.name();
255 header->value = it.value();
256 request_to_pass->headers.push_back(std::move(header));
257 }
258 request_to_pass->headers_text =
259 base::StringPrintf("GET %s HTTP/1.1\r\n",
260 request_to_pass->url.spec().c_str()) +
261 request->headers.ToString();
262
263 impl_->client_->OnStartOpeningHandshake(std::move(request_to_pass));
264
265 return WebSocketEventInterface::CHANNEL_ALIVE;
266 }
267
268 ChannelState WebSocketImpl::WebSocketEventHandler::OnFinishOpeningHandshake(
269 std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) {
270 bool should_send =
271 ChildProcessSecurityPolicyImpl::GetInstance()->CanReadRawCookies(
272 impl_->delegate_->GetClientProcessId());
273
274 DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
275 << reinterpret_cast<void*>(this) << " should_send=" << should_send;
276
277 if (!should_send)
278 return WebSocketEventInterface::CHANNEL_ALIVE;
279
280 mojom::WebSocketHandshakeResponsePtr response_to_pass(
281 mojom::WebSocketHandshakeResponse::New());
282 response_to_pass->url.Swap(&response->url);
283 response_to_pass->status_code = response->status_code;
284 response_to_pass->status_text = response->status_text;
285 size_t iter = 0;
286 std::string name, value;
287 while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) {
288 mojom::HttpHeaderPtr header(mojom::HttpHeader::New());
289 header->name = name;
290 header->value = value;
291 response_to_pass->headers.push_back(std::move(header));
292 }
293 response_to_pass->headers_text =
294 net::HttpUtil::ConvertHeadersBackToHTTPResponse(
295 response->headers->raw_headers());
296
297 impl_->client_->OnFinishOpeningHandshake(std::move(response_to_pass));
298
299 return WebSocketEventInterface::CHANNEL_ALIVE;
300 }
301
302 ChannelState WebSocketImpl::WebSocketEventHandler::OnSSLCertificateError(
303 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
304 const GURL& url,
305 const net::SSLInfo& ssl_info,
306 bool fatal) {
307 DVLOG(3) << "WebSocketEventHandler::OnSSLCertificateError"
308 << reinterpret_cast<void*>(this) << " url=" << url.spec()
309 << " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
310 ssl_error_handler_delegate_.reset(
311 new SSLErrorHandlerDelegate(std::move(callbacks)));
312 SSLManager::OnSSLCertificateSubresourceError(
313 ssl_error_handler_delegate_->GetWeakPtr(),
314 url,
315 impl_->delegate_->GetClientProcessId(),
316 impl_->frame_id_,
317 ssl_info,
318 fatal);
319 // The above method is always asynchronous.
320 return WebSocketEventInterface::CHANNEL_ALIVE;
321 }
322
323 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
324 SSLErrorHandlerDelegate(
325 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
326 callbacks)
327 : callbacks_(std::move(callbacks)), weak_ptr_factory_(this) {}
328
329 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
330 ~SSLErrorHandlerDelegate() {}
331
332 base::WeakPtr<SSLErrorHandler::Delegate>
333 WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
334 return weak_ptr_factory_.GetWeakPtr();
335 }
336
337 void WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
338 CancelSSLRequest(int error, const net::SSLInfo* ssl_info) {
339 DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest"
340 << " error=" << error
341 << " cert_status=" << (ssl_info ? ssl_info->cert_status
342 : static_cast<net::CertStatus>(-1));
343 callbacks_->CancelSSLRequest(error, ssl_info);
344 }
345
346 void WebSocketImpl::WebSocketEventHandler::SSLErrorHandlerDelegate::
347 ContinueSSLRequest() {
348 DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest";
349 callbacks_->ContinueSSLRequest();
350 }
351
352 WebSocketImpl::WebSocketImpl(
353 Delegate* delegate,
354 mojom::WebSocketRequest request,
355 int frame_id,
356 base::TimeDelta delay)
357 : delegate_(delegate),
358 binding_(this, std::move(request)),
359 delay_(delay),
360 pending_flow_control_quota_(0),
361 frame_id_(frame_id),
362 handshake_succeeded_(false),
363 weak_ptr_factory_(this) {
364 binding_.set_connection_error_handler(
365 base::Bind(&WebSocketImpl::OnConnectionError, base::Unretained(this)));
366 }
367
368 WebSocketImpl::~WebSocketImpl() {}
369
370 void WebSocketImpl::GoAway() {
371 StartClosingHandshake(static_cast<uint16_t>(net::kWebSocketErrorGoingAway),
372 "");
373 }
374
375 void WebSocketImpl::AddChannelRequest(
376 const GURL& socket_url,
377 mojo::Array<mojo::String> requested_protocols_mojo,
378 const url::Origin& origin,
379 const GURL& first_party_for_cookies,
380 const mojo::String& user_agent_override,
381 mojom::WebSocketClientPtr client) {
382 // Convert to STL types.
383 std::vector<std::string> requested_protocols(
384 requested_protocols_mojo.begin(),
385 requested_protocols_mojo.end());
386
387 DVLOG(3) << "WebSocketImpl::AddChannelRequest @"
388 << reinterpret_cast<void*>(this)
389 << " socket_url=\"" << socket_url << "\" requested_protocols=\""
390 << base::JoinString(requested_protocols, ", ")
391 << "\" origin=\"" << origin
392 << "\" first_party_for_cookies=\"" << first_party_for_cookies
393 << "\" user_agent_override=\"" << user_agent_override
394 << "\"";
395
396 if (client_ || !client) {
397 bad_message::ReceivedBadMessage(
398 delegate_->GetClientProcessId(),
399 bad_message::WSI_UNEXPECTED_ADD_CHANNEL_REQUEST);
400 return;
401 }
402
403 client_ = std::move(client);
404
405 DCHECK(!channel_);
406 if (delay_ > base::TimeDelta()) {
407 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
408 FROM_HERE,
409 base::Bind(&WebSocketImpl::AddChannel,
410 weak_ptr_factory_.GetWeakPtr(),
411 socket_url,
412 requested_protocols,
413 origin,
414 first_party_for_cookies,
415 user_agent_override),
416 delay_);
417 } else {
418 AddChannel(socket_url, requested_protocols, origin, first_party_for_cookies,
419 user_agent_override);
420 }
421 }
422
423 void WebSocketImpl::SendFrame(bool fin, mojom::WebSocketMessageType type,
424 mojo::Array<uint8_t> data) {
425 DVLOG(3) << "WebSocketImpl::SendFrame @"
426 << reinterpret_cast<void*>(this) << " fin=" << fin
427 << " type=" << type << " data is " << data.size() << " bytes";
428
429 if (!channel_) {
430 // The client should not be sending us frames until after we've informed
431 // it that the channel has been opened (OnAddChannelResponse).
432 if (handshake_succeeded_) {
433 DVLOG(1) << "Dropping frame sent to closed websocket";
434 } else {
435 bad_message::ReceivedBadMessage(
436 delegate_->GetClientProcessId(),
437 bad_message::WSI_UNEXPECTED_SEND_FRAME);
438 }
439 return;
440 }
441
442 // TODO(darin): Avoid this copy.
443 std::vector<char> data_to_pass(data.size());
444 std::copy(data.begin(), data.end(), data_to_pass.begin());
445
446 channel_->SendFrame(fin, MessageTypeToOpCode(type), data_to_pass);
447 }
448
449 void WebSocketImpl::SendFlowControl(int64_t quota) {
450 DVLOG(3) << "WebSocketImpl::OnFlowControl @"
451 << reinterpret_cast<void*>(this) << " quota=" << quota;
452
453 if (!channel_) {
454 // WebSocketChannel is not yet created due to the delay introduced by
455 // per-renderer WebSocket throttling.
456 // SendFlowControl() is called after WebSocketChannel is created.
457 pending_flow_control_quota_ += quota;
458 return;
459 }
460
461 ignore_result(channel_->SendFlowControl(quota));
462 }
463
464 void WebSocketImpl::StartClosingHandshake(uint16_t code,
465 const mojo::String& reason) {
466 DVLOG(3) << "WebSocketImpl::StartClosingHandshake @"
467 << reinterpret_cast<void*>(this)
468 << " code=" << code << " reason=\"" << reason << "\"";
469
470 if (!channel_) {
471 // WebSocketChannel is not yet created due to the delay introduced by
472 // per-renderer WebSocket throttling.
473 if (client_)
474 client_->OnDropChannel(false, net::kWebSocketErrorAbnormalClosure, "");
475 return;
476 }
477
478 ignore_result(channel_->StartClosingHandshake(code, reason));
479 }
480
481 void WebSocketImpl::OnConnectionError() {
482 DVLOG(3) << "WebSocketImpl::OnConnectionError @"
483 << reinterpret_cast<void*>(this);
484
485 delegate_->OnLostConnectionToClient(this);
486 }
487
488 void WebSocketImpl::AddChannel(
489 const GURL& socket_url,
490 const std::vector<std::string>& requested_protocols,
491 const url::Origin& origin,
492 const GURL& first_party_for_cookies,
493 const std::string& user_agent_override) {
494 DVLOG(3) << "WebSocketImpl::AddChannel @"
495 << reinterpret_cast<void*>(this)
496 << " socket_url=\"" << socket_url
497 << "\" requested_protocols=\""
498 << base::JoinString(requested_protocols, ", ")
499 << "\" origin=\"" << origin
500 << "\" first_party_for_cookies=\"" << first_party_for_cookies
501 << "\" user_agent_override=\"" << user_agent_override
502 << "\"";
503
504 DCHECK(!channel_);
505
506 StoragePartition* partition = delegate_->GetStoragePartition();
507
508 std::unique_ptr<net::WebSocketEventInterface> event_interface(
509 new WebSocketEventHandler(this));
510 channel_.reset(
511 new net::WebSocketChannel(
512 std::move(event_interface),
513 partition->GetURLRequestContext()->GetURLRequestContext()));
514
515 int64_t quota = pending_flow_control_quota_;
516 pending_flow_control_quota_ = 0;
517
518 std::string additional_headers;
519 if (!user_agent_override.empty()) {
520 if (!net::HttpUtil::IsValidHeaderValue(user_agent_override)) {
521 bad_message::ReceivedBadMessage(
522 delegate_->GetClientProcessId(),
523 bad_message::WSI_INVALID_HEADER_VALUE);
524 return;
525 }
526 additional_headers = base::StringPrintf("%s:%s",
527 net::HttpRequestHeaders::kUserAgent,
528 user_agent_override.c_str());
529 }
530 channel_->SendAddChannelRequest(socket_url, requested_protocols, origin,
531 first_party_for_cookies, additional_headers);
532 if (quota > 0)
533 SendFlowControl(quota);
534 }
535
536 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698