Chromium Code Reviews| 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 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 break; | 121 break; |
| 122 | 122 |
| 123 default: | 123 default: |
| 124 *name = "Unknown frame type"; | 124 *name = "Unknown frame type"; |
| 125 break; | 125 break; |
| 126 } | 126 } |
| 127 | 127 |
| 128 return; | 128 return; |
| 129 } | 129 } |
| 130 | 130 |
| 131 class DependentIOBuffer : public WrappedIOBuffer { | |
| 132 public: | |
| 133 DependentIOBuffer(const scoped_refptr<IOBuffer>& buffer, size_t offset) | |
|
yhirano
2016/09/06 12:19:48
I think |const scoped_refptr<T>&| is discouraged.
| |
| 134 : WrappedIOBuffer(buffer->data() + offset), buffer_(buffer) {} | |
| 135 private: | |
| 136 ~DependentIOBuffer() override {} | |
| 137 scoped_refptr<net::IOBuffer> buffer_; | |
| 138 }; | |
| 139 | |
| 131 } // namespace | 140 } // namespace |
| 132 | 141 |
| 133 // A class to encapsulate a set of frames and information about the size of | 142 // A class to encapsulate a set of frames and information about the size of |
| 134 // those frames. | 143 // those frames. |
| 135 class WebSocketChannel::SendBuffer { | 144 class WebSocketChannel::SendBuffer { |
| 136 public: | 145 public: |
| 137 SendBuffer() : total_bytes_(0) {} | 146 SendBuffer() : total_bytes_(0) {} |
| 138 | 147 |
| 139 // Add a WebSocketFrame to the buffer and increase total_bytes_. | 148 // Add a WebSocketFrame to the buffer and increase total_bytes_. |
| 140 void AddFrame(std::unique_ptr<WebSocketFrame> chunk); | 149 void AddFrame(std::unique_ptr<WebSocketFrame> chunk); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 // The state RECV_CLOSED is not supported here, because it is only used in one | 372 // The state RECV_CLOSED is not supported here, because it is only used in one |
| 364 // code path and should not leak into the code in general. | 373 // code path and should not leak into the code in general. |
| 365 DCHECK_NE(RECV_CLOSED, state_) | 374 DCHECK_NE(RECV_CLOSED, state_) |
| 366 << "InClosingState called with state_ == RECV_CLOSED"; | 375 << "InClosingState called with state_ == RECV_CLOSED"; |
| 367 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED; | 376 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED; |
| 368 } | 377 } |
| 369 | 378 |
| 370 WebSocketChannel::ChannelState WebSocketChannel::SendFrame( | 379 WebSocketChannel::ChannelState WebSocketChannel::SendFrame( |
| 371 bool fin, | 380 bool fin, |
| 372 WebSocketFrameHeader::OpCode op_code, | 381 WebSocketFrameHeader::OpCode op_code, |
| 373 const std::vector<char>& data) { | 382 scoped_refptr<IOBuffer> buffer, |
| 374 if (data.size() > INT_MAX) { | 383 size_t buffer_size) { |
| 384 if (buffer_size > INT_MAX) { | |
| 375 NOTREACHED() << "Frame size sanity check failed"; | 385 NOTREACHED() << "Frame size sanity check failed"; |
| 376 return CHANNEL_ALIVE; | 386 return CHANNEL_ALIVE; |
| 377 } | 387 } |
| 378 if (stream_ == NULL) { | 388 if (stream_ == NULL) { |
| 379 LOG(DFATAL) << "Got SendFrame without a connection established; " | 389 LOG(DFATAL) << "Got SendFrame without a connection established; " |
| 380 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code | 390 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code |
| 381 << " data.size()=" << data.size(); | 391 << " buffer_size=" << buffer_size; |
| 382 return CHANNEL_ALIVE; | 392 return CHANNEL_ALIVE; |
| 383 } | 393 } |
| 384 if (InClosingState()) { | 394 if (InClosingState()) { |
| 385 DVLOG(1) << "SendFrame called in state " << state_ | 395 DVLOG(1) << "SendFrame called in state " << state_ |
| 386 << ". This may be a bug, or a harmless race."; | 396 << ". This may be a bug, or a harmless race."; |
| 387 return CHANNEL_ALIVE; | 397 return CHANNEL_ALIVE; |
| 388 } | 398 } |
| 389 if (state_ != CONNECTED) { | 399 if (state_ != CONNECTED) { |
| 390 NOTREACHED() << "SendFrame() called in state " << state_; | 400 NOTREACHED() << "SendFrame() called in state " << state_; |
| 391 return CHANNEL_ALIVE; | 401 return CHANNEL_ALIVE; |
| 392 } | 402 } |
| 393 if (data.size() > base::checked_cast<size_t>(current_send_quota_)) { | 403 if (buffer_size > base::checked_cast<size_t>(current_send_quota_)) { |
| 394 // TODO(ricea): Kill renderer. | 404 // TODO(ricea): Kill renderer. |
| 395 return FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""); | 405 return FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""); |
| 396 // |this| has been deleted. | 406 // |this| has been deleted. |
| 397 } | 407 } |
| 398 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { | 408 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { |
| 399 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code | 409 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code |
| 400 << "; misbehaving renderer? fin=" << fin | 410 << "; misbehaving renderer? fin=" << fin |
| 401 << " data.size()=" << data.size(); | 411 << " buffer_size=" << buffer_size; |
| 402 return CHANNEL_ALIVE; | 412 return CHANNEL_ALIVE; |
| 403 } | 413 } |
| 404 if (op_code == WebSocketFrameHeader::kOpCodeText || | 414 if (op_code == WebSocketFrameHeader::kOpCodeText || |
| 405 (op_code == WebSocketFrameHeader::kOpCodeContinuation && | 415 (op_code == WebSocketFrameHeader::kOpCodeContinuation && |
| 406 sending_text_message_)) { | 416 sending_text_message_)) { |
| 407 StreamingUtf8Validator::State state = | 417 StreamingUtf8Validator::State state = |
| 408 outgoing_utf8_validator_.AddBytes(data.data(), data.size()); | 418 outgoing_utf8_validator_.AddBytes(buffer->data(), buffer_size); |
| 409 if (state == StreamingUtf8Validator::INVALID || | 419 if (state == StreamingUtf8Validator::INVALID || |
| 410 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) { | 420 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) { |
| 411 // TODO(ricea): Kill renderer. | 421 // TODO(ricea): Kill renderer. |
| 412 return FailChannel("Browser sent a text frame containing invalid UTF-8", | 422 return FailChannel("Browser sent a text frame containing invalid UTF-8", |
| 413 kWebSocketErrorGoingAway, ""); | 423 kWebSocketErrorGoingAway, ""); |
| 414 // |this| has been deleted. | 424 // |this| has been deleted. |
| 415 } | 425 } |
| 416 sending_text_message_ = !fin; | 426 sending_text_message_ = !fin; |
| 417 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT); | 427 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT); |
| 418 } | 428 } |
| 419 current_send_quota_ -= data.size(); | 429 current_send_quota_ -= buffer_size; |
| 420 // TODO(ricea): If current_send_quota_ has dropped below | 430 // TODO(ricea): If current_send_quota_ has dropped below |
| 421 // send_quota_low_water_mark_, it might be good to increase the "low | 431 // send_quota_low_water_mark_, it might be good to increase the "low |
| 422 // water mark" and "high water mark", but only if the link to the WebSocket | 432 // water mark" and "high water mark", but only if the link to the WebSocket |
| 423 // server is not saturated. | 433 // server is not saturated. |
| 424 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); | 434 return SendFrameFromIOBuffer(fin, op_code, std::move(buffer), buffer_size); |
|
yhirano
2016/09/06 12:19:48
With this change SendFrame also takes an IOBuffer.
| |
| 425 std::copy(data.begin(), data.end(), buffer->data()); | |
| 426 return SendFrameFromIOBuffer(fin, op_code, buffer, data.size()); | |
| 427 // |this| may have been deleted. | 435 // |this| may have been deleted. |
| 428 } | 436 } |
| 429 | 437 |
| 430 ChannelState WebSocketChannel::SendFlowControl(int64_t quota) { | 438 ChannelState WebSocketChannel::SendFlowControl(int64_t quota) { |
| 431 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || | 439 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || |
| 432 state_ == CLOSE_WAIT); | 440 state_ == CLOSE_WAIT); |
| 433 // TODO(ricea): Kill the renderer if it tries to send us a negative quota | 441 // TODO(ricea): Kill the renderer if it tries to send us a negative quota |
| 434 // value or > INT_MAX. | 442 // value or > INT_MAX. |
| 435 DCHECK_GE(quota, 0); | 443 DCHECK_GE(quota, 0); |
| 436 DCHECK_LE(quota, INT_MAX); | 444 DCHECK_LE(quota, INT_MAX); |
| 437 if (!pending_received_frames_.empty()) { | 445 if (!pending_received_frames_.empty()) { |
| 438 DCHECK_EQ(0u, current_receive_quota_); | 446 DCHECK_EQ(0u, current_receive_quota_); |
| 439 } | 447 } |
| 440 while (!pending_received_frames_.empty() && quota > 0) { | 448 while (!pending_received_frames_.empty() && quota > 0) { |
| 441 PendingReceivedFrame& front = pending_received_frames_.front(); | 449 PendingReceivedFrame& front = pending_received_frames_.front(); |
| 442 const uint64_t data_size = front.size() - front.offset(); | 450 const uint64_t data_size = front.size() - front.offset(); |
| 443 const uint64_t bytes_to_send = | 451 const uint64_t bytes_to_send = |
| 444 std::min(base::checked_cast<uint64_t>(quota), data_size); | 452 std::min(base::checked_cast<uint64_t>(quota), data_size); |
| 445 const bool final = front.final() && data_size == bytes_to_send; | 453 const bool final = front.final() && data_size == bytes_to_send; |
| 446 const char* data = | 454 scoped_refptr<IOBuffer> buffer_to_pass; |
| 447 front.data().get() ? front.data()->data() + front.offset() : NULL; | 455 if (front.data().get()) { |
|
Ryan Sleevi
2016/08/30 08:07:39
The .get() here is superfluous due to the bool ope
| |
| 448 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; | 456 buffer_to_pass = new DependentIOBuffer(front.data(), front.offset()); |
| 449 const std::vector<char> data_vector(data, data + bytes_to_send); | 457 } else { |
| 458 DCHECK(!bytes_to_send) << "Non empty data should not be null."; | |
| 459 } | |
| 450 DVLOG(3) << "Sending frame previously split due to quota to the " | 460 DVLOG(3) << "Sending frame previously split due to quota to the " |
| 451 << "renderer: quota=" << quota << " data_size=" << data_size | 461 << "renderer: quota=" << quota << " data_size=" << data_size |
| 452 << " bytes_to_send=" << bytes_to_send; | 462 << " bytes_to_send=" << bytes_to_send; |
| 453 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == | 463 if (event_interface_->OnDataFrame( |
| 454 CHANNEL_DELETED) | 464 final, front.opcode(), std::move(buffer_to_pass), bytes_to_send) == |
| 465 CHANNEL_DELETED) | |
| 455 return CHANNEL_DELETED; | 466 return CHANNEL_DELETED; |
| 456 if (bytes_to_send < data_size) { | 467 if (bytes_to_send < data_size) { |
| 457 front.DidConsume(bytes_to_send); | 468 front.DidConsume(bytes_to_send); |
| 458 front.ResetOpcode(); | 469 front.ResetOpcode(); |
| 459 return CHANNEL_ALIVE; | 470 return CHANNEL_ALIVE; |
| 460 } | 471 } |
| 461 quota -= bytes_to_send; | 472 quota -= bytes_to_send; |
| 462 | 473 |
| 463 pending_received_frames_.pop(); | 474 pending_received_frames_.pop(); |
| 464 } | 475 } |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 825 "One or more reserved bits are on: reserved1 = %d, " | 836 "One or more reserved bits are on: reserved1 = %d, " |
| 826 "reserved2 = %d, reserved3 = %d", | 837 "reserved2 = %d, reserved3 = %d", |
| 827 static_cast<int>(frame->header.reserved1), | 838 static_cast<int>(frame->header.reserved1), |
| 828 static_cast<int>(frame->header.reserved2), | 839 static_cast<int>(frame->header.reserved2), |
| 829 static_cast<int>(frame->header.reserved3)), | 840 static_cast<int>(frame->header.reserved3)), |
| 830 kWebSocketErrorProtocolError, | 841 kWebSocketErrorProtocolError, |
| 831 "Invalid reserved bit"); | 842 "Invalid reserved bit"); |
| 832 } | 843 } |
| 833 | 844 |
| 834 // Respond to the frame appropriately to its type. | 845 // Respond to the frame appropriately to its type. |
| 835 return HandleFrameByState( | 846 return HandleFrameByState(opcode, frame->header.final, std::move(frame->data), |
| 836 opcode, frame->header.final, frame->data, frame->header.payload_length); | 847 frame->header.payload_length); |
| 837 } | 848 } |
| 838 | 849 |
| 839 ChannelState WebSocketChannel::HandleFrameByState( | 850 ChannelState WebSocketChannel::HandleFrameByState( |
| 840 const WebSocketFrameHeader::OpCode opcode, | 851 const WebSocketFrameHeader::OpCode opcode, |
| 841 bool final, | 852 bool final, |
| 842 const scoped_refptr<IOBuffer>& data_buffer, | 853 scoped_refptr<IOBuffer> data_buffer, |
| 843 uint64_t size) { | 854 uint64_t size) { |
| 844 DCHECK_NE(RECV_CLOSED, state_) | 855 DCHECK_NE(RECV_CLOSED, state_) |
| 845 << "HandleFrame() does not support being called re-entrantly from within " | 856 << "HandleFrame() does not support being called re-entrantly from within " |
| 846 "SendClose()"; | 857 "SendClose()"; |
| 847 DCHECK_NE(CLOSED, state_); | 858 DCHECK_NE(CLOSED, state_); |
| 848 if (state_ == CLOSE_WAIT) { | 859 if (state_ == CLOSE_WAIT) { |
| 849 std::string frame_name; | 860 std::string frame_name; |
| 850 GetFrameTypeForOpcode(opcode, &frame_name); | 861 GetFrameTypeForOpcode(opcode, &frame_name); |
| 851 | 862 |
| 852 // FailChannel() won't send another Close frame. | 863 // FailChannel() won't send another Close frame. |
| 853 return FailChannel( | 864 return FailChannel( |
| 854 frame_name + " received after close", kWebSocketErrorProtocolError, ""); | 865 frame_name + " received after close", kWebSocketErrorProtocolError, ""); |
| 855 } | 866 } |
| 856 switch (opcode) { | 867 switch (opcode) { |
| 857 case WebSocketFrameHeader::kOpCodeText: // fall-thru | 868 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 858 case WebSocketFrameHeader::kOpCodeBinary: | 869 case WebSocketFrameHeader::kOpCodeBinary: |
| 859 case WebSocketFrameHeader::kOpCodeContinuation: | 870 case WebSocketFrameHeader::kOpCodeContinuation: |
| 860 return HandleDataFrame(opcode, final, data_buffer, size); | 871 return HandleDataFrame(opcode, final, std::move(data_buffer), size); |
| 861 | 872 |
| 862 case WebSocketFrameHeader::kOpCodePing: | 873 case WebSocketFrameHeader::kOpCodePing: |
| 863 DVLOG(1) << "Got Ping of size " << size; | 874 DVLOG(1) << "Got Ping of size " << size; |
| 864 if (state_ == CONNECTED) | 875 if (state_ == CONNECTED) |
| 865 return SendFrameFromIOBuffer( | 876 return SendFrameFromIOBuffer( |
| 866 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); | 877 true, WebSocketFrameHeader::kOpCodePong, std::move(data_buffer), |
| 878 size); | |
| 867 DVLOG(3) << "Ignored ping in state " << state_; | 879 DVLOG(3) << "Ignored ping in state " << state_; |
| 868 return CHANNEL_ALIVE; | 880 return CHANNEL_ALIVE; |
| 869 | 881 |
| 870 case WebSocketFrameHeader::kOpCodePong: | 882 case WebSocketFrameHeader::kOpCodePong: |
| 871 DVLOG(1) << "Got Pong of size " << size; | 883 DVLOG(1) << "Got Pong of size " << size; |
| 872 // There is no need to do anything with pong messages. | 884 // There is no need to do anything with pong messages. |
| 873 return CHANNEL_ALIVE; | 885 return CHANNEL_ALIVE; |
| 874 | 886 |
| 875 case WebSocketFrameHeader::kOpCodeClose: { | 887 case WebSocketFrameHeader::kOpCodeClose: { |
| 876 uint16_t code = kWebSocketNormalClosure; | 888 uint16_t code = kWebSocketNormalClosure; |
| 877 std::string reason; | 889 std::string reason; |
| 878 std::string message; | 890 std::string message; |
| 879 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { | 891 if (!ParseClose(std::move(data_buffer), size, &code, &reason, &message)) { |
| 880 return FailChannel(message, code, reason); | 892 return FailChannel(message, code, reason); |
| 881 } | 893 } |
| 882 // TODO(ricea): Find a way to safely log the message from the close | 894 // TODO(ricea): Find a way to safely log the message from the close |
| 883 // message (escape control codes and so on). | 895 // message (escape control codes and so on). |
| 884 DVLOG(1) << "Got Close with code " << code; | 896 DVLOG(1) << "Got Close with code " << code; |
| 885 return HandleCloseFrame(code, reason); | 897 return HandleCloseFrame(code, reason); |
| 886 } | 898 } |
| 887 | 899 |
| 888 default: | 900 default: |
| 889 return FailChannel( | 901 return FailChannel( |
| 890 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 902 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
| 891 kWebSocketErrorProtocolError, | 903 kWebSocketErrorProtocolError, |
| 892 "Unknown opcode"); | 904 "Unknown opcode"); |
| 893 } | 905 } |
| 894 } | 906 } |
| 895 | 907 |
| 896 ChannelState WebSocketChannel::HandleDataFrame( | 908 ChannelState WebSocketChannel::HandleDataFrame( |
| 897 WebSocketFrameHeader::OpCode opcode, | 909 WebSocketFrameHeader::OpCode opcode, |
| 898 bool final, | 910 bool final, |
| 899 const scoped_refptr<IOBuffer>& data_buffer, | 911 scoped_refptr<IOBuffer> data_buffer, |
| 900 uint64_t size) { | 912 uint64_t size) { |
| 901 if (state_ != CONNECTED) { | 913 if (state_ != CONNECTED) { |
| 902 DVLOG(3) << "Ignored data packet received in state " << state_; | 914 DVLOG(3) << "Ignored data packet received in state " << state_; |
| 903 return CHANNEL_ALIVE; | 915 return CHANNEL_ALIVE; |
| 904 } | 916 } |
| 905 if (has_received_close_frame_) { | 917 if (has_received_close_frame_) { |
| 906 DVLOG(3) << "Ignored data packet as we've received a close frame."; | 918 DVLOG(3) << "Ignored data packet as we've received a close frame."; |
| 907 return CHANNEL_ALIVE; | 919 return CHANNEL_ALIVE; |
| 908 } | 920 } |
| 909 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || | 921 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 956 WebSocketFrameHeader::OpCode opcode_to_queue = | 968 WebSocketFrameHeader::OpCode opcode_to_queue = |
| 957 no_quota ? opcode_to_send : WebSocketFrameHeader::kOpCodeContinuation; | 969 no_quota ? opcode_to_send : WebSocketFrameHeader::kOpCodeContinuation; |
| 958 pending_received_frames_.push(PendingReceivedFrame( | 970 pending_received_frames_.push(PendingReceivedFrame( |
| 959 final, opcode_to_queue, data_buffer, current_receive_quota_, size)); | 971 final, opcode_to_queue, data_buffer, current_receive_quota_, size)); |
| 960 if (no_quota) | 972 if (no_quota) |
| 961 return CHANNEL_ALIVE; | 973 return CHANNEL_ALIVE; |
| 962 size = current_receive_quota_; | 974 size = current_receive_quota_; |
| 963 final = false; | 975 final = false; |
| 964 } | 976 } |
| 965 | 977 |
| 966 // TODO(ricea): Can this copy be eliminated? | |
| 967 const char* const data_begin = size ? data_buffer->data() : NULL; | |
| 968 const char* const data_end = data_begin + size; | |
| 969 const std::vector<char> data(data_begin, data_end); | |
| 970 current_receive_quota_ -= size; | 978 current_receive_quota_ -= size; |
| 971 | 979 |
| 972 // Sends the received frame to the renderer process. | 980 // Sends the received frame to the renderer process. |
| 973 return event_interface_->OnDataFrame(final, opcode_to_send, data); | 981 return event_interface_->OnDataFrame( |
| 982 final, opcode_to_send, std::move(data_buffer), size); | |
| 974 } | 983 } |
| 975 | 984 |
| 976 ChannelState WebSocketChannel::HandleCloseFrame(uint16_t code, | 985 ChannelState WebSocketChannel::HandleCloseFrame(uint16_t code, |
| 977 const std::string& reason) { | 986 const std::string& reason) { |
| 978 DVLOG(1) << "Got Close with code " << code; | 987 DVLOG(1) << "Got Close with code " << code; |
| 979 switch (state_) { | 988 switch (state_) { |
| 980 case CONNECTED: | 989 case CONNECTED: |
| 981 has_received_close_frame_ = true; | 990 has_received_close_frame_ = true; |
| 982 received_close_code_ = code; | 991 received_close_code_ = code; |
| 983 received_close_reason_ = reason; | 992 received_close_reason_ = reason; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1029 close_timer_.Start( | 1038 close_timer_.Start( |
| 1030 FROM_HERE, underlying_connection_close_timeout_, | 1039 FROM_HERE, underlying_connection_close_timeout_, |
| 1031 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); | 1040 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); |
| 1032 | 1041 |
| 1033 return event_interface_->OnClosingHandshake(); | 1042 return event_interface_->OnClosingHandshake(); |
| 1034 } | 1043 } |
| 1035 | 1044 |
| 1036 ChannelState WebSocketChannel::SendFrameFromIOBuffer( | 1045 ChannelState WebSocketChannel::SendFrameFromIOBuffer( |
| 1037 bool fin, | 1046 bool fin, |
| 1038 WebSocketFrameHeader::OpCode op_code, | 1047 WebSocketFrameHeader::OpCode op_code, |
| 1039 const scoped_refptr<IOBuffer>& buffer, | 1048 scoped_refptr<IOBuffer> buffer, |
| 1040 uint64_t size) { | 1049 uint64_t size) { |
| 1041 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 1050 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
| 1042 DCHECK(stream_); | 1051 DCHECK(stream_); |
| 1043 | 1052 |
| 1044 std::unique_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); | 1053 std::unique_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); |
| 1045 WebSocketFrameHeader& header = frame->header; | 1054 WebSocketFrameHeader& header = frame->header; |
| 1046 header.final = fin; | 1055 header.final = fin; |
| 1047 header.masked = true; | 1056 header.masked = true; |
| 1048 header.payload_length = size; | 1057 header.payload_length = size; |
| 1049 frame->data = buffer; | 1058 frame->data = std::move(buffer); |
| 1050 | 1059 |
| 1051 if (data_being_sent_) { | 1060 if (data_being_sent_) { |
| 1052 // Either the link to the WebSocket server is saturated, or several messages | 1061 // Either the link to the WebSocket server is saturated, or several messages |
| 1053 // are being sent in a batch. | 1062 // are being sent in a batch. |
| 1054 // TODO(ricea): Keep some statistics to work out the situation and adjust | 1063 // TODO(ricea): Keep some statistics to work out the situation and adjust |
| 1055 // quota appropriately. | 1064 // quota appropriately. |
| 1056 if (!data_to_send_next_) | 1065 if (!data_to_send_next_) |
| 1057 data_to_send_next_.reset(new SendBuffer); | 1066 data_to_send_next_.reset(new SendBuffer); |
| 1058 data_to_send_next_->AddFrame(std::move(frame)); | 1067 data_to_send_next_->AddFrame(std::move(frame)); |
| 1059 return CHANNEL_ALIVE; | 1068 return CHANNEL_ALIVE; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1102 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); | 1111 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); |
| 1103 body = new IOBuffer(payload_length); | 1112 body = new IOBuffer(payload_length); |
| 1104 size = payload_length; | 1113 size = payload_length; |
| 1105 base::WriteBigEndian(body->data(), code); | 1114 base::WriteBigEndian(body->data(), code); |
| 1106 static_assert(sizeof(code) == kWebSocketCloseCodeLength, | 1115 static_assert(sizeof(code) == kWebSocketCloseCodeLength, |
| 1107 "they should both be two"); | 1116 "they should both be two"); |
| 1108 std::copy( | 1117 std::copy( |
| 1109 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); | 1118 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); |
| 1110 } | 1119 } |
| 1111 if (SendFrameFromIOBuffer( | 1120 if (SendFrameFromIOBuffer( |
| 1112 true, WebSocketFrameHeader::kOpCodeClose, body, size) == | 1121 true, WebSocketFrameHeader::kOpCodeClose, std::move(body), size) == |
| 1113 CHANNEL_DELETED) | 1122 CHANNEL_DELETED) |
| 1114 return CHANNEL_DELETED; | 1123 return CHANNEL_DELETED; |
| 1115 return CHANNEL_ALIVE; | 1124 return CHANNEL_ALIVE; |
| 1116 } | 1125 } |
| 1117 | 1126 |
| 1118 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, | 1127 bool WebSocketChannel::ParseClose(scoped_refptr<IOBuffer> buffer, |
| 1119 uint64_t size, | 1128 uint64_t size, |
| 1120 uint16_t* code, | 1129 uint16_t* code, |
| 1121 std::string* reason, | 1130 std::string* reason, |
| 1122 std::string* message) { | 1131 std::string* message) { |
| 1123 reason->clear(); | 1132 reason->clear(); |
| 1124 if (size < kWebSocketCloseCodeLength) { | 1133 if (size < kWebSocketCloseCodeLength) { |
| 1125 if (size == 0U) { | 1134 if (size == 0U) { |
| 1126 *code = kWebSocketErrorNoStatusReceived; | 1135 *code = kWebSocketErrorNoStatusReceived; |
| 1127 return true; | 1136 return true; |
| 1128 } | 1137 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1181 } | 1190 } |
| 1182 | 1191 |
| 1183 void WebSocketChannel::CloseTimeout() { | 1192 void WebSocketChannel::CloseTimeout() { |
| 1184 stream_->Close(); | 1193 stream_->Close(); |
| 1185 SetState(CLOSED); | 1194 SetState(CLOSED); |
| 1186 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 1195 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
| 1187 // |this| has been deleted. | 1196 // |this| has been deleted. |
| 1188 } | 1197 } |
| 1189 | 1198 |
| 1190 } // namespace net | 1199 } // namespace net |
| OLD | NEW |