| 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(scoped_refptr<IOBuffer> buffer, size_t offset) |
| 134 : WrappedIOBuffer(buffer->data() + offset), buffer_(std::move(buffer)) {} |
| 135 |
| 136 private: |
| 137 ~DependentIOBuffer() override {} |
| 138 scoped_refptr<net::IOBuffer> buffer_; |
| 139 }; |
| 140 |
| 131 } // namespace | 141 } // namespace |
| 132 | 142 |
| 133 // A class to encapsulate a set of frames and information about the size of | 143 // A class to encapsulate a set of frames and information about the size of |
| 134 // those frames. | 144 // those frames. |
| 135 class WebSocketChannel::SendBuffer { | 145 class WebSocketChannel::SendBuffer { |
| 136 public: | 146 public: |
| 137 SendBuffer() : total_bytes_(0) {} | 147 SendBuffer() : total_bytes_(0) {} |
| 138 | 148 |
| 139 // Add a WebSocketFrame to the buffer and increase total_bytes_. | 149 // Add a WebSocketFrame to the buffer and increase total_bytes_. |
| 140 void AddFrame(std::unique_ptr<WebSocketFrame> chunk); | 150 void AddFrame(std::unique_ptr<WebSocketFrame> chunk); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 // TODO(yhirano): We can release |this| to save memory because | 282 // TODO(yhirano): We can release |this| to save memory because |
| 273 // there will be no more opening handshake notification. | 283 // there will be no more opening handshake notification. |
| 274 } | 284 } |
| 275 | 285 |
| 276 return CHANNEL_ALIVE; | 286 return CHANNEL_ALIVE; |
| 277 } | 287 } |
| 278 | 288 |
| 279 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( | 289 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( |
| 280 bool final, | 290 bool final, |
| 281 WebSocketFrameHeader::OpCode opcode, | 291 WebSocketFrameHeader::OpCode opcode, |
| 282 const scoped_refptr<IOBuffer>& data, | 292 scoped_refptr<IOBuffer> data, |
| 283 uint64_t offset, | 293 uint64_t offset, |
| 284 uint64_t size) | 294 uint64_t size) |
| 285 : final_(final), | 295 : final_(final), |
| 286 opcode_(opcode), | 296 opcode_(opcode), |
| 287 data_(data), | 297 data_(std::move(data)), |
| 288 offset_(offset), | 298 offset_(offset), |
| 289 size_(size) {} | 299 size_(size) {} |
| 290 | 300 |
| 291 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( | 301 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( |
| 292 const PendingReceivedFrame& other) = default; | 302 const PendingReceivedFrame& other) = default; |
| 293 | 303 |
| 294 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} | 304 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} |
| 295 | 305 |
| 296 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { | 306 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { |
| 297 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); | 307 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); |
| (...skipping 65 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 | 373 // 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. | 374 // code path and should not leak into the code in general. |
| 365 DCHECK_NE(RECV_CLOSED, state_) | 375 DCHECK_NE(RECV_CLOSED, state_) |
| 366 << "InClosingState called with state_ == RECV_CLOSED"; | 376 << "InClosingState called with state_ == RECV_CLOSED"; |
| 367 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED; | 377 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED; |
| 368 } | 378 } |
| 369 | 379 |
| 370 WebSocketChannel::ChannelState WebSocketChannel::SendFrame( | 380 WebSocketChannel::ChannelState WebSocketChannel::SendFrame( |
| 371 bool fin, | 381 bool fin, |
| 372 WebSocketFrameHeader::OpCode op_code, | 382 WebSocketFrameHeader::OpCode op_code, |
| 373 const std::vector<char>& data) { | 383 scoped_refptr<IOBuffer> buffer, |
| 374 if (data.size() > INT_MAX) { | 384 size_t buffer_size) { |
| 385 if (buffer_size > INT_MAX) { |
| 375 NOTREACHED() << "Frame size sanity check failed"; | 386 NOTREACHED() << "Frame size sanity check failed"; |
| 376 return CHANNEL_ALIVE; | 387 return CHANNEL_ALIVE; |
| 377 } | 388 } |
| 378 if (stream_ == NULL) { | 389 if (stream_ == NULL) { |
| 379 LOG(DFATAL) << "Got SendFrame without a connection established; " | 390 LOG(DFATAL) << "Got SendFrame without a connection established; " |
| 380 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code | 391 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code |
| 381 << " data.size()=" << data.size(); | 392 << " buffer_size=" << buffer_size; |
| 382 return CHANNEL_ALIVE; | 393 return CHANNEL_ALIVE; |
| 383 } | 394 } |
| 384 if (InClosingState()) { | 395 if (InClosingState()) { |
| 385 DVLOG(1) << "SendFrame called in state " << state_ | 396 DVLOG(1) << "SendFrame called in state " << state_ |
| 386 << ". This may be a bug, or a harmless race."; | 397 << ". This may be a bug, or a harmless race."; |
| 387 return CHANNEL_ALIVE; | 398 return CHANNEL_ALIVE; |
| 388 } | 399 } |
| 389 if (state_ != CONNECTED) { | 400 if (state_ != CONNECTED) { |
| 390 NOTREACHED() << "SendFrame() called in state " << state_; | 401 NOTREACHED() << "SendFrame() called in state " << state_; |
| 391 return CHANNEL_ALIVE; | 402 return CHANNEL_ALIVE; |
| 392 } | 403 } |
| 393 if (data.size() > base::checked_cast<size_t>(current_send_quota_)) { | 404 if (buffer_size > base::checked_cast<size_t>(current_send_quota_)) { |
| 394 // TODO(ricea): Kill renderer. | 405 // TODO(ricea): Kill renderer. |
| 395 return FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""); | 406 return FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""); |
| 396 // |this| has been deleted. | 407 // |this| has been deleted. |
| 397 } | 408 } |
| 398 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { | 409 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { |
| 399 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code | 410 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code |
| 400 << "; misbehaving renderer? fin=" << fin | 411 << "; misbehaving renderer? fin=" << fin |
| 401 << " data.size()=" << data.size(); | 412 << " buffer_size=" << buffer_size; |
| 402 return CHANNEL_ALIVE; | 413 return CHANNEL_ALIVE; |
| 403 } | 414 } |
| 404 if (op_code == WebSocketFrameHeader::kOpCodeText || | 415 if (op_code == WebSocketFrameHeader::kOpCodeText || |
| 405 (op_code == WebSocketFrameHeader::kOpCodeContinuation && | 416 (op_code == WebSocketFrameHeader::kOpCodeContinuation && |
| 406 sending_text_message_)) { | 417 sending_text_message_)) { |
| 407 StreamingUtf8Validator::State state = | 418 StreamingUtf8Validator::State state = |
| 408 outgoing_utf8_validator_.AddBytes(data.data(), data.size()); | 419 outgoing_utf8_validator_.AddBytes(buffer->data(), buffer_size); |
| 409 if (state == StreamingUtf8Validator::INVALID || | 420 if (state == StreamingUtf8Validator::INVALID || |
| 410 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) { | 421 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) { |
| 411 // TODO(ricea): Kill renderer. | 422 // TODO(ricea): Kill renderer. |
| 412 return FailChannel("Browser sent a text frame containing invalid UTF-8", | 423 return FailChannel("Browser sent a text frame containing invalid UTF-8", |
| 413 kWebSocketErrorGoingAway, ""); | 424 kWebSocketErrorGoingAway, ""); |
| 414 // |this| has been deleted. | 425 // |this| has been deleted. |
| 415 } | 426 } |
| 416 sending_text_message_ = !fin; | 427 sending_text_message_ = !fin; |
| 417 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT); | 428 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT); |
| 418 } | 429 } |
| 419 current_send_quota_ -= data.size(); | 430 current_send_quota_ -= buffer_size; |
| 420 // TODO(ricea): If current_send_quota_ has dropped below | 431 // TODO(ricea): If current_send_quota_ has dropped below |
| 421 // send_quota_low_water_mark_, it might be good to increase the "low | 432 // 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 | 433 // water mark" and "high water mark", but only if the link to the WebSocket |
| 423 // server is not saturated. | 434 // server is not saturated. |
| 424 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); | 435 return SendFrameInternal(fin, op_code, std::move(buffer), buffer_size); |
| 425 std::copy(data.begin(), data.end(), buffer->data()); | |
| 426 return SendFrameFromIOBuffer(fin, op_code, buffer, data.size()); | |
| 427 // |this| may have been deleted. | 436 // |this| may have been deleted. |
| 428 } | 437 } |
| 429 | 438 |
| 430 ChannelState WebSocketChannel::SendFlowControl(int64_t quota) { | 439 ChannelState WebSocketChannel::SendFlowControl(int64_t quota) { |
| 431 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || | 440 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || |
| 432 state_ == CLOSE_WAIT); | 441 state_ == CLOSE_WAIT); |
| 433 // TODO(ricea): Kill the renderer if it tries to send us a negative quota | 442 // TODO(ricea): Kill the renderer if it tries to send us a negative quota |
| 434 // value or > INT_MAX. | 443 // value or > INT_MAX. |
| 435 DCHECK_GE(quota, 0); | 444 DCHECK_GE(quota, 0); |
| 436 DCHECK_LE(quota, INT_MAX); | 445 DCHECK_LE(quota, INT_MAX); |
| 437 if (!pending_received_frames_.empty()) { | 446 if (!pending_received_frames_.empty()) { |
| 438 DCHECK_EQ(0u, current_receive_quota_); | 447 DCHECK_EQ(0u, current_receive_quota_); |
| 439 } | 448 } |
| 440 while (!pending_received_frames_.empty() && quota > 0) { | 449 while (!pending_received_frames_.empty() && quota > 0) { |
| 441 PendingReceivedFrame& front = pending_received_frames_.front(); | 450 PendingReceivedFrame& front = pending_received_frames_.front(); |
| 442 const uint64_t data_size = front.size() - front.offset(); | 451 const uint64_t data_size = front.size() - front.offset(); |
| 443 const uint64_t bytes_to_send = | 452 const uint64_t bytes_to_send = |
| 444 std::min(base::checked_cast<uint64_t>(quota), data_size); | 453 std::min(base::checked_cast<uint64_t>(quota), data_size); |
| 445 const bool final = front.final() && data_size == bytes_to_send; | 454 const bool final = front.final() && data_size == bytes_to_send; |
| 446 const char* data = | 455 scoped_refptr<IOBuffer> buffer_to_pass; |
| 447 front.data().get() ? front.data()->data() + front.offset() : NULL; | 456 if (front.data()) { |
| 448 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; | 457 buffer_to_pass = new DependentIOBuffer(front.data(), front.offset()); |
| 449 const std::vector<char> data_vector(data, data + bytes_to_send); | 458 } else { |
| 459 DCHECK(!bytes_to_send) << "Non empty data should not be null."; |
| 460 } |
| 450 DVLOG(3) << "Sending frame previously split due to quota to the " | 461 DVLOG(3) << "Sending frame previously split due to quota to the " |
| 451 << "renderer: quota=" << quota << " data_size=" << data_size | 462 << "renderer: quota=" << quota << " data_size=" << data_size |
| 452 << " bytes_to_send=" << bytes_to_send; | 463 << " bytes_to_send=" << bytes_to_send; |
| 453 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == | 464 if (event_interface_->OnDataFrame(final, front.opcode(), |
| 454 CHANNEL_DELETED) | 465 std::move(buffer_to_pass), |
| 466 bytes_to_send) == CHANNEL_DELETED) |
| 455 return CHANNEL_DELETED; | 467 return CHANNEL_DELETED; |
| 456 if (bytes_to_send < data_size) { | 468 if (bytes_to_send < data_size) { |
| 457 front.DidConsume(bytes_to_send); | 469 front.DidConsume(bytes_to_send); |
| 458 front.ResetOpcode(); | 470 front.ResetOpcode(); |
| 459 return CHANNEL_ALIVE; | 471 return CHANNEL_ALIVE; |
| 460 } | 472 } |
| 461 quota -= bytes_to_send; | 473 quota -= bytes_to_send; |
| 462 | 474 |
| 463 pending_received_frames_.pop(); | 475 pending_received_frames_.pop(); |
| 464 } | 476 } |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 "One or more reserved bits are on: reserved1 = %d, " | 837 "One or more reserved bits are on: reserved1 = %d, " |
| 826 "reserved2 = %d, reserved3 = %d", | 838 "reserved2 = %d, reserved3 = %d", |
| 827 static_cast<int>(frame->header.reserved1), | 839 static_cast<int>(frame->header.reserved1), |
| 828 static_cast<int>(frame->header.reserved2), | 840 static_cast<int>(frame->header.reserved2), |
| 829 static_cast<int>(frame->header.reserved3)), | 841 static_cast<int>(frame->header.reserved3)), |
| 830 kWebSocketErrorProtocolError, | 842 kWebSocketErrorProtocolError, |
| 831 "Invalid reserved bit"); | 843 "Invalid reserved bit"); |
| 832 } | 844 } |
| 833 | 845 |
| 834 // Respond to the frame appropriately to its type. | 846 // Respond to the frame appropriately to its type. |
| 835 return HandleFrameByState( | 847 return HandleFrameByState(opcode, frame->header.final, std::move(frame->data), |
| 836 opcode, frame->header.final, frame->data, frame->header.payload_length); | 848 frame->header.payload_length); |
| 837 } | 849 } |
| 838 | 850 |
| 839 ChannelState WebSocketChannel::HandleFrameByState( | 851 ChannelState WebSocketChannel::HandleFrameByState( |
| 840 const WebSocketFrameHeader::OpCode opcode, | 852 const WebSocketFrameHeader::OpCode opcode, |
| 841 bool final, | 853 bool final, |
| 842 const scoped_refptr<IOBuffer>& data_buffer, | 854 scoped_refptr<IOBuffer> data_buffer, |
| 843 uint64_t size) { | 855 uint64_t size) { |
| 844 DCHECK_NE(RECV_CLOSED, state_) | 856 DCHECK_NE(RECV_CLOSED, state_) |
| 845 << "HandleFrame() does not support being called re-entrantly from within " | 857 << "HandleFrame() does not support being called re-entrantly from within " |
| 846 "SendClose()"; | 858 "SendClose()"; |
| 847 DCHECK_NE(CLOSED, state_); | 859 DCHECK_NE(CLOSED, state_); |
| 848 if (state_ == CLOSE_WAIT) { | 860 if (state_ == CLOSE_WAIT) { |
| 849 std::string frame_name; | 861 std::string frame_name; |
| 850 GetFrameTypeForOpcode(opcode, &frame_name); | 862 GetFrameTypeForOpcode(opcode, &frame_name); |
| 851 | 863 |
| 852 // FailChannel() won't send another Close frame. | 864 // FailChannel() won't send another Close frame. |
| 853 return FailChannel( | 865 return FailChannel( |
| 854 frame_name + " received after close", kWebSocketErrorProtocolError, ""); | 866 frame_name + " received after close", kWebSocketErrorProtocolError, ""); |
| 855 } | 867 } |
| 856 switch (opcode) { | 868 switch (opcode) { |
| 857 case WebSocketFrameHeader::kOpCodeText: // fall-thru | 869 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 858 case WebSocketFrameHeader::kOpCodeBinary: | 870 case WebSocketFrameHeader::kOpCodeBinary: |
| 859 case WebSocketFrameHeader::kOpCodeContinuation: | 871 case WebSocketFrameHeader::kOpCodeContinuation: |
| 860 return HandleDataFrame(opcode, final, data_buffer, size); | 872 return HandleDataFrame(opcode, final, std::move(data_buffer), size); |
| 861 | 873 |
| 862 case WebSocketFrameHeader::kOpCodePing: | 874 case WebSocketFrameHeader::kOpCodePing: |
| 863 DVLOG(1) << "Got Ping of size " << size; | 875 DVLOG(1) << "Got Ping of size " << size; |
| 864 if (state_ == CONNECTED) | 876 if (state_ == CONNECTED) |
| 865 return SendFrameFromIOBuffer( | 877 return SendFrameInternal(true, WebSocketFrameHeader::kOpCodePong, |
| 866 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); | 878 std::move(data_buffer), 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(final, opcode_to_send, |
| 982 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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1026 DCHECK(!close_timer_.IsRunning()); | 1035 DCHECK(!close_timer_.IsRunning()); |
| 1027 // This use of base::Unretained() is safe because we stop the timer | 1036 // This use of base::Unretained() is safe because we stop the timer |
| 1028 // in the destructor. | 1037 // in the destructor. |
| 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::SendFrameInternal( |
| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 } else { | 1110 } else { |
| 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 (SendFrameInternal(true, WebSocketFrameHeader::kOpCodeClose, |
| 1112 true, WebSocketFrameHeader::kOpCodeClose, body, size) == | 1121 std::move(body), size) == CHANNEL_DELETED) |
| 1113 CHANNEL_DELETED) | |
| 1114 return CHANNEL_DELETED; | 1122 return CHANNEL_DELETED; |
| 1115 return CHANNEL_ALIVE; | 1123 return CHANNEL_ALIVE; |
| 1116 } | 1124 } |
| 1117 | 1125 |
| 1118 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, | 1126 bool WebSocketChannel::ParseClose(scoped_refptr<IOBuffer> buffer, |
| 1119 uint64_t size, | 1127 uint64_t size, |
| 1120 uint16_t* code, | 1128 uint16_t* code, |
| 1121 std::string* reason, | 1129 std::string* reason, |
| 1122 std::string* message) { | 1130 std::string* message) { |
| 1123 reason->clear(); | 1131 reason->clear(); |
| 1124 if (size < kWebSocketCloseCodeLength) { | 1132 if (size < kWebSocketCloseCodeLength) { |
| 1125 if (size == 0U) { | 1133 if (size == 0U) { |
| 1126 *code = kWebSocketErrorNoStatusReceived; | 1134 *code = kWebSocketErrorNoStatusReceived; |
| 1127 return true; | 1135 return true; |
| 1128 } | 1136 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1181 } | 1189 } |
| 1182 | 1190 |
| 1183 void WebSocketChannel::CloseTimeout() { | 1191 void WebSocketChannel::CloseTimeout() { |
| 1184 stream_->Close(); | 1192 stream_->Close(); |
| 1185 SetState(CLOSED); | 1193 SetState(CLOSED); |
| 1186 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 1194 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
| 1187 // |this| has been deleted. | 1195 // |this| has been deleted. |
| 1188 } | 1196 } |
| 1189 | 1197 |
| 1190 } // namespace net | 1198 } // namespace net |
| OLD | NEW |