| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 /** | 51 /** |
| 52 * The web socket protocol transformer handles the protocol byte stream | 52 * The web socket protocol transformer handles the protocol byte stream |
| 53 * which is supplied through the [:handleData:]. As the protocol is processed, | 53 * which is supplied through the [:handleData:]. As the protocol is processed, |
| 54 * it'll output frame data as either a List<int> or String. | 54 * it'll output frame data as either a List<int> or String. |
| 55 * | 55 * |
| 56 * Important information about usage: Be sure you use cancelOnError, so the | 56 * Important information about usage: Be sure you use cancelOnError, so the |
| 57 * socket will be closed when the processor encounter an error. Not using it | 57 * socket will be closed when the processor encounter an error. Not using it |
| 58 * will lead to undefined behaviour. | 58 * will lead to undefined behaviour. |
| 59 */ | 59 */ |
| 60 // TODO(ajohnsen): make this transformer reusable? | 60 // TODO(ajohnsen): make this transformer reusable? |
| 61 class _WebSocketProtocolTransformer implements StreamTransformer, EventSink { | 61 class _WebSocketProtocolTransformer |
| 62 implements StreamTransformer<List<int>, dynamic>, EventSink<List<int>> { |
| 62 static const int START = 0; | 63 static const int START = 0; |
| 63 static const int LEN_FIRST = 1; | 64 static const int LEN_FIRST = 1; |
| 64 static const int LEN_REST = 2; | 65 static const int LEN_REST = 2; |
| 65 static const int MASK = 3; | 66 static const int MASK = 3; |
| 66 static const int PAYLOAD = 4; | 67 static const int PAYLOAD = 4; |
| 67 static const int CLOSED = 5; | 68 static const int CLOSED = 5; |
| 68 static const int FAILURE = 6; | 69 static const int FAILURE = 6; |
| 69 static const int FIN = 0x80; | 70 static const int FIN = 0x80; |
| 70 static const int RSV1 = 0x40; | 71 static const int RSV1 = 0x40; |
| 71 static const int RSV2 = 0x20; | 72 static const int RSV2 = 0x20; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 | 108 |
| 108 void addError(Object error, [StackTrace stackTrace]) { | 109 void addError(Object error, [StackTrace stackTrace]) { |
| 109 _eventSink.addError(error, stackTrace); | 110 _eventSink.addError(error, stackTrace); |
| 110 } | 111 } |
| 111 | 112 |
| 112 void close() { _eventSink.close(); } | 113 void close() { _eventSink.close(); } |
| 113 | 114 |
| 114 /** | 115 /** |
| 115 * Process data received from the underlying communication channel. | 116 * Process data received from the underlying communication channel. |
| 116 */ | 117 */ |
| 117 void add(Uint8List buffer) { | 118 void add(List<int> bytes) { |
| 119 var buffer = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes); |
| 118 int index = 0; | 120 int index = 0; |
| 119 int lastIndex = buffer.length; | 121 int lastIndex = buffer.length; |
| 120 if (_state == CLOSED) { | 122 if (_state == CLOSED) { |
| 121 throw new WebSocketException("Data on closed connection"); | 123 throw new WebSocketException("Data on closed connection"); |
| 122 } | 124 } |
| 123 if (_state == FAILURE) { | 125 if (_state == FAILURE) { |
| 124 throw new WebSocketException("Data on failed connection"); | 126 throw new WebSocketException("Data on failed connection"); |
| 125 } | 127 } |
| 126 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { | 128 while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) { |
| 127 int byte = buffer[index]; | 129 int byte = buffer[index]; |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 | 621 |
| 620 if (result.length > 4) { | 622 if (result.length > 4) { |
| 621 result = result.sublist(0, result.length - 4); | 623 result = result.sublist(0, result.length - 4); |
| 622 } | 624 } |
| 623 | 625 |
| 624 return result; | 626 return result; |
| 625 } | 627 } |
| 626 } | 628 } |
| 627 | 629 |
| 628 // TODO(ajohnsen): Make this transformer reusable. | 630 // TODO(ajohnsen): Make this transformer reusable. |
| 629 class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink { | 631 class _WebSocketOutgoingTransformer |
| 632 implements StreamTransformer<dynamic, List<int>>, EventSink { |
| 630 final _WebSocketImpl webSocket; | 633 final _WebSocketImpl webSocket; |
| 631 EventSink _eventSink; | 634 EventSink<List<int>> _eventSink; |
| 632 | 635 |
| 633 _WebSocketPerMessageDeflate _deflateHelper; | 636 _WebSocketPerMessageDeflate _deflateHelper; |
| 634 | 637 |
| 635 _WebSocketOutgoingTransformer(this.webSocket) { | 638 _WebSocketOutgoingTransformer(this.webSocket) { |
| 636 _deflateHelper = webSocket._deflate; | 639 _deflateHelper = webSocket._deflate; |
| 637 } | 640 } |
| 638 | 641 |
| 639 Stream bind(Stream stream) { | 642 Stream<List<int>> bind(Stream stream) { |
| 640 return new Stream.eventTransformed(stream, (EventSink eventSink) { | 643 return new Stream.eventTransformed(stream, (eventSink) { |
| 641 if (_eventSink != null) { | 644 if (_eventSink != null) { |
| 642 throw new StateError("WebSocket transformer already used"); | 645 throw new StateError("WebSocket transformer already used"); |
| 643 } | 646 } |
| 644 _eventSink = eventSink; | 647 _eventSink = eventSink; |
| 645 return this; | 648 return this; |
| 646 }); | 649 }); |
| 647 } | 650 } |
| 648 | 651 |
| 649 void add(message) { | 652 void add(message) { |
| 650 if (message is _WebSocketPong) { | 653 if (message is _WebSocketPong) { |
| 651 addFrame(_WebSocketOpcode.PONG, message.payload); | 654 addFrame(_WebSocketOpcode.PONG, message.payload); |
| 652 return; | 655 return; |
| 653 } | 656 } |
| 654 if (message is _WebSocketPing) { | 657 if (message is _WebSocketPing) { |
| 655 addFrame(_WebSocketOpcode.PING, message.payload); | 658 addFrame(_WebSocketOpcode.PING, message.payload); |
| 656 return; | 659 return; |
| 657 } | 660 } |
| 658 List<int> data; | 661 List<int> data; |
| 659 int opcode; | 662 int opcode; |
| 660 if (message != null) { | 663 if (message != null) { |
| 661 if (message is String) { | 664 if (message is String) { |
| 662 opcode = _WebSocketOpcode.TEXT; | 665 opcode = _WebSocketOpcode.TEXT; |
| 663 data = UTF8.encode(message); | 666 data = UTF8.encode(message); |
| 664 } else { | 667 } else { |
| 665 if (message is! List<int>) { | 668 if (message is List<int>) { |
| 669 data = message; |
| 670 opcode = _WebSocketOpcode.BINARY; |
| 671 } else { |
| 666 throw new ArgumentError(message); | 672 throw new ArgumentError(message); |
| 667 } | 673 } |
| 668 opcode = _WebSocketOpcode.BINARY; | |
| 669 data = message; | |
| 670 } | 674 } |
| 671 | 675 |
| 672 if (_deflateHelper != null) { | 676 if (_deflateHelper != null) { |
| 673 data = _deflateHelper.processOutgoingMessage(data); | 677 data = _deflateHelper.processOutgoingMessage(data); |
| 674 } | 678 } |
| 675 } else { | 679 } else { |
| 676 opcode = _WebSocketOpcode.TEXT; | 680 opcode = _WebSocketOpcode.TEXT; |
| 677 } | 681 } |
| 678 addFrame(opcode, data); | 682 addFrame(opcode, data); |
| 679 } | 683 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 701 void addFrame(int opcode, List<int> data) => createFrame( | 705 void addFrame(int opcode, List<int> data) => createFrame( |
| 702 opcode, | 706 opcode, |
| 703 data, | 707 data, |
| 704 webSocket._serverSide, | 708 webSocket._serverSide, |
| 705 _deflateHelper != null && | 709 _deflateHelper != null && |
| 706 (opcode == _WebSocketOpcode.TEXT || | 710 (opcode == _WebSocketOpcode.TEXT || |
| 707 opcode == _WebSocketOpcode.BINARY)).forEach((e) { | 711 opcode == _WebSocketOpcode.BINARY)).forEach((e) { |
| 708 _eventSink.add(e); | 712 _eventSink.add(e); |
| 709 }); | 713 }); |
| 710 | 714 |
| 711 static Iterable createFrame( | 715 static Iterable<List<int>> createFrame( |
| 712 int opcode, List<int> data, bool serverSide, bool compressed) { | 716 int opcode, List<int> data, bool serverSide, bool compressed) { |
| 713 bool mask = !serverSide; // Masking not implemented for server. | 717 bool mask = !serverSide; // Masking not implemented for server. |
| 714 int dataLength = data == null ? 0 : data.length; | 718 int dataLength = data == null ? 0 : data.length; |
| 715 // Determine the header size. | 719 // Determine the header size. |
| 716 int headerSize = (mask) ? 6 : 2; | 720 int headerSize = (mask) ? 6 : 2; |
| 717 if (dataLength > 65535) { | 721 if (dataLength > 65535) { |
| 718 headerSize += 8; | 722 headerSize += 8; |
| 719 } else if (dataLength > 125) { | 723 } else if (dataLength > 125) { |
| 720 headerSize += 2; | 724 headerSize += 2; |
| 721 } | 725 } |
| (...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 _writeClosed = true; | 1215 _writeClosed = true; |
| 1212 _consumer.closeSocket(); | 1216 _consumer.closeSocket(); |
| 1213 _webSockets.remove(_serviceId); | 1217 _webSockets.remove(_serviceId); |
| 1214 } | 1218 } |
| 1215 | 1219 |
| 1216 String get _serviceTypePath => 'io/websockets'; | 1220 String get _serviceTypePath => 'io/websockets'; |
| 1217 String get _serviceTypeName => 'WebSocket'; | 1221 String get _serviceTypeName => 'WebSocket'; |
| 1218 | 1222 |
| 1219 Map _toJSON(bool ref) { | 1223 Map _toJSON(bool ref) { |
| 1220 var name = '${_socket.address.host}:${_socket.port}'; | 1224 var name = '${_socket.address.host}:${_socket.port}'; |
| 1221 var r = { | 1225 var r = <String, dynamic>{ |
| 1222 'id': _servicePath, | 1226 'id': _servicePath, |
| 1223 'type': _serviceType(ref), | 1227 'type': _serviceType(ref), |
| 1224 'name': name, | 1228 'name': name, |
| 1225 'user_name': name, | 1229 'user_name': name, |
| 1226 }; | 1230 }; |
| 1227 if (ref) { | 1231 if (ref) { |
| 1228 return r; | 1232 return r; |
| 1229 } | 1233 } |
| 1230 try { | 1234 try { |
| 1231 r['socket'] = _socket._toJSON(true); | 1235 r['socket'] = _socket._toJSON(true); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1244 return code != null && | 1248 return code != null && |
| 1245 (code < WebSocketStatus.NORMAL_CLOSURE || | 1249 (code < WebSocketStatus.NORMAL_CLOSURE || |
| 1246 code == WebSocketStatus.RESERVED_1004 || | 1250 code == WebSocketStatus.RESERVED_1004 || |
| 1247 code == WebSocketStatus.NO_STATUS_RECEIVED || | 1251 code == WebSocketStatus.NO_STATUS_RECEIVED || |
| 1248 code == WebSocketStatus.ABNORMAL_CLOSURE || | 1252 code == WebSocketStatus.ABNORMAL_CLOSURE || |
| 1249 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && | 1253 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && |
| 1250 code < WebSocketStatus.RESERVED_1015) || | 1254 code < WebSocketStatus.RESERVED_1015) || |
| 1251 (code >= WebSocketStatus.RESERVED_1015 && code < 3000)); | 1255 (code >= WebSocketStatus.RESERVED_1015 && code < 3000)); |
| 1252 } | 1256 } |
| 1253 } | 1257 } |
| OLD | NEW |