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 const String _clientNoContextTakeover = "client_no_context_takeover"; | 8 const String _clientNoContextTakeover = "client_no_context_takeover"; |
9 const String _serverNoContextTakeover = "server_no_context_takeover"; | 9 const String _serverNoContextTakeover = "server_no_context_takeover"; |
10 const String _clientMaxWindowBits = "client_max_window_bits"; | 10 const String _clientMaxWindowBits = "client_max_window_bits"; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 * The web socket protocol transformer handles the protocol byte stream | 57 * The web socket protocol transformer handles the protocol byte stream |
58 * which is supplied through the `handleData`. As the protocol is processed, | 58 * which is supplied through the `handleData`. As the protocol is processed, |
59 * it'll output frame data as either a List<int> or String. | 59 * it'll output frame data as either a List<int> or String. |
60 * | 60 * |
61 * Important information about usage: Be sure you use cancelOnError, so the | 61 * Important information about usage: Be sure you use cancelOnError, so the |
62 * socket will be closed when the processor encounter an error. Not using it | 62 * socket will be closed when the processor encounter an error. Not using it |
63 * will lead to undefined behaviour. | 63 * will lead to undefined behaviour. |
64 */ | 64 */ |
65 // TODO(ajohnsen): make this transformer reusable? | 65 // TODO(ajohnsen): make this transformer reusable? |
66 class _WebSocketProtocolTransformer | 66 class _WebSocketProtocolTransformer |
67 implements EventSink<List<int>>, StreamTransformer< | 67 implements |
68 List<int>, dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> { | 68 EventSink<List<int>>, |
| 69 StreamTransformer<List<int>, |
| 70 dynamic /*List<int>|_WebSocketPing|_WebSocketPong>*/ > { |
69 static const int START = 0; | 71 static const int START = 0; |
70 static const int LEN_FIRST = 1; | 72 static const int LEN_FIRST = 1; |
71 static const int LEN_REST = 2; | 73 static const int LEN_REST = 2; |
72 static const int MASK = 3; | 74 static const int MASK = 3; |
73 static const int PAYLOAD = 4; | 75 static const int PAYLOAD = 4; |
74 static const int CLOSED = 5; | 76 static const int CLOSED = 5; |
75 static const int FAILURE = 6; | 77 static const int FAILURE = 6; |
76 static const int FIN = 0x80; | 78 static const int FIN = 0x80; |
77 static const int RSV1 = 0x40; | 79 static const int RSV1 = 0x40; |
78 static const int RSV2 = 0x20; | 80 static const int RSV2 = 0x20; |
79 static const int RSV3 = 0x10; | 81 static const int RSV3 = 0x10; |
80 static const int OPCODE = 0xF; | 82 static const int OPCODE = 0xF; |
81 | 83 |
82 int _state = START; | 84 int _state = START; |
83 bool _fin = false; | 85 bool _fin = false; |
84 bool _compressed = false; | 86 bool _compressed = false; |
85 int _opcode = -1; | 87 int _opcode = -1; |
86 int _len = -1; | 88 int _len = -1; |
87 bool _masked = false; | 89 bool _masked = false; |
88 int _remainingLenBytes = -1; | 90 int _remainingLenBytes = -1; |
89 int _remainingMaskingKeyBytes = 4; | 91 int _remainingMaskingKeyBytes = 4; |
90 int _remainingPayloadBytes = -1; | 92 int _remainingPayloadBytes = -1; |
91 int _unmaskingIndex = 0; | 93 int _unmaskingIndex = 0; |
92 int _currentMessageType = _WebSocketMessageType.NONE; | 94 int _currentMessageType = _WebSocketMessageType.NONE; |
93 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED; | 95 int closeCode = WebSocketStatus.NO_STATUS_RECEIVED; |
94 String closeReason = ""; | 96 String closeReason = ""; |
95 | 97 |
96 EventSink<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> _eventSink; | 98 EventSink<dynamic /*List<int>|_WebSocketPing|_WebSocketPong>*/ > _eventSink; |
97 | 99 |
98 final bool _serverSide; | 100 final bool _serverSide; |
99 final List _maskingBytes = new List(4); | 101 final List _maskingBytes = new List(4); |
100 final BytesBuilder _payload = new BytesBuilder(copy: false); | 102 final BytesBuilder _payload = new BytesBuilder(copy: false); |
101 | 103 |
102 _WebSocketPerMessageDeflate _deflate; | 104 _WebSocketPerMessageDeflate _deflate; |
103 _WebSocketProtocolTransformer([this._serverSide = false, this._deflate]); | 105 _WebSocketProtocolTransformer([this._serverSide = false, this._deflate]); |
104 | 106 |
105 Stream<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> bind( | 107 Stream<dynamic /*List<int>|_WebSocketPing|_WebSocketPong>*/ > bind( |
106 Stream<List<int>> stream) { | 108 Stream<List<int>> stream) { |
107 return new Stream.eventTransformed(stream, (EventSink eventSink) { | 109 return new Stream.eventTransformed(stream, (EventSink eventSink) { |
108 if (_eventSink != null) { | 110 if (_eventSink != null) { |
109 throw new StateError("WebSocket transformer already used."); | 111 throw new StateError("WebSocket transformer already used."); |
110 } | 112 } |
111 _eventSink = eventSink; | 113 _eventSink = eventSink; |
112 return this; | 114 return this; |
113 }); | 115 }); |
114 } | 116 } |
115 | 117 |
116 void addError(Object error, [StackTrace stackTrace]) { | 118 void addError(Object error, [StackTrace stackTrace]) { |
117 _eventSink.addError(error, stackTrace); | 119 _eventSink.addError(error, stackTrace); |
118 } | 120 } |
119 | 121 |
120 void close() { _eventSink.close(); } | 122 void close() { |
| 123 _eventSink.close(); |
| 124 } |
121 | 125 |
122 /** | 126 /** |
123 * Process data received from the underlying communication channel. | 127 * Process data received from the underlying communication channel. |
124 */ | 128 */ |
125 void add(List<int> bytes) { | 129 void add(List<int> bytes) { |
126 var buffer = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes); | 130 var buffer = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes); |
127 int index = 0; | 131 int index = 0; |
128 int lastIndex = buffer.length; | 132 int lastIndex = buffer.length; |
129 if (_state == CLOSED) { | 133 if (_state == CLOSED) { |
130 throw new WebSocketException("Data on closed connection"); | 134 throw new WebSocketException("Data on closed connection"); |
131 } | 135 } |
132 if (_state == FAILURE) { | 136 if (_state == FAILURE) { |
133 throw new WebSocketException("Data on failed connection"); | 137 throw new WebSocketException("Data on failed connection"); |
134 } | 138 } |
135 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { | 139 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { |
136 int byte = buffer[index]; | 140 int byte = buffer[index]; |
137 if (_state <= LEN_REST) { | 141 if (_state <= LEN_REST) { |
138 if (_state == START) { | 142 if (_state == START) { |
139 _fin = (byte & FIN) != 0; | 143 _fin = (byte & FIN) != 0; |
140 | 144 |
141 if((byte & (RSV2 | RSV3)) != 0) { | 145 if ((byte & (RSV2 | RSV3)) != 0) { |
142 // The RSV2, RSV3 bits must both be zero. | 146 // The RSV2, RSV3 bits must both be zero. |
143 throw new WebSocketException("Protocol error"); | 147 throw new WebSocketException("Protocol error"); |
144 } | 148 } |
145 | 149 |
146 _opcode = (byte & OPCODE); | 150 _opcode = (byte & OPCODE); |
147 | 151 |
148 if (_opcode != _WebSocketOpcode.CONTINUATION) { | 152 if (_opcode != _WebSocketOpcode.CONTINUATION) { |
149 if ((byte & RSV1) != 0) { | 153 if ((byte & RSV1) != 0) { |
150 _compressed = true; | 154 _compressed = true; |
151 } else { | 155 } else { |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 | 492 |
489 extensionHeader ??= ""; | 493 extensionHeader ??= ""; |
490 | 494 |
491 var hv = HeaderValue.parse(extensionHeader, valueSeparator: ','); | 495 var hv = HeaderValue.parse(extensionHeader, valueSeparator: ','); |
492 if (compression.enabled && hv.value == _WebSocketImpl.PER_MESSAGE_DEFLATE) { | 496 if (compression.enabled && hv.value == _WebSocketImpl.PER_MESSAGE_DEFLATE) { |
493 var info = compression._createHeader(hv); | 497 var info = compression._createHeader(hv); |
494 | 498 |
495 response.headers.add("Sec-WebSocket-Extensions", info.headerValue); | 499 response.headers.add("Sec-WebSocket-Extensions", info.headerValue); |
496 var serverNoContextTakeover = | 500 var serverNoContextTakeover = |
497 (hv.parameters.containsKey(_serverNoContextTakeover) && | 501 (hv.parameters.containsKey(_serverNoContextTakeover) && |
498 compression.serverNoContextTakeover); | 502 compression.serverNoContextTakeover); |
499 var clientNoContextTakeover = | 503 var clientNoContextTakeover = |
500 (hv.parameters.containsKey(_clientNoContextTakeover) && | 504 (hv.parameters.containsKey(_clientNoContextTakeover) && |
501 compression.clientNoContextTakeover); | 505 compression.clientNoContextTakeover); |
502 var deflate = new _WebSocketPerMessageDeflate( | 506 var deflate = new _WebSocketPerMessageDeflate( |
503 serverNoContextTakeover: serverNoContextTakeover, | 507 serverNoContextTakeover: serverNoContextTakeover, |
504 clientNoContextTakeover: clientNoContextTakeover, | 508 clientNoContextTakeover: clientNoContextTakeover, |
505 serverMaxWindowBits: info.maxWindowBits, | 509 serverMaxWindowBits: info.maxWindowBits, |
506 clientMaxWindowBits: info.maxWindowBits, | 510 clientMaxWindowBits: info.maxWindowBits, |
507 serverSide: true); | 511 serverSide: true); |
508 | 512 |
509 return deflate; | 513 return deflate; |
510 } | 514 } |
511 | 515 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 bool clientNoContextTakeover; | 549 bool clientNoContextTakeover; |
546 int clientMaxWindowBits; | 550 int clientMaxWindowBits; |
547 int serverMaxWindowBits; | 551 int serverMaxWindowBits; |
548 bool serverSide; | 552 bool serverSide; |
549 | 553 |
550 _Filter decoder; | 554 _Filter decoder; |
551 _Filter encoder; | 555 _Filter encoder; |
552 | 556 |
553 _WebSocketPerMessageDeflate( | 557 _WebSocketPerMessageDeflate( |
554 {this.clientMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS, | 558 {this.clientMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS, |
555 this.serverMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS, | 559 this.serverMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS, |
556 this.serverNoContextTakeover: false, | 560 this.serverNoContextTakeover: false, |
557 this.clientNoContextTakeover: false, | 561 this.clientNoContextTakeover: false, |
558 this.serverSide: false}); | 562 this.serverSide: false}); |
559 | 563 |
560 void _ensureDecoder() { | 564 void _ensureDecoder() { |
561 if (decoder == null) { | 565 if (decoder == null) { |
562 decoder = _Filter._newZLibInflateFilter( | 566 decoder = _Filter._newZLibInflateFilter( |
563 serverSide ? clientMaxWindowBits : serverMaxWindowBits, null, true); | 567 serverSide ? clientMaxWindowBits : serverMaxWindowBits, null, true); |
564 } | 568 } |
565 } | 569 } |
566 | 570 |
567 void _ensureEncoder() { | 571 void _ensureEncoder() { |
568 if (encoder == null) { | 572 if (encoder == null) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 final _WebSocketImpl webSocket; | 647 final _WebSocketImpl webSocket; |
644 EventSink<List<int>> _eventSink; | 648 EventSink<List<int>> _eventSink; |
645 | 649 |
646 _WebSocketPerMessageDeflate _deflateHelper; | 650 _WebSocketPerMessageDeflate _deflateHelper; |
647 | 651 |
648 _WebSocketOutgoingTransformer(this.webSocket) { | 652 _WebSocketOutgoingTransformer(this.webSocket) { |
649 _deflateHelper = webSocket._deflate; | 653 _deflateHelper = webSocket._deflate; |
650 } | 654 } |
651 | 655 |
652 Stream<List<int>> bind(Stream stream) { | 656 Stream<List<int>> bind(Stream stream) { |
653 return new Stream<List<int>>.eventTransformed( | 657 return new Stream<List<int>>.eventTransformed(stream, |
654 stream, (EventSink<List<int>> eventSink) { | 658 (EventSink<List<int>> eventSink) { |
655 if (_eventSink != null) { | 659 if (_eventSink != null) { |
656 throw new StateError("WebSocket transformer already used"); | 660 throw new StateError("WebSocket transformer already used"); |
657 } | 661 } |
658 _eventSink = eventSink; | 662 _eventSink = eventSink; |
659 return this; | 663 return this; |
660 }); | 664 }); |
661 } | 665 } |
662 | 666 |
663 void add(message) { | 667 void add(message) { |
664 if (message is _WebSocketPong) { | 668 if (message is _WebSocketPong) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 _eventSink.close(); | 718 _eventSink.close(); |
715 } | 719 } |
716 | 720 |
717 void addFrame(int opcode, List<int> data) { | 721 void addFrame(int opcode, List<int> data) { |
718 createFrame( | 722 createFrame( |
719 opcode, | 723 opcode, |
720 data, | 724 data, |
721 webSocket._serverSide, | 725 webSocket._serverSide, |
722 _deflateHelper != null && | 726 _deflateHelper != null && |
723 (opcode == _WebSocketOpcode.TEXT || | 727 (opcode == _WebSocketOpcode.TEXT || |
724 opcode == _WebSocketOpcode.BINARY)) | 728 opcode == _WebSocketOpcode.BINARY)).forEach((e) { |
725 .forEach((e) { _eventSink.add(e); }); | 729 _eventSink.add(e); |
| 730 }); |
726 } | 731 } |
727 | 732 |
728 static Iterable<List<int>> createFrame( | 733 static Iterable<List<int>> createFrame( |
729 int opcode, List<int> data, bool serverSide, bool compressed) { | 734 int opcode, List<int> data, bool serverSide, bool compressed) { |
730 bool mask = !serverSide; // Masking not implemented for server. | 735 bool mask = !serverSide; // Masking not implemented for server. |
731 int dataLength = data == null ? 0 : data.length; | 736 int dataLength = data == null ? 0 : data.length; |
732 // Determine the header size. | 737 // Determine the header size. |
733 int headerSize = (mask) ? 6 : 2; | 738 int headerSize = (mask) ? 6 : 2; |
734 if (dataLength > 65535) { | 739 if (dataLength > 65535) { |
735 headerSize += 8; | 740 headerSize += 8; |
736 } else if (dataLength > 125) { | 741 } else if (dataLength > 125) { |
737 headerSize += 2; | 742 headerSize += 2; |
738 } | 743 } |
739 Uint8List header = new Uint8List(headerSize); | 744 Uint8List header = new Uint8List(headerSize); |
740 int index = 0; | 745 int index = 0; |
741 | 746 |
742 // Set FIN and opcode. | 747 // Set FIN and opcode. |
743 var hoc = _WebSocketProtocolTransformer.FIN | 748 var hoc = _WebSocketProtocolTransformer.FIN | |
744 | (compressed ? _WebSocketProtocolTransformer.RSV1 : 0) | 749 (compressed ? _WebSocketProtocolTransformer.RSV1 : 0) | |
745 | (opcode & _WebSocketProtocolTransformer.OPCODE); | 750 (opcode & _WebSocketProtocolTransformer.OPCODE); |
746 | 751 |
747 header[index++] = hoc; | 752 header[index++] = hoc; |
748 // Determine size and position of length field. | 753 // Determine size and position of length field. |
749 int lengthBytes = 1; | 754 int lengthBytes = 1; |
750 if (dataLength > 65535) { | 755 if (dataLength > 65535) { |
751 header[index++] = 127; | 756 header[index++] = 127; |
752 lengthBytes = 8; | 757 lengthBytes = 8; |
753 } else if (dataLength > 125) { | 758 } else if (dataLength > 125) { |
754 header[index++] = 126; | 759 header[index++] = 126; |
755 lengthBytes = 2; | 760 lengthBytes = 2; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 _issuedPause = false; | 913 _issuedPause = false; |
909 } | 914 } |
910 return _completer.future; | 915 return _completer.future; |
911 } | 916 } |
912 | 917 |
913 Future close() { | 918 Future close() { |
914 _ensureController(); | 919 _ensureController(); |
915 Future closeSocket() { | 920 Future closeSocket() { |
916 return socket.close().catchError((_) {}).then((_) => webSocket); | 921 return socket.close().catchError((_) {}).then((_) => webSocket); |
917 } | 922 } |
| 923 |
918 _controller.close(); | 924 _controller.close(); |
919 return _closeCompleter.future.then((_) => closeSocket()); | 925 return _closeCompleter.future.then((_) => closeSocket()); |
920 } | 926 } |
921 | 927 |
922 void add(data) { | 928 void add(data) { |
923 if (_closed) return; | 929 if (_closed) return; |
924 _ensureController(); | 930 _ensureController(); |
925 _controller.add(data); | 931 _controller.add(data); |
926 } | 932 } |
927 | 933 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 request.headers.add("Sec-WebSocket-Protocol", protocols.toList()); | 1012 request.headers.add("Sec-WebSocket-Protocol", protocols.toList()); |
1007 } | 1013 } |
1008 | 1014 |
1009 if (compression.enabled) { | 1015 if (compression.enabled) { |
1010 request.headers | 1016 request.headers |
1011 .add("Sec-WebSocket-Extensions", compression._createHeader()); | 1017 .add("Sec-WebSocket-Extensions", compression._createHeader()); |
1012 } | 1018 } |
1013 | 1019 |
1014 return request.close(); | 1020 return request.close(); |
1015 }).then((response) { | 1021 }).then((response) { |
1016 | |
1017 void error(String message) { | 1022 void error(String message) { |
1018 // Flush data. | 1023 // Flush data. |
1019 response.detachSocket().then((socket) { | 1024 response.detachSocket().then((socket) { |
1020 socket.destroy(); | 1025 socket.destroy(); |
1021 }); | 1026 }); |
1022 throw new WebSocketException(message); | 1027 throw new WebSocketException(message); |
1023 } | 1028 } |
1024 | 1029 |
1025 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS || | 1030 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS || |
1026 response.headers[HttpHeaders.CONNECTION] == null || | 1031 response.headers[HttpHeaders.CONNECTION] == null || |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 } | 1137 } |
1133 _readyState = WebSocket.CLOSED; | 1138 _readyState = WebSocket.CLOSED; |
1134 } | 1139 } |
1135 // Protocol close, use close code from transformer. | 1140 // Protocol close, use close code from transformer. |
1136 _closeCode = transformer.closeCode; | 1141 _closeCode = transformer.closeCode; |
1137 _closeReason = transformer.closeReason; | 1142 _closeReason = transformer.closeReason; |
1138 _controller.close(); | 1143 _controller.close(); |
1139 }, cancelOnError: true); | 1144 }, cancelOnError: true); |
1140 _subscription.pause(); | 1145 _subscription.pause(); |
1141 _controller = new StreamController( | 1146 _controller = new StreamController( |
1142 sync: true, onListen: _subscription.resume, onCancel: () { | 1147 sync: true, |
1143 _subscription.cancel(); | 1148 onListen: _subscription.resume, |
1144 _subscription = null; | 1149 onCancel: () { |
1145 }, onPause: _subscription.pause, onResume: _subscription.resume); | 1150 _subscription.cancel(); |
| 1151 _subscription = null; |
| 1152 }, |
| 1153 onPause: _subscription.pause, |
| 1154 onResume: _subscription.resume); |
1146 | 1155 |
1147 _webSockets[_serviceId] = this; | 1156 _webSockets[_serviceId] = this; |
1148 try { | 1157 try { |
1149 _socket._owner = this; | 1158 _socket._owner = this; |
1150 } catch (_) {} | 1159 } catch (_) {} |
1151 } | 1160 } |
1152 | 1161 |
1153 StreamSubscription listen(void onData(message), | 1162 StreamSubscription listen(void onData(message), |
1154 {Function onError, void onDone(), bool cancelOnError}) { | 1163 {Function onError, void onDone(), bool cancelOnError}) { |
1155 return _controller.stream.listen(onData, | 1164 return _controller.stream.listen(onData, |
(...skipping 18 matching lines...) Expand all Loading... |
1174 }); | 1183 }); |
1175 }); | 1184 }); |
1176 } | 1185 } |
1177 | 1186 |
1178 int get readyState => _readyState; | 1187 int get readyState => _readyState; |
1179 | 1188 |
1180 String get extensions => null; | 1189 String get extensions => null; |
1181 int get closeCode => _closeCode; | 1190 int get closeCode => _closeCode; |
1182 String get closeReason => _closeReason; | 1191 String get closeReason => _closeReason; |
1183 | 1192 |
1184 void add(data) { _sink.add(data); } | 1193 void add(data) { |
| 1194 _sink.add(data); |
| 1195 } |
| 1196 |
1185 void addUtf8Text(List<int> bytes) { | 1197 void addUtf8Text(List<int> bytes) { |
1186 if (bytes is! List<int>) { | 1198 if (bytes is! List<int>) { |
1187 throw new ArgumentError.value(bytes, "bytes", "Is not a list of bytes"); | 1199 throw new ArgumentError.value(bytes, "bytes", "Is not a list of bytes"); |
1188 } | 1200 } |
1189 _sink.add(new _EncodedString(bytes)); | 1201 _sink.add(new _EncodedString(bytes)); |
1190 } | 1202 } |
| 1203 |
1191 void addError(error, [StackTrace stackTrace]) { | 1204 void addError(error, [StackTrace stackTrace]) { |
1192 _sink.addError(error, stackTrace); | 1205 _sink.addError(error, stackTrace); |
1193 } | 1206 } |
| 1207 |
1194 Future addStream(Stream stream) => _sink.addStream(stream); | 1208 Future addStream(Stream stream) => _sink.addStream(stream); |
1195 Future get done => _sink.done; | 1209 Future get done => _sink.done; |
1196 | 1210 |
1197 Future close([int code, String reason]) { | 1211 Future close([int code, String reason]) { |
1198 if (_isReservedStatusCode(code)) { | 1212 if (_isReservedStatusCode(code)) { |
1199 throw new WebSocketException("Reserved status code $code"); | 1213 throw new WebSocketException("Reserved status code $code"); |
1200 } | 1214 } |
1201 if (_outCloseCode == null) { | 1215 if (_outCloseCode == null) { |
1202 _outCloseCode = code; | 1216 _outCloseCode = code; |
1203 _outCloseReason = reason; | 1217 _outCloseReason = reason; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1268 return code != null && | 1282 return code != null && |
1269 (code < WebSocketStatus.NORMAL_CLOSURE || | 1283 (code < WebSocketStatus.NORMAL_CLOSURE || |
1270 code == WebSocketStatus.RESERVED_1004 || | 1284 code == WebSocketStatus.RESERVED_1004 || |
1271 code == WebSocketStatus.NO_STATUS_RECEIVED || | 1285 code == WebSocketStatus.NO_STATUS_RECEIVED || |
1272 code == WebSocketStatus.ABNORMAL_CLOSURE || | 1286 code == WebSocketStatus.ABNORMAL_CLOSURE || |
1273 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && | 1287 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && |
1274 code < WebSocketStatus.RESERVED_1015) || | 1288 code < WebSocketStatus.RESERVED_1015) || |
1275 (code >= WebSocketStatus.RESERVED_1015 && code < 3000)); | 1289 (code >= WebSocketStatus.RESERVED_1015 && code < 3000)); |
1276 } | 1290 } |
1277 } | 1291 } |
OLD | NEW |