| 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 |