blob: 1786c34590facfbd4b962549714da3cbc7fb468c [file] [log] [blame]
[email protected]999bcaa2013-07-17 13:42:541// 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 "net/websockets/websocket_channel.h"
6
[email protected]4256dbb2014-03-24 15:39:367#include <limits.h> // for INT_MAX
gabf767595f2016-05-11 18:50:358#include <stddef.h>
[email protected]4256dbb2014-03-24 15:39:369
[email protected]999bcaa2013-07-17 13:42:5410#include <algorithm>
yhirano592ff7f2015-12-07 08:45:1911#include <utility>
12#include <vector>
[email protected]999bcaa2013-07-17 13:42:5413
[email protected]d9806a972014-02-26 18:14:5714#include "base/big_endian.h"
[email protected]999bcaa2013-07-17 13:42:5415#include "base/bind.h"
Brett Wilsonc6a0c822017-09-12 00:04:2916#include "base/containers/circular_deque.h"
skyostil4891b25b2015-06-11 11:43:4517#include "base/location.h"
Keishi Hattori0e45c022021-11-27 09:25:5218#include "base/memory/raw_ptr.h"
[email protected]cd48ed12014-01-22 14:34:2219#include "base/memory/weak_ptr.h"
[email protected]cb154062014-01-17 03:32:4020#include "base/numerics/safe_conversions.h"
Nanami Mikiya504e7042022-02-10 09:57:5021#include "base/strings/string_piece.h"
[email protected]ea56b982014-01-27 03:21:0322#include "base/strings/stringprintf.h"
Patrick Monette643cdf62021-10-15 19:13:4223#include "base/task/single_thread_task_runner.h"
gabf767595f2016-05-11 18:50:3524#include "base/threading/thread_task_runner_handle.h"
[email protected]3a266762013-10-23 08:15:1025#include "base/time/time.h"
Yutaka Hirano70fa25912018-06-06 05:26:5426#include "net/base/auth.h"
[email protected]999bcaa2013-07-17 13:42:5427#include "net/base/io_buffer.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3728#include "net/base/ip_endpoint.h"
[email protected]cd48ed12014-01-22 14:34:2229#include "net/http/http_request_headers.h"
30#include "net/http/http_response_headers.h"
[email protected]53deacb2013-11-22 14:02:4331#include "net/http/http_util.h"
mikecironef22f9812016-10-04 03:40:1932#include "net/log/net_log_with_source.h"
Adam Langleyacbad242020-08-18 15:14:5233#include "net/traffic_annotation/network_traffic_annotation.h"
[email protected]999bcaa2013-07-17 13:42:5434#include "net/websockets/websocket_errors.h"
35#include "net/websockets/websocket_event_interface.h"
36#include "net/websockets/websocket_frame.h"
[email protected]cd48ed12014-01-22 14:34:2237#include "net/websockets/websocket_handshake_request_info.h"
38#include "net/websockets/websocket_handshake_response_info.h"
[email protected]999bcaa2013-07-17 13:42:5439#include "net/websockets/websocket_stream.h"
mkwst4997ce82015-07-25 12:00:0540#include "url/origin.h"
[email protected]999bcaa2013-07-17 13:42:5441
42namespace net {
43
44namespace {
45
[email protected]48cc6922014-02-10 14:20:4846using base::StreamingUtf8Validator;
47
Adam Ricee77e5b7d2020-08-31 23:31:0948constexpr size_t kWebSocketCloseCodeLength = 2;
tyoshinod4d1d302014-11-07 04:31:1649// Timeout for waiting for the server to acknowledge a closing handshake.
Adam Ricee77e5b7d2020-08-31 23:31:0950constexpr int kClosingHandshakeTimeoutSeconds = 60;
tyoshinod4d1d302014-11-07 04:31:1651// We wait for the server to close the underlying connection as recommended in
52// https://tools.ietf.org/html/rfc6455#section-7.1.1
53// We don't use 2MSL since there're server implementations that don't follow
54// the recommendation and wait for the client to close the underlying
55// connection. It leads to unnecessarily long time before CloseEvent
56// invocation. We want to avoid this rather than strictly following the spec
57// recommendation.
Adam Ricee77e5b7d2020-08-31 23:31:0958constexpr int kUnderlyingConnectionCloseTimeoutSeconds = 2;
[email protected]999bcaa2013-07-17 13:42:5459
Yutaka Hirano4165de92018-04-10 11:46:4960using ChannelState = WebSocketChannel::ChannelState;
[email protected]f485985e2013-10-24 13:47:4461
[email protected]3de65092013-10-24 09:39:4462// Maximum close reason length = max control frame payload -
63// status code length
64// = 125 - 2
Adam Ricee77e5b7d2020-08-31 23:31:0965constexpr size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength;
[email protected]3de65092013-10-24 09:39:4466
67// Check a close status code for strict compliance with RFC6455. This is only
68// used for close codes received from a renderer that we are intending to send
69// out over the network. See ParseClose() for the restrictions on incoming close
70// codes. The |code| parameter is type int for convenience of implementation;
tfarina8a2c66c22015-10-13 19:14:4971// the real type is uint16_t. Code 1005 is treated specially; it cannot be set
[email protected]aa984e5f2014-02-26 07:33:0972// explicitly by Javascript but the renderer uses it to indicate we should send
73// a Close frame with no payload.
[email protected]3de65092013-10-24 09:39:4474bool IsStrictlyValidCloseStatusCode(int code) {
75 static const int kInvalidRanges[] = {
76 // [BAD, OK)
77 0, 1000, // 1000 is the first valid code
[email protected]aa984e5f2014-02-26 07:33:0978 1006, 1007, // 1006 MUST NOT be set.
[email protected]3de65092013-10-24 09:39:4479 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved.
80 5000, 65536, // Codes above 5000 are invalid.
81 };
82 const int* const kInvalidRangesEnd =
Daniel Cheng5feb16f2022-02-28 06:52:0783 kInvalidRanges + std::size(kInvalidRanges);
[email protected]3de65092013-10-24 09:39:4484
85 DCHECK_GE(code, 0);
86 DCHECK_LT(code, 65536);
87 const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code);
88 DCHECK_NE(kInvalidRangesEnd, upper);
89 DCHECK_GT(upper, kInvalidRanges);
90 DCHECK_GT(*upper, code);
91 DCHECK_LE(*(upper - 1), code);
92 return ((upper - kInvalidRanges) % 2) == 0;
93}
94
[email protected]8b3d14e2014-02-13 14:24:2895// Sets |name| to the name of the frame type for the given |opcode|. Note that
96// for all of Text, Binary and Continuation opcode, this method returns
97// "Data frame".
98void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode,
99 std::string* name) {
100 switch (opcode) {
101 case WebSocketFrameHeader::kOpCodeText: // fall-thru
102 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
103 case WebSocketFrameHeader::kOpCodeContinuation:
104 *name = "Data frame";
105 break;
106
107 case WebSocketFrameHeader::kOpCodePing:
108 *name = "Ping";
109 break;
110
111 case WebSocketFrameHeader::kOpCodePong:
112 *name = "Pong";
113 break;
114
115 case WebSocketFrameHeader::kOpCodeClose:
116 *name = "Close";
117 break;
118
119 default:
120 *name = "Unknown frame type";
121 break;
122 }
123
124 return;
125}
126
Nanami Mikiya504e7042022-02-10 09:57:50127base::Value NetLogFailParam(uint16_t code,
128 base::StringPiece reason,
129 base::StringPiece message) {
Travis Skareadae7ff2022-07-27 16:23:33130 base::Value::Dict dict;
131 dict.Set("code", code);
132 dict.Set("reason", reason);
133 dict.Set("internal_reason", message);
134 return base::Value(std::move(dict));
Nanami Mikiya504e7042022-02-10 09:57:50135}
136
darin0da77e922016-10-04 17:31:23137class DependentIOBuffer : public WrappedIOBuffer {
138 public:
139 DependentIOBuffer(scoped_refptr<IOBuffer> buffer, size_t offset)
140 : WrappedIOBuffer(buffer->data() + offset), buffer_(std::move(buffer)) {}
141
142 private:
Chris Watkins28c2fdd2017-11-30 06:06:52143 ~DependentIOBuffer() override = default;
Matt Menke29a538d2020-04-29 16:12:17144 scoped_refptr<IOBuffer> buffer_;
darin0da77e922016-10-04 17:31:23145};
146
[email protected]999bcaa2013-07-17 13:42:54147} // namespace
148
149// A class to encapsulate a set of frames and information about the size of
150// those frames.
151class WebSocketChannel::SendBuffer {
152 public:
Tsuyoshi Horoa0b9c0f2022-06-09 01:41:51153 SendBuffer() = default;
[email protected]999bcaa2013-07-17 13:42:54154
[email protected]2f5d9f62013-09-26 12:14:28155 // Add a WebSocketFrame to the buffer and increase total_bytes_.
Yutaka Hirano76aacb202019-09-05 16:36:56156 void AddFrame(std::unique_ptr<WebSocketFrame> chunk,
157 scoped_refptr<IOBuffer> buffer);
[email protected]999bcaa2013-07-17 13:42:54158
159 // Return a pointer to the frames_ for write purposes.
danakj9c5cab52016-04-16 00:54:33160 std::vector<std::unique_ptr<WebSocketFrame>>* frames() { return &frames_; }
[email protected]999bcaa2013-07-17 13:42:54161
162 private:
163 // The frames_ that will be sent in the next call to WriteFrames().
danakj9c5cab52016-04-16 00:54:33164 std::vector<std::unique_ptr<WebSocketFrame>> frames_;
Yutaka Hirano76aacb202019-09-05 16:36:56165 // References of each WebSocketFrame.data;
166 std::vector<scoped_refptr<IOBuffer>> buffers_;
[email protected]999bcaa2013-07-17 13:42:54167
[email protected]2f5d9f62013-09-26 12:14:28168 // The total size of the payload data in |frames_|. This will be used to
169 // measure the throughput of the link.
[email protected]999bcaa2013-07-17 13:42:54170 // TODO(ricea): Measure the throughput of the link.
Tsuyoshi Horoa0b9c0f2022-06-09 01:41:51171 uint64_t total_bytes_ = 0;
[email protected]999bcaa2013-07-17 13:42:54172};
173
danakj9c5cab52016-04-16 00:54:33174void WebSocketChannel::SendBuffer::AddFrame(
Yutaka Hirano76aacb202019-09-05 16:36:56175 std::unique_ptr<WebSocketFrame> frame,
176 scoped_refptr<IOBuffer> buffer) {
[email protected]2f5d9f62013-09-26 12:14:28177 total_bytes_ += frame->header.payload_length;
dchengc7eeda422015-12-26 03:56:48178 frames_.push_back(std::move(frame));
Yutaka Hirano76aacb202019-09-05 16:36:56179 buffers_.push_back(std::move(buffer));
[email protected]999bcaa2013-07-17 13:42:54180}
181
182// Implementation of WebSocketStream::ConnectDelegate that simply forwards the
183// calls on to the WebSocketChannel that created it.
184class WebSocketChannel::ConnectDelegate
185 : public WebSocketStream::ConnectDelegate {
186 public:
187 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {}
188
Peter Boström407869b2021-10-07 04:42:48189 ConnectDelegate(const ConnectDelegate&) = delete;
190 ConnectDelegate& operator=(const ConnectDelegate&) = delete;
191
Matt Menke29a538d2020-04-29 16:12:17192 void OnCreateRequest(URLRequest* request) override {
yhirano4a593832016-10-24 18:58:22193 creator_->OnCreateURLRequest(request);
194 }
195
Yoichi Osato1ead61a2020-01-06 04:52:57196 void OnSuccess(
197 std::unique_ptr<WebSocketStream> stream,
198 std::unique_ptr<WebSocketHandshakeResponseInfo> response) override {
199 creator_->OnConnectSuccess(std::move(stream), std::move(response));
[email protected]f485985e2013-10-24 13:47:44200 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54201 }
202
Adam Langleya48b636a2020-11-12 23:42:52203 void OnFailure(const std::string& message,
204 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52205 absl::optional<int> response_code) override {
Adam Langleya48b636a2020-11-12 23:42:52206 creator_->OnConnectFailure(message, net_error, response_code);
[email protected]f485985e2013-10-24 13:47:44207 // |this| has been deleted.
[email protected]999bcaa2013-07-17 13:42:54208 }
209
dchengb03027d2014-10-21 12:00:20210 void OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33211 std::unique_ptr<WebSocketHandshakeRequestInfo> request) override {
dchengc7eeda422015-12-26 03:56:48212 creator_->OnStartOpeningHandshake(std::move(request));
[email protected]cd48ed12014-01-22 14:34:22213 }
214
dchengb03027d2014-10-21 12:00:20215 void OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33216 std::unique_ptr<WebSocketEventInterface::SSLErrorCallbacks>
[email protected]a62449522014-06-05 11:11:15217 ssl_error_callbacks,
Emily Stark79fba5842019-04-25 04:59:36218 int net_error,
[email protected]a62449522014-06-05 11:11:15219 const SSLInfo& ssl_info,
mostynbba063d6032014-10-09 11:01:13220 bool fatal) override {
Emily Starkd9df3d32019-04-29 17:54:57221 creator_->OnSSLCertificateError(std::move(ssl_error_callbacks), net_error,
222 ssl_info, fatal);
[email protected]a62449522014-06-05 11:11:15223 }
224
Emily Starkf2c9bbd2019-04-09 17:08:58225 int OnAuthRequired(const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54226 scoped_refptr<HttpResponseHeaders> headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37227 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54228 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52229 absl::optional<AuthCredentials>* credentials) override {
Emily Starkf2c9bbd2019-04-09 17:08:58230 return creator_->OnAuthRequired(auth_info, std::move(headers),
Tsuyoshi Horo01faed62019-02-20 22:11:37231 remote_endpoint, std::move(callback),
Yutaka Hirano70fa25912018-06-06 05:26:54232 credentials);
233 }
234
[email protected]999bcaa2013-07-17 13:42:54235 private:
[email protected]caab2cc2013-08-27 10:24:37236 // A pointer to the WebSocketChannel that created this object. There is no
237 // danger of this pointer being stale, because deleting the WebSocketChannel
238 // cancels the connect process, deleting this object and preventing its
239 // callbacks from being called.
Keishi Hattori0e45c022021-11-27 09:25:52240 const raw_ptr<WebSocketChannel> creator_;
[email protected]999bcaa2013-07-17 13:42:54241};
242
243WebSocketChannel::WebSocketChannel(
danakj9c5cab52016-04-16 00:54:33244 std::unique_ptr<WebSocketEventInterface> event_interface,
[email protected]dab33eb2013-10-08 02:27:51245 URLRequestContext* url_request_context)
dchengc7eeda422015-12-26 03:56:48246 : event_interface_(std::move(event_interface)),
[email protected]dab33eb2013-10-08 02:27:51247 url_request_context_(url_request_context),
dchengc7eeda422015-12-26 03:56:48248 closing_handshake_timeout_(
Peter Kastinge5a38ed2021-10-02 03:06:35249 base::Seconds(kClosingHandshakeTimeoutSeconds)),
250 underlying_connection_close_timeout_(
Tsuyoshi Horoa0b9c0f2022-06-09 01:41:51251 base::Seconds(kUnderlyingConnectionCloseTimeoutSeconds)) {}
[email protected]999bcaa2013-07-17 13:42:54252
253WebSocketChannel::~WebSocketChannel() {
[email protected]2f5d9f62013-09-26 12:14:28254 // The stream may hold a pointer to read_frames_, and so it needs to be
[email protected]999bcaa2013-07-17 13:42:54255 // destroyed first.
256 stream_.reset();
[email protected]3a266762013-10-23 08:15:10257 // The timer may have a callback pointing back to us, so stop it just in case
258 // someone decides to run the event loop from their destructor.
tyoshinod4d1d302014-11-07 04:31:16259 close_timer_.Stop();
[email protected]999bcaa2013-07-17 13:42:54260}
261
262void WebSocketChannel::SendAddChannelRequest(
[email protected]dab33eb2013-10-08 02:27:51263 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54264 const std::vector<std::string>& requested_subprotocols,
alladacef397d2016-06-29 17:52:23265 const url::Origin& origin,
Maks Orlovich8be0e252019-12-09 18:35:49266 const SiteForCookies& site_for_cookies,
Matt Menke29a538d2020-04-29 16:12:17267 const IsolationInfo& isolation_info,
Adam Langleyacbad242020-08-18 15:14:52268 const HttpRequestHeaders& additional_headers,
269 NetworkTrafficAnnotationTag traffic_annotation) {
tyoshinoccfcfde2016-07-21 14:06:55270 SendAddChannelRequestWithSuppliedCallback(
Mike Westb85da8ed2017-08-10 14:16:46271 socket_url, requested_subprotocols, origin, site_for_cookies,
Adam Langleyacbad242020-08-18 15:14:52272 isolation_info, additional_headers, traffic_annotation,
Anna Malova5a2d13182020-03-05 11:04:07273 base::BindOnce(&WebSocketStream::CreateAndConnectStream));
[email protected]999bcaa2013-07-17 13:42:54274}
275
[email protected]09ef67362014-04-24 08:48:58276void WebSocketChannel::SetState(State new_state) {
277 DCHECK_NE(state_, new_state);
278
[email protected]09ef67362014-04-24 08:48:58279 state_ = new_state;
280}
281
[email protected]c0d29c22013-07-26 20:40:41282bool WebSocketChannel::InClosingState() const {
[email protected]caab2cc2013-08-27 10:24:37283 // The state RECV_CLOSED is not supported here, because it is only used in one
284 // code path and should not leak into the code in general.
[email protected]c0d29c22013-07-26 20:40:41285 DCHECK_NE(RECV_CLOSED, state_)
286 << "InClosingState called with state_ == RECV_CLOSED";
287 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED;
288}
289
riceae01cd6142016-01-14 20:41:30290WebSocketChannel::ChannelState WebSocketChannel::SendFrame(
291 bool fin,
292 WebSocketFrameHeader::OpCode op_code,
darin0da77e922016-10-04 17:31:23293 scoped_refptr<IOBuffer> buffer,
294 size_t buffer_size) {
Adam Rice666d0352018-05-28 06:08:38295 DCHECK_LE(buffer_size, static_cast<size_t>(INT_MAX));
296 DCHECK(stream_) << "Got SendFrame without a connection established; fin="
297 << fin << " op_code=" << op_code
298 << " buffer_size=" << buffer_size;
299
[email protected]c0d29c22013-07-26 20:40:41300 if (InClosingState()) {
[email protected]b8393cc2014-04-14 06:22:25301 DVLOG(1) << "SendFrame called in state " << state_
302 << ". This may be a bug, or a harmless race.";
riceae01cd6142016-01-14 20:41:30303 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54304 }
Adam Rice666d0352018-05-28 06:08:38305
306 DCHECK_EQ(state_, CONNECTED);
Adam Rice666d0352018-05-28 06:08:38307
308 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(op_code))
309 << "Got SendFrame with bogus op_code " << op_code << " fin=" << fin
310 << " buffer_size=" << buffer_size;
311
[email protected]48cc6922014-02-10 14:20:48312 if (op_code == WebSocketFrameHeader::kOpCodeText ||
313 (op_code == WebSocketFrameHeader::kOpCodeContinuation &&
314 sending_text_message_)) {
315 StreamingUtf8Validator::State state =
darin0da77e922016-10-04 17:31:23316 outgoing_utf8_validator_.AddBytes(buffer->data(), buffer_size);
[email protected]48cc6922014-02-10 14:20:48317 if (state == StreamingUtf8Validator::INVALID ||
318 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) {
319 // TODO(ricea): Kill renderer.
Yutaka Hirano4165de92018-04-10 11:46:49320 FailChannel("Browser sent a text frame containing invalid UTF-8",
321 kWebSocketErrorGoingAway, "");
322 return CHANNEL_DELETED;
[email protected]48cc6922014-02-10 14:20:48323 // |this| has been deleted.
[email protected]48cc6922014-02-10 14:20:48324 }
325 sending_text_message_ = !fin;
326 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT);
327 }
Adam Rice250bb012020-05-26 15:56:10328
darin0da77e922016-10-04 17:31:23329 return SendFrameInternal(fin, op_code, std::move(buffer), buffer_size);
[email protected]f485985e2013-10-24 13:47:44330 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54331}
332
yhiranod2727df2016-04-11 05:32:49333ChannelState WebSocketChannel::StartClosingHandshake(
334 uint16_t code,
335 const std::string& reason) {
[email protected]c0d29c22013-07-26 20:40:41336 if (InClosingState()) {
[email protected]e778f322014-07-28 10:00:53337 // When the associated renderer process is killed while the channel is in
338 // CLOSING state we reach here.
[email protected]b8393cc2014-04-14 06:22:25339 DVLOG(1) << "StartClosingHandshake called in state " << state_
340 << ". This may be a bug, or a harmless race.";
yhiranod2727df2016-04-11 05:32:49341 return CHANNEL_ALIVE;
342 }
343 if (has_received_close_frame_) {
344 // We reach here if the client wants to start a closing handshake while
345 // the browser is waiting for the client to consume incoming data frames
346 // before responding to a closing handshake initiated by the server.
347 // As the client doesn't want the data frames any more, we can respond to
348 // the closing handshake initiated by the server.
349 return RespondToClosingHandshake();
[email protected]999bcaa2013-07-17 13:42:54350 }
[email protected]6dfd8b32014-02-05 11:24:49351 if (state_ == CONNECTING) {
352 // Abort the in-progress handshake and drop the connection immediately.
353 stream_request_.reset();
[email protected]09ef67362014-04-24 08:48:58354 SetState(CLOSED);
Yutaka Hirano4165de92018-04-10 11:46:49355 DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
356 return CHANNEL_DELETED;
[email protected]6dfd8b32014-02-05 11:24:49357 }
Adam Rice666d0352018-05-28 06:08:38358 DCHECK_EQ(state_, CONNECTED);
tyoshinod4d1d302014-11-07 04:31:16359
360 DCHECK(!close_timer_.IsRunning());
361 // This use of base::Unretained() is safe because we stop the timer in the
362 // destructor.
363 close_timer_.Start(
Yannic Bonenberger782a28602019-09-03 10:36:52364 FROM_HERE, closing_handshake_timeout_,
365 base::BindOnce(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
tyoshinod4d1d302014-11-07 04:31:16366
[email protected]3de65092013-10-24 09:39:44367 // Javascript actually only permits 1000 and 3000-4999, but the implementation
368 // itself may produce different codes. The length of |reason| is also checked
369 // by Javascript.
370 if (!IsStrictlyValidCloseStatusCode(code) ||
371 reason.size() > kMaximumCloseReasonLength) {
372 // "InternalServerError" is actually used for errors from any endpoint, per
373 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
374 // reason it must be malfunctioning in some way, and based on that we
375 // interpret this as an internal error.
yhiranod2727df2016-04-11 05:32:49376 if (SendClose(kWebSocketErrorInternalServerError, "") == CHANNEL_DELETED)
377 return CHANNEL_DELETED;
378 DCHECK_EQ(CONNECTED, state_);
379 SetState(SEND_CLOSED);
380 return CHANNEL_ALIVE;
[email protected]3de65092013-10-24 09:39:44381 }
Yutaka Hirano4165de92018-04-10 11:46:49382 if (SendClose(code, StreamingUtf8Validator::Validate(reason)
383 ? reason
384 : std::string()) == CHANNEL_DELETED)
yhiranod2727df2016-04-11 05:32:49385 return CHANNEL_DELETED;
[email protected]0f5f1bb2014-04-22 08:34:35386 DCHECK_EQ(CONNECTED, state_);
[email protected]09ef67362014-04-24 08:48:58387 SetState(SEND_CLOSED);
yhiranod2727df2016-04-11 05:32:49388 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54389}
390
391void WebSocketChannel::SendAddChannelRequestForTesting(
[email protected]dab33eb2013-10-08 02:27:51392 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54393 const std::vector<std::string>& requested_subprotocols,
mkwst4997ce82015-07-25 12:00:05394 const url::Origin& origin,
Maks Orlovich8be0e252019-12-09 18:35:49395 const SiteForCookies& site_for_cookies,
Matt Menke29a538d2020-04-29 16:12:17396 const IsolationInfo& isolation_info,
Yutaka Hirano2f65eec2018-05-23 01:58:22397 const HttpRequestHeaders& additional_headers,
Adam Langleyacbad242020-08-18 15:14:52398 NetworkTrafficAnnotationTag traffic_annotation,
Anna Malova5a2d13182020-03-05 11:04:07399 WebSocketStreamRequestCreationCallback callback) {
Ehimare Okoyomon4446d8c2019-10-23 12:47:32400 SendAddChannelRequestWithSuppliedCallback(
401 socket_url, requested_subprotocols, origin, site_for_cookies,
Adam Langleyacbad242020-08-18 15:14:52402 isolation_info, additional_headers, traffic_annotation,
403 std::move(callback));
[email protected]3a266762013-10-23 08:15:10404}
405
406void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
407 base::TimeDelta delay) {
tyoshinod4d1d302014-11-07 04:31:16408 closing_handshake_timeout_ = delay;
409}
410
411void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting(
412 base::TimeDelta delay) {
413 underlying_connection_close_timeout_ = delay;
[email protected]999bcaa2013-07-17 13:42:54414}
415
tyoshinoccfcfde2016-07-21 14:06:55416void WebSocketChannel::SendAddChannelRequestWithSuppliedCallback(
[email protected]dab33eb2013-10-08 02:27:51417 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54418 const std::vector<std::string>& requested_subprotocols,
mkwst4997ce82015-07-25 12:00:05419 const url::Origin& origin,
Maks Orlovich8be0e252019-12-09 18:35:49420 const SiteForCookies& site_for_cookies,
Matt Menke29a538d2020-04-29 16:12:17421 const IsolationInfo& isolation_info,
Yutaka Hirano2f65eec2018-05-23 01:58:22422 const HttpRequestHeaders& additional_headers,
Adam Langleyacbad242020-08-18 15:14:52423 NetworkTrafficAnnotationTag traffic_annotation,
Anna Malova5a2d13182020-03-05 11:04:07424 WebSocketStreamRequestCreationCallback callback) {
[email protected]999bcaa2013-07-17 13:42:54425 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
[email protected]53deacb2013-11-22 14:02:43426 if (!socket_url.SchemeIsWSOrWSS()) {
427 // TODO(ricea): Kill the renderer (this error should have been caught by
428 // Javascript).
Adam Langleya48b636a2020-11-12 23:42:52429 event_interface_->OnFailChannel("Invalid scheme", ERR_FAILED,
Anton Bikineev068d2912021-05-15 20:43:52430 absl::nullopt);
[email protected]53deacb2013-11-22 14:02:43431 // |this| is deleted here.
432 return;
433 }
[email protected]dab33eb2013-10-08 02:27:51434 socket_url_ = socket_url;
Bence Béky65623972018-03-05 15:31:56435 auto connect_delegate = std::make_unique<ConnectDelegate>(this);
Anna Malova5a2d13182020-03-05 11:04:07436 stream_request_ = std::move(callback).Run(
Ehimare Okoyomon4446d8c2019-10-23 12:47:32437 socket_url_, requested_subprotocols, origin, site_for_cookies,
Keishi Hattori0e45c022021-11-27 09:25:52438 isolation_info, additional_headers, url_request_context_.get(),
Adam Langleyacbad242020-08-18 15:14:52439 NetLogWithSource(), traffic_annotation, std::move(connect_delegate));
[email protected]09ef67362014-04-24 08:48:58440 SetState(CONNECTING);
[email protected]999bcaa2013-07-17 13:42:54441}
442
yhirano4a593832016-10-24 18:58:22443void WebSocketChannel::OnCreateURLRequest(URLRequest* request) {
444 event_interface_->OnCreateURLRequest(request);
445}
446
danakj9c5cab52016-04-16 00:54:33447void WebSocketChannel::OnConnectSuccess(
Yoichi Osato1ead61a2020-01-06 04:52:57448 std::unique_ptr<WebSocketStream> stream,
449 std::unique_ptr<WebSocketHandshakeResponseInfo> response) {
[email protected]999bcaa2013-07-17 13:42:54450 DCHECK(stream);
451 DCHECK_EQ(CONNECTING, state_);
[email protected]09ef67362014-04-24 08:48:58452
dchengc7eeda422015-12-26 03:56:48453 stream_ = std::move(stream);
[email protected]09ef67362014-04-24 08:48:58454
455 SetState(CONNECTED);
456
Yoichi Osato1bcffbc2019-10-30 03:17:31457 // |stream_request_| is not used once the connection has succeeded.
458 stream_request_.reset();
[email protected]999bcaa2013-07-17 13:42:54459
Yoichi Osato1ead61a2020-01-06 04:52:57460 event_interface_->OnAddChannelResponse(
Adam Rice250bb012020-05-26 15:56:10461 std::move(response), stream_->GetSubProtocol(), stream_->GetExtensions());
Yoichi Osato1bcffbc2019-10-30 03:17:31462 // |this| may have been deleted after OnAddChannelResponse.
[email protected]999bcaa2013-07-17 13:42:54463}
464
Adam Langleya48b636a2020-11-12 23:42:52465void WebSocketChannel::OnConnectFailure(const std::string& message,
466 int net_error,
Anton Bikineev068d2912021-05-15 20:43:52467 absl::optional<int> response_code) {
[email protected]999bcaa2013-07-17 13:42:54468 DCHECK_EQ(CONNECTING, state_);
[email protected]09ef67362014-04-24 08:48:58469
[email protected]8aba0172014-07-03 12:09:53470 // Copy the message before we delete its owner.
471 std::string message_copy = message;
472
[email protected]09ef67362014-04-24 08:48:58473 SetState(CLOSED);
[email protected]999bcaa2013-07-17 13:42:54474 stream_request_.reset();
[email protected]cd48ed12014-01-22 14:34:22475
Adam Langleya48b636a2020-11-12 23:42:52476 event_interface_->OnFailChannel(message_copy, net_error, response_code);
[email protected]f485985e2013-10-24 13:47:44477 // |this| has been deleted.
[email protected]999bcaa2013-07-17 13:42:54478}
479
[email protected]a62449522014-06-05 11:11:15480void WebSocketChannel::OnSSLCertificateError(
danakj9c5cab52016-04-16 00:54:33481 std::unique_ptr<WebSocketEventInterface::SSLErrorCallbacks>
482 ssl_error_callbacks,
Emily Starkd9df3d32019-04-29 17:54:57483 int net_error,
[email protected]a62449522014-06-05 11:11:15484 const SSLInfo& ssl_info,
485 bool fatal) {
Emily Starkd9df3d32019-04-29 17:54:57486 event_interface_->OnSSLCertificateError(
487 std::move(ssl_error_callbacks), socket_url_, net_error, ssl_info, fatal);
[email protected]a62449522014-06-05 11:11:15488}
489
Yutaka Hirano70fa25912018-06-06 05:26:54490int WebSocketChannel::OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58491 const AuthChallengeInfo& auth_info,
Yutaka Hirano70fa25912018-06-06 05:26:54492 scoped_refptr<HttpResponseHeaders> response_headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37493 const IPEndPoint& remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54494 base::OnceCallback<void(const AuthCredentials*)> callback,
Anton Bikineev068d2912021-05-15 20:43:52495 absl::optional<AuthCredentials>* credentials) {
Yutaka Hirano70fa25912018-06-06 05:26:54496 return event_interface_->OnAuthRequired(
Emily Starkf2c9bbd2019-04-09 17:08:58497 auth_info, std::move(response_headers), remote_endpoint,
Yutaka Hirano70fa25912018-06-06 05:26:54498 std::move(callback), credentials);
499}
500
[email protected]cd48ed12014-01-22 14:34:22501void WebSocketChannel::OnStartOpeningHandshake(
danakj9c5cab52016-04-16 00:54:33502 std::unique_ptr<WebSocketHandshakeRequestInfo> request) {
Yutaka Hirano6c960cc2018-05-24 05:34:38503 event_interface_->OnStartOpeningHandshake(std::move(request));
[email protected]cd48ed12014-01-22 14:34:22504}
505
[email protected]f485985e2013-10-24 13:47:44506ChannelState WebSocketChannel::WriteFrames() {
[email protected]999bcaa2013-07-17 13:42:54507 int result = OK;
508 do {
[email protected]caab2cc2013-08-27 10:24:37509 // This use of base::Unretained is safe because this object owns the
510 // WebSocketStream and destroying it cancels all callbacks.
[email protected]999bcaa2013-07-17 13:42:54511 result = stream_->WriteFrames(
[email protected]c0d29c22013-07-26 20:40:41512 data_being_sent_->frames(),
Yannic Bonenberger782a28602019-09-03 10:36:52513 base::BindOnce(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
514 base::Unretained(this), false));
[email protected]999bcaa2013-07-17 13:42:54515 if (result != ERR_IO_PENDING) {
[email protected]f485985e2013-10-24 13:47:44516 if (OnWriteDone(true, result) == CHANNEL_DELETED)
517 return CHANNEL_DELETED;
[email protected]3d5637692014-03-19 16:48:22518 // OnWriteDone() returns CHANNEL_DELETED on error. Here |state_| is
519 // guaranteed to be the same as before OnWriteDone() call.
[email protected]999bcaa2013-07-17 13:42:54520 }
521 } while (result == OK && data_being_sent_);
[email protected]f485985e2013-10-24 13:47:44522 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54523}
524
[email protected]f485985e2013-10-24 13:47:44525ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
[email protected]999bcaa2013-07-17 13:42:54526 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
527 DCHECK_NE(CONNECTING, state_);
528 DCHECK_NE(ERR_IO_PENDING, result);
529 DCHECK(data_being_sent_);
530 switch (result) {
531 case OK:
532 if (data_to_send_next_) {
dchengc7eeda422015-12-26 03:56:48533 data_being_sent_ = std::move(data_to_send_next_);
[email protected]f485985e2013-10-24 13:47:44534 if (!synchronous)
535 return WriteFrames();
[email protected]999bcaa2013-07-17 13:42:54536 } else {
537 data_being_sent_.reset();
Adam Riced0095702020-05-26 06:18:25538 event_interface_->OnSendDataFrameDone();
[email protected]999bcaa2013-07-17 13:42:54539 }
[email protected]f485985e2013-10-24 13:47:44540 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54541
542 // If a recoverable error condition existed, it would go here.
543
544 default:
545 DCHECK_LT(result, 0)
546 << "WriteFrames() should only return OK or ERR_ codes";
[email protected]09ef67362014-04-24 08:48:58547
[email protected]999bcaa2013-07-17 13:42:54548 stream_->Close();
[email protected]09ef67362014-04-24 08:48:58549 SetState(CLOSED);
Yutaka Hirano4165de92018-04-10 11:46:49550 DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
551 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54552 }
553}
554
[email protected]f485985e2013-10-24 13:47:44555ChannelState WebSocketChannel::ReadFrames() {
Yutaka Hirano8fa32842019-08-29 03:13:06556 DCHECK(stream_);
Yoichi Osatofcaa2a22019-08-28 08:22:36557 DCHECK(state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT);
558 DCHECK(read_frames_.empty());
559 if (is_reading_) {
560 return CHANNEL_ALIVE;
561 }
562
Yoichi Osatofcaa2a22019-08-28 08:22:36563 if (!InClosingState() && has_received_close_frame_) {
564 DCHECK(!event_interface_->HasPendingDataFrames());
565 // We've been waiting for the client to consume the frames before
566 // responding to the closing handshake initiated by the server.
Yutaka Hiranod9331732019-09-30 09:46:20567 if (RespondToClosingHandshake() == CHANNEL_DELETED) {
568 return CHANNEL_DELETED;
569 }
Yoichi Osatofcaa2a22019-08-28 08:22:36570 }
571
Yutaka Hiranofcfbeb42019-09-25 14:43:39572 // TODO(crbug.com/999235): Remove this CHECK.
573 CHECK(event_interface_);
Yoichi Osatofcaa2a22019-08-28 08:22:36574 while (!event_interface_->HasPendingDataFrames()) {
Yutaka Hirano8fa32842019-08-29 03:13:06575 DCHECK(stream_);
[email protected]caab2cc2013-08-27 10:24:37576 // This use of base::Unretained is safe because this object owns the
577 // WebSocketStream, and any pending reads will be cancelled when it is
578 // destroyed.
Yutaka Hiranodfa67e52019-07-29 03:13:26579 const int result = stream_->ReadFrames(
[email protected]2f5d9f62013-09-26 12:14:28580 &read_frames_,
Yannic Bonenberger782a28602019-09-03 10:36:52581 base::BindOnce(base::IgnoreResult(&WebSocketChannel::OnReadDone),
582 base::Unretained(this), false));
Yutaka Hiranodfa67e52019-07-29 03:13:26583 if (result == ERR_IO_PENDING) {
Yoichi Osatofcaa2a22019-08-28 08:22:36584 is_reading_ = true;
Yutaka Hiranodfa67e52019-07-29 03:13:26585 return CHANNEL_ALIVE;
586 }
587 if (OnReadDone(true, result) == CHANNEL_DELETED) {
588 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54589 }
[email protected]f485985e2013-10-24 13:47:44590 DCHECK_NE(CLOSED, state_);
Yutaka Hiranofcfbeb42019-09-25 14:43:39591 // TODO(crbug.com/999235): Remove this CHECK.
592 CHECK(event_interface_);
[email protected]4256dbb2014-03-24 15:39:36593 }
[email protected]f485985e2013-10-24 13:47:44594 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54595}
596
[email protected]f485985e2013-10-24 13:47:44597ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
Yoichi Osatofcaa2a22019-08-28 08:22:36598 DVLOG(3) << "WebSocketChannel::OnReadDone synchronous?" << synchronous
599 << ", result=" << result
600 << ", read_frames_.size=" << read_frames_.size();
[email protected]999bcaa2013-07-17 13:42:54601 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
602 DCHECK_NE(CONNECTING, state_);
603 DCHECK_NE(ERR_IO_PENDING, result);
604 switch (result) {
605 case OK:
606 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
607 // with no data read, not an empty response.
[email protected]2f5d9f62013-09-26 12:14:28608 DCHECK(!read_frames_.empty())
[email protected]999bcaa2013-07-17 13:42:54609 << "ReadFrames() returned OK, but nothing was read.";
Tsuyoshi Horo17ef47d02022-06-30 10:58:27610 for (auto& read_frame : read_frames_) {
611 if (HandleFrame(std::move(read_frame)) == CHANNEL_DELETED)
[email protected]f485985e2013-10-24 13:47:44612 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54613 }
[email protected]2f5d9f62013-09-26 12:14:28614 read_frames_.clear();
[email protected]f485985e2013-10-24 13:47:44615 DCHECK_NE(CLOSED, state_);
Yoichi Osatofcaa2a22019-08-28 08:22:36616 if (!synchronous) {
617 is_reading_ = false;
618 if (!event_interface_->HasPendingDataFrames()) {
619 return ReadFrames();
620 }
621 }
[email protected]f485985e2013-10-24 13:47:44622 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54623
[email protected]2f5d9f62013-09-26 12:14:28624 case ERR_WS_PROTOCOL_ERROR:
[email protected]ea56b982014-01-27 03:21:03625 // This could be kWebSocketErrorProtocolError (specifically, non-minimal
626 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an
627 // extension-specific error.
Yutaka Hirano4165de92018-04-10 11:46:49628 FailChannel("Invalid frame header", kWebSocketErrorProtocolError,
629 "WebSocket Protocol Error");
630 return CHANNEL_DELETED;
[email protected]2f5d9f62013-09-26 12:14:28631
[email protected]c0d29c22013-07-26 20:40:41632 default:
[email protected]999bcaa2013-07-17 13:42:54633 DCHECK_LT(result, 0)
634 << "ReadFrames() should only return OK or ERR_ codes";
[email protected]09ef67362014-04-24 08:48:58635
[email protected]999bcaa2013-07-17 13:42:54636 stream_->Close();
[email protected]09ef67362014-04-24 08:48:58637 SetState(CLOSED);
638
tfarina8a2c66c22015-10-13 19:14:49639 uint16_t code = kWebSocketErrorAbnormalClosure;
[email protected]5742ae62014-02-06 11:03:18640 std::string reason = "";
[email protected]86ec55502014-02-10 13:16:16641 bool was_clean = false;
tyoshinoceae3b242014-10-31 06:43:19642 if (has_received_close_frame_) {
[email protected]8b3d14e2014-02-13 14:24:28643 code = received_close_code_;
644 reason = received_close_reason_;
[email protected]86ec55502014-02-10 13:16:16645 was_clean = (result == ERR_CONNECTION_CLOSED);
[email protected]999bcaa2013-07-17 13:42:54646 }
[email protected]09ef67362014-04-24 08:48:58647
Yutaka Hirano4165de92018-04-10 11:46:49648 DoDropChannel(was_clean, code, reason);
649 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54650 }
651}
652
danakj9c5cab52016-04-16 00:54:33653ChannelState WebSocketChannel::HandleFrame(
654 std::unique_ptr<WebSocketFrame> frame) {
[email protected]2f5d9f62013-09-26 12:14:28655 if (frame->header.masked) {
656 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
657 // masked frame."
Yutaka Hirano4165de92018-04-10 11:46:49658 FailChannel(
[email protected]ea56b982014-01-27 03:21:03659 "A server must not mask any frames that it sends to the "
660 "client.",
Yutaka Hirano4165de92018-04-10 11:46:49661 kWebSocketErrorProtocolError, "Masked frame from server");
662 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54663 }
[email protected]2f5d9f62013-09-26 12:14:28664 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
[email protected]bae48422014-03-05 15:07:25665 DCHECK(!WebSocketFrameHeader::IsKnownControlOpCode(opcode) ||
666 frame->header.final);
[email protected]658d7672014-02-26 13:11:35667 if (frame->header.reserved1 || frame->header.reserved2 ||
668 frame->header.reserved3) {
Yutaka Hirano4165de92018-04-10 11:46:49669 FailChannel(
670 base::StringPrintf("One or more reserved bits are on: reserved1 = %d, "
[email protected]c46c2612014-02-28 17:08:02671 "reserved2 = %d, reserved3 = %d",
672 static_cast<int>(frame->header.reserved1),
673 static_cast<int>(frame->header.reserved2),
674 static_cast<int>(frame->header.reserved3)),
Yutaka Hirano4165de92018-04-10 11:46:49675 kWebSocketErrorProtocolError, "Invalid reserved bit");
676 return CHANNEL_DELETED;
[email protected]658d7672014-02-26 13:11:35677 }
[email protected]999bcaa2013-07-17 13:42:54678
[email protected]999bcaa2013-07-17 13:42:54679 // Respond to the frame appropriately to its type.
Yutaka Hirano76aacb202019-09-05 16:36:56680 return HandleFrameByState(
681 opcode, frame->header.final,
Yoichi Osato05cd3642019-09-09 18:13:08682 base::make_span(frame->payload, frame->header.payload_length));
[email protected]999bcaa2013-07-17 13:42:54683}
684
[email protected]8b3d14e2014-02-13 14:24:28685ChannelState WebSocketChannel::HandleFrameByState(
[email protected]f485985e2013-10-24 13:47:44686 const WebSocketFrameHeader::OpCode opcode,
687 bool final,
Yutaka Hirano76aacb202019-09-05 16:36:56688 base::span<const char> payload) {
[email protected]999bcaa2013-07-17 13:42:54689 DCHECK_NE(RECV_CLOSED, state_)
690 << "HandleFrame() does not support being called re-entrantly from within "
691 "SendClose()";
[email protected]f485985e2013-10-24 13:47:44692 DCHECK_NE(CLOSED, state_);
693 if (state_ == CLOSE_WAIT) {
[email protected]999bcaa2013-07-17 13:42:54694 std::string frame_name;
[email protected]8b3d14e2014-02-13 14:24:28695 GetFrameTypeForOpcode(opcode, &frame_name);
[email protected]999bcaa2013-07-17 13:42:54696
[email protected]ea56b982014-01-27 03:21:03697 // FailChannel() won't send another Close frame.
Yutaka Hirano4165de92018-04-10 11:46:49698 FailChannel(frame_name + " received after close",
699 kWebSocketErrorProtocolError, "");
700 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54701 }
702 switch (opcode) {
[email protected]4256dbb2014-03-24 15:39:36703 case WebSocketFrameHeader::kOpCodeText: // fall-thru
[email protected]4e4bbaae7e2014-02-19 08:28:53704 case WebSocketFrameHeader::kOpCodeBinary:
[email protected]999bcaa2013-07-17 13:42:54705 case WebSocketFrameHeader::kOpCodeContinuation:
Yutaka Hirano76aacb202019-09-05 16:36:56706 return HandleDataFrame(opcode, final, std::move(payload));
[email protected]999bcaa2013-07-17 13:42:54707
708 case WebSocketFrameHeader::kOpCodePing:
Yutaka Hirano76aacb202019-09-05 16:36:56709 DVLOG(1) << "Got Ping of size " << payload.size();
710 if (state_ == CONNECTED) {
711 auto buffer = base::MakeRefCounted<IOBuffer>(payload.size());
712 memcpy(buffer->data(), payload.data(), payload.size());
darin0da77e922016-10-04 17:31:23713 return SendFrameInternal(true, WebSocketFrameHeader::kOpCodePong,
Yutaka Hirano76aacb202019-09-05 16:36:56714 std::move(buffer), payload.size());
715 }
[email protected]b8393cc2014-04-14 06:22:25716 DVLOG(3) << "Ignored ping in state " << state_;
[email protected]f485985e2013-10-24 13:47:44717 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54718
719 case WebSocketFrameHeader::kOpCodePong:
Yutaka Hirano76aacb202019-09-05 16:36:56720 DVLOG(1) << "Got Pong of size " << payload.size();
[email protected]caab2cc2013-08-27 10:24:37721 // There is no need to do anything with pong messages.
[email protected]f485985e2013-10-24 13:47:44722 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54723
724 case WebSocketFrameHeader::kOpCodeClose: {
tfarina8a2c66c22015-10-13 19:14:49725 uint16_t code = kWebSocketNormalClosure;
[email protected]999bcaa2013-07-17 13:42:54726 std::string reason;
[email protected]ea56b982014-01-27 03:21:03727 std::string message;
Yutaka Hirano76aacb202019-09-05 16:36:56728 if (!ParseClose(payload, &code, &reason, &message)) {
Yutaka Hirano4165de92018-04-10 11:46:49729 FailChannel(message, code, reason);
730 return CHANNEL_DELETED;
[email protected]ea56b982014-01-27 03:21:03731 }
[email protected]999bcaa2013-07-17 13:42:54732 // TODO(ricea): Find a way to safely log the message from the close
733 // message (escape control codes and so on).
yhiranod2727df2016-04-11 05:32:49734 return HandleCloseFrame(code, reason);
[email protected]999bcaa2013-07-17 13:42:54735 }
736
737 default:
Yutaka Hirano4165de92018-04-10 11:46:49738 FailChannel(base::StringPrintf("Unrecognized frame opcode: %d", opcode),
739 kWebSocketErrorProtocolError, "Unknown opcode");
740 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54741 }
742}
743
[email protected]4e4bbaae7e2014-02-19 08:28:53744ChannelState WebSocketChannel::HandleDataFrame(
[email protected]326b8fb2014-02-21 21:14:00745 WebSocketFrameHeader::OpCode opcode,
[email protected]4e4bbaae7e2014-02-19 08:28:53746 bool final,
Yutaka Hirano76aacb202019-09-05 16:36:56747 base::span<const char> payload) {
Yoichi Osatofcaa2a22019-08-28 08:22:36748 DVLOG(3) << "WebSocketChannel::HandleDataFrame opcode=" << opcode
Yutaka Hirano76aacb202019-09-05 16:36:56749 << ", final?" << final << ", data=" << (void*)payload.data()
750 << ", size=" << payload.size();
[email protected]4e4bbaae7e2014-02-19 08:28:53751 if (state_ != CONNECTED) {
752 DVLOG(3) << "Ignored data packet received in state " << state_;
753 return CHANNEL_ALIVE;
754 }
yhiranod2727df2016-04-11 05:32:49755 if (has_received_close_frame_) {
756 DVLOG(3) << "Ignored data packet as we've received a close frame.";
757 return CHANNEL_ALIVE;
758 }
[email protected]4e4bbaae7e2014-02-19 08:28:53759 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation ||
760 opcode == WebSocketFrameHeader::kOpCodeText ||
761 opcode == WebSocketFrameHeader::kOpCodeBinary);
762 const bool got_continuation =
763 (opcode == WebSocketFrameHeader::kOpCodeContinuation);
764 if (got_continuation != expecting_to_handle_continuation_) {
765 const std::string console_log = got_continuation
766 ? "Received unexpected continuation frame."
767 : "Received start of new message but previous message is unfinished.";
768 const std::string reason = got_continuation
769 ? "Unexpected continuation"
770 : "Previous data frame unfinished";
Yutaka Hirano4165de92018-04-10 11:46:49771 FailChannel(console_log, kWebSocketErrorProtocolError, reason);
772 return CHANNEL_DELETED;
[email protected]4e4bbaae7e2014-02-19 08:28:53773 }
774 expecting_to_handle_continuation_ = !final;
[email protected]326b8fb2014-02-21 21:14:00775 WebSocketFrameHeader::OpCode opcode_to_send = opcode;
776 if (!initial_frame_forwarded_ &&
777 opcode == WebSocketFrameHeader::kOpCodeContinuation) {
778 opcode_to_send = receiving_text_message_
779 ? WebSocketFrameHeader::kOpCodeText
780 : WebSocketFrameHeader::kOpCodeBinary;
781 }
[email protected]4e4bbaae7e2014-02-19 08:28:53782 if (opcode == WebSocketFrameHeader::kOpCodeText ||
783 (opcode == WebSocketFrameHeader::kOpCodeContinuation &&
784 receiving_text_message_)) {
785 // This call is not redundant when size == 0 because it tells us what
786 // the current state is.
787 StreamingUtf8Validator::State state = incoming_utf8_validator_.AddBytes(
Yutaka Hirano76aacb202019-09-05 16:36:56788 payload.data(), static_cast<size_t>(payload.size()));
[email protected]4e4bbaae7e2014-02-19 08:28:53789 if (state == StreamingUtf8Validator::INVALID ||
790 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) {
Yutaka Hirano4165de92018-04-10 11:46:49791 FailChannel("Could not decode a text frame as UTF-8.",
792 kWebSocketErrorProtocolError, "Invalid UTF-8 in text frame");
793 return CHANNEL_DELETED;
[email protected]4e4bbaae7e2014-02-19 08:28:53794 }
795 receiving_text_message_ = !final;
796 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT);
797 }
Yutaka Hirano76aacb202019-09-05 16:36:56798 if (payload.size() == 0U && !final)
[email protected]326b8fb2014-02-21 21:14:00799 return CHANNEL_ALIVE;
800
801 initial_frame_forwarded_ = !final;
[email protected]4e4bbaae7e2014-02-19 08:28:53802 // Sends the received frame to the renderer process.
Yutaka Hirano76aacb202019-09-05 16:36:56803 event_interface_->OnDataFrame(final, opcode_to_send, payload);
Yutaka Hirano4165de92018-04-10 11:46:49804 return CHANNEL_ALIVE;
[email protected]4e4bbaae7e2014-02-19 08:28:53805}
806
yhiranod2727df2016-04-11 05:32:49807ChannelState WebSocketChannel::HandleCloseFrame(uint16_t code,
808 const std::string& reason) {
809 DVLOG(1) << "Got Close with code " << code;
810 switch (state_) {
811 case CONNECTED:
812 has_received_close_frame_ = true;
813 received_close_code_ = code;
814 received_close_reason_ = reason;
Yoichi Osatofcaa2a22019-08-28 08:22:36815 if (event_interface_->HasPendingDataFrames()) {
yhiranod2727df2016-04-11 05:32:49816 // We have some data to be sent to the renderer before sending this
817 // frame.
818 return CHANNEL_ALIVE;
819 }
820 return RespondToClosingHandshake();
821
822 case SEND_CLOSED:
823 SetState(CLOSE_WAIT);
824 DCHECK(close_timer_.IsRunning());
825 close_timer_.Stop();
826 // This use of base::Unretained() is safe because we stop the timer
827 // in the destructor.
Yannic Bonenberger782a28602019-09-03 10:36:52828 close_timer_.Start(FROM_HERE, underlying_connection_close_timeout_,
829 base::BindOnce(&WebSocketChannel::CloseTimeout,
830 base::Unretained(this)));
yhiranod2727df2016-04-11 05:32:49831
832 // From RFC6455 section 7.1.5: "Each endpoint
833 // will see the status code sent by the other end as _The WebSocket
834 // Connection Close Code_."
835 has_received_close_frame_ = true;
836 received_close_code_ = code;
837 received_close_reason_ = reason;
838 break;
839
840 default:
841 LOG(DFATAL) << "Got Close in unexpected state " << state_;
842 break;
843 }
844 return CHANNEL_ALIVE;
845}
846
847ChannelState WebSocketChannel::RespondToClosingHandshake() {
848 DCHECK(has_received_close_frame_);
849 DCHECK_EQ(CONNECTED, state_);
850 SetState(RECV_CLOSED);
851 if (SendClose(received_close_code_, received_close_reason_) ==
852 CHANNEL_DELETED)
853 return CHANNEL_DELETED;
854 DCHECK_EQ(RECV_CLOSED, state_);
855
856 SetState(CLOSE_WAIT);
857 DCHECK(!close_timer_.IsRunning());
858 // This use of base::Unretained() is safe because we stop the timer
859 // in the destructor.
860 close_timer_.Start(
861 FROM_HERE, underlying_connection_close_timeout_,
Yannic Bonenberger782a28602019-09-03 10:36:52862 base::BindOnce(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
yhiranod2727df2016-04-11 05:32:49863
Yutaka Hirano4165de92018-04-10 11:46:49864 event_interface_->OnClosingHandshake();
865 return CHANNEL_ALIVE;
yhiranod2727df2016-04-11 05:32:49866}
867
darin0da77e922016-10-04 17:31:23868ChannelState WebSocketChannel::SendFrameInternal(
[email protected]f485985e2013-10-24 13:47:44869 bool fin,
870 WebSocketFrameHeader::OpCode op_code,
darin0da77e922016-10-04 17:31:23871 scoped_refptr<IOBuffer> buffer,
Yutaka Hirano76aacb202019-09-05 16:36:56872 uint64_t buffer_size) {
[email protected]999bcaa2013-07-17 13:42:54873 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
874 DCHECK(stream_);
[email protected]3d5637692014-03-19 16:48:22875
Bence Béky65623972018-03-05 15:31:56876 auto frame = std::make_unique<WebSocketFrame>(op_code);
[email protected]2f5d9f62013-09-26 12:14:28877 WebSocketFrameHeader& header = frame->header;
878 header.final = fin;
879 header.masked = true;
Yutaka Hirano76aacb202019-09-05 16:36:56880 header.payload_length = buffer_size;
Yoichi Osato05cd3642019-09-09 18:13:08881 frame->payload = buffer->data();
[email protected]3d5637692014-03-19 16:48:22882
[email protected]999bcaa2013-07-17 13:42:54883 if (data_being_sent_) {
[email protected]caab2cc2013-08-27 10:24:37884 // Either the link to the WebSocket server is saturated, or several messages
885 // are being sent in a batch.
[email protected]999bcaa2013-07-17 13:42:54886 if (!data_to_send_next_)
Bence Béky65623972018-03-05 15:31:56887 data_to_send_next_ = std::make_unique<SendBuffer>();
Yutaka Hirano76aacb202019-09-05 16:36:56888 data_to_send_next_->AddFrame(std::move(frame), std::move(buffer));
[email protected]f485985e2013-10-24 13:47:44889 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54890 }
[email protected]3d5637692014-03-19 16:48:22891
Bence Béky65623972018-03-05 15:31:56892 data_being_sent_ = std::make_unique<SendBuffer>();
Yutaka Hirano76aacb202019-09-05 16:36:56893 data_being_sent_->AddFrame(std::move(frame), std::move(buffer));
[email protected]f485985e2013-10-24 13:47:44894 return WriteFrames();
[email protected]999bcaa2013-07-17 13:42:54895}
896
Yutaka Hirano4165de92018-04-10 11:46:49897void WebSocketChannel::FailChannel(const std::string& message,
898 uint16_t code,
899 const std::string& reason) {
[email protected]999bcaa2013-07-17 13:42:54900 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
901 DCHECK_NE(CONNECTING, state_);
[email protected]f485985e2013-10-24 13:47:44902 DCHECK_NE(CLOSED, state_);
[email protected]09ef67362014-04-24 08:48:58903
Nanami Mikiya504e7042022-02-10 09:57:50904 stream_->GetNetLogWithSource().AddEvent(
905 net::NetLogEventType::WEBSOCKET_INVALID_FRAME,
906 [&] { return NetLogFailParam(code, reason, message); });
907
[email protected]999bcaa2013-07-17 13:42:54908 if (state_ == CONNECTED) {
[email protected]3d5637692014-03-19 16:48:22909 if (SendClose(code, reason) == CHANNEL_DELETED)
Yutaka Hirano4165de92018-04-10 11:46:49910 return;
[email protected]999bcaa2013-07-17 13:42:54911 }
[email protected]09ef67362014-04-24 08:48:58912
[email protected]caab2cc2013-08-27 10:24:37913 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
914 // should close the connection itself without waiting for the closing
915 // handshake.
[email protected]999bcaa2013-07-17 13:42:54916 stream_->Close();
[email protected]09ef67362014-04-24 08:48:58917 SetState(CLOSED);
Anton Bikineev068d2912021-05-15 20:43:52918 event_interface_->OnFailChannel(message, ERR_FAILED, absl::nullopt);
[email protected]999bcaa2013-07-17 13:42:54919}
920
tfarina8a2c66c22015-10-13 19:14:49921ChannelState WebSocketChannel::SendClose(uint16_t code,
[email protected]f485985e2013-10-24 13:47:44922 const std::string& reason) {
[email protected]999bcaa2013-07-17 13:42:54923 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
[email protected]3de65092013-10-24 09:39:44924 DCHECK_LE(reason.size(), kMaximumCloseReasonLength);
[email protected]2f5d9f62013-09-26 12:14:28925 scoped_refptr<IOBuffer> body;
tfarina8a2c66c22015-10-13 19:14:49926 uint64_t size = 0;
[email protected]c0d29c22013-07-26 20:40:41927 if (code == kWebSocketErrorNoStatusReceived) {
928 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
929 // frame with no payload.
[email protected]aa984e5f2014-02-26 07:33:09930 DCHECK(reason.empty());
Bence Béky65623972018-03-05 15:31:56931 body = base::MakeRefCounted<IOBuffer>(0);
[email protected]c0d29c22013-07-26 20:40:41932 } else {
933 const size_t payload_length = kWebSocketCloseCodeLength + reason.length();
Bence Béky65623972018-03-05 15:31:56934 body = base::MakeRefCounted<IOBuffer>(payload_length);
[email protected]2f5d9f62013-09-26 12:14:28935 size = payload_length;
[email protected]d9806a972014-02-26 18:14:57936 base::WriteBigEndian(body->data(), code);
mostynb91e0da982015-01-20 19:17:27937 static_assert(sizeof(code) == kWebSocketCloseCodeLength,
938 "they should both be two");
[email protected]c0d29c22013-07-26 20:40:41939 std::copy(
940 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
941 }
Adam Rice250bb012020-05-26 15:56:10942
Yutaka Hirano4165de92018-04-10 11:46:49943 return SendFrameInternal(true, WebSocketFrameHeader::kOpCodeClose,
944 std::move(body), size);
[email protected]999bcaa2013-07-17 13:42:54945}
946
Yutaka Hirano76aacb202019-09-05 16:36:56947bool WebSocketChannel::ParseClose(base::span<const char> payload,
tfarina8a2c66c22015-10-13 19:14:49948 uint16_t* code,
[email protected]ea56b982014-01-27 03:21:03949 std::string* reason,
950 std::string* message) {
Yutaka Hirano76aacb202019-09-05 16:36:56951 const uint64_t size = static_cast<uint64_t>(payload.size());
[email protected]999bcaa2013-07-17 13:42:54952 reason->clear();
953 if (size < kWebSocketCloseCodeLength) {
[email protected]c4432932014-03-19 05:55:13954 if (size == 0U) {
955 *code = kWebSocketErrorNoStatusReceived;
956 return true;
[email protected]999bcaa2013-07-17 13:42:54957 }
[email protected]c4432932014-03-19 05:55:13958
959 DVLOG(1) << "Close frame with payload size " << size << " received "
960 << "(the first byte is " << std::hex
Yutaka Hirano76aacb202019-09-05 16:36:56961 << static_cast<int>(payload.data()[0]) << ")";
[email protected]c4432932014-03-19 05:55:13962 *code = kWebSocketErrorProtocolError;
963 *message =
964 "Received a broken close frame containing an invalid size body.";
965 return false;
[email protected]999bcaa2013-07-17 13:42:54966 }
[email protected]c4432932014-03-19 05:55:13967
Yutaka Hirano76aacb202019-09-05 16:36:56968 const char* data = payload.data();
tfarina8a2c66c22015-10-13 19:14:49969 uint16_t unchecked_code = 0;
Felix Weilbachb7f34d812021-11-17 18:42:45970 base::ReadBigEndian(reinterpret_cast<const uint8_t*>(data), &unchecked_code);
mostynb91e0da982015-01-20 19:17:27971 static_assert(sizeof(unchecked_code) == kWebSocketCloseCodeLength,
972 "they should both be two bytes");
[email protected]c4432932014-03-19 05:55:13973
[email protected]ea56b982014-01-27 03:21:03974 switch (unchecked_code) {
975 case kWebSocketErrorNoStatusReceived:
976 case kWebSocketErrorAbnormalClosure:
977 case kWebSocketErrorTlsHandshake:
978 *code = kWebSocketErrorProtocolError;
979 *message =
980 "Received a broken close frame containing a reserved status code.";
[email protected]c4432932014-03-19 05:55:13981 return false;
[email protected]ea56b982014-01-27 03:21:03982
983 default:
984 *code = unchecked_code;
985 break;
[email protected]999bcaa2013-07-17 13:42:54986 }
[email protected]c4432932014-03-19 05:55:13987
988 std::string text(data + kWebSocketCloseCodeLength, data + size);
989 if (StreamingUtf8Validator::Validate(text)) {
990 reason->swap(text);
991 return true;
[email protected]999bcaa2013-07-17 13:42:54992 }
[email protected]c4432932014-03-19 05:55:13993
994 *code = kWebSocketErrorProtocolError;
995 *reason = "Invalid UTF-8 in Close frame";
996 *message = "Received a broken close frame containing invalid UTF-8.";
997 return false;
[email protected]999bcaa2013-07-17 13:42:54998}
999
Yutaka Hirano4165de92018-04-10 11:46:491000void WebSocketChannel::DoDropChannel(bool was_clean,
1001 uint16_t code,
1002 const std::string& reason) {
Yutaka Hirano4165de92018-04-10 11:46:491003 event_interface_->OnDropChannel(was_clean, code, reason);
[email protected]cd48ed12014-01-22 14:34:221004}
1005
[email protected]3a266762013-10-23 08:15:101006void WebSocketChannel::CloseTimeout() {
Nanami Mikiya8d6f8a132022-02-09 02:14:181007 stream_->GetNetLogWithSource().AddEvent(
1008 net::NetLogEventType::WEBSOCKET_CLOSE_TIMEOUT);
[email protected]3a266762013-10-23 08:15:101009 stream_->Close();
[email protected]09ef67362014-04-24 08:48:581010 SetState(CLOSED);
pkasting47ceb872014-10-09 18:53:221011 DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
[email protected]f485985e2013-10-24 13:47:441012 // |this| has been deleted.
[email protected]3a266762013-10-23 08:15:101013}
1014
[email protected]999bcaa2013-07-17 13:42:541015} // namespace net