OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/websockets/websocket_channel.h" | 5 #include "net/websockets/websocket_channel.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/basictypes.h" // for size_t | 9 #include "base/basictypes.h" // for size_t |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 DCHECK_NE(kInvalidRangesEnd, upper); | 73 DCHECK_NE(kInvalidRangesEnd, upper); |
74 DCHECK_GT(upper, kInvalidRanges); | 74 DCHECK_GT(upper, kInvalidRanges); |
75 DCHECK_GT(*upper, code); | 75 DCHECK_GT(*upper, code); |
76 DCHECK_LE(*(upper - 1), code); | 76 DCHECK_LE(*(upper - 1), code); |
77 return ((upper - kInvalidRanges) % 2) == 0; | 77 return ((upper - kInvalidRanges) % 2) == 0; |
78 } | 78 } |
79 | 79 |
80 // This function avoids a bunch of boilerplate code. | 80 // This function avoids a bunch of boilerplate code. |
81 void AllowUnused(ChannelState ALLOW_UNUSED unused) {} | 81 void AllowUnused(ChannelState ALLOW_UNUSED unused) {} |
82 | 82 |
| 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 |
| 85 // "Data frame". |
| 86 void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode, |
| 87 std::string* name) { |
| 88 switch (opcode) { |
| 89 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 90 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru |
| 91 case WebSocketFrameHeader::kOpCodeContinuation: |
| 92 *name = "Data frame"; |
| 93 break; |
| 94 |
| 95 case WebSocketFrameHeader::kOpCodePing: |
| 96 *name = "Ping"; |
| 97 break; |
| 98 |
| 99 case WebSocketFrameHeader::kOpCodePong: |
| 100 *name = "Pong"; |
| 101 break; |
| 102 |
| 103 case WebSocketFrameHeader::kOpCodeClose: |
| 104 *name = "Close"; |
| 105 break; |
| 106 |
| 107 default: |
| 108 *name = "Unknown frame type"; |
| 109 break; |
| 110 } |
| 111 |
| 112 return; |
| 113 } |
| 114 |
83 } // namespace | 115 } // namespace |
84 | 116 |
85 // A class to encapsulate a set of frames and information about the size of | 117 // A class to encapsulate a set of frames and information about the size of |
86 // those frames. | 118 // those frames. |
87 class WebSocketChannel::SendBuffer { | 119 class WebSocketChannel::SendBuffer { |
88 public: | 120 public: |
89 SendBuffer() : total_bytes_(0) {} | 121 SendBuffer() : total_bytes_(0) {} |
90 | 122 |
91 // Add a WebSocketFrame to the buffer and increase total_bytes_. | 123 // Add a WebSocketFrame to the buffer and increase total_bytes_. |
92 void AddFrame(scoped_ptr<WebSocketFrame> chunk); | 124 void AddFrame(scoped_ptr<WebSocketFrame> chunk); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 | 250 |
219 WebSocketChannel::WebSocketChannel( | 251 WebSocketChannel::WebSocketChannel( |
220 scoped_ptr<WebSocketEventInterface> event_interface, | 252 scoped_ptr<WebSocketEventInterface> event_interface, |
221 URLRequestContext* url_request_context) | 253 URLRequestContext* url_request_context) |
222 : event_interface_(event_interface.Pass()), | 254 : event_interface_(event_interface.Pass()), |
223 url_request_context_(url_request_context), | 255 url_request_context_(url_request_context), |
224 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), | 256 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), |
225 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), | 257 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), |
226 current_send_quota_(0), | 258 current_send_quota_(0), |
227 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), | 259 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), |
228 closing_code_(0), | 260 received_close_code_(0), |
229 state_(FRESHLY_CONSTRUCTED), | 261 state_(FRESHLY_CONSTRUCTED), |
230 notification_sender_(new HandshakeNotificationSender(this)), | 262 notification_sender_(new HandshakeNotificationSender(this)), |
231 sending_text_message_(false), | 263 sending_text_message_(false), |
232 receiving_text_message_(false) {} | 264 receiving_text_message_(false) {} |
233 | 265 |
234 WebSocketChannel::~WebSocketChannel() { | 266 WebSocketChannel::~WebSocketChannel() { |
235 // The stream may hold a pointer to read_frames_, and so it needs to be | 267 // The stream may hold a pointer to read_frames_, and so it needs to be |
236 // destroyed first. | 268 // destroyed first. |
237 stream_.reset(); | 269 stream_.reset(); |
238 // The timer may have a callback pointing back to us, so stop it just in case | 270 // The timer may have a callback pointing back to us, so stop it just in case |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 DCHECK_NE(ERR_IO_PENDING, result); | 588 DCHECK_NE(ERR_IO_PENDING, result); |
557 switch (result) { | 589 switch (result) { |
558 case OK: | 590 case OK: |
559 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection | 591 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection |
560 // with no data read, not an empty response. | 592 // with no data read, not an empty response. |
561 DCHECK(!read_frames_.empty()) | 593 DCHECK(!read_frames_.empty()) |
562 << "ReadFrames() returned OK, but nothing was read."; | 594 << "ReadFrames() returned OK, but nothing was read."; |
563 for (size_t i = 0; i < read_frames_.size(); ++i) { | 595 for (size_t i = 0; i < read_frames_.size(); ++i) { |
564 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); | 596 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); |
565 read_frames_[i] = NULL; | 597 read_frames_[i] = NULL; |
566 if (ProcessFrame(frame.Pass()) == CHANNEL_DELETED) | 598 if (HandleFrame(frame.Pass()) == CHANNEL_DELETED) |
567 return CHANNEL_DELETED; | 599 return CHANNEL_DELETED; |
568 } | 600 } |
569 read_frames_.clear(); | 601 read_frames_.clear(); |
570 // There should always be a call to ReadFrames pending. | 602 // There should always be a call to ReadFrames pending. |
571 // TODO(ricea): Unless we are out of quota. | 603 // TODO(ricea): Unless we are out of quota. |
572 DCHECK_NE(CLOSED, state_); | 604 DCHECK_NE(CLOSED, state_); |
573 if (!synchronous) | 605 if (!synchronous) |
574 return ReadFrames(); | 606 return ReadFrames(); |
575 return CHANNEL_ALIVE; | 607 return CHANNEL_ALIVE; |
576 | 608 |
577 case ERR_WS_PROTOCOL_ERROR: | 609 case ERR_WS_PROTOCOL_ERROR: |
578 // This could be kWebSocketErrorProtocolError (specifically, non-minimal | 610 // This could be kWebSocketErrorProtocolError (specifically, non-minimal |
579 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an | 611 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an |
580 // extension-specific error. | 612 // extension-specific error. |
581 return FailChannel("Invalid frame header", | 613 return FailChannel("Invalid frame header", |
582 kWebSocketErrorProtocolError, | 614 kWebSocketErrorProtocolError, |
583 "WebSocket Protocol Error"); | 615 "WebSocket Protocol Error"); |
584 | 616 |
585 default: | 617 default: |
586 DCHECK_LT(result, 0) | 618 DCHECK_LT(result, 0) |
587 << "ReadFrames() should only return OK or ERR_ codes"; | 619 << "ReadFrames() should only return OK or ERR_ codes"; |
588 stream_->Close(); | 620 stream_->Close(); |
589 DCHECK_NE(CLOSED, state_); | 621 DCHECK_NE(CLOSED, state_); |
590 state_ = CLOSED; | 622 state_ = CLOSED; |
591 uint16 code = kWebSocketErrorAbnormalClosure; | 623 uint16 code = kWebSocketErrorAbnormalClosure; |
592 std::string reason = ""; | 624 std::string reason = ""; |
593 bool was_clean = false; | 625 bool was_clean = false; |
594 if (closing_code_ != 0) { | 626 if (received_close_code_ != 0) { |
595 code = closing_code_; | 627 code = received_close_code_; |
596 reason = closing_reason_; | 628 reason = received_close_reason_; |
597 was_clean = (result == ERR_CONNECTION_CLOSED); | 629 was_clean = (result == ERR_CONNECTION_CLOSED); |
598 } | 630 } |
599 return DoDropChannel(was_clean, code, reason); | 631 return DoDropChannel(was_clean, code, reason); |
600 } | 632 } |
601 } | 633 } |
602 | 634 |
603 ChannelState WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) { | 635 ChannelState WebSocketChannel::HandleFrame( |
| 636 scoped_ptr<WebSocketFrame> frame) { |
604 if (frame->header.masked) { | 637 if (frame->header.masked) { |
605 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a | 638 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a |
606 // masked frame." | 639 // masked frame." |
607 return FailChannel( | 640 return FailChannel( |
608 "A server must not mask any frames that it sends to the " | 641 "A server must not mask any frames that it sends to the " |
609 "client.", | 642 "client.", |
610 kWebSocketErrorProtocolError, | 643 kWebSocketErrorProtocolError, |
611 "Masked frame from server"); | 644 "Masked frame from server"); |
612 } | 645 } |
613 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; | 646 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; |
614 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && | 647 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && |
615 !frame->header.final) { | 648 !frame->header.final) { |
616 return FailChannel( | 649 return FailChannel( |
617 base::StringPrintf("Received fragmented control frame: opcode = %d", | 650 base::StringPrintf("Received fragmented control frame: opcode = %d", |
618 opcode), | 651 opcode), |
619 kWebSocketErrorProtocolError, | 652 kWebSocketErrorProtocolError, |
620 "Control message with FIN bit unset received"); | 653 "Control message with FIN bit unset received"); |
621 } | 654 } |
622 | 655 |
623 // Respond to the frame appropriately to its type. | 656 // Respond to the frame appropriately to its type. |
624 return HandleFrame( | 657 return HandleFrameByState( |
625 opcode, frame->header.final, frame->data, frame->header.payload_length); | 658 opcode, frame->header.final, frame->data, frame->header.payload_length); |
626 } | 659 } |
627 | 660 |
628 ChannelState WebSocketChannel::HandleFrame( | 661 ChannelState WebSocketChannel::HandleFrameByState( |
629 const WebSocketFrameHeader::OpCode opcode, | 662 const WebSocketFrameHeader::OpCode opcode, |
630 bool final, | 663 bool final, |
631 const scoped_refptr<IOBuffer>& data_buffer, | 664 const scoped_refptr<IOBuffer>& data_buffer, |
632 size_t size) { | 665 size_t size) { |
633 DCHECK_NE(RECV_CLOSED, state_) | 666 DCHECK_NE(RECV_CLOSED, state_) |
634 << "HandleFrame() does not support being called re-entrantly from within " | 667 << "HandleFrame() does not support being called re-entrantly from within " |
635 "SendClose()"; | 668 "SendClose()"; |
636 DCHECK_NE(CLOSED, state_); | 669 DCHECK_NE(CLOSED, state_); |
637 if (state_ == CLOSE_WAIT) { | 670 if (state_ == CLOSE_WAIT) { |
638 std::string frame_name; | 671 std::string frame_name; |
639 switch (opcode) { | 672 GetFrameTypeForOpcode(opcode, &frame_name); |
640 case WebSocketFrameHeader::kOpCodeText: // fall-thru | |
641 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru | |
642 case WebSocketFrameHeader::kOpCodeContinuation: | |
643 frame_name = "Data frame"; | |
644 break; | |
645 | 673 |
646 case WebSocketFrameHeader::kOpCodePing: | |
647 frame_name = "Ping"; | |
648 break; | |
649 | |
650 case WebSocketFrameHeader::kOpCodePong: | |
651 frame_name = "Pong"; | |
652 break; | |
653 | |
654 case WebSocketFrameHeader::kOpCodeClose: | |
655 frame_name = "Close"; | |
656 break; | |
657 | |
658 default: | |
659 frame_name = "Unknown frame type"; | |
660 break; | |
661 } | |
662 // FailChannel() won't send another Close frame. | 674 // FailChannel() won't send another Close frame. |
663 return FailChannel( | 675 return FailChannel( |
664 frame_name + " received after close", kWebSocketErrorProtocolError, ""); | 676 frame_name + " received after close", kWebSocketErrorProtocolError, ""); |
665 } | 677 } |
666 switch (opcode) { | 678 switch (opcode) { |
667 case WebSocketFrameHeader::kOpCodeText: // fall-thru | 679 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
668 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru | 680 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru |
669 case WebSocketFrameHeader::kOpCodeContinuation: | 681 case WebSocketFrameHeader::kOpCodeContinuation: |
670 if (state_ == CONNECTED) { | 682 if (state_ == CONNECTED) { |
671 if (opcode == WebSocketFrameHeader::kOpCodeText || | 683 if (opcode == WebSocketFrameHeader::kOpCodeText || |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 // message (escape control codes and so on). | 736 // message (escape control codes and so on). |
725 VLOG(1) << "Got Close with code " << code; | 737 VLOG(1) << "Got Close with code " << code; |
726 switch (state_) { | 738 switch (state_) { |
727 case CONNECTED: | 739 case CONNECTED: |
728 state_ = RECV_CLOSED; | 740 state_ = RECV_CLOSED; |
729 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT | 741 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT |
730 CHANNEL_DELETED) | 742 CHANNEL_DELETED) |
731 return CHANNEL_DELETED; | 743 return CHANNEL_DELETED; |
732 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) | 744 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) |
733 return CHANNEL_DELETED; | 745 return CHANNEL_DELETED; |
734 closing_code_ = code; | 746 received_close_code_ = code; |
735 closing_reason_ = reason; | 747 received_close_reason_ = reason; |
736 break; | 748 break; |
737 | 749 |
738 case SEND_CLOSED: | 750 case SEND_CLOSED: |
739 state_ = CLOSE_WAIT; | 751 state_ = CLOSE_WAIT; |
740 // From RFC6455 section 7.1.5: "Each endpoint | 752 // From RFC6455 section 7.1.5: "Each endpoint |
741 // will see the status code sent by the other end as _The WebSocket | 753 // will see the status code sent by the other end as _The WebSocket |
742 // Connection Close Code_." | 754 // Connection Close Code_." |
743 closing_code_ = code; | 755 received_close_code_ = code; |
744 closing_reason_ = reason; | 756 received_close_reason_ = reason; |
745 break; | 757 break; |
746 | 758 |
747 default: | 759 default: |
748 LOG(DFATAL) << "Got Close in unexpected state " << state_; | 760 LOG(DFATAL) << "Got Close in unexpected state " << state_; |
749 break; | 761 break; |
750 } | 762 } |
751 return CHANNEL_ALIVE; | 763 return CHANNEL_ALIVE; |
752 } | 764 } |
753 | 765 |
754 default: | 766 default: |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 | 919 |
908 void WebSocketChannel::CloseTimeout() { | 920 void WebSocketChannel::CloseTimeout() { |
909 stream_->Close(); | 921 stream_->Close(); |
910 DCHECK_NE(CLOSED, state_); | 922 DCHECK_NE(CLOSED, state_); |
911 state_ = CLOSED; | 923 state_ = CLOSED; |
912 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); | 924 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); |
913 // |this| has been deleted. | 925 // |this| has been deleted. |
914 } | 926 } |
915 | 927 |
916 } // namespace net | 928 } // namespace net |
OLD | NEW |