OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
8 | 8 |
9 // Matches _WebSocketOpcode. | 9 // Matches _WebSocketOpcode. |
10 class _WebSocketMessageType { | 10 class _WebSocketMessageType { |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 int _readyState = WebSocket.CONNECTING; | 774 int _readyState = WebSocket.CONNECTING; |
775 bool _writeClosed = false; | 775 bool _writeClosed = false; |
776 int _closeCode; | 776 int _closeCode; |
777 String _closeReason; | 777 String _closeReason; |
778 Duration _pingInterval; | 778 Duration _pingInterval; |
779 Timer _pingTimer; | 779 Timer _pingTimer; |
780 _WebSocketConsumer _consumer; | 780 _WebSocketConsumer _consumer; |
781 | 781 |
782 int _outCloseCode; | 782 int _outCloseCode; |
783 String _outCloseReason; | 783 String _outCloseReason; |
| 784 Timer _closeTimer; |
784 | 785 |
785 static final HttpClient _httpClient = new HttpClient(); | 786 static final HttpClient _httpClient = new HttpClient(); |
786 | 787 |
787 static Future<WebSocket> connect(String url, List<String> protocols) { | 788 static Future<WebSocket> connect(String url, List<String> protocols) { |
788 Uri uri = Uri.parse(url); | 789 Uri uri = Uri.parse(url); |
789 if (uri.scheme != "ws" && uri.scheme != "wss") { | 790 if (uri.scheme != "ws" && uri.scheme != "wss") { |
790 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); | 791 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); |
791 } | 792 } |
792 if (uri.userInfo != "") { | 793 if (uri.userInfo != "") { |
793 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); | 794 throw new WebSocketException("Unsupported user info '${uri.userInfo}'"); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 if (data is _WebSocketPing) { | 873 if (data is _WebSocketPing) { |
873 if (!_writeClosed) _consumer.add(new _WebSocketPong(data.payload)); | 874 if (!_writeClosed) _consumer.add(new _WebSocketPong(data.payload)); |
874 } else if (data is _WebSocketPong) { | 875 } else if (data is _WebSocketPong) { |
875 // Simply set pingInterval, as it'll cancel any timers. | 876 // Simply set pingInterval, as it'll cancel any timers. |
876 pingInterval = _pingInterval; | 877 pingInterval = _pingInterval; |
877 } else { | 878 } else { |
878 _controller.add(data); | 879 _controller.add(data); |
879 } | 880 } |
880 }, | 881 }, |
881 onError: (error) { | 882 onError: (error) { |
| 883 if (_closeTimer != null) _closeTimer.cancel(); |
882 if (error is FormatException) { | 884 if (error is FormatException) { |
883 _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA); | 885 _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA); |
884 } else { | 886 } else { |
885 _close(WebSocketStatus.PROTOCOL_ERROR); | 887 _close(WebSocketStatus.PROTOCOL_ERROR); |
886 } | 888 } |
887 _controller.close(); | 889 _controller.close(); |
888 }, | 890 }, |
889 onDone: () { | 891 onDone: () { |
| 892 if (_closeTimer != null) _closeTimer.cancel(); |
890 if (_readyState == WebSocket.OPEN) { | 893 if (_readyState == WebSocket.OPEN) { |
891 _readyState = WebSocket.CLOSING; | 894 _readyState = WebSocket.CLOSING; |
892 if (!_isReservedStatusCode(transformer.closeCode)) { | 895 if (!_isReservedStatusCode(transformer.closeCode)) { |
893 _close(transformer.closeCode); | 896 _close(transformer.closeCode); |
894 } else { | 897 } else { |
895 _close(); | 898 _close(); |
896 } | 899 } |
897 _readyState = WebSocket.CLOSED; | 900 _readyState = WebSocket.CLOSED; |
898 } | 901 } |
899 _closeCode = transformer.closeCode; | 902 _closeCode = transformer.closeCode; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
950 Future get done => _sink.done; | 953 Future get done => _sink.done; |
951 | 954 |
952 Future close([int code, String reason]) { | 955 Future close([int code, String reason]) { |
953 if (_isReservedStatusCode(code)) { | 956 if (_isReservedStatusCode(code)) { |
954 throw new WebSocketException("Reserved status code $code"); | 957 throw new WebSocketException("Reserved status code $code"); |
955 } | 958 } |
956 if (_outCloseCode == null) { | 959 if (_outCloseCode == null) { |
957 _outCloseCode = code; | 960 _outCloseCode = code; |
958 _outCloseReason = reason; | 961 _outCloseReason = reason; |
959 } | 962 } |
| 963 if (_closeTimer == null && !_controller.isClosed) { |
| 964 // When closing the web-socket, we no longer accept data. |
| 965 _closeTimer = new Timer(const Duration(seconds: 5), () { |
| 966 _subscription.cancel(); |
| 967 _controller.close(); |
| 968 }); |
| 969 } |
960 return _sink.close(); | 970 return _sink.close(); |
961 } | 971 } |
962 | 972 |
963 void _close([int code, String reason]) { | 973 void _close([int code, String reason]) { |
964 if (_writeClosed) return; | 974 if (_writeClosed) return; |
965 if (_outCloseCode == null) { | 975 if (_outCloseCode == null) { |
966 _outCloseCode = code; | 976 _outCloseCode = code; |
967 _outCloseReason = reason; | 977 _outCloseReason = reason; |
968 } | 978 } |
969 _writeClosed = true; | 979 _writeClosed = true; |
970 _consumer.closeSocket(); | 980 _consumer.closeSocket(); |
971 } | 981 } |
972 | 982 |
973 static bool _isReservedStatusCode(int code) { | 983 static bool _isReservedStatusCode(int code) { |
974 return code != null && | 984 return code != null && |
975 (code < WebSocketStatus.NORMAL_CLOSURE || | 985 (code < WebSocketStatus.NORMAL_CLOSURE || |
976 code == WebSocketStatus.RESERVED_1004 || | 986 code == WebSocketStatus.RESERVED_1004 || |
977 code == WebSocketStatus.NO_STATUS_RECEIVED || | 987 code == WebSocketStatus.NO_STATUS_RECEIVED || |
978 code == WebSocketStatus.ABNORMAL_CLOSURE || | 988 code == WebSocketStatus.ABNORMAL_CLOSURE || |
979 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && | 989 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && |
980 code < WebSocketStatus.RESERVED_1015) || | 990 code < WebSocketStatus.RESERVED_1015) || |
981 (code >= WebSocketStatus.RESERVED_1015 && | 991 (code >= WebSocketStatus.RESERVED_1015 && |
982 code < 3000)); | 992 code < 3000)); |
983 } | 993 } |
984 } | 994 } |
OLD | NEW |