| 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 DCHECK_NE(kInvalidRangesEnd, upper); | 71 DCHECK_NE(kInvalidRangesEnd, upper); |
| 72 DCHECK_GT(upper, kInvalidRanges); | 72 DCHECK_GT(upper, kInvalidRanges); |
| 73 DCHECK_GT(*upper, code); | 73 DCHECK_GT(*upper, code); |
| 74 DCHECK_LE(*(upper - 1), code); | 74 DCHECK_LE(*(upper - 1), code); |
| 75 return ((upper - kInvalidRanges) % 2) == 0; | 75 return ((upper - kInvalidRanges) % 2) == 0; |
| 76 } | 76 } |
| 77 | 77 |
| 78 // This function avoids a bunch of boilerplate code. | 78 // This function avoids a bunch of boilerplate code. |
| 79 void AllowUnused(ChannelState ALLOW_UNUSED unused) {} | 79 void AllowUnused(ChannelState ALLOW_UNUSED unused) {} |
| 80 | 80 |
| 81 // Sets |name| to the name of the frame type for the given |opcode|. Note that |
| 82 // for all of Text, Binary and Continuation opcode, this method returns |
| 83 // "Data frame". |
| 84 void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode, |
| 85 std::string* name) { |
| 86 switch (opcode) { |
| 87 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 88 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru |
| 89 case WebSocketFrameHeader::kOpCodeContinuation: |
| 90 *name = "Data frame"; |
| 91 break; |
| 92 |
| 93 case WebSocketFrameHeader::kOpCodePing: |
| 94 *name = "Ping"; |
| 95 break; |
| 96 |
| 97 case WebSocketFrameHeader::kOpCodePong: |
| 98 *name = "Pong"; |
| 99 break; |
| 100 |
| 101 case WebSocketFrameHeader::kOpCodeClose: |
| 102 *name = "Close"; |
| 103 break; |
| 104 |
| 105 default: |
| 106 *name = "Unknown frame type"; |
| 107 break; |
| 108 } |
| 109 |
| 110 return; |
| 111 } |
| 112 |
| 81 } // namespace | 113 } // namespace |
| 82 | 114 |
| 83 // A class to encapsulate a set of frames and information about the size of | 115 // A class to encapsulate a set of frames and information about the size of |
| 84 // those frames. | 116 // those frames. |
| 85 class WebSocketChannel::SendBuffer { | 117 class WebSocketChannel::SendBuffer { |
| 86 public: | 118 public: |
| 87 SendBuffer() : total_bytes_(0) {} | 119 SendBuffer() : total_bytes_(0) {} |
| 88 | 120 |
| 89 // Add a WebSocketFrame to the buffer and increase total_bytes_. | 121 // Add a WebSocketFrame to the buffer and increase total_bytes_. |
| 90 void AddFrame(scoped_ptr<WebSocketFrame> chunk); | 122 void AddFrame(scoped_ptr<WebSocketFrame> chunk); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 | 248 |
| 217 WebSocketChannel::WebSocketChannel( | 249 WebSocketChannel::WebSocketChannel( |
| 218 scoped_ptr<WebSocketEventInterface> event_interface, | 250 scoped_ptr<WebSocketEventInterface> event_interface, |
| 219 URLRequestContext* url_request_context) | 251 URLRequestContext* url_request_context) |
| 220 : event_interface_(event_interface.Pass()), | 252 : event_interface_(event_interface.Pass()), |
| 221 url_request_context_(url_request_context), | 253 url_request_context_(url_request_context), |
| 222 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), | 254 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), |
| 223 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), | 255 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), |
| 224 current_send_quota_(0), | 256 current_send_quota_(0), |
| 225 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), | 257 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), |
| 226 closing_code_(0), | 258 received_close_code_(0), |
| 227 state_(FRESHLY_CONSTRUCTED), | 259 state_(FRESHLY_CONSTRUCTED), |
| 228 notification_sender_(new HandshakeNotificationSender(this)) {} | 260 notification_sender_(new HandshakeNotificationSender(this)) {} |
| 229 | 261 |
| 230 WebSocketChannel::~WebSocketChannel() { | 262 WebSocketChannel::~WebSocketChannel() { |
| 231 // The stream may hold a pointer to read_frames_, and so it needs to be | 263 // The stream may hold a pointer to read_frames_, and so it needs to be |
| 232 // destroyed first. | 264 // destroyed first. |
| 233 stream_.reset(); | 265 stream_.reset(); |
| 234 // The timer may have a callback pointing back to us, so stop it just in case | 266 // The timer may have a callback pointing back to us, so stop it just in case |
| 235 // someone decides to run the event loop from their destructor. | 267 // someone decides to run the event loop from their destructor. |
| 236 timer_.Stop(); | 268 timer_.Stop(); |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 DCHECK_NE(ERR_IO_PENDING, result); | 566 DCHECK_NE(ERR_IO_PENDING, result); |
| 535 switch (result) { | 567 switch (result) { |
| 536 case OK: | 568 case OK: |
| 537 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection | 569 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection |
| 538 // with no data read, not an empty response. | 570 // with no data read, not an empty response. |
| 539 DCHECK(!read_frames_.empty()) | 571 DCHECK(!read_frames_.empty()) |
| 540 << "ReadFrames() returned OK, but nothing was read."; | 572 << "ReadFrames() returned OK, but nothing was read."; |
| 541 for (size_t i = 0; i < read_frames_.size(); ++i) { | 573 for (size_t i = 0; i < read_frames_.size(); ++i) { |
| 542 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); | 574 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); |
| 543 read_frames_[i] = NULL; | 575 read_frames_[i] = NULL; |
| 544 if (ProcessFrame(frame.Pass()) == CHANNEL_DELETED) | 576 if (HandleFrame(frame.Pass()) == CHANNEL_DELETED) |
| 545 return CHANNEL_DELETED; | 577 return CHANNEL_DELETED; |
| 546 } | 578 } |
| 547 read_frames_.clear(); | 579 read_frames_.clear(); |
| 548 // There should always be a call to ReadFrames pending. | 580 // There should always be a call to ReadFrames pending. |
| 549 // TODO(ricea): Unless we are out of quota. | 581 // TODO(ricea): Unless we are out of quota. |
| 550 DCHECK_NE(CLOSED, state_); | 582 DCHECK_NE(CLOSED, state_); |
| 551 if (!synchronous) | 583 if (!synchronous) |
| 552 return ReadFrames(); | 584 return ReadFrames(); |
| 553 return CHANNEL_ALIVE; | 585 return CHANNEL_ALIVE; |
| 554 | 586 |
| 555 case ERR_WS_PROTOCOL_ERROR: | 587 case ERR_WS_PROTOCOL_ERROR: |
| 556 // This could be kWebSocketErrorProtocolError (specifically, non-minimal | 588 // This could be kWebSocketErrorProtocolError (specifically, non-minimal |
| 557 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an | 589 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an |
| 558 // extension-specific error. | 590 // extension-specific error. |
| 559 return FailChannel("Invalid frame header", | 591 return FailChannel("Invalid frame header", |
| 560 kWebSocketErrorProtocolError, | 592 kWebSocketErrorProtocolError, |
| 561 "WebSocket Protocol Error"); | 593 "WebSocket Protocol Error"); |
| 562 | 594 |
| 563 default: | 595 default: |
| 564 DCHECK_LT(result, 0) | 596 DCHECK_LT(result, 0) |
| 565 << "ReadFrames() should only return OK or ERR_ codes"; | 597 << "ReadFrames() should only return OK or ERR_ codes"; |
| 566 stream_->Close(); | 598 stream_->Close(); |
| 567 DCHECK_NE(CLOSED, state_); | 599 DCHECK_NE(CLOSED, state_); |
| 568 state_ = CLOSED; | 600 state_ = CLOSED; |
| 569 uint16 code = kWebSocketErrorAbnormalClosure; | 601 uint16 code = kWebSocketErrorAbnormalClosure; |
| 570 std::string reason = ""; | 602 std::string reason = ""; |
| 571 if (closing_code_ != 0) { | 603 if (received_close_code_ != 0) { |
| 572 code = closing_code_; | 604 code = received_close_code_; |
| 573 reason = closing_reason_; | 605 reason = received_close_reason_; |
| 574 } | 606 } |
| 575 return DoDropChannel(code, reason); | 607 return DoDropChannel(code, reason); |
| 576 } | 608 } |
| 577 } | 609 } |
| 578 | 610 |
| 579 ChannelState WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) { | 611 ChannelState WebSocketChannel::HandleFrame( |
| 612 scoped_ptr<WebSocketFrame> frame) { |
| 580 if (frame->header.masked) { | 613 if (frame->header.masked) { |
| 581 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a | 614 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a |
| 582 // masked frame." | 615 // masked frame." |
| 583 return FailChannel( | 616 return FailChannel( |
| 584 "A server must not mask any frames that it sends to the " | 617 "A server must not mask any frames that it sends to the " |
| 585 "client.", | 618 "client.", |
| 586 kWebSocketErrorProtocolError, | 619 kWebSocketErrorProtocolError, |
| 587 "Masked frame from server"); | 620 "Masked frame from server"); |
| 588 } | 621 } |
| 589 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; | 622 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; |
| 590 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && | 623 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && |
| 591 !frame->header.final) { | 624 !frame->header.final) { |
| 592 return FailChannel( | 625 return FailChannel( |
| 593 base::StringPrintf("Received fragmented control frame: opcode = %d", | 626 base::StringPrintf("Received fragmented control frame: opcode = %d", |
| 594 opcode), | 627 opcode), |
| 595 kWebSocketErrorProtocolError, | 628 kWebSocketErrorProtocolError, |
| 596 "Control message with FIN bit unset received"); | 629 "Control message with FIN bit unset received"); |
| 597 } | 630 } |
| 598 | 631 |
| 599 // Respond to the frame appropriately to its type. | 632 // Respond to the frame appropriately to its type. |
| 600 return HandleFrame( | 633 return HandleFrameBottomHalf( |
| 601 opcode, frame->header.final, frame->data, frame->header.payload_length); | 634 opcode, frame->header.final, frame->data, frame->header.payload_length); |
| 602 } | 635 } |
| 603 | 636 |
| 604 ChannelState WebSocketChannel::HandleFrame( | 637 ChannelState WebSocketChannel::HandleFrameBottomHalf( |
| 605 const WebSocketFrameHeader::OpCode opcode, | 638 const WebSocketFrameHeader::OpCode opcode, |
| 606 bool final, | 639 bool final, |
| 607 const scoped_refptr<IOBuffer>& data_buffer, | 640 const scoped_refptr<IOBuffer>& data_buffer, |
| 608 size_t size) { | 641 size_t size) { |
| 609 DCHECK_NE(RECV_CLOSED, state_) | 642 DCHECK_NE(RECV_CLOSED, state_) |
| 610 << "HandleFrame() does not support being called re-entrantly from within " | 643 << "HandleFrame() does not support being called re-entrantly from within " |
| 611 "SendClose()"; | 644 "SendClose()"; |
| 612 DCHECK_NE(CLOSED, state_); | 645 DCHECK_NE(CLOSED, state_); |
| 613 if (state_ == CLOSE_WAIT) { | 646 if (state_ == CLOSE_WAIT) { |
| 614 std::string frame_name; | 647 std::string frame_name; |
| 615 switch (opcode) { | 648 GetFrameTypeForOpcode(opcode, &frame_name); |
| 616 case WebSocketFrameHeader::kOpCodeText: // fall-thru | |
| 617 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru | |
| 618 case WebSocketFrameHeader::kOpCodeContinuation: | |
| 619 frame_name = "Data frame"; | |
| 620 break; | |
| 621 | 649 |
| 622 case WebSocketFrameHeader::kOpCodePing: | |
| 623 frame_name = "Ping"; | |
| 624 break; | |
| 625 | |
| 626 case WebSocketFrameHeader::kOpCodePong: | |
| 627 frame_name = "Pong"; | |
| 628 break; | |
| 629 | |
| 630 case WebSocketFrameHeader::kOpCodeClose: | |
| 631 frame_name = "Close"; | |
| 632 break; | |
| 633 | |
| 634 default: | |
| 635 frame_name = "Unknown frame type"; | |
| 636 break; | |
| 637 } | |
| 638 // FailChannel() won't send another Close frame. | 650 // FailChannel() won't send another Close frame. |
| 639 return FailChannel( | 651 return FailChannel( |
| 640 frame_name + " received after close", kWebSocketErrorProtocolError, ""); | 652 frame_name + " received after close", kWebSocketErrorProtocolError, ""); |
| 641 } | 653 } |
| 642 switch (opcode) { | 654 switch (opcode) { |
| 643 case WebSocketFrameHeader::kOpCodeText: // fall-thru | 655 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 644 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru | 656 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru |
| 645 case WebSocketFrameHeader::kOpCodeContinuation: | 657 case WebSocketFrameHeader::kOpCodeContinuation: |
| 646 if (state_ == CONNECTED) { | 658 if (state_ == CONNECTED) { |
| 647 // TODO(ricea): Need to fail the connection if UTF-8 is invalid | 659 // TODO(ricea): Need to fail the connection if UTF-8 is invalid |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 // message (escape control codes and so on). | 697 // message (escape control codes and so on). |
| 686 VLOG(1) << "Got Close with code " << code; | 698 VLOG(1) << "Got Close with code " << code; |
| 687 switch (state_) { | 699 switch (state_) { |
| 688 case CONNECTED: | 700 case CONNECTED: |
| 689 state_ = RECV_CLOSED; | 701 state_ = RECV_CLOSED; |
| 690 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT | 702 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT |
| 691 CHANNEL_DELETED) | 703 CHANNEL_DELETED) |
| 692 return CHANNEL_DELETED; | 704 return CHANNEL_DELETED; |
| 693 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) | 705 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) |
| 694 return CHANNEL_DELETED; | 706 return CHANNEL_DELETED; |
| 695 closing_code_ = code; | 707 received_close_code_ = code; |
| 696 closing_reason_ = reason; | 708 received_close_reason_ = reason; |
| 697 break; | 709 break; |
| 698 | 710 |
| 699 case SEND_CLOSED: | 711 case SEND_CLOSED: |
| 700 state_ = CLOSE_WAIT; | 712 state_ = CLOSE_WAIT; |
| 701 // From RFC6455 section 7.1.5: "Each endpoint | 713 // From RFC6455 section 7.1.5: "Each endpoint |
| 702 // will see the status code sent by the other end as _The WebSocket | 714 // will see the status code sent by the other end as _The WebSocket |
| 703 // Connection Close Code_." | 715 // Connection Close Code_." |
| 704 closing_code_ = code; | 716 received_close_code_ = code; |
| 705 closing_reason_ = reason; | 717 received_close_reason_ = reason; |
| 706 break; | 718 break; |
| 707 | 719 |
| 708 default: | 720 default: |
| 709 LOG(DFATAL) << "Got Close in unexpected state " << state_; | 721 LOG(DFATAL) << "Got Close in unexpected state " << state_; |
| 710 break; | 722 break; |
| 711 } | 723 } |
| 712 return CHANNEL_ALIVE; | 724 return CHANNEL_ALIVE; |
| 713 } | 725 } |
| 714 | 726 |
| 715 default: | 727 default: |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 | 881 |
| 870 void WebSocketChannel::CloseTimeout() { | 882 void WebSocketChannel::CloseTimeout() { |
| 871 stream_->Close(); | 883 stream_->Close(); |
| 872 DCHECK_NE(CLOSED, state_); | 884 DCHECK_NE(CLOSED, state_); |
| 873 state_ = CLOSED; | 885 state_ = CLOSED; |
| 874 AllowUnused(DoDropChannel(kWebSocketErrorAbnormalClosure, "")); | 886 AllowUnused(DoDropChannel(kWebSocketErrorAbnormalClosure, "")); |
| 875 // |this| has been deleted. | 887 // |this| has been deleted. |
| 876 } | 888 } |
| 877 | 889 |
| 878 } // namespace net | 890 } // namespace net |
| OLD | NEW |