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 |