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.
5 #include "net/websockets/websocket_channel.h"
7 #include <limits.h> // for INT_MAX
12 #include "base/basictypes.h" // for size_t
13 #include "base/big_endian.h"
14 #include "base/bind.h"
15 #include "base/compiler_specific.h"
16 #include "base/location.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/metrics/histogram.h"
20 #include "base/numerics/safe_conversions.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/stl_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/thread_task_runner_handle.h"
25 #include "base/time/time.h"
26 #include "net/base/io_buffer.h"
27 #include "net/http/http_request_headers.h"
28 #include "net/http/http_response_headers.h"
29 #include "net/http/http_util.h"
30 #include "net/log/net_log.h"
31 #include "net/websockets/websocket_errors.h"
32 #include "net/websockets/websocket_event_interface.h"
33 #include "net/websockets/websocket_frame.h"
34 #include "net/websockets/websocket_handshake_request_info.h"
35 #include "net/websockets/websocket_handshake_response_info.h"
36 #include "net/websockets/websocket_mux.h"
37 #include "net/websockets/websocket_stream.h"
38 #include "url/origin.h"
44 using base::StreamingUtf8Validator
;
46 const int kDefaultSendQuotaLowWaterMark
= 1 << 16;
47 const int kDefaultSendQuotaHighWaterMark
= 1 << 17;
48 const size_t kWebSocketCloseCodeLength
= 2;
49 // Timeout for waiting for the server to acknowledge a closing handshake.
50 const int kClosingHandshakeTimeoutSeconds
= 60;
51 // 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
58 const int kUnderlyingConnectionCloseTimeoutSeconds
= 2;
60 typedef WebSocketEventInterface::ChannelState ChannelState
;
61 const ChannelState CHANNEL_ALIVE
= WebSocketEventInterface::CHANNEL_ALIVE
;
62 const ChannelState CHANNEL_DELETED
= WebSocketEventInterface::CHANNEL_DELETED
;
64 // Maximum close reason length = max control frame payload -
67 const size_t kMaximumCloseReasonLength
= 125 - kWebSocketCloseCodeLength
;
69 // Check a close status code for strict compliance with RFC6455. This is only
70 // used for close codes received from a renderer that we are intending to send
71 // out over the network. See ParseClose() for the restrictions on incoming close
72 // codes. The |code| parameter is type int for convenience of implementation;
73 // the real type is uint16. Code 1005 is treated specially; it cannot be set
74 // explicitly by Javascript but the renderer uses it to indicate we should send
75 // a Close frame with no payload.
76 bool IsStrictlyValidCloseStatusCode(int code
) {
77 static const int kInvalidRanges
[] = {
79 0, 1000, // 1000 is the first valid code
80 1006, 1007, // 1006 MUST NOT be set.
81 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved.
82 5000, 65536, // Codes above 5000 are invalid.
84 const int* const kInvalidRangesEnd
=
85 kInvalidRanges
+ arraysize(kInvalidRanges
);
88 DCHECK_LT(code
, 65536);
89 const int* upper
= std::upper_bound(kInvalidRanges
, kInvalidRangesEnd
, code
);
90 DCHECK_NE(kInvalidRangesEnd
, upper
);
91 DCHECK_GT(upper
, kInvalidRanges
);
92 DCHECK_GT(*upper
, code
);
93 DCHECK_LE(*(upper
- 1), code
);
94 return ((upper
- kInvalidRanges
) % 2) == 0;
97 // Sets |name| to the name of the frame type for the given |opcode|. Note that
98 // for all of Text, Binary and Continuation opcode, this method returns
100 void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode
,
103 case WebSocketFrameHeader::kOpCodeText
: // fall-thru
104 case WebSocketFrameHeader::kOpCodeBinary
: // fall-thru
105 case WebSocketFrameHeader::kOpCodeContinuation
:
106 *name
= "Data frame";
109 case WebSocketFrameHeader::kOpCodePing
:
113 case WebSocketFrameHeader::kOpCodePong
:
117 case WebSocketFrameHeader::kOpCodeClose
:
122 *name
= "Unknown frame type";
131 // A class to encapsulate a set of frames and information about the size of
133 class WebSocketChannel::SendBuffer
{
135 SendBuffer() : total_bytes_(0) {}
137 // Add a WebSocketFrame to the buffer and increase total_bytes_.
138 void AddFrame(scoped_ptr
<WebSocketFrame
> chunk
);
140 // Return a pointer to the frames_ for write purposes.
141 ScopedVector
<WebSocketFrame
>* frames() { return &frames_
; }
144 // The frames_ that will be sent in the next call to WriteFrames().
145 ScopedVector
<WebSocketFrame
> frames_
;
147 // The total size of the payload data in |frames_|. This will be used to
148 // measure the throughput of the link.
149 // TODO(ricea): Measure the throughput of the link.
153 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr
<WebSocketFrame
> frame
) {
154 total_bytes_
+= frame
->header
.payload_length
;
155 frames_
.push_back(frame
.Pass());
158 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the
159 // calls on to the WebSocketChannel that created it.
160 class WebSocketChannel::ConnectDelegate
161 : public WebSocketStream::ConnectDelegate
{
163 explicit ConnectDelegate(WebSocketChannel
* creator
) : creator_(creator
) {}
165 void OnSuccess(scoped_ptr
<WebSocketStream
> stream
) override
{
166 creator_
->OnConnectSuccess(stream
.Pass());
167 // |this| may have been deleted.
170 void OnFailure(const std::string
& message
) override
{
171 creator_
->OnConnectFailure(message
);
172 // |this| has been deleted.
175 void OnStartOpeningHandshake(
176 scoped_ptr
<WebSocketHandshakeRequestInfo
> request
) override
{
177 creator_
->OnStartOpeningHandshake(request
.Pass());
180 void OnFinishOpeningHandshake(
181 scoped_ptr
<WebSocketHandshakeResponseInfo
> response
) override
{
182 creator_
->OnFinishOpeningHandshake(response
.Pass());
185 void OnSSLCertificateError(
186 scoped_ptr
<WebSocketEventInterface::SSLErrorCallbacks
>
188 const SSLInfo
& ssl_info
,
189 bool fatal
) override
{
190 creator_
->OnSSLCertificateError(
191 ssl_error_callbacks
.Pass(), ssl_info
, fatal
);
195 // A pointer to the WebSocketChannel that created this object. There is no
196 // danger of this pointer being stale, because deleting the WebSocketChannel
197 // cancels the connect process, deleting this object and preventing its
198 // callbacks from being called.
199 WebSocketChannel
* const creator_
;
201 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate
);
204 class WebSocketChannel::HandshakeNotificationSender
205 : public base::SupportsWeakPtr
<HandshakeNotificationSender
> {
207 explicit HandshakeNotificationSender(WebSocketChannel
* channel
);
208 ~HandshakeNotificationSender();
210 static void Send(base::WeakPtr
<HandshakeNotificationSender
> sender
);
212 ChannelState
SendImmediately(WebSocketEventInterface
* event_interface
);
214 const WebSocketHandshakeRequestInfo
* handshake_request_info() const {
215 return handshake_request_info_
.get();
218 void set_handshake_request_info(
219 scoped_ptr
<WebSocketHandshakeRequestInfo
> request_info
) {
220 handshake_request_info_
= request_info
.Pass();
223 const WebSocketHandshakeResponseInfo
* handshake_response_info() const {
224 return handshake_response_info_
.get();
227 void set_handshake_response_info(
228 scoped_ptr
<WebSocketHandshakeResponseInfo
> response_info
) {
229 handshake_response_info_
= response_info
.Pass();
233 WebSocketChannel
* owner_
;
234 scoped_ptr
<WebSocketHandshakeRequestInfo
> handshake_request_info_
;
235 scoped_ptr
<WebSocketHandshakeResponseInfo
> handshake_response_info_
;
238 WebSocketChannel::HandshakeNotificationSender::HandshakeNotificationSender(
239 WebSocketChannel
* channel
)
242 WebSocketChannel::HandshakeNotificationSender::~HandshakeNotificationSender() {}
244 void WebSocketChannel::HandshakeNotificationSender::Send(
245 base::WeakPtr
<HandshakeNotificationSender
> sender
) {
246 // Do nothing if |sender| is already destructed.
248 WebSocketChannel
* channel
= sender
->owner_
;
249 sender
->SendImmediately(channel
->event_interface_
.get());
253 ChannelState
WebSocketChannel::HandshakeNotificationSender::SendImmediately(
254 WebSocketEventInterface
* event_interface
) {
256 if (handshake_request_info_
.get()) {
257 if (CHANNEL_DELETED
== event_interface
->OnStartOpeningHandshake(
258 handshake_request_info_
.Pass()))
259 return CHANNEL_DELETED
;
262 if (handshake_response_info_
.get()) {
263 if (CHANNEL_DELETED
== event_interface
->OnFinishOpeningHandshake(
264 handshake_response_info_
.Pass()))
265 return CHANNEL_DELETED
;
267 // TODO(yhirano): We can release |this| to save memory because
268 // there will be no more opening handshake notification.
271 return CHANNEL_ALIVE
;
274 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame(
276 WebSocketFrameHeader::OpCode opcode
,
277 const scoped_refptr
<IOBuffer
>& data
,
286 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {}
288 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() {
289 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_
));
290 opcode_
= WebSocketFrameHeader::kOpCodeContinuation
;
293 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64 bytes
) {
294 DCHECK_LE(offset_
, size_
);
295 DCHECK_LE(bytes
, size_
- offset_
);
299 WebSocketChannel::WebSocketChannel(
300 scoped_ptr
<WebSocketEventInterface
> event_interface
,
301 URLRequestContext
* url_request_context
)
302 : event_interface_(event_interface
.Pass()),
303 url_request_context_(url_request_context
),
304 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark
),
305 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark
),
306 current_send_quota_(0),
307 current_receive_quota_(0),
308 closing_handshake_timeout_(base::TimeDelta::FromSeconds(
309 kClosingHandshakeTimeoutSeconds
)),
310 underlying_connection_close_timeout_(base::TimeDelta::FromSeconds(
311 kUnderlyingConnectionCloseTimeoutSeconds
)),
312 has_received_close_frame_(false),
313 received_close_code_(0),
314 state_(FRESHLY_CONSTRUCTED
),
315 notification_sender_(new HandshakeNotificationSender(this)),
316 sending_text_message_(false),
317 receiving_text_message_(false),
318 expecting_to_handle_continuation_(false),
319 initial_frame_forwarded_(false) {}
321 WebSocketChannel::~WebSocketChannel() {
322 // The stream may hold a pointer to read_frames_, and so it needs to be
325 // The timer may have a callback pointing back to us, so stop it just in case
326 // someone decides to run the event loop from their destructor.
330 void WebSocketChannel::SendAddChannelRequest(
331 const GURL
& socket_url
,
332 const std::vector
<std::string
>& requested_subprotocols
,
333 const url::Origin
& origin
) {
334 // Delegate to the tested version.
335 SendAddChannelRequestWithSuppliedCreator(
337 requested_subprotocols
,
339 base::Bind(&WebSocketStream::CreateAndConnectStream
));
342 void WebSocketChannel::SetState(State new_state
) {
343 DCHECK_NE(state_
, new_state
);
345 if (new_state
== CONNECTED
)
346 established_on_
= base::TimeTicks::Now();
347 if (state_
== CONNECTED
&& !established_on_
.is_null()) {
348 UMA_HISTOGRAM_LONG_TIMES(
349 "Net.WebSocket.Duration", base::TimeTicks::Now() - established_on_
);
355 bool WebSocketChannel::InClosingState() const {
356 // The state RECV_CLOSED is not supported here, because it is only used in one
357 // code path and should not leak into the code in general.
358 DCHECK_NE(RECV_CLOSED
, state_
)
359 << "InClosingState called with state_ == RECV_CLOSED";
360 return state_
== SEND_CLOSED
|| state_
== CLOSE_WAIT
|| state_
== CLOSED
;
363 void WebSocketChannel::SendFrame(bool fin
,
364 WebSocketFrameHeader::OpCode op_code
,
365 const std::vector
<char>& data
) {
366 if (data
.size() > INT_MAX
) {
367 NOTREACHED() << "Frame size sanity check failed";
370 if (stream_
== NULL
) {
371 LOG(DFATAL
) << "Got SendFrame without a connection established; "
372 << "misbehaving renderer? fin=" << fin
<< " op_code=" << op_code
373 << " data.size()=" << data
.size();
376 if (InClosingState()) {
377 DVLOG(1) << "SendFrame called in state " << state_
378 << ". This may be a bug, or a harmless race.";
381 if (state_
!= CONNECTED
) {
382 NOTREACHED() << "SendFrame() called in state " << state_
;
385 if (data
.size() > base::checked_cast
<size_t>(current_send_quota_
)) {
386 // TODO(ricea): Kill renderer.
388 FailChannel("Send quota exceeded", kWebSocketErrorGoingAway
, ""));
389 // |this| has been deleted.
392 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code
)) {
393 LOG(DFATAL
) << "Got SendFrame with bogus op_code " << op_code
394 << "; misbehaving renderer? fin=" << fin
395 << " data.size()=" << data
.size();
398 if (op_code
== WebSocketFrameHeader::kOpCodeText
||
399 (op_code
== WebSocketFrameHeader::kOpCodeContinuation
&&
400 sending_text_message_
)) {
401 StreamingUtf8Validator::State state
=
402 outgoing_utf8_validator_
.AddBytes(vector_as_array(&data
), data
.size());
403 if (state
== StreamingUtf8Validator::INVALID
||
404 (state
== StreamingUtf8Validator::VALID_MIDPOINT
&& fin
)) {
405 // TODO(ricea): Kill renderer.
407 FailChannel("Browser sent a text frame containing invalid UTF-8",
408 kWebSocketErrorGoingAway
,
410 // |this| has been deleted.
413 sending_text_message_
= !fin
;
414 DCHECK(!fin
|| state
== StreamingUtf8Validator::VALID_ENDPOINT
);
416 current_send_quota_
-= data
.size();
417 // TODO(ricea): If current_send_quota_ has dropped below
418 // send_quota_low_water_mark_, it might be good to increase the "low
419 // water mark" and "high water mark", but only if the link to the WebSocket
420 // server is not saturated.
421 scoped_refptr
<IOBuffer
> buffer(new IOBuffer(data
.size()));
422 std::copy(data
.begin(), data
.end(), buffer
->data());
423 ignore_result(SendFrameFromIOBuffer(fin
, op_code
, buffer
, data
.size()));
424 // |this| may have been deleted.
427 void WebSocketChannel::SendFlowControl(int64 quota
) {
428 DCHECK(state_
== CONNECTING
|| state_
== CONNECTED
|| state_
== SEND_CLOSED
||
429 state_
== CLOSE_WAIT
);
430 // TODO(ricea): Kill the renderer if it tries to send us a negative quota
431 // value or > INT_MAX.
433 DCHECK_LE(quota
, INT_MAX
);
434 if (!pending_received_frames_
.empty()) {
435 DCHECK_EQ(0u, current_receive_quota_
);
437 while (!pending_received_frames_
.empty() && quota
> 0) {
438 PendingReceivedFrame
& front
= pending_received_frames_
.front();
439 const uint64 data_size
= front
.size() - front
.offset();
440 const uint64 bytes_to_send
=
441 std::min(base::checked_cast
<uint64
>(quota
), data_size
);
442 const bool final
= front
.final() && data_size
== bytes_to_send
;
444 front
.data().get() ? front
.data()->data() + front
.offset() : NULL
;
445 DCHECK(!bytes_to_send
|| data
) << "Non empty data should not be null.";
446 const std::vector
<char> data_vector(data
, data
+ bytes_to_send
);
447 DVLOG(3) << "Sending frame previously split due to quota to the "
448 << "renderer: quota=" << quota
<< " data_size=" << data_size
449 << " bytes_to_send=" << bytes_to_send
;
450 if (event_interface_
->OnDataFrame(final
, front
.opcode(), data_vector
) ==
453 if (bytes_to_send
< data_size
) {
454 front
.DidConsume(bytes_to_send
);
458 quota
-= bytes_to_send
;
460 pending_received_frames_
.pop();
462 // If current_receive_quota_ == 0 then there is no pending ReadFrames()
464 const bool start_read
=
465 current_receive_quota_
== 0 && quota
> 0 &&
466 (state_
== CONNECTED
|| state_
== SEND_CLOSED
|| state_
== CLOSE_WAIT
);
467 current_receive_quota_
+= quota
;
469 ignore_result(ReadFrames());
470 // |this| may have been deleted.
473 void WebSocketChannel::StartClosingHandshake(uint16 code
,
474 const std::string
& reason
) {
475 if (InClosingState()) {
476 // When the associated renderer process is killed while the channel is in
477 // CLOSING state we reach here.
478 DVLOG(1) << "StartClosingHandshake called in state " << state_
479 << ". This may be a bug, or a harmless race.";
482 if (state_
== CONNECTING
) {
483 // Abort the in-progress handshake and drop the connection immediately.
484 stream_request_
.reset();
486 DoDropChannel(false, kWebSocketErrorAbnormalClosure
, "");
489 if (state_
!= CONNECTED
) {
490 NOTREACHED() << "StartClosingHandshake() called in state " << state_
;
494 DCHECK(!close_timer_
.IsRunning());
495 // This use of base::Unretained() is safe because we stop the timer in the
499 closing_handshake_timeout_
,
500 base::Bind(&WebSocketChannel::CloseTimeout
, base::Unretained(this)));
502 // Javascript actually only permits 1000 and 3000-4999, but the implementation
503 // itself may produce different codes. The length of |reason| is also checked
505 if (!IsStrictlyValidCloseStatusCode(code
) ||
506 reason
.size() > kMaximumCloseReasonLength
) {
507 // "InternalServerError" is actually used for errors from any endpoint, per
508 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
509 // reason it must be malfunctioning in some way, and based on that we
510 // interpret this as an internal error.
511 if (SendClose(kWebSocketErrorInternalServerError
, "") != CHANNEL_DELETED
) {
512 DCHECK_EQ(CONNECTED
, state_
);
513 SetState(SEND_CLOSED
);
519 StreamingUtf8Validator::Validate(reason
) ? reason
: std::string()) ==
522 DCHECK_EQ(CONNECTED
, state_
);
523 SetState(SEND_CLOSED
);
526 void WebSocketChannel::SendAddChannelRequestForTesting(
527 const GURL
& socket_url
,
528 const std::vector
<std::string
>& requested_subprotocols
,
529 const url::Origin
& origin
,
530 const WebSocketStreamCreator
& creator
) {
531 SendAddChannelRequestWithSuppliedCreator(
532 socket_url
, requested_subprotocols
, origin
, creator
);
535 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
536 base::TimeDelta delay
) {
537 closing_handshake_timeout_
= delay
;
540 void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting(
541 base::TimeDelta delay
) {
542 underlying_connection_close_timeout_
= delay
;
545 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
546 const GURL
& socket_url
,
547 const std::vector
<std::string
>& requested_subprotocols
,
548 const url::Origin
& origin
,
549 const WebSocketStreamCreator
& creator
) {
550 DCHECK_EQ(FRESHLY_CONSTRUCTED
, state_
);
551 if (!socket_url
.SchemeIsWSOrWSS()) {
552 // TODO(ricea): Kill the renderer (this error should have been caught by
554 ignore_result(event_interface_
->OnFailChannel("Invalid scheme"));
555 // |this| is deleted here.
558 socket_url_
= socket_url
;
559 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate(
560 new ConnectDelegate(this));
561 stream_request_
= creator
.Run(socket_url_
,
562 requested_subprotocols
,
564 url_request_context_
,
566 connect_delegate
.Pass());
567 SetState(CONNECTING
);
570 void WebSocketChannel::OnConnectSuccess(scoped_ptr
<WebSocketStream
> stream
) {
572 DCHECK_EQ(CONNECTING
, state_
);
574 stream_
= stream
.Pass();
578 if (event_interface_
->OnAddChannelResponse(stream_
->GetSubProtocol(),
579 stream_
->GetExtensions()) ==
583 // TODO(ricea): Get flow control information from the WebSocketStream once we
584 // have a multiplexing WebSocketStream.
585 current_send_quota_
= send_quota_high_water_mark_
;
586 if (event_interface_
->OnFlowControl(send_quota_high_water_mark_
) ==
590 // |stream_request_| is not used once the connection has succeeded.
591 stream_request_
.reset();
593 ignore_result(ReadFrames());
594 // |this| may have been deleted.
597 void WebSocketChannel::OnConnectFailure(const std::string
& message
) {
598 DCHECK_EQ(CONNECTING
, state_
);
600 // Copy the message before we delete its owner.
601 std::string message_copy
= message
;
604 stream_request_
.reset();
606 if (CHANNEL_DELETED
==
607 notification_sender_
->SendImmediately(event_interface_
.get())) {
608 // |this| has been deleted.
611 ChannelState result
= event_interface_
->OnFailChannel(message_copy
);
612 DCHECK_EQ(CHANNEL_DELETED
, result
);
613 // |this| has been deleted.
616 void WebSocketChannel::OnSSLCertificateError(
617 scoped_ptr
<WebSocketEventInterface::SSLErrorCallbacks
> ssl_error_callbacks
,
618 const SSLInfo
& ssl_info
,
620 ignore_result(event_interface_
->OnSSLCertificateError(
621 ssl_error_callbacks
.Pass(), socket_url_
, ssl_info
, fatal
));
624 void WebSocketChannel::OnStartOpeningHandshake(
625 scoped_ptr
<WebSocketHandshakeRequestInfo
> request
) {
626 DCHECK(!notification_sender_
->handshake_request_info());
628 // Because it is hard to handle an IPC error synchronously is difficult,
629 // we asynchronously notify the information.
630 notification_sender_
->set_handshake_request_info(request
.Pass());
631 ScheduleOpeningHandshakeNotification();
634 void WebSocketChannel::OnFinishOpeningHandshake(
635 scoped_ptr
<WebSocketHandshakeResponseInfo
> response
) {
636 DCHECK(!notification_sender_
->handshake_response_info());
638 // Because it is hard to handle an IPC error synchronously is difficult,
639 // we asynchronously notify the information.
640 notification_sender_
->set_handshake_response_info(response
.Pass());
641 ScheduleOpeningHandshakeNotification();
644 void WebSocketChannel::ScheduleOpeningHandshakeNotification() {
645 base::ThreadTaskRunnerHandle::Get()->PostTask(
646 FROM_HERE
, base::Bind(HandshakeNotificationSender::Send
,
647 notification_sender_
->AsWeakPtr()));
650 ChannelState
WebSocketChannel::WriteFrames() {
653 // This use of base::Unretained is safe because this object owns the
654 // WebSocketStream and destroying it cancels all callbacks.
655 result
= stream_
->WriteFrames(
656 data_being_sent_
->frames(),
657 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone
),
658 base::Unretained(this),
660 if (result
!= ERR_IO_PENDING
) {
661 if (OnWriteDone(true, result
) == CHANNEL_DELETED
)
662 return CHANNEL_DELETED
;
663 // OnWriteDone() returns CHANNEL_DELETED on error. Here |state_| is
664 // guaranteed to be the same as before OnWriteDone() call.
666 } while (result
== OK
&& data_being_sent_
);
667 return CHANNEL_ALIVE
;
670 ChannelState
WebSocketChannel::OnWriteDone(bool synchronous
, int result
) {
671 DCHECK_NE(FRESHLY_CONSTRUCTED
, state_
);
672 DCHECK_NE(CONNECTING
, state_
);
673 DCHECK_NE(ERR_IO_PENDING
, result
);
674 DCHECK(data_being_sent_
);
677 if (data_to_send_next_
) {
678 data_being_sent_
= data_to_send_next_
.Pass();
680 return WriteFrames();
682 data_being_sent_
.reset();
683 if (current_send_quota_
< send_quota_low_water_mark_
) {
684 // TODO(ricea): Increase low_water_mark and high_water_mark if
685 // throughput is high, reduce them if throughput is low. Low water
686 // mark needs to be >= the bandwidth delay product *of the IPC
687 // channel*. Because factors like context-switch time, thread wake-up
688 // time, and bus speed come into play it is complex and probably needs
689 // to be determined empirically.
690 DCHECK_LE(send_quota_low_water_mark_
, send_quota_high_water_mark_
);
691 // TODO(ricea): Truncate quota by the quota specified by the remote
692 // server, if the protocol in use supports quota.
693 int fresh_quota
= send_quota_high_water_mark_
- current_send_quota_
;
694 current_send_quota_
+= fresh_quota
;
695 return event_interface_
->OnFlowControl(fresh_quota
);
698 return CHANNEL_ALIVE
;
700 // If a recoverable error condition existed, it would go here.
704 << "WriteFrames() should only return OK or ERR_ codes";
708 return DoDropChannel(false, kWebSocketErrorAbnormalClosure
, "");
712 ChannelState
WebSocketChannel::ReadFrames() {
714 while (result
== OK
&& current_receive_quota_
> 0) {
715 // This use of base::Unretained is safe because this object owns the
716 // WebSocketStream, and any pending reads will be cancelled when it is
718 result
= stream_
->ReadFrames(
720 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone
),
721 base::Unretained(this),
723 if (result
!= ERR_IO_PENDING
) {
724 if (OnReadDone(true, result
) == CHANNEL_DELETED
)
725 return CHANNEL_DELETED
;
727 DCHECK_NE(CLOSED
, state_
);
729 return CHANNEL_ALIVE
;
732 ChannelState
WebSocketChannel::OnReadDone(bool synchronous
, int result
) {
733 DCHECK_NE(FRESHLY_CONSTRUCTED
, state_
);
734 DCHECK_NE(CONNECTING
, state_
);
735 DCHECK_NE(ERR_IO_PENDING
, result
);
738 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
739 // with no data read, not an empty response.
740 DCHECK(!read_frames_
.empty())
741 << "ReadFrames() returned OK, but nothing was read.";
742 for (size_t i
= 0; i
< read_frames_
.size(); ++i
) {
743 scoped_ptr
<WebSocketFrame
> frame(read_frames_
[i
]);
744 read_frames_
[i
] = NULL
;
745 if (HandleFrame(frame
.Pass()) == CHANNEL_DELETED
)
746 return CHANNEL_DELETED
;
748 read_frames_
.clear();
749 // There should always be a call to ReadFrames pending.
750 // TODO(ricea): Unless we are out of quota.
751 DCHECK_NE(CLOSED
, state_
);
754 return CHANNEL_ALIVE
;
756 case ERR_WS_PROTOCOL_ERROR
:
757 // This could be kWebSocketErrorProtocolError (specifically, non-minimal
758 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an
759 // extension-specific error.
760 return FailChannel("Invalid frame header",
761 kWebSocketErrorProtocolError
,
762 "WebSocket Protocol Error");
766 << "ReadFrames() should only return OK or ERR_ codes";
771 uint16 code
= kWebSocketErrorAbnormalClosure
;
772 std::string reason
= "";
773 bool was_clean
= false;
774 if (has_received_close_frame_
) {
775 code
= received_close_code_
;
776 reason
= received_close_reason_
;
777 was_clean
= (result
== ERR_CONNECTION_CLOSED
);
780 return DoDropChannel(was_clean
, code
, reason
);
784 ChannelState
WebSocketChannel::HandleFrame(scoped_ptr
<WebSocketFrame
> frame
) {
785 if (frame
->header
.masked
) {
786 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
789 "A server must not mask any frames that it sends to the "
791 kWebSocketErrorProtocolError
,
792 "Masked frame from server");
794 const WebSocketFrameHeader::OpCode opcode
= frame
->header
.opcode
;
795 DCHECK(!WebSocketFrameHeader::IsKnownControlOpCode(opcode
) ||
796 frame
->header
.final
);
797 if (frame
->header
.reserved1
|| frame
->header
.reserved2
||
798 frame
->header
.reserved3
) {
799 return FailChannel(base::StringPrintf(
800 "One or more reserved bits are on: reserved1 = %d, "
801 "reserved2 = %d, reserved3 = %d",
802 static_cast<int>(frame
->header
.reserved1
),
803 static_cast<int>(frame
->header
.reserved2
),
804 static_cast<int>(frame
->header
.reserved3
)),
805 kWebSocketErrorProtocolError
,
806 "Invalid reserved bit");
809 // Respond to the frame appropriately to its type.
810 return HandleFrameByState(
811 opcode
, frame
->header
.final
, frame
->data
, frame
->header
.payload_length
);
814 ChannelState
WebSocketChannel::HandleFrameByState(
815 const WebSocketFrameHeader::OpCode opcode
,
817 const scoped_refptr
<IOBuffer
>& data_buffer
,
819 DCHECK_NE(RECV_CLOSED
, state_
)
820 << "HandleFrame() does not support being called re-entrantly from within "
822 DCHECK_NE(CLOSED
, state_
);
823 if (state_
== CLOSE_WAIT
) {
824 std::string frame_name
;
825 GetFrameTypeForOpcode(opcode
, &frame_name
);
827 // FailChannel() won't send another Close frame.
829 frame_name
+ " received after close", kWebSocketErrorProtocolError
, "");
832 case WebSocketFrameHeader::kOpCodeText
: // fall-thru
833 case WebSocketFrameHeader::kOpCodeBinary
:
834 case WebSocketFrameHeader::kOpCodeContinuation
:
835 return HandleDataFrame(opcode
, final
, data_buffer
, size
);
837 case WebSocketFrameHeader::kOpCodePing
:
838 DVLOG(1) << "Got Ping of size " << size
;
839 if (state_
== CONNECTED
)
840 return SendFrameFromIOBuffer(
841 true, WebSocketFrameHeader::kOpCodePong
, data_buffer
, size
);
842 DVLOG(3) << "Ignored ping in state " << state_
;
843 return CHANNEL_ALIVE
;
845 case WebSocketFrameHeader::kOpCodePong
:
846 DVLOG(1) << "Got Pong of size " << size
;
847 // There is no need to do anything with pong messages.
848 return CHANNEL_ALIVE
;
850 case WebSocketFrameHeader::kOpCodeClose
: {
851 // TODO(ricea): If there is a message which is queued for transmission to
852 // the renderer, then the renderer should not receive an
853 // OnClosingHandshake or OnDropChannel IPC until the queued message has
854 // been completedly transmitted.
855 uint16 code
= kWebSocketNormalClosure
;
858 if (!ParseClose(data_buffer
, size
, &code
, &reason
, &message
)) {
859 return FailChannel(message
, code
, reason
);
861 // TODO(ricea): Find a way to safely log the message from the close
862 // message (escape control codes and so on).
863 DVLOG(1) << "Got Close with code " << code
;
866 SetState(RECV_CLOSED
);
868 if (SendClose(code
, reason
) == CHANNEL_DELETED
)
869 return CHANNEL_DELETED
;
870 DCHECK_EQ(RECV_CLOSED
, state_
);
872 SetState(CLOSE_WAIT
);
873 DCHECK(!close_timer_
.IsRunning());
874 // This use of base::Unretained() is safe because we stop the timer
875 // in the destructor.
878 underlying_connection_close_timeout_
,
880 &WebSocketChannel::CloseTimeout
, base::Unretained(this)));
882 if (event_interface_
->OnClosingHandshake() == CHANNEL_DELETED
)
883 return CHANNEL_DELETED
;
884 has_received_close_frame_
= true;
885 received_close_code_
= code
;
886 received_close_reason_
= reason
;
890 SetState(CLOSE_WAIT
);
891 DCHECK(close_timer_
.IsRunning());
893 // This use of base::Unretained() is safe because we stop the timer
894 // in the destructor.
897 underlying_connection_close_timeout_
,
899 &WebSocketChannel::CloseTimeout
, base::Unretained(this)));
901 // From RFC6455 section 7.1.5: "Each endpoint
902 // will see the status code sent by the other end as _The WebSocket
903 // Connection Close Code_."
904 has_received_close_frame_
= true;
905 received_close_code_
= code
;
906 received_close_reason_
= reason
;
910 LOG(DFATAL
) << "Got Close in unexpected state " << state_
;
913 return CHANNEL_ALIVE
;
918 base::StringPrintf("Unrecognized frame opcode: %d", opcode
),
919 kWebSocketErrorProtocolError
,
924 ChannelState
WebSocketChannel::HandleDataFrame(
925 WebSocketFrameHeader::OpCode opcode
,
927 const scoped_refptr
<IOBuffer
>& data_buffer
,
929 if (state_
!= CONNECTED
) {
930 DVLOG(3) << "Ignored data packet received in state " << state_
;
931 return CHANNEL_ALIVE
;
933 DCHECK(opcode
== WebSocketFrameHeader::kOpCodeContinuation
||
934 opcode
== WebSocketFrameHeader::kOpCodeText
||
935 opcode
== WebSocketFrameHeader::kOpCodeBinary
);
936 const bool got_continuation
=
937 (opcode
== WebSocketFrameHeader::kOpCodeContinuation
);
938 if (got_continuation
!= expecting_to_handle_continuation_
) {
939 const std::string console_log
= got_continuation
940 ? "Received unexpected continuation frame."
941 : "Received start of new message but previous message is unfinished.";
942 const std::string reason
= got_continuation
943 ? "Unexpected continuation"
944 : "Previous data frame unfinished";
945 return FailChannel(console_log
, kWebSocketErrorProtocolError
, reason
);
947 expecting_to_handle_continuation_
= !final
;
948 WebSocketFrameHeader::OpCode opcode_to_send
= opcode
;
949 if (!initial_frame_forwarded_
&&
950 opcode
== WebSocketFrameHeader::kOpCodeContinuation
) {
951 opcode_to_send
= receiving_text_message_
952 ? WebSocketFrameHeader::kOpCodeText
953 : WebSocketFrameHeader::kOpCodeBinary
;
955 if (opcode
== WebSocketFrameHeader::kOpCodeText
||
956 (opcode
== WebSocketFrameHeader::kOpCodeContinuation
&&
957 receiving_text_message_
)) {
958 // This call is not redundant when size == 0 because it tells us what
959 // the current state is.
960 StreamingUtf8Validator::State state
= incoming_utf8_validator_
.AddBytes(
961 size
? data_buffer
->data() : NULL
, static_cast<size_t>(size
));
962 if (state
== StreamingUtf8Validator::INVALID
||
963 (state
== StreamingUtf8Validator::VALID_MIDPOINT
&& final
)) {
964 return FailChannel("Could not decode a text frame as UTF-8.",
965 kWebSocketErrorProtocolError
,
966 "Invalid UTF-8 in text frame");
968 receiving_text_message_
= !final
;
969 DCHECK(!final
|| state
== StreamingUtf8Validator::VALID_ENDPOINT
);
971 if (size
== 0U && !final
)
972 return CHANNEL_ALIVE
;
974 initial_frame_forwarded_
= !final
;
975 if (size
> current_receive_quota_
|| !pending_received_frames_
.empty()) {
976 const bool no_quota
= (current_receive_quota_
== 0);
977 DCHECK(no_quota
|| pending_received_frames_
.empty());
978 DVLOG(3) << "Queueing frame to renderer due to quota. quota="
979 << current_receive_quota_
<< " size=" << size
;
980 WebSocketFrameHeader::OpCode opcode_to_queue
=
981 no_quota
? opcode_to_send
: WebSocketFrameHeader::kOpCodeContinuation
;
982 pending_received_frames_
.push(PendingReceivedFrame(
983 final
, opcode_to_queue
, data_buffer
, current_receive_quota_
, size
));
985 return CHANNEL_ALIVE
;
986 size
= current_receive_quota_
;
990 // TODO(ricea): Can this copy be eliminated?
991 const char* const data_begin
= size
? data_buffer
->data() : NULL
;
992 const char* const data_end
= data_begin
+ size
;
993 const std::vector
<char> data(data_begin
, data_end
);
994 current_receive_quota_
-= size
;
996 // Sends the received frame to the renderer process.
997 return event_interface_
->OnDataFrame(final
, opcode_to_send
, data
);
1000 ChannelState
WebSocketChannel::SendFrameFromIOBuffer(
1002 WebSocketFrameHeader::OpCode op_code
,
1003 const scoped_refptr
<IOBuffer
>& buffer
,
1005 DCHECK(state_
== CONNECTED
|| state_
== RECV_CLOSED
);
1008 scoped_ptr
<WebSocketFrame
> frame(new WebSocketFrame(op_code
));
1009 WebSocketFrameHeader
& header
= frame
->header
;
1011 header
.masked
= true;
1012 header
.payload_length
= size
;
1013 frame
->data
= buffer
;
1015 if (data_being_sent_
) {
1016 // Either the link to the WebSocket server is saturated, or several messages
1017 // are being sent in a batch.
1018 // TODO(ricea): Keep some statistics to work out the situation and adjust
1019 // quota appropriately.
1020 if (!data_to_send_next_
)
1021 data_to_send_next_
.reset(new SendBuffer
);
1022 data_to_send_next_
->AddFrame(frame
.Pass());
1023 return CHANNEL_ALIVE
;
1026 data_being_sent_
.reset(new SendBuffer
);
1027 data_being_sent_
->AddFrame(frame
.Pass());
1028 return WriteFrames();
1031 ChannelState
WebSocketChannel::FailChannel(const std::string
& message
,
1033 const std::string
& reason
) {
1034 DCHECK_NE(FRESHLY_CONSTRUCTED
, state_
);
1035 DCHECK_NE(CONNECTING
, state_
);
1036 DCHECK_NE(CLOSED
, state_
);
1038 // TODO(ricea): Logging.
1039 if (state_
== CONNECTED
) {
1040 if (SendClose(code
, reason
) == CHANNEL_DELETED
)
1041 return CHANNEL_DELETED
;
1044 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
1045 // should close the connection itself without waiting for the closing
1049 ChannelState result
= event_interface_
->OnFailChannel(message
);
1050 DCHECK_EQ(CHANNEL_DELETED
, result
);
1054 ChannelState
WebSocketChannel::SendClose(uint16 code
,
1055 const std::string
& reason
) {
1056 DCHECK(state_
== CONNECTED
|| state_
== RECV_CLOSED
);
1057 DCHECK_LE(reason
.size(), kMaximumCloseReasonLength
);
1058 scoped_refptr
<IOBuffer
> body
;
1060 if (code
== kWebSocketErrorNoStatusReceived
) {
1061 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
1062 // frame with no payload.
1063 DCHECK(reason
.empty());
1064 body
= new IOBuffer(0);
1066 const size_t payload_length
= kWebSocketCloseCodeLength
+ reason
.length();
1067 body
= new IOBuffer(payload_length
);
1068 size
= payload_length
;
1069 base::WriteBigEndian(body
->data(), code
);
1070 static_assert(sizeof(code
) == kWebSocketCloseCodeLength
,
1071 "they should both be two");
1073 reason
.begin(), reason
.end(), body
->data() + kWebSocketCloseCodeLength
);
1075 if (SendFrameFromIOBuffer(
1076 true, WebSocketFrameHeader::kOpCodeClose
, body
, size
) ==
1078 return CHANNEL_DELETED
;
1079 return CHANNEL_ALIVE
;
1082 bool WebSocketChannel::ParseClose(const scoped_refptr
<IOBuffer
>& buffer
,
1085 std::string
* reason
,
1086 std::string
* message
) {
1088 if (size
< kWebSocketCloseCodeLength
) {
1090 *code
= kWebSocketErrorNoStatusReceived
;
1094 DVLOG(1) << "Close frame with payload size " << size
<< " received "
1095 << "(the first byte is " << std::hex
1096 << static_cast<int>(buffer
->data()[0]) << ")";
1097 *code
= kWebSocketErrorProtocolError
;
1099 "Received a broken close frame containing an invalid size body.";
1103 const char* data
= buffer
->data();
1104 uint16 unchecked_code
= 0;
1105 base::ReadBigEndian(data
, &unchecked_code
);
1106 static_assert(sizeof(unchecked_code
) == kWebSocketCloseCodeLength
,
1107 "they should both be two bytes");
1109 switch (unchecked_code
) {
1110 case kWebSocketErrorNoStatusReceived
:
1111 case kWebSocketErrorAbnormalClosure
:
1112 case kWebSocketErrorTlsHandshake
:
1113 *code
= kWebSocketErrorProtocolError
;
1115 "Received a broken close frame containing a reserved status code.";
1119 *code
= unchecked_code
;
1123 std::string
text(data
+ kWebSocketCloseCodeLength
, data
+ size
);
1124 if (StreamingUtf8Validator::Validate(text
)) {
1129 *code
= kWebSocketErrorProtocolError
;
1130 *reason
= "Invalid UTF-8 in Close frame";
1131 *message
= "Received a broken close frame containing invalid UTF-8.";
1135 ChannelState
WebSocketChannel::DoDropChannel(bool was_clean
,
1137 const std::string
& reason
) {
1138 if (CHANNEL_DELETED
==
1139 notification_sender_
->SendImmediately(event_interface_
.get()))
1140 return CHANNEL_DELETED
;
1141 ChannelState result
=
1142 event_interface_
->OnDropChannel(was_clean
, code
, reason
);
1143 DCHECK_EQ(CHANNEL_DELETED
, result
);
1147 void WebSocketChannel::CloseTimeout() {
1150 DoDropChannel(false, kWebSocketErrorAbnormalClosure
, "");
1151 // |this| has been deleted.