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"
9 #include "base/basictypes.h" // for size_t
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/time/time.h"
18 #include "net/base/big_endian.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/net_log.h"
21 #include "net/http/http_request_headers.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/http/http_util.h"
24 #include "net/websockets/websocket_errors.h"
25 #include "net/websockets/websocket_event_interface.h"
26 #include "net/websockets/websocket_frame.h"
27 #include "net/websockets/websocket_handshake_request_info.h"
28 #include "net/websockets/websocket_handshake_response_info.h"
29 #include "net/websockets/websocket_mux.h"
30 #include "net/websockets/websocket_stream.h"
36 using base::StreamingUtf8Validator;
38 const int kDefaultSendQuotaLowWaterMark = 1 << 16;
39 const int kDefaultSendQuotaHighWaterMark = 1 << 17;
40 const size_t kWebSocketCloseCodeLength = 2;
41 // This timeout is based on TCPMaximumSegmentLifetime * 2 from
42 // MainThreadWebSocketChannel.cpp in Blink.
43 const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
45 typedef WebSocketEventInterface::ChannelState ChannelState;
46 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
47 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
49 // Maximum close reason length = max control frame payload -
52 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength;
54 // Check a close status code for strict compliance with RFC6455. This is only
55 // used for close codes received from a renderer that we are intending to send
56 // out over the network. See ParseClose() for the restrictions on incoming close
57 // codes. The |code| parameter is type int for convenience of implementation;
58 // the real type is uint16.
59 bool IsStrictlyValidCloseStatusCode(int code) {
60 static const int kInvalidRanges[] = {
62 0, 1000, // 1000 is the first valid code
63 1005, 1007, // 1005 and 1006 MUST NOT be set.
64 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved.
65 5000, 65536, // Codes above 5000 are invalid.
67 const int* const kInvalidRangesEnd =
68 kInvalidRanges + arraysize(kInvalidRanges);
71 DCHECK_LT(code, 65536);
72 const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code);
73 DCHECK_NE(kInvalidRangesEnd, upper);
74 DCHECK_GT(upper, kInvalidRanges);
75 DCHECK_GT(*upper, code);
76 DCHECK_LE(*(upper - 1), code);
77 return ((upper - kInvalidRanges) % 2) == 0;
80 // This function avoids a bunch of boilerplate code.
81 void AllowUnused(ChannelState ALLOW_UNUSED unused) {}
83 // Sets |name| to the name of the frame type for the given |opcode|. Note that
84 // for all of Text, Binary and Continuation opcode, this method returns
86 void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode,
89 case WebSocketFrameHeader::kOpCodeText: // fall-thru
90 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
91 case WebSocketFrameHeader::kOpCodeContinuation:
95 case WebSocketFrameHeader::kOpCodePing:
99 case WebSocketFrameHeader::kOpCodePong:
103 case WebSocketFrameHeader::kOpCodeClose:
108 *name = "Unknown frame type";
117 // A class to encapsulate a set of frames and information about the size of
119 class WebSocketChannel::SendBuffer {
121 SendBuffer() : total_bytes_(0) {}
123 // Add a WebSocketFrame to the buffer and increase total_bytes_.
124 void AddFrame(scoped_ptr<WebSocketFrame> chunk);
126 // Return a pointer to the frames_ for write purposes.
127 ScopedVector<WebSocketFrame>* frames() { return &frames_; }
130 // The frames_ that will be sent in the next call to WriteFrames().
131 ScopedVector<WebSocketFrame> frames_;
133 // The total size of the payload data in |frames_|. This will be used to
134 // measure the throughput of the link.
135 // TODO(ricea): Measure the throughput of the link.
139 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) {
140 total_bytes_ += frame->header.payload_length;
141 frames_.push_back(frame.release());
144 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the
145 // calls on to the WebSocketChannel that created it.
146 class WebSocketChannel::ConnectDelegate
147 : public WebSocketStream::ConnectDelegate {
149 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {}
151 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
152 creator_->OnConnectSuccess(stream.Pass());
153 // |this| may have been deleted.
156 virtual void OnFailure(const std::string& message) OVERRIDE {
157 creator_->OnConnectFailure(message);
158 // |this| has been deleted.
161 virtual void OnStartOpeningHandshake(
162 scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
163 creator_->OnStartOpeningHandshake(request.Pass());
166 virtual void OnFinishOpeningHandshake(
167 scoped_ptr<WebSocketHandshakeResponseInfo> response)
169 creator_->OnFinishOpeningHandshake(response.Pass());
173 // A pointer to the WebSocketChannel that created this object. There is no
174 // danger of this pointer being stale, because deleting the WebSocketChannel
175 // cancels the connect process, deleting this object and preventing its
176 // callbacks from being called.
177 WebSocketChannel* const creator_;
179 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate);
182 class WebSocketChannel::HandshakeNotificationSender
183 : public base::SupportsWeakPtr<HandshakeNotificationSender> {
185 explicit HandshakeNotificationSender(WebSocketChannel* channel);
186 ~HandshakeNotificationSender();
188 static void Send(base::WeakPtr<HandshakeNotificationSender> sender);
190 ChannelState SendImmediately(WebSocketEventInterface* event_interface);
192 const WebSocketHandshakeRequestInfo* handshake_request_info() const {
193 return handshake_request_info_.get();
196 void set_handshake_request_info(
197 scoped_ptr<WebSocketHandshakeRequestInfo> request_info) {
198 handshake_request_info_ = request_info.Pass();
201 const WebSocketHandshakeResponseInfo* handshake_response_info() const {
202 return handshake_response_info_.get();
205 void set_handshake_response_info(
206 scoped_ptr<WebSocketHandshakeResponseInfo> response_info) {
207 handshake_response_info_ = response_info.Pass();
211 WebSocketChannel* owner_;
212 scoped_ptr<WebSocketHandshakeRequestInfo> handshake_request_info_;
213 scoped_ptr<WebSocketHandshakeResponseInfo> handshake_response_info_;
216 WebSocketChannel::HandshakeNotificationSender::HandshakeNotificationSender(
217 WebSocketChannel* channel) : owner_(channel) {}
219 WebSocketChannel::HandshakeNotificationSender::~HandshakeNotificationSender() {}
221 void WebSocketChannel::HandshakeNotificationSender::Send(
222 base::WeakPtr<HandshakeNotificationSender> sender) {
223 // Do nothing if |sender| is already destructed.
225 WebSocketChannel* channel = sender->owner_;
226 AllowUnused(sender->SendImmediately(channel->event_interface_.get()));
230 ChannelState WebSocketChannel::HandshakeNotificationSender::SendImmediately(
231 WebSocketEventInterface* event_interface) {
233 if (handshake_request_info_.get()) {
234 if (CHANNEL_DELETED == event_interface->OnStartOpeningHandshake(
235 handshake_request_info_.Pass()))
236 return CHANNEL_DELETED;
239 if (handshake_response_info_.get()) {
240 if (CHANNEL_DELETED == event_interface->OnFinishOpeningHandshake(
241 handshake_response_info_.Pass()))
242 return CHANNEL_DELETED;
244 // TODO(yhirano): We can release |this| to save memory because
245 // there will be no more opening handshake notification.
248 return CHANNEL_ALIVE;
251 WebSocketChannel::WebSocketChannel(
252 scoped_ptr<WebSocketEventInterface> event_interface,
253 URLRequestContext* url_request_context)
254 : event_interface_(event_interface.Pass()),
255 url_request_context_(url_request_context),
256 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark),
257 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
258 current_send_quota_(0),
259 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
260 received_close_code_(0),
261 state_(FRESHLY_CONSTRUCTED),
262 notification_sender_(new HandshakeNotificationSender(this)),
263 sending_text_message_(false),
264 receiving_text_message_(false) {}
266 WebSocketChannel::~WebSocketChannel() {
267 // The stream may hold a pointer to read_frames_, and so it needs to be
270 // The timer may have a callback pointing back to us, so stop it just in case
271 // someone decides to run the event loop from their destructor.
275 void WebSocketChannel::SendAddChannelRequest(
276 const GURL& socket_url,
277 const std::vector<std::string>& requested_subprotocols,
278 const GURL& origin) {
279 // Delegate to the tested version.
280 SendAddChannelRequestWithSuppliedCreator(
282 requested_subprotocols,
284 base::Bind(&WebSocketStream::CreateAndConnectStream));
287 bool WebSocketChannel::InClosingState() const {
288 // The state RECV_CLOSED is not supported here, because it is only used in one
289 // code path and should not leak into the code in general.
290 DCHECK_NE(RECV_CLOSED, state_)
291 << "InClosingState called with state_ == RECV_CLOSED";
292 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED;
295 void WebSocketChannel::SendFrame(bool fin,
296 WebSocketFrameHeader::OpCode op_code,
297 const std::vector<char>& data) {
298 if (data.size() > INT_MAX) {
299 NOTREACHED() << "Frame size sanity check failed";
302 if (stream_ == NULL) {
303 LOG(DFATAL) << "Got SendFrame without a connection established; "
304 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code
305 << " data.size()=" << data.size();
308 if (InClosingState()) {
309 VLOG(1) << "SendFrame called in state " << state_
310 << ". This may be a bug, or a harmless race.";
313 if (state_ != CONNECTED) {
314 NOTREACHED() << "SendFrame() called in state " << state_;
317 if (data.size() > base::checked_cast<size_t>(current_send_quota_)) {
318 // TODO(ricea): Kill renderer.
320 FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""));
321 // |this| has been deleted.
324 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
325 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code
326 << "; misbehaving renderer? fin=" << fin
327 << " data.size()=" << data.size();
330 if (op_code == WebSocketFrameHeader::kOpCodeText ||
331 (op_code == WebSocketFrameHeader::kOpCodeContinuation &&
332 sending_text_message_)) {
333 StreamingUtf8Validator::State state =
334 outgoing_utf8_validator_.AddBytes(vector_as_array(&data), data.size());
335 if (state == StreamingUtf8Validator::INVALID ||
336 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) {
337 // TODO(ricea): Kill renderer.
339 FailChannel("Browser sent a text frame containing invalid UTF-8",
340 kWebSocketErrorGoingAway,
342 // |this| has been deleted.
345 sending_text_message_ = !fin;
346 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT);
348 current_send_quota_ -= data.size();
349 // TODO(ricea): If current_send_quota_ has dropped below
350 // send_quota_low_water_mark_, it might be good to increase the "low
351 // water mark" and "high water mark", but only if the link to the WebSocket
352 // server is not saturated.
353 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
354 std::copy(data.begin(), data.end(), buffer->data());
355 AllowUnused(SendIOBuffer(fin, op_code, buffer, data.size()));
356 // |this| may have been deleted.
359 void WebSocketChannel::SendFlowControl(int64 quota) {
360 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED ||
361 state_ == CLOSE_WAIT);
362 // TODO(ricea): Add interface to WebSocketStream and implement.
363 // stream_->SendFlowControl(quota);
366 void WebSocketChannel::StartClosingHandshake(uint16 code,
367 const std::string& reason) {
368 if (InClosingState()) {
369 VLOG(1) << "StartClosingHandshake called in state " << state_
370 << ". This may be a bug, or a harmless race.";
373 if (state_ == CONNECTING) {
374 // Abort the in-progress handshake and drop the connection immediately.
375 stream_request_.reset();
377 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""));
380 if (state_ != CONNECTED) {
381 NOTREACHED() << "StartClosingHandshake() called in state " << state_;
384 // Javascript actually only permits 1000 and 3000-4999, but the implementation
385 // itself may produce different codes. The length of |reason| is also checked
387 if (!IsStrictlyValidCloseStatusCode(code) ||
388 reason.size() > kMaximumCloseReasonLength) {
389 // "InternalServerError" is actually used for errors from any endpoint, per
390 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
391 // reason it must be malfunctioning in some way, and based on that we
392 // interpret this as an internal error.
393 AllowUnused(SendClose(kWebSocketErrorInternalServerError, ""));
394 // |this| may have been deleted.
397 AllowUnused(SendClose(
398 code, StreamingUtf8Validator::Validate(reason) ? reason : std::string()));
399 // |this| may have been deleted.
402 void WebSocketChannel::SendAddChannelRequestForTesting(
403 const GURL& socket_url,
404 const std::vector<std::string>& requested_subprotocols,
406 const WebSocketStreamCreator& creator) {
407 SendAddChannelRequestWithSuppliedCreator(
408 socket_url, requested_subprotocols, origin, creator);
411 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
412 base::TimeDelta delay) {
416 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
417 const GURL& socket_url,
418 const std::vector<std::string>& requested_subprotocols,
420 const WebSocketStreamCreator& creator) {
421 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
422 if (!socket_url.SchemeIsWSOrWSS()) {
423 // TODO(ricea): Kill the renderer (this error should have been caught by
425 AllowUnused(event_interface_->OnAddChannelResponse(true, "", ""));
426 // |this| is deleted here.
429 socket_url_ = socket_url;
430 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
431 new ConnectDelegate(this));
432 stream_request_ = creator.Run(socket_url_,
433 requested_subprotocols,
435 url_request_context_,
437 connect_delegate.Pass());
441 void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) {
443 DCHECK_EQ(CONNECTING, state_);
444 stream_ = stream.Pass();
446 if (event_interface_->OnAddChannelResponse(
447 false, stream_->GetSubProtocol(), stream_->GetExtensions()) ==
451 // TODO(ricea): Get flow control information from the WebSocketStream once we
452 // have a multiplexing WebSocketStream.
453 current_send_quota_ = send_quota_high_water_mark_;
454 if (event_interface_->OnFlowControl(send_quota_high_water_mark_) ==
458 // |stream_request_| is not used once the connection has succeeded.
459 stream_request_.reset();
460 AllowUnused(ReadFrames());
461 // |this| may have been deleted.
464 void WebSocketChannel::OnConnectFailure(const std::string& message) {
465 DCHECK_EQ(CONNECTING, state_);
467 stream_request_.reset();
469 if (CHANNEL_DELETED ==
470 notification_sender_->SendImmediately(event_interface_.get())) {
471 // |this| has been deleted.
474 AllowUnused(event_interface_->OnFailChannel(message));
475 // |this| has been deleted.
478 void WebSocketChannel::OnStartOpeningHandshake(
479 scoped_ptr<WebSocketHandshakeRequestInfo> request) {
480 DCHECK(!notification_sender_->handshake_request_info());
482 // Because it is hard to handle an IPC error synchronously is difficult,
483 // we asynchronously notify the information.
484 notification_sender_->set_handshake_request_info(request.Pass());
485 ScheduleOpeningHandshakeNotification();
488 void WebSocketChannel::OnFinishOpeningHandshake(
489 scoped_ptr<WebSocketHandshakeResponseInfo> response) {
490 DCHECK(!notification_sender_->handshake_response_info());
492 // Because it is hard to handle an IPC error synchronously is difficult,
493 // we asynchronously notify the information.
494 notification_sender_->set_handshake_response_info(response.Pass());
495 ScheduleOpeningHandshakeNotification();
498 void WebSocketChannel::ScheduleOpeningHandshakeNotification() {
499 base::MessageLoop::current()->PostTask(
501 base::Bind(HandshakeNotificationSender::Send,
502 notification_sender_->AsWeakPtr()));
505 ChannelState WebSocketChannel::WriteFrames() {
508 // This use of base::Unretained is safe because this object owns the
509 // WebSocketStream and destroying it cancels all callbacks.
510 result = stream_->WriteFrames(
511 data_being_sent_->frames(),
512 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
513 base::Unretained(this),
515 if (result != ERR_IO_PENDING) {
516 if (OnWriteDone(true, result) == CHANNEL_DELETED)
517 return CHANNEL_DELETED;
519 } while (result == OK && data_being_sent_);
520 return CHANNEL_ALIVE;
523 ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
524 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
525 DCHECK_NE(CONNECTING, state_);
526 DCHECK_NE(ERR_IO_PENDING, result);
527 DCHECK(data_being_sent_);
530 if (data_to_send_next_) {
531 data_being_sent_ = data_to_send_next_.Pass();
533 return WriteFrames();
535 data_being_sent_.reset();
536 if (current_send_quota_ < send_quota_low_water_mark_) {
537 // TODO(ricea): Increase low_water_mark and high_water_mark if
538 // throughput is high, reduce them if throughput is low. Low water
539 // mark needs to be >= the bandwidth delay product *of the IPC
540 // channel*. Because factors like context-switch time, thread wake-up
541 // time, and bus speed come into play it is complex and probably needs
542 // to be determined empirically.
543 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_);
544 // TODO(ricea): Truncate quota by the quota specified by the remote
545 // server, if the protocol in use supports quota.
546 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_;
547 current_send_quota_ += fresh_quota;
548 return event_interface_->OnFlowControl(fresh_quota);
551 return CHANNEL_ALIVE;
553 // If a recoverable error condition existed, it would go here.
557 << "WriteFrames() should only return OK or ERR_ codes";
559 DCHECK_NE(CLOSED, state_);
561 return DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
565 ChannelState WebSocketChannel::ReadFrames() {
568 // This use of base::Unretained is safe because this object owns the
569 // WebSocketStream, and any pending reads will be cancelled when it is
571 result = stream_->ReadFrames(
573 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone),
574 base::Unretained(this),
576 if (result != ERR_IO_PENDING) {
577 if (OnReadDone(true, result) == CHANNEL_DELETED)
578 return CHANNEL_DELETED;
580 DCHECK_NE(CLOSED, state_);
581 } while (result == OK);
582 return CHANNEL_ALIVE;
585 ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
586 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
587 DCHECK_NE(CONNECTING, state_);
588 DCHECK_NE(ERR_IO_PENDING, result);
591 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
592 // with no data read, not an empty response.
593 DCHECK(!read_frames_.empty())
594 << "ReadFrames() returned OK, but nothing was read.";
595 for (size_t i = 0; i < read_frames_.size(); ++i) {
596 scoped_ptr<WebSocketFrame> frame(read_frames_[i]);
597 read_frames_[i] = NULL;
598 if (HandleFrame(frame.Pass()) == CHANNEL_DELETED)
599 return CHANNEL_DELETED;
601 read_frames_.clear();
602 // There should always be a call to ReadFrames pending.
603 // TODO(ricea): Unless we are out of quota.
604 DCHECK_NE(CLOSED, state_);
607 return CHANNEL_ALIVE;
609 case ERR_WS_PROTOCOL_ERROR:
610 // This could be kWebSocketErrorProtocolError (specifically, non-minimal
611 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an
612 // extension-specific error.
613 return FailChannel("Invalid frame header",
614 kWebSocketErrorProtocolError,
615 "WebSocket Protocol Error");
619 << "ReadFrames() should only return OK or ERR_ codes";
621 DCHECK_NE(CLOSED, state_);
623 uint16 code = kWebSocketErrorAbnormalClosure;
624 std::string reason = "";
625 bool was_clean = false;
626 if (received_close_code_ != 0) {
627 code = received_close_code_;
628 reason = received_close_reason_;
629 was_clean = (result == ERR_CONNECTION_CLOSED);
631 return DoDropChannel(was_clean, code, reason);
635 ChannelState WebSocketChannel::HandleFrame(
636 scoped_ptr<WebSocketFrame> frame) {
637 if (frame->header.masked) {
638 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
641 "A server must not mask any frames that it sends to the "
643 kWebSocketErrorProtocolError,
644 "Masked frame from server");
646 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
647 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) &&
648 !frame->header.final) {
650 base::StringPrintf("Received fragmented control frame: opcode = %d",
652 kWebSocketErrorProtocolError,
653 "Control message with FIN bit unset received");
656 // Respond to the frame appropriately to its type.
657 return HandleFrameByState(
658 opcode, frame->header.final, frame->data, frame->header.payload_length);
661 ChannelState WebSocketChannel::HandleFrameByState(
662 const WebSocketFrameHeader::OpCode opcode,
664 const scoped_refptr<IOBuffer>& data_buffer,
666 DCHECK_NE(RECV_CLOSED, state_)
667 << "HandleFrame() does not support being called re-entrantly from within "
669 DCHECK_NE(CLOSED, state_);
670 if (state_ == CLOSE_WAIT) {
671 std::string frame_name;
672 GetFrameTypeForOpcode(opcode, &frame_name);
674 // FailChannel() won't send another Close frame.
676 frame_name + " received after close", kWebSocketErrorProtocolError, "");
679 case WebSocketFrameHeader::kOpCodeText: // fall-thru
680 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
681 case WebSocketFrameHeader::kOpCodeContinuation:
682 if (state_ == CONNECTED) {
683 if (opcode == WebSocketFrameHeader::kOpCodeText ||
684 (opcode == WebSocketFrameHeader::kOpCodeContinuation &&
685 receiving_text_message_)) {
686 // This call is not redundant when size == 0 because it tells us what
687 // the current state is.
688 StreamingUtf8Validator::State state =
689 incoming_utf8_validator_.AddBytes(
690 size ? data_buffer->data() : NULL, size);
691 if (state == StreamingUtf8Validator::INVALID ||
692 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) {
693 return FailChannel("Could not decode a text frame as UTF-8.",
694 kWebSocketErrorProtocolError,
695 "Invalid UTF-8 in text frame");
697 receiving_text_message_ = !final;
698 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT);
700 // TODO(ricea): Can this copy be eliminated?
701 const char* const data_begin = size ? data_buffer->data() : NULL;
702 const char* const data_end = data_begin + size;
703 const std::vector<char> data(data_begin, data_end);
704 // TODO(ricea): Handle the case when ReadFrames returns far
705 // more data at once than should be sent in a single IPC. This needs to
706 // be handled carefully, as an overloaded IO thread is one possible
707 // cause of receiving very large chunks.
709 // Sends the received frame to the renderer process.
710 return event_interface_->OnDataFrame(final, opcode, data);
712 VLOG(3) << "Ignored data packet received in state " << state_;
713 return CHANNEL_ALIVE;
715 case WebSocketFrameHeader::kOpCodePing:
716 VLOG(1) << "Got Ping of size " << size;
717 if (state_ == CONNECTED)
719 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size);
720 VLOG(3) << "Ignored ping in state " << state_;
721 return CHANNEL_ALIVE;
723 case WebSocketFrameHeader::kOpCodePong:
724 VLOG(1) << "Got Pong of size " << size;
725 // There is no need to do anything with pong messages.
726 return CHANNEL_ALIVE;
728 case WebSocketFrameHeader::kOpCodeClose: {
729 uint16 code = kWebSocketNormalClosure;
732 if (!ParseClose(data_buffer, size, &code, &reason, &message)) {
733 return FailChannel(message, code, reason);
735 // TODO(ricea): Find a way to safely log the message from the close
736 // message (escape control codes and so on).
737 VLOG(1) << "Got Close with code " << code;
740 state_ = RECV_CLOSED;
741 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT
743 return CHANNEL_DELETED;
744 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
745 return CHANNEL_DELETED;
746 received_close_code_ = code;
747 received_close_reason_ = reason;
752 // From RFC6455 section 7.1.5: "Each endpoint
753 // will see the status code sent by the other end as _The WebSocket
754 // Connection Close Code_."
755 received_close_code_ = code;
756 received_close_reason_ = reason;
760 LOG(DFATAL) << "Got Close in unexpected state " << state_;
763 return CHANNEL_ALIVE;
768 base::StringPrintf("Unrecognized frame opcode: %d", opcode),
769 kWebSocketErrorProtocolError,
774 ChannelState WebSocketChannel::SendIOBuffer(
776 WebSocketFrameHeader::OpCode op_code,
777 const scoped_refptr<IOBuffer>& buffer,
779 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
781 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code));
782 WebSocketFrameHeader& header = frame->header;
784 header.masked = true;
785 header.payload_length = size;
786 frame->data = buffer;
787 if (data_being_sent_) {
788 // Either the link to the WebSocket server is saturated, or several messages
789 // are being sent in a batch.
790 // TODO(ricea): Keep some statistics to work out the situation and adjust
791 // quota appropriately.
792 if (!data_to_send_next_)
793 data_to_send_next_.reset(new SendBuffer);
794 data_to_send_next_->AddFrame(frame.Pass());
795 return CHANNEL_ALIVE;
797 data_being_sent_.reset(new SendBuffer);
798 data_being_sent_->AddFrame(frame.Pass());
799 return WriteFrames();
802 ChannelState WebSocketChannel::FailChannel(const std::string& message,
804 const std::string& reason) {
805 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
806 DCHECK_NE(CONNECTING, state_);
807 DCHECK_NE(CLOSED, state_);
808 // TODO(ricea): Logging.
809 if (state_ == CONNECTED) {
810 if (SendClose(code, reason) == // Sets state_ to SEND_CLOSED
812 return CHANNEL_DELETED;
814 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
815 // should close the connection itself without waiting for the closing
820 return event_interface_->OnFailChannel(message);
823 ChannelState WebSocketChannel::SendClose(uint16 code,
824 const std::string& reason) {
825 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
826 DCHECK_LE(reason.size(), kMaximumCloseReasonLength);
827 scoped_refptr<IOBuffer> body;
829 if (code == kWebSocketErrorNoStatusReceived) {
830 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
831 // frame with no payload.
832 body = new IOBuffer(0);
834 const size_t payload_length = kWebSocketCloseCodeLength + reason.length();
835 body = new IOBuffer(payload_length);
836 size = payload_length;
837 WriteBigEndian(body->data(), code);
838 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength,
839 they_should_both_be_two);
841 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
843 // This use of base::Unretained() is safe because we stop the timer in the
848 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
849 if (SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
851 return CHANNEL_DELETED;
852 // SendIOBuffer() checks |state_|, so it is best not to change it until after
853 // SendIOBuffer() returns.
854 state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT;
855 return CHANNEL_ALIVE;
858 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
862 std::string* message) {
863 bool parsed_ok = true;
865 if (size < kWebSocketCloseCodeLength) {
866 *code = kWebSocketErrorNoStatusReceived;
868 DVLOG(1) << "Close frame with payload size " << size << " received "
869 << "(the first byte is " << std::hex
870 << static_cast<int>(buffer->data()[0]) << ")";
872 *code = kWebSocketErrorProtocolError;
874 "Received a broken close frame containing an invalid size body.";
878 const char* data = buffer->data();
879 uint16 unchecked_code = 0;
880 ReadBigEndian(data, &unchecked_code);
881 COMPILE_ASSERT(sizeof(unchecked_code) == kWebSocketCloseCodeLength,
882 they_should_both_be_two_bytes);
883 switch (unchecked_code) {
884 case kWebSocketErrorNoStatusReceived:
885 case kWebSocketErrorAbnormalClosure:
886 case kWebSocketErrorTlsHandshake:
887 *code = kWebSocketErrorProtocolError;
889 "Received a broken close frame containing a reserved status code.";
894 *code = unchecked_code;
898 std::string text(data + kWebSocketCloseCodeLength, data + size);
899 if (StreamingUtf8Validator::Validate(text)) {
902 *code = kWebSocketErrorProtocolError;
903 *reason = "Invalid UTF-8 in Close frame";
904 *message = "Received a broken close frame containing invalid UTF-8.";
911 ChannelState WebSocketChannel::DoDropChannel(bool was_clean,
913 const std::string& reason) {
914 if (CHANNEL_DELETED ==
915 notification_sender_->SendImmediately(event_interface_.get()))
916 return CHANNEL_DELETED;
917 return event_interface_->OnDropChannel(was_clean, code, reason);
920 void WebSocketChannel::CloseTimeout() {
922 DCHECK_NE(CLOSED, state_);
924 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""));
925 // |this| has been deleted.