| 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 <limits.h> // for INT_MAX | 7 #include <limits.h> // for INT_MAX |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <deque> | 10 #include <deque> |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 | 63 |
| 64 // Maximum close reason length = max control frame payload - | 64 // Maximum close reason length = max control frame payload - |
| 65 // status code length | 65 // status code length |
| 66 // = 125 - 2 | 66 // = 125 - 2 |
| 67 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; | 67 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; |
| 68 | 68 |
| 69 // Check a close status code for strict compliance with RFC6455. This is only | 69 // Check a close status code for strict compliance with RFC6455. This is only |
| 70 // used for close codes received from a renderer that we are intending to send | 70 // used for close codes received from a renderer that we are intending to send |
| 71 // out over the network. See ParseClose() for the restrictions on incoming close | 71 // out over the network. See ParseClose() for the restrictions on incoming close |
| 72 // codes. The |code| parameter is type int for convenience of implementation; | 72 // codes. The |code| parameter is type int for convenience of implementation; |
| 73 // the real type is uint16. Code 1005 is treated specially; it cannot be set | 73 // the real type is uint16_t. Code 1005 is treated specially; it cannot be set |
| 74 // explicitly by Javascript but the renderer uses it to indicate we should send | 74 // explicitly by Javascript but the renderer uses it to indicate we should send |
| 75 // a Close frame with no payload. | 75 // a Close frame with no payload. |
| 76 bool IsStrictlyValidCloseStatusCode(int code) { | 76 bool IsStrictlyValidCloseStatusCode(int code) { |
| 77 static const int kInvalidRanges[] = { | 77 static const int kInvalidRanges[] = { |
| 78 // [BAD, OK) | 78 // [BAD, OK) |
| 79 0, 1000, // 1000 is the first valid code | 79 0, 1000, // 1000 is the first valid code |
| 80 1006, 1007, // 1006 MUST NOT be set. | 80 1006, 1007, // 1006 MUST NOT be set. |
| 81 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved. | 81 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved. |
| 82 5000, 65536, // Codes above 5000 are invalid. | 82 5000, 65536, // Codes above 5000 are invalid. |
| 83 }; | 83 }; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 // Return a pointer to the frames_ for write purposes. | 140 // Return a pointer to the frames_ for write purposes. |
| 141 ScopedVector<WebSocketFrame>* frames() { return &frames_; } | 141 ScopedVector<WebSocketFrame>* frames() { return &frames_; } |
| 142 | 142 |
| 143 private: | 143 private: |
| 144 // The frames_ that will be sent in the next call to WriteFrames(). | 144 // The frames_ that will be sent in the next call to WriteFrames(). |
| 145 ScopedVector<WebSocketFrame> frames_; | 145 ScopedVector<WebSocketFrame> frames_; |
| 146 | 146 |
| 147 // The total size of the payload data in |frames_|. This will be used to | 147 // The total size of the payload data in |frames_|. This will be used to |
| 148 // measure the throughput of the link. | 148 // measure the throughput of the link. |
| 149 // TODO(ricea): Measure the throughput of the link. | 149 // TODO(ricea): Measure the throughput of the link. |
| 150 uint64 total_bytes_; | 150 uint64_t total_bytes_; |
| 151 }; | 151 }; |
| 152 | 152 |
| 153 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) { | 153 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) { |
| 154 total_bytes_ += frame->header.payload_length; | 154 total_bytes_ += frame->header.payload_length; |
| 155 frames_.push_back(frame.Pass()); | 155 frames_.push_back(frame.Pass()); |
| 156 } | 156 } |
| 157 | 157 |
| 158 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the | 158 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the |
| 159 // calls on to the WebSocketChannel that created it. | 159 // calls on to the WebSocketChannel that created it. |
| 160 class WebSocketChannel::ConnectDelegate | 160 class WebSocketChannel::ConnectDelegate |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 // there will be no more opening handshake notification. | 268 // there will be no more opening handshake notification. |
| 269 } | 269 } |
| 270 | 270 |
| 271 return CHANNEL_ALIVE; | 271 return CHANNEL_ALIVE; |
| 272 } | 272 } |
| 273 | 273 |
| 274 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( | 274 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( |
| 275 bool final, | 275 bool final, |
| 276 WebSocketFrameHeader::OpCode opcode, | 276 WebSocketFrameHeader::OpCode opcode, |
| 277 const scoped_refptr<IOBuffer>& data, | 277 const scoped_refptr<IOBuffer>& data, |
| 278 uint64 offset, | 278 uint64_t offset, |
| 279 uint64 size) | 279 uint64_t size) |
| 280 : final_(final), | 280 : final_(final), |
| 281 opcode_(opcode), | 281 opcode_(opcode), |
| 282 data_(data), | 282 data_(data), |
| 283 offset_(offset), | 283 offset_(offset), |
| 284 size_(size) {} | 284 size_(size) {} |
| 285 | 285 |
| 286 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} | 286 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} |
| 287 | 287 |
| 288 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { | 288 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { |
| 289 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); | 289 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); |
| 290 opcode_ = WebSocketFrameHeader::kOpCodeContinuation; | 290 opcode_ = WebSocketFrameHeader::kOpCodeContinuation; |
| 291 } | 291 } |
| 292 | 292 |
| 293 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64 bytes) { | 293 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64_t bytes) { |
| 294 DCHECK_LE(offset_, size_); | 294 DCHECK_LE(offset_, size_); |
| 295 DCHECK_LE(bytes, size_ - offset_); | 295 DCHECK_LE(bytes, size_ - offset_); |
| 296 offset_ += bytes; | 296 offset_ += bytes; |
| 297 } | 297 } |
| 298 | 298 |
| 299 WebSocketChannel::WebSocketChannel( | 299 WebSocketChannel::WebSocketChannel( |
| 300 scoped_ptr<WebSocketEventInterface> event_interface, | 300 scoped_ptr<WebSocketEventInterface> event_interface, |
| 301 URLRequestContext* url_request_context) | 301 URLRequestContext* url_request_context) |
| 302 : event_interface_(event_interface.Pass()), | 302 : event_interface_(event_interface.Pass()), |
| 303 url_request_context_(url_request_context), | 303 url_request_context_(url_request_context), |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 // TODO(ricea): If current_send_quota_ has dropped below | 417 // TODO(ricea): If current_send_quota_ has dropped below |
| 418 // send_quota_low_water_mark_, it might be good to increase the "low | 418 // send_quota_low_water_mark_, it might be good to increase the "low |
| 419 // water mark" and "high water mark", but only if the link to the WebSocket | 419 // water mark" and "high water mark", but only if the link to the WebSocket |
| 420 // server is not saturated. | 420 // server is not saturated. |
| 421 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); | 421 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); |
| 422 std::copy(data.begin(), data.end(), buffer->data()); | 422 std::copy(data.begin(), data.end(), buffer->data()); |
| 423 ignore_result(SendFrameFromIOBuffer(fin, op_code, buffer, data.size())); | 423 ignore_result(SendFrameFromIOBuffer(fin, op_code, buffer, data.size())); |
| 424 // |this| may have been deleted. | 424 // |this| may have been deleted. |
| 425 } | 425 } |
| 426 | 426 |
| 427 void WebSocketChannel::SendFlowControl(int64 quota) { | 427 void WebSocketChannel::SendFlowControl(int64_t quota) { |
| 428 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || | 428 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || |
| 429 state_ == CLOSE_WAIT); | 429 state_ == CLOSE_WAIT); |
| 430 // TODO(ricea): Kill the renderer if it tries to send us a negative quota | 430 // TODO(ricea): Kill the renderer if it tries to send us a negative quota |
| 431 // value or > INT_MAX. | 431 // value or > INT_MAX. |
| 432 DCHECK_GE(quota, 0); | 432 DCHECK_GE(quota, 0); |
| 433 DCHECK_LE(quota, INT_MAX); | 433 DCHECK_LE(quota, INT_MAX); |
| 434 if (!pending_received_frames_.empty()) { | 434 if (!pending_received_frames_.empty()) { |
| 435 DCHECK_EQ(0u, current_receive_quota_); | 435 DCHECK_EQ(0u, current_receive_quota_); |
| 436 } | 436 } |
| 437 while (!pending_received_frames_.empty() && quota > 0) { | 437 while (!pending_received_frames_.empty() && quota > 0) { |
| 438 PendingReceivedFrame& front = pending_received_frames_.front(); | 438 PendingReceivedFrame& front = pending_received_frames_.front(); |
| 439 const uint64 data_size = front.size() - front.offset(); | 439 const uint64_t data_size = front.size() - front.offset(); |
| 440 const uint64 bytes_to_send = | 440 const uint64_t bytes_to_send = |
| 441 std::min(base::checked_cast<uint64>(quota), data_size); | 441 std::min(base::checked_cast<uint64_t>(quota), data_size); |
| 442 const bool final = front.final() && data_size == bytes_to_send; | 442 const bool final = front.final() && data_size == bytes_to_send; |
| 443 const char* data = | 443 const char* data = |
| 444 front.data().get() ? front.data()->data() + front.offset() : NULL; | 444 front.data().get() ? front.data()->data() + front.offset() : NULL; |
| 445 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; | 445 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; |
| 446 const std::vector<char> data_vector(data, data + bytes_to_send); | 446 const std::vector<char> data_vector(data, data + bytes_to_send); |
| 447 DVLOG(3) << "Sending frame previously split due to quota to the " | 447 DVLOG(3) << "Sending frame previously split due to quota to the " |
| 448 << "renderer: quota=" << quota << " data_size=" << data_size | 448 << "renderer: quota=" << quota << " data_size=" << data_size |
| 449 << " bytes_to_send=" << bytes_to_send; | 449 << " bytes_to_send=" << bytes_to_send; |
| 450 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == | 450 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == |
| 451 CHANNEL_DELETED) | 451 CHANNEL_DELETED) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 463 // operation. | 463 // operation. |
| 464 const bool start_read = | 464 const bool start_read = |
| 465 current_receive_quota_ == 0 && quota > 0 && | 465 current_receive_quota_ == 0 && quota > 0 && |
| 466 (state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT); | 466 (state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT); |
| 467 current_receive_quota_ += quota; | 467 current_receive_quota_ += quota; |
| 468 if (start_read) | 468 if (start_read) |
| 469 ignore_result(ReadFrames()); | 469 ignore_result(ReadFrames()); |
| 470 // |this| may have been deleted. | 470 // |this| may have been deleted. |
| 471 } | 471 } |
| 472 | 472 |
| 473 void WebSocketChannel::StartClosingHandshake(uint16 code, | 473 void WebSocketChannel::StartClosingHandshake(uint16_t code, |
| 474 const std::string& reason) { | 474 const std::string& reason) { |
| 475 if (InClosingState()) { | 475 if (InClosingState()) { |
| 476 // When the associated renderer process is killed while the channel is in | 476 // When the associated renderer process is killed while the channel is in |
| 477 // CLOSING state we reach here. | 477 // CLOSING state we reach here. |
| 478 DVLOG(1) << "StartClosingHandshake called in state " << state_ | 478 DVLOG(1) << "StartClosingHandshake called in state " << state_ |
| 479 << ". This may be a bug, or a harmless race."; | 479 << ". This may be a bug, or a harmless race."; |
| 480 return; | 480 return; |
| 481 } | 481 } |
| 482 if (state_ == CONNECTING) { | 482 if (state_ == CONNECTING) { |
| 483 // Abort the in-progress handshake and drop the connection immediately. | 483 // Abort the in-progress handshake and drop the connection immediately. |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 kWebSocketErrorProtocolError, | 761 kWebSocketErrorProtocolError, |
| 762 "WebSocket Protocol Error"); | 762 "WebSocket Protocol Error"); |
| 763 | 763 |
| 764 default: | 764 default: |
| 765 DCHECK_LT(result, 0) | 765 DCHECK_LT(result, 0) |
| 766 << "ReadFrames() should only return OK or ERR_ codes"; | 766 << "ReadFrames() should only return OK or ERR_ codes"; |
| 767 | 767 |
| 768 stream_->Close(); | 768 stream_->Close(); |
| 769 SetState(CLOSED); | 769 SetState(CLOSED); |
| 770 | 770 |
| 771 uint16 code = kWebSocketErrorAbnormalClosure; | 771 uint16_t code = kWebSocketErrorAbnormalClosure; |
| 772 std::string reason = ""; | 772 std::string reason = ""; |
| 773 bool was_clean = false; | 773 bool was_clean = false; |
| 774 if (has_received_close_frame_) { | 774 if (has_received_close_frame_) { |
| 775 code = received_close_code_; | 775 code = received_close_code_; |
| 776 reason = received_close_reason_; | 776 reason = received_close_reason_; |
| 777 was_clean = (result == ERR_CONNECTION_CLOSED); | 777 was_clean = (result == ERR_CONNECTION_CLOSED); |
| 778 } | 778 } |
| 779 | 779 |
| 780 return DoDropChannel(was_clean, code, reason); | 780 return DoDropChannel(was_clean, code, reason); |
| 781 } | 781 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 808 | 808 |
| 809 // Respond to the frame appropriately to its type. | 809 // Respond to the frame appropriately to its type. |
| 810 return HandleFrameByState( | 810 return HandleFrameByState( |
| 811 opcode, frame->header.final, frame->data, frame->header.payload_length); | 811 opcode, frame->header.final, frame->data, frame->header.payload_length); |
| 812 } | 812 } |
| 813 | 813 |
| 814 ChannelState WebSocketChannel::HandleFrameByState( | 814 ChannelState WebSocketChannel::HandleFrameByState( |
| 815 const WebSocketFrameHeader::OpCode opcode, | 815 const WebSocketFrameHeader::OpCode opcode, |
| 816 bool final, | 816 bool final, |
| 817 const scoped_refptr<IOBuffer>& data_buffer, | 817 const scoped_refptr<IOBuffer>& data_buffer, |
| 818 uint64 size) { | 818 uint64_t size) { |
| 819 DCHECK_NE(RECV_CLOSED, state_) | 819 DCHECK_NE(RECV_CLOSED, state_) |
| 820 << "HandleFrame() does not support being called re-entrantly from within " | 820 << "HandleFrame() does not support being called re-entrantly from within " |
| 821 "SendClose()"; | 821 "SendClose()"; |
| 822 DCHECK_NE(CLOSED, state_); | 822 DCHECK_NE(CLOSED, state_); |
| 823 if (state_ == CLOSE_WAIT) { | 823 if (state_ == CLOSE_WAIT) { |
| 824 std::string frame_name; | 824 std::string frame_name; |
| 825 GetFrameTypeForOpcode(opcode, &frame_name); | 825 GetFrameTypeForOpcode(opcode, &frame_name); |
| 826 | 826 |
| 827 // FailChannel() won't send another Close frame. | 827 // FailChannel() won't send another Close frame. |
| 828 return FailChannel( | 828 return FailChannel( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 845 case WebSocketFrameHeader::kOpCodePong: | 845 case WebSocketFrameHeader::kOpCodePong: |
| 846 DVLOG(1) << "Got Pong of size " << size; | 846 DVLOG(1) << "Got Pong of size " << size; |
| 847 // There is no need to do anything with pong messages. | 847 // There is no need to do anything with pong messages. |
| 848 return CHANNEL_ALIVE; | 848 return CHANNEL_ALIVE; |
| 849 | 849 |
| 850 case WebSocketFrameHeader::kOpCodeClose: { | 850 case WebSocketFrameHeader::kOpCodeClose: { |
| 851 // TODO(ricea): If there is a message which is queued for transmission to | 851 // TODO(ricea): If there is a message which is queued for transmission to |
| 852 // the renderer, then the renderer should not receive an | 852 // the renderer, then the renderer should not receive an |
| 853 // OnClosingHandshake or OnDropChannel IPC until the queued message has | 853 // OnClosingHandshake or OnDropChannel IPC until the queued message has |
| 854 // been completedly transmitted. | 854 // been completedly transmitted. |
| 855 uint16 code = kWebSocketNormalClosure; | 855 uint16_t code = kWebSocketNormalClosure; |
| 856 std::string reason; | 856 std::string reason; |
| 857 std::string message; | 857 std::string message; |
| 858 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { | 858 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { |
| 859 return FailChannel(message, code, reason); | 859 return FailChannel(message, code, reason); |
| 860 } | 860 } |
| 861 // TODO(ricea): Find a way to safely log the message from the close | 861 // TODO(ricea): Find a way to safely log the message from the close |
| 862 // message (escape control codes and so on). | 862 // message (escape control codes and so on). |
| 863 DVLOG(1) << "Got Close with code " << code; | 863 DVLOG(1) << "Got Close with code " << code; |
| 864 switch (state_) { | 864 switch (state_) { |
| 865 case CONNECTED: | 865 case CONNECTED: |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 918 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
| 919 kWebSocketErrorProtocolError, | 919 kWebSocketErrorProtocolError, |
| 920 "Unknown opcode"); | 920 "Unknown opcode"); |
| 921 } | 921 } |
| 922 } | 922 } |
| 923 | 923 |
| 924 ChannelState WebSocketChannel::HandleDataFrame( | 924 ChannelState WebSocketChannel::HandleDataFrame( |
| 925 WebSocketFrameHeader::OpCode opcode, | 925 WebSocketFrameHeader::OpCode opcode, |
| 926 bool final, | 926 bool final, |
| 927 const scoped_refptr<IOBuffer>& data_buffer, | 927 const scoped_refptr<IOBuffer>& data_buffer, |
| 928 uint64 size) { | 928 uint64_t size) { |
| 929 if (state_ != CONNECTED) { | 929 if (state_ != CONNECTED) { |
| 930 DVLOG(3) << "Ignored data packet received in state " << state_; | 930 DVLOG(3) << "Ignored data packet received in state " << state_; |
| 931 return CHANNEL_ALIVE; | 931 return CHANNEL_ALIVE; |
| 932 } | 932 } |
| 933 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || | 933 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || |
| 934 opcode == WebSocketFrameHeader::kOpCodeText || | 934 opcode == WebSocketFrameHeader::kOpCodeText || |
| 935 opcode == WebSocketFrameHeader::kOpCodeBinary); | 935 opcode == WebSocketFrameHeader::kOpCodeBinary); |
| 936 const bool got_continuation = | 936 const bool got_continuation = |
| 937 (opcode == WebSocketFrameHeader::kOpCodeContinuation); | 937 (opcode == WebSocketFrameHeader::kOpCodeContinuation); |
| 938 if (got_continuation != expecting_to_handle_continuation_) { | 938 if (got_continuation != expecting_to_handle_continuation_) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 current_receive_quota_ -= size; | 994 current_receive_quota_ -= size; |
| 995 | 995 |
| 996 // Sends the received frame to the renderer process. | 996 // Sends the received frame to the renderer process. |
| 997 return event_interface_->OnDataFrame(final, opcode_to_send, data); | 997 return event_interface_->OnDataFrame(final, opcode_to_send, data); |
| 998 } | 998 } |
| 999 | 999 |
| 1000 ChannelState WebSocketChannel::SendFrameFromIOBuffer( | 1000 ChannelState WebSocketChannel::SendFrameFromIOBuffer( |
| 1001 bool fin, | 1001 bool fin, |
| 1002 WebSocketFrameHeader::OpCode op_code, | 1002 WebSocketFrameHeader::OpCode op_code, |
| 1003 const scoped_refptr<IOBuffer>& buffer, | 1003 const scoped_refptr<IOBuffer>& buffer, |
| 1004 uint64 size) { | 1004 uint64_t size) { |
| 1005 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 1005 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
| 1006 DCHECK(stream_); | 1006 DCHECK(stream_); |
| 1007 | 1007 |
| 1008 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); | 1008 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); |
| 1009 WebSocketFrameHeader& header = frame->header; | 1009 WebSocketFrameHeader& header = frame->header; |
| 1010 header.final = fin; | 1010 header.final = fin; |
| 1011 header.masked = true; | 1011 header.masked = true; |
| 1012 header.payload_length = size; | 1012 header.payload_length = size; |
| 1013 frame->data = buffer; | 1013 frame->data = buffer; |
| 1014 | 1014 |
| 1015 if (data_being_sent_) { | 1015 if (data_being_sent_) { |
| 1016 // Either the link to the WebSocket server is saturated, or several messages | 1016 // Either the link to the WebSocket server is saturated, or several messages |
| 1017 // are being sent in a batch. | 1017 // are being sent in a batch. |
| 1018 // TODO(ricea): Keep some statistics to work out the situation and adjust | 1018 // TODO(ricea): Keep some statistics to work out the situation and adjust |
| 1019 // quota appropriately. | 1019 // quota appropriately. |
| 1020 if (!data_to_send_next_) | 1020 if (!data_to_send_next_) |
| 1021 data_to_send_next_.reset(new SendBuffer); | 1021 data_to_send_next_.reset(new SendBuffer); |
| 1022 data_to_send_next_->AddFrame(frame.Pass()); | 1022 data_to_send_next_->AddFrame(frame.Pass()); |
| 1023 return CHANNEL_ALIVE; | 1023 return CHANNEL_ALIVE; |
| 1024 } | 1024 } |
| 1025 | 1025 |
| 1026 data_being_sent_.reset(new SendBuffer); | 1026 data_being_sent_.reset(new SendBuffer); |
| 1027 data_being_sent_->AddFrame(frame.Pass()); | 1027 data_being_sent_->AddFrame(frame.Pass()); |
| 1028 return WriteFrames(); | 1028 return WriteFrames(); |
| 1029 } | 1029 } |
| 1030 | 1030 |
| 1031 ChannelState WebSocketChannel::FailChannel(const std::string& message, | 1031 ChannelState WebSocketChannel::FailChannel(const std::string& message, |
| 1032 uint16 code, | 1032 uint16_t code, |
| 1033 const std::string& reason) { | 1033 const std::string& reason) { |
| 1034 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); | 1034 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); |
| 1035 DCHECK_NE(CONNECTING, state_); | 1035 DCHECK_NE(CONNECTING, state_); |
| 1036 DCHECK_NE(CLOSED, state_); | 1036 DCHECK_NE(CLOSED, state_); |
| 1037 | 1037 |
| 1038 // TODO(ricea): Logging. | 1038 // TODO(ricea): Logging. |
| 1039 if (state_ == CONNECTED) { | 1039 if (state_ == CONNECTED) { |
| 1040 if (SendClose(code, reason) == CHANNEL_DELETED) | 1040 if (SendClose(code, reason) == CHANNEL_DELETED) |
| 1041 return CHANNEL_DELETED; | 1041 return CHANNEL_DELETED; |
| 1042 } | 1042 } |
| 1043 | 1043 |
| 1044 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser | 1044 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser |
| 1045 // should close the connection itself without waiting for the closing | 1045 // should close the connection itself without waiting for the closing |
| 1046 // handshake. | 1046 // handshake. |
| 1047 stream_->Close(); | 1047 stream_->Close(); |
| 1048 SetState(CLOSED); | 1048 SetState(CLOSED); |
| 1049 ChannelState result = event_interface_->OnFailChannel(message); | 1049 ChannelState result = event_interface_->OnFailChannel(message); |
| 1050 DCHECK_EQ(CHANNEL_DELETED, result); | 1050 DCHECK_EQ(CHANNEL_DELETED, result); |
| 1051 return result; | 1051 return result; |
| 1052 } | 1052 } |
| 1053 | 1053 |
| 1054 ChannelState WebSocketChannel::SendClose(uint16 code, | 1054 ChannelState WebSocketChannel::SendClose(uint16_t code, |
| 1055 const std::string& reason) { | 1055 const std::string& reason) { |
| 1056 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 1056 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
| 1057 DCHECK_LE(reason.size(), kMaximumCloseReasonLength); | 1057 DCHECK_LE(reason.size(), kMaximumCloseReasonLength); |
| 1058 scoped_refptr<IOBuffer> body; | 1058 scoped_refptr<IOBuffer> body; |
| 1059 uint64 size = 0; | 1059 uint64_t size = 0; |
| 1060 if (code == kWebSocketErrorNoStatusReceived) { | 1060 if (code == kWebSocketErrorNoStatusReceived) { |
| 1061 // Special case: translate kWebSocketErrorNoStatusReceived into a Close | 1061 // Special case: translate kWebSocketErrorNoStatusReceived into a Close |
| 1062 // frame with no payload. | 1062 // frame with no payload. |
| 1063 DCHECK(reason.empty()); | 1063 DCHECK(reason.empty()); |
| 1064 body = new IOBuffer(0); | 1064 body = new IOBuffer(0); |
| 1065 } else { | 1065 } else { |
| 1066 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); | 1066 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); |
| 1067 body = new IOBuffer(payload_length); | 1067 body = new IOBuffer(payload_length); |
| 1068 size = payload_length; | 1068 size = payload_length; |
| 1069 base::WriteBigEndian(body->data(), code); | 1069 base::WriteBigEndian(body->data(), code); |
| 1070 static_assert(sizeof(code) == kWebSocketCloseCodeLength, | 1070 static_assert(sizeof(code) == kWebSocketCloseCodeLength, |
| 1071 "they should both be two"); | 1071 "they should both be two"); |
| 1072 std::copy( | 1072 std::copy( |
| 1073 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); | 1073 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); |
| 1074 } | 1074 } |
| 1075 if (SendFrameFromIOBuffer( | 1075 if (SendFrameFromIOBuffer( |
| 1076 true, WebSocketFrameHeader::kOpCodeClose, body, size) == | 1076 true, WebSocketFrameHeader::kOpCodeClose, body, size) == |
| 1077 CHANNEL_DELETED) | 1077 CHANNEL_DELETED) |
| 1078 return CHANNEL_DELETED; | 1078 return CHANNEL_DELETED; |
| 1079 return CHANNEL_ALIVE; | 1079 return CHANNEL_ALIVE; |
| 1080 } | 1080 } |
| 1081 | 1081 |
| 1082 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, | 1082 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, |
| 1083 uint64 size, | 1083 uint64_t size, |
| 1084 uint16* code, | 1084 uint16_t* code, |
| 1085 std::string* reason, | 1085 std::string* reason, |
| 1086 std::string* message) { | 1086 std::string* message) { |
| 1087 reason->clear(); | 1087 reason->clear(); |
| 1088 if (size < kWebSocketCloseCodeLength) { | 1088 if (size < kWebSocketCloseCodeLength) { |
| 1089 if (size == 0U) { | 1089 if (size == 0U) { |
| 1090 *code = kWebSocketErrorNoStatusReceived; | 1090 *code = kWebSocketErrorNoStatusReceived; |
| 1091 return true; | 1091 return true; |
| 1092 } | 1092 } |
| 1093 | 1093 |
| 1094 DVLOG(1) << "Close frame with payload size " << size << " received " | 1094 DVLOG(1) << "Close frame with payload size " << size << " received " |
| 1095 << "(the first byte is " << std::hex | 1095 << "(the first byte is " << std::hex |
| 1096 << static_cast<int>(buffer->data()[0]) << ")"; | 1096 << static_cast<int>(buffer->data()[0]) << ")"; |
| 1097 *code = kWebSocketErrorProtocolError; | 1097 *code = kWebSocketErrorProtocolError; |
| 1098 *message = | 1098 *message = |
| 1099 "Received a broken close frame containing an invalid size body."; | 1099 "Received a broken close frame containing an invalid size body."; |
| 1100 return false; | 1100 return false; |
| 1101 } | 1101 } |
| 1102 | 1102 |
| 1103 const char* data = buffer->data(); | 1103 const char* data = buffer->data(); |
| 1104 uint16 unchecked_code = 0; | 1104 uint16_t unchecked_code = 0; |
| 1105 base::ReadBigEndian(data, &unchecked_code); | 1105 base::ReadBigEndian(data, &unchecked_code); |
| 1106 static_assert(sizeof(unchecked_code) == kWebSocketCloseCodeLength, | 1106 static_assert(sizeof(unchecked_code) == kWebSocketCloseCodeLength, |
| 1107 "they should both be two bytes"); | 1107 "they should both be two bytes"); |
| 1108 | 1108 |
| 1109 switch (unchecked_code) { | 1109 switch (unchecked_code) { |
| 1110 case kWebSocketErrorNoStatusReceived: | 1110 case kWebSocketErrorNoStatusReceived: |
| 1111 case kWebSocketErrorAbnormalClosure: | 1111 case kWebSocketErrorAbnormalClosure: |
| 1112 case kWebSocketErrorTlsHandshake: | 1112 case kWebSocketErrorTlsHandshake: |
| 1113 *code = kWebSocketErrorProtocolError; | 1113 *code = kWebSocketErrorProtocolError; |
| 1114 *message = | 1114 *message = |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1126 return true; | 1126 return true; |
| 1127 } | 1127 } |
| 1128 | 1128 |
| 1129 *code = kWebSocketErrorProtocolError; | 1129 *code = kWebSocketErrorProtocolError; |
| 1130 *reason = "Invalid UTF-8 in Close frame"; | 1130 *reason = "Invalid UTF-8 in Close frame"; |
| 1131 *message = "Received a broken close frame containing invalid UTF-8."; | 1131 *message = "Received a broken close frame containing invalid UTF-8."; |
| 1132 return false; | 1132 return false; |
| 1133 } | 1133 } |
| 1134 | 1134 |
| 1135 ChannelState WebSocketChannel::DoDropChannel(bool was_clean, | 1135 ChannelState WebSocketChannel::DoDropChannel(bool was_clean, |
| 1136 uint16 code, | 1136 uint16_t code, |
| 1137 const std::string& reason) { | 1137 const std::string& reason) { |
| 1138 if (CHANNEL_DELETED == | 1138 if (CHANNEL_DELETED == |
| 1139 notification_sender_->SendImmediately(event_interface_.get())) | 1139 notification_sender_->SendImmediately(event_interface_.get())) |
| 1140 return CHANNEL_DELETED; | 1140 return CHANNEL_DELETED; |
| 1141 ChannelState result = | 1141 ChannelState result = |
| 1142 event_interface_->OnDropChannel(was_clean, code, reason); | 1142 event_interface_->OnDropChannel(was_clean, code, reason); |
| 1143 DCHECK_EQ(CHANNEL_DELETED, result); | 1143 DCHECK_EQ(CHANNEL_DELETED, result); |
| 1144 return result; | 1144 return result; |
| 1145 } | 1145 } |
| 1146 | 1146 |
| 1147 void WebSocketChannel::CloseTimeout() { | 1147 void WebSocketChannel::CloseTimeout() { |
| 1148 stream_->Close(); | 1148 stream_->Close(); |
| 1149 SetState(CLOSED); | 1149 SetState(CLOSED); |
| 1150 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 1150 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
| 1151 // |this| has been deleted. | 1151 // |this| has been deleted. |
| 1152 } | 1152 } |
| 1153 | 1153 |
| 1154 } // namespace net | 1154 } // namespace net |
| OLD | NEW |