| 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 |