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 |