From fb522073e8daa79e550ac9779994e15f33bee183 Mon Sep 17 00:00:00 2001 From: Felix Angelov Date: Mon, 19 Nov 2018 21:32:48 -0600 Subject: [PATCH 1/2] upgrade to dart2 --- .gitignore | 1 + lib/socket_io.dart | 2 +- lib/src/adapter/adapter.dart | 27 ++-- lib/src/client.dart | 16 +-- lib/src/engine/connect.dart | 21 ++- lib/src/engine/engine.dart | 3 +- lib/src/engine/parser/parser.dart | 125 ++++++++--------- lib/src/engine/parser/wtf8.dart | 17 ++- lib/src/engine/server.dart | 103 +++++++------- lib/src/engine/socket.dart | 47 ++++--- lib/src/engine/transport/jsonp_transport.dart | 15 +- .../engine/transport/polling_transport.dart | 130 +++++++++--------- lib/src/engine/transport/transports.dart | 13 +- .../engine/transport/websocket_transport.dart | 16 ++- lib/src/engine/transport/xhr_transport.dart | 18 +-- lib/src/namespace.dart | 14 +- lib/src/parser/binary.dart | 17 +-- lib/src/parser/parser.dart | 107 +++++++------- lib/src/server.dart | 50 +++---- lib/src/socket.dart | 80 +++++------ lib/src/util/event_emitter.dart | 4 +- pubspec.yaml | 11 +- test/socket.test.dart | 33 +++-- 23 files changed, 439 insertions(+), 431 deletions(-) diff --git a/.gitignore b/.gitignore index 2205f7b..f587070 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Files and directories created by pub +.dart_tool .packages .pub/ build/ diff --git a/lib/socket_io.dart b/lib/socket_io.dart index f3c7e38..f8ebdb7 100644 --- a/lib/socket_io.dart +++ b/lib/socket_io.dart @@ -7,4 +7,4 @@ export 'src/engine/transport/jsonp_transport.dart' show JSONPTransport; export 'src/engine/transport/polling_transport.dart' show PollingTransport; export 'src/engine/transport/websocket_transport.dart' show WebSocketTransport; -export 'package:socket_io/src/engine/parser/parser.dart' show PacketParser; \ No newline at end of file +export 'package:socket_io/src/engine/parser/parser.dart' show PacketParser; diff --git a/lib/src/adapter/adapter.dart b/lib/src/adapter/adapter.dart index f88ed5f..d1fa087 100644 --- a/lib/src/adapter/adapter.dart +++ b/lib/src/adapter/adapter.dart @@ -28,12 +28,13 @@ abstract class Adapter { clientRooms(String id, [fn(err, [_])]); static Adapter newInstance(String key, Namespace nsp) { - if ('default' == key ) { + if ('default' == key) { return new _MemoryStoreAdapter(nsp); } throw new UnimplementedError('not supported other adapter yet.'); } } + class _MemoryStoreAdapter extends EventEmitter implements Adapter { Map nsps = {}; Map rooms; @@ -59,7 +60,7 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { add(String id, String room, [fn([_])]) { this.sids[id] = this.sids[id] ?? {}; this.sids[id][room] = true; - this.rooms[room] = this.rooms[room] ?? new _Room(); + this.rooms[room] = this.rooms[room] ?? new _Room(); this.rooms[room].add(id); if (fn != null) scheduleMicrotask(() => fn(null)); } @@ -77,8 +78,7 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { this.sids[id].remove(room); if (this.rooms.containsKey(room)) { this.rooms[room].del(id); - if (this.rooms[room].length == 0) - this.rooms.remove(room); + if (this.rooms[room].length == 0) this.rooms.remove(room); } if (fn != null) scheduleMicrotask(() => fn(null)); @@ -97,14 +97,13 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { for (var room in rooms.keys) { if (this.rooms.containsKey(room)) { this.rooms[room].del(id); - if (this.rooms[room].length == 0) - this.rooms.remove(room); + if (this.rooms[room].length == 0) this.rooms.remove(room); } } } this.sids.remove(id); - if (fn != null) scheduleMicrotask(() => fn(null)); + if (fn != null) scheduleMicrotask(() => fn(null)); } /** @@ -151,9 +150,9 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { } } else { for (var id in this.sids.keys) { - if (except.indexOf(id) >= 0) continue; - socket = this.nsp.connected[id]; - if (socket != null) socket.packet(encodedPackets, packetOpts); + if (except.indexOf(id) >= 0) continue; + socket = this.nsp.connected[id]; + if (socket != null) socket.packet(encodedPackets, packetOpts); } } }); @@ -191,8 +190,8 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { } } else { for (var id in this.sids.keys) { - socket = this.nsp.connected[id]; - if (socket != null) sids.add(id); + socket = this.nsp.connected[id]; + if (socket != null) sids.add(id); } } @@ -211,7 +210,7 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { if (fn != null) scheduleMicrotask(() => fn(null, rooms?.keys)); } } - /** +/** * Room constructor. * * @api private @@ -250,4 +249,4 @@ class _Room { this.length--; } } -} \ No newline at end of file +} diff --git a/lib/src/client.dart b/lib/src/client.dart index cff42c0..0f1284c 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -64,8 +64,7 @@ class Client { connect(name, [query]) { _logger.fine('connecting to namespace $name'); if (!this.server.nsps.containsKey(name)) { - this.packet( - {'type': ERROR, 'nsp': name, 'data': 'Invalid namespace'}); + this.packet({'type': ERROR, 'nsp': name, 'data': 'Invalid namespace'}); return; } var nsp = this.server.of(name); @@ -92,7 +91,6 @@ class Client { * @api private */ disconnect() { - var socket; // we don't use a for loop because the length of // `sockets` changes upon each iteration this.sockets.toList().forEach((socket) { @@ -146,18 +144,20 @@ class Client { writeToEngine(encodedPackets) { if (opts['volatile'] != null && !self.conn.transport.writable) return; for (var i = 0; i < encodedPackets.length; i++) { - self.conn.write(encodedPackets[i], { 'compress': opts['compress']}); + self.conn.write(encodedPackets[i], {'compress': opts['compress']}); } } if ('open' == this.conn.readyState) { _logger.fine('writing packet $packet'); - if (opts['preEncoded'] != true) { // not broadcasting, need to encode - this.encoder.encode( - packet, (encodedPackets) { // encode, then write results to engine + if (opts['preEncoded'] != true) { + // not broadcasting, need to encode + this.encoder.encode(packet, (encodedPackets) { + // encode, then write results to engine writeToEngine(encodedPackets); }); - } else { // a broadcast pre-encodes a packet + } else { + // a broadcast pre-encodes a packet writeToEngine(packet); } } else { diff --git a/lib/src/engine/connect.dart b/lib/src/engine/connect.dart index 3b4e196..707cce4 100644 --- a/lib/src/engine/connect.dart +++ b/lib/src/engine/connect.dart @@ -1,4 +1,3 @@ - /** * connect.dart * @@ -21,7 +20,8 @@ class SocketConnect extends HttpConnectWrapper { bool _completed; SocketConnect(HttpConnect origin) : super(origin); - SocketConnect.fromWebSocket(HttpConnect origin, WebSocket socket) : super(origin) { + SocketConnect.fromWebSocket(HttpConnect origin, WebSocket socket) + : super(origin) { _socket = socket; } @@ -45,13 +45,12 @@ class SocketConnect extends HttpConnectWrapper { * Closes the current connection. */ void close() { - if (_done != null) { - _done.complete('done'); - } else if (_socket != null) { - _socket.close(); - } else { - _completed = true; - } + if (_done != null) { + _done.complete('done'); + } else if (_socket != null) { + _socket.close(); + } else { + _completed = true; + } } - -} \ No newline at end of file +} diff --git a/lib/src/engine/engine.dart b/lib/src/engine/engine.dart index 8f57476..24e6ddd 100644 --- a/lib/src/engine/engine.dart +++ b/lib/src/engine/engine.dart @@ -19,6 +19,7 @@ class Engine extends EventEmitter { engine.attachTo(server, options); return engine; } + dynamic operator [](Object key) {} /** @@ -35,4 +36,4 @@ class Engine extends EventEmitter { close() {} // handleRequest() {} // handshake() {} -} \ No newline at end of file +} diff --git a/lib/src/engine/parser/parser.dart b/lib/src/engine/parser/parser.dart index 892833b..81cbe00 100644 --- a/lib/src/engine/parser/parser.dart +++ b/lib/src/engine/parser/parser.dart @@ -20,21 +20,19 @@ import 'package:socket_io/src/engine/parser/wtf8.dart'; // Protocol version final protocol = 3; -enum PacketType { - OPEN, - CLOSE, - PING, - PONG, - MESSAGE, - UPGRADE, - NOOP -} +enum PacketType { OPEN, CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP } const List PacketTypeList = const [ - 'open', 'close', 'ping', 'pong', 'message', 'upgrade', 'noop']; - -const Map PacketTypeMap = const -{ + 'open', + 'close', + 'ping', + 'pong', + 'message', + 'upgrade', + 'noop' +]; + +const Map PacketTypeMap = const { 'open': 0, 'close': 1, 'ping': 2, @@ -45,10 +43,12 @@ const Map PacketTypeMap = const }; class PacketParser { - static const ERROR = const { 'type': 'error', 'data': 'parser error'}; + static const ERROR = const {'type': 'error', 'data': 'parser error'}; static String encodePacket(Map packet, - {supportsBinary, utf8encode = false, callback( - _), bool fromClient = false}) { + {supportsBinary, + utf8encode = false, + callback(_), + bool fromClient = false}) { if (supportsBinary is Function) { callback = supportsBinary; supportsBinary = null; @@ -60,13 +60,17 @@ class PacketParser { } if (packet['data'] is Uint8List) { - return encodeBuffer(packet, supportsBinary, callback, fromClient: fromClient); - } else if (packet['data'] is Map && packet['data']['buffer'] is ByteBuffer) { + return encodeBuffer(packet, supportsBinary, callback, + fromClient: fromClient); + } else if (packet['data'] is Map && + packet['data']['buffer'] is ByteBuffer) { packet['data'] = (packet['data']['buffer'] as ByteBuffer).asUint8List(); - return encodeBuffer(packet, supportsBinary, callback, fromClient: fromClient); + return encodeBuffer(packet, supportsBinary, callback, + fromClient: fromClient); } else if (packet['data'] is ByteBuffer) { packet['data'] = (packet['data'] as ByteBuffer).asUint8List(); - return encodeBuffer(packet, supportsBinary, callback, fromClient: fromClient); + return encodeBuffer(packet, supportsBinary, callback, + fromClient: fromClient); } // Sending data as a utf-8 string @@ -74,9 +78,9 @@ class PacketParser { // data fragment is optional if (packet['data'] != null) { - encoded += - utf8encode == true ? WTF8.encode('''${packet['data']}''') - : '''${packet['data']}'''; + encoded += utf8encode == true + ? WTF8.encode('''${packet['data']}''') + : '''${packet['data']}'''; } return callback('$encoded'); @@ -86,7 +90,8 @@ class PacketParser { * Encode Buffer data */ - static encodeBuffer(packet, supportsBinary, callback, {fromClient = false /*use this to check whether is in client or not*/}) { + static encodeBuffer(packet, supportsBinary, callback, + {fromClient = false /*use this to check whether is in client or not*/}) { if (!supportsBinary) { return encodeBase64Packet(packet, callback); } @@ -95,7 +100,9 @@ class PacketParser { // 'fromClient' is to check if the runtime is on server side or not, // because Dart server's websocket cannot send data with byte buffer. final newData = new Uint8List(data.length + 1); - newData..setAll(0, [PacketTypeMap[packet['type']]]..length = 1)..setAll(1, data); + newData + ..setAll(0, [PacketTypeMap[packet['type']]]..length = 1) + ..setAll(1, data); if (fromClient) { return callback(newData.buffer); } else { @@ -112,9 +119,7 @@ class PacketParser { static encodeBase64Packet(packet, callback) { var message = '''b${PacketTypeMap[packet['type']]}'''; - message += BASE64.encode(packet.data - .toString() - .codeUnits); + message += base64.encode(packet.data.toString().codeUnits); return callback(message); } @@ -126,12 +131,12 @@ class PacketParser { type = data[0]; if (type == 'b') { - return decodeBase64Packet(data.substr(1), binaryType); + return decodeBase64Packet((data as String).substring(1), binaryType); } if (utf8decode == true) { try { - data = UTF8.decode(data.codeUnits); + data = utf8.decode(data.codeUnits); } catch (e) { return ERROR; } @@ -142,9 +147,9 @@ class PacketParser { } if (data.length > 1) { - return { 'type': PacketTypeList[type], 'data': data.substring(1)}; + return {'type': PacketTypeList[type], 'data': data.substring(1)}; } else { - return { 'type': PacketTypeList[type]}; + return {'type': PacketTypeList[type]}; } } @@ -153,29 +158,27 @@ class PacketParser { // wrap Buffer/ArrayBuffer data into an Uint8Array var intArray = (data as ByteBuffer).asUint8List(); type = intArray[0]; - return { 'type': PacketTypeList[type], 'data': intArray.sublist(0)}; + return {'type': PacketTypeList[type], 'data': intArray.sublist(0)}; } // if (data instanceof ArrayBuffer) { // data = arrayBufferToBuffer(data); // } type = data[0]; - return { 'type': PacketTypeList[type], 'data': data.sublist(1)}; + return {'type': PacketTypeList[type], 'data': data.sublist(1)}; } static decodeBase64Packet(String msg, String binaryType) { var type = PacketTypeList[msg.codeUnitAt(0)]; - var data = BASE64.decode(UTF8.decode(msg - .substring(1) - .codeUnits)); + var data = base64.decode(utf8.decode(msg.substring(1).codeUnits)); if (binaryType == 'arraybuffer') { var abv = new Uint8List(data.length); - for (var i = 0; i < abv.length; i++){ + for (var i = 0; i < abv.length; i++) { abv[i] = data[i]; } - return { 'type': type, 'data': abv.buffer}; + return {'type': type, 'data': abv.buffer}; } - return { 'type': type, 'data': data}; + return {'type': type, 'data': data}; } static hasBinary(List packets) { @@ -184,8 +187,9 @@ class PacketParser { return data is ByteBuffer; }); } + static encodePayload(List packets, - {bool supportsBinary = false, callback(_)}) { + {bool supportsBinary = false, callback(_)}) { if (supportsBinary && hasBinary(packets)) { return encodePayloadAsBinary(packets, callback); } @@ -195,11 +199,10 @@ class PacketParser { } var encodeOne = (packet, [doneCallback(err, _)]) { - encodePacket(packet, supportsBinary: supportsBinary, - utf8encode: false, + encodePacket(packet, supportsBinary: supportsBinary, utf8encode: false, callback: (message) { - doneCallback(null, _setLengthHeader(message)); - }); + doneCallback(null, _setLengthHeader(message)); + }); }; map(packets, encodeOne, (err, results) { @@ -217,8 +220,7 @@ class PacketParser { static map(List ary, each(_, [callback(err, msg)]), done(err, results)) { var result = []; Future.wait(ary.map((e) { - return new Future.microtask(() => - each(e, (err, msg) { + return new Future.microtask(() => each(e, (err, msg) { result.add(msg); })); })).then((r) => done(null, result)); @@ -233,9 +235,10 @@ class PacketParser { */ static decodePayload(data, - {bool binaryType = false, callback(err, [foo, bar])}) { + {bool binaryType = false, callback(err, [foo, bar])}) { if (data is! String) { - return decodePayloadAsBinary(data, binaryType: binaryType, callback: callback); + return decodePayloadAsBinary(data, + binaryType: binaryType, callback: callback); } if (data == '') { @@ -243,10 +246,7 @@ class PacketParser { return callback(Error, 0, 1); } - var length = '', - n, - msg, - packet; + var length = '', n, msg, packet; for (var i = 0, l = data.length; i < l; i++) { var chr = data[i]; @@ -256,8 +256,7 @@ class PacketParser { continue; } - if (length.isEmpty || (length != - '${(n = num.parse(length, (data) => data.isEmpty ? 0 : null))}')) { + if (length.isEmpty || (length != '${(n = num.parse(length))}')) { // parser error - ignoring payload return callback(ERROR, 0, 1); } @@ -294,7 +293,7 @@ class PacketParser { } static decodePayloadAsBinary(List data, - {bool binaryType, callback(err, [foo, bar])}) { + {bool binaryType, callback(err, [foo, bar])}) { var bufferTail = data; var buffers = []; var i; @@ -323,9 +322,8 @@ class PacketParser { var total = buffers.length; for (i = 0; i < total; i++) { var buffer = buffers[i]; - callback( - decodePacket(buffer, binaryType: binaryType, utf8decode: true), i, - total); + callback(decodePacket(buffer, binaryType: binaryType, utf8decode: true), + i, total); } } @@ -334,7 +332,7 @@ class PacketParser { return callback(new Uint8List(0)); } - map(packets, encodeOneBinaryPacket, (err, List results) { + map(packets, encodeOneBinaryPacket, (err, results) { var list = []; results.forEach((e) => list.addAll(e)); return callback(list); @@ -366,9 +364,8 @@ class PacketParser { doneCallback(null, new List.from(sizeBuffer)..addAll(packet)); }; - encodePacket(p, supportsBinary: true, - utf8encode: true, - callback: onBinaryPacketEncode); + encodePacket(p, + supportsBinary: true, utf8encode: true, callback: onBinaryPacketEncode); } static List stringToBuffer(String string) { @@ -378,4 +375,4 @@ class PacketParser { } return buf; } -} \ No newline at end of file +} diff --git a/lib/src/engine/parser/wtf8.dart b/lib/src/engine/parser/wtf8.dart index ba34a97..afcc02f 100644 --- a/lib/src/engine/parser/wtf8.dart +++ b/lib/src/engine/parser/wtf8.dart @@ -36,7 +36,8 @@ class WTF8 { if (value >= 0xD800 && value <= 0xDBFF && counter < length) { // high surrogate, and there is a next character extra = string.codeUnitAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate + if ((extra & 0xFC00) == 0xDC00) { + // low surrogate output.add(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); } else { // unmatched surrogate; only append this code unit, in case the next @@ -52,16 +53,20 @@ class WTF8 { } static _encodeCodePoint(int codePoint) { - if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence + if ((codePoint & 0xFFFFFF80) == 0) { + // 1-byte sequence return new String.fromCharCode(codePoint); } var symbol = ''; - if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence + if ((codePoint & 0xFFFFF800) == 0) { + // 2-byte sequence symbol = new String.fromCharCode(((codePoint >> 6) & 0x1F) | 0xC0); - } else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence + } else if ((codePoint & 0xFFFF0000) == 0) { + // 3-byte sequence symbol = new String.fromCharCode(((codePoint >> 12) & 0x0F) | 0xE0); symbol += _createByte(codePoint, 6); - } else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence + } else if ((codePoint & 0xFFE00000) == 0) { + // 4-byte sequence symbol = new String.fromCharCode(((codePoint >> 18) & 0x07) | 0xF0); symbol += _createByte(codePoint, 12); symbol += _createByte(codePoint, 6); @@ -73,4 +78,4 @@ class WTF8 { static _createByte(codePoint, shift) { return new String.fromCharCode(((codePoint >> shift) & 0x3F) | 0x80); } -} \ No newline at end of file +} diff --git a/lib/src/engine/server.dart b/lib/src/engine/server.dart index a3b55ff..21a9869 100644 --- a/lib/src/engine/server.dart +++ b/lib/src/engine/server.dart @@ -10,7 +10,6 @@ * * Copyright (C) 2017 Potix Corporation. All Rights Reserved. */ -import 'dart:async'; import 'dart:convert'; import 'dart:io' hide Socket; import 'package:logging/logging.dart'; @@ -75,17 +74,25 @@ class Server extends Engine { this.transports = ['polling', 'websocket']; this.allowUpgrades = false != opts['allowUpgrades']; this.allowRequest = opts['allowRequest']; - this.cookie = opts['cookie'] == false ? false : opts['cookie'] ?? 'io'; //false != opts.cookie ? (opts.cookie || 'io') : false; - this.cookiePath = opts['cookiePath'] == false ? false : opts['cookiePath'] ?? '/'; //false != opts.cookiePath ? (opts.cookiePath || '/') : false; + this.cookie = opts['cookie'] == false + ? false + : opts['cookie'] ?? + 'io'; //false != opts.cookie ? (opts.cookie || 'io') : false; + this.cookiePath = opts['cookiePath'] == false + ? false + : opts['cookiePath'] ?? + '/'; //false != opts.cookiePath ? (opts.cookiePath || '/') : false; this.cookieHttpOnly = opts['cookieHttpOnly'] != false; - if (!opts.containsKey('perMessageDeflate') || opts['perMessageDeflate'] == true) { - this.perMessageDeflate = opts['perMessageDeflate'] is Map ? opts['perMessageDeflate'] : {}; + if (!opts.containsKey('perMessageDeflate') || + opts['perMessageDeflate'] == true) { + this.perMessageDeflate = + opts['perMessageDeflate'] is Map ? opts['perMessageDeflate'] : {}; if (!this.perMessageDeflate.containsKey('threshold')) this.perMessageDeflate['threshold'] = 1024; } this.httpCompression = opts['httpCompression'] ?? {}; - if (!this.httpCompression .containsKey('threshold')) + if (!this.httpCompression.containsKey('threshold')) this.httpCompression['threshold'] = 1024; this.initialPacket = opts['initialPacket']; @@ -212,7 +219,8 @@ class Server extends Engine { //print('sid ${req.uri.queryParameters['sid']}'); if (req.uri.queryParameters['sid'] != null) { _logger.fine('setting new request for existing client'); - self.clients[req.uri.queryParameters['sid']].transport.onRequest(connect); + self.clients[req.uri.queryParameters['sid']].transport + .onRequest(connect); } else { self.handshake(req.uri.queryParameters['transport'], connect); } @@ -231,9 +239,9 @@ class Server extends Engine { var res = req.response; var isForbidden = !ServerErrorMessages.containsKey(code); if (isForbidden) { - res.statusCode = HttpStatus.FORBIDDEN; - res.headers.contentType = ContentType.JSON; - res.write(JSON.encode({ + res.statusCode = HttpStatus.forbidden; + res.headers.contentType = ContentType.json; + res.write(json.encode({ 'code': ServerErrors.FORBIDDEN, 'message': code ?? ServerErrorMessages[ServerErrors.FORBIDDEN] })); @@ -241,14 +249,14 @@ class Server extends Engine { } if (req.headers.value('origin') != null) { res.headers.add('Access-Control-Allow-Credentials', 'true'); - res.headers.add( - 'Access-Control-Allow-Origin', req.headers.value('origin')); + res.headers + .add('Access-Control-Allow-Origin', req.headers.value('origin')); } else { res.headers.add('Access-Control-Allow-Origin', '*'); } - res.statusCode = HttpStatus.BAD_REQUEST; + res.statusCode = HttpStatus.badRequest; res.write( - JSON.encode({'code': code, 'message': ServerErrorMessages[code]})); + json.encode({'code': code, 'message': ServerErrorMessages[code]})); } /** @@ -276,7 +284,7 @@ class Server extends Engine { var transport; var req = connect.request; try { - transport = Transports.newInstance(transportName, connect); + transport = Transports.newInstance(transportName, connect); if ('polling' == transportName) { transport.maxHttpBufferSize = this.maxHttpBufferSize; transport.httpCompression = this.httpCompression; @@ -298,10 +306,12 @@ class Server extends Engine { if (false != this.cookie) { transport.on('headers', (headers) { headers['Set-Cookie'] = '${this.cookie}=${Uri.encodeComponent(id)}' + - (this.cookiePath?.isNotEmpty == true ? '; Path=${this.cookiePath}' - : '') + - (this.cookiePath?.isNotEmpty && this.cookieHttpOnly == true ? '; HttpOnly' - : ''); + (this.cookiePath?.isNotEmpty == true + ? '; Path=${this.cookiePath}' + : '') + + (this.cookiePath?.isNotEmpty == true && this.cookieHttpOnly == true + ? '; HttpOnly' + : ''); }); } @@ -326,7 +336,6 @@ class Server extends Engine { handleUpgrade(SocketConnect connect) { // this.prepare(req); - var self = this; this.verify(connect, true, (err, success) { if (!success) { abortConnection(connect, err); @@ -407,11 +416,9 @@ class Server extends Engine { * @api public */ attachTo(StreamServer server, Map options) { - var self = this; options = options ?? {}; - var path = (options['path'] ?? '/engine.io').replaceFirst(new RegExp(r"\/$"), ''); - - var destroyUpgradeTimeout = options['destroyUpgradeTimeout'] ?? 1000; + var path = + (options['path'] ?? '/engine.io').replaceFirst(new RegExp(r"\/$"), ''); // normalize path path += '/'; @@ -420,21 +427,21 @@ class Server extends Engine { server.map('$path.*', (HttpConnect connect) async { var req = connect.request; - _logger.fine('intercepting request for path "$path"'); - if (WebSocketTransformer.isUpgradeRequest(req) && - this.transports.contains('websocket')) { + _logger.fine('intercepting request for path "$path"'); + if (WebSocketTransformer.isUpgradeRequest(req) && + this.transports.contains('websocket')) { // print('init websocket... ${req.uri}'); - var socket = await WebSocketTransformer.upgrade(req); - var socketConnect = new SocketConnect.fromWebSocket(connect, socket); - socketConnect.dataset['options'] = options; - this.handleUpgrade(socketConnect); - return socketConnect.done; - } else { - var socketConnect = new SocketConnect(connect); - socketConnect.dataset['options'] = options; - this.handleRequest(socketConnect); - return socketConnect.done; - } + var socket = await WebSocketTransformer.upgrade(req); + var socketConnect = new SocketConnect.fromWebSocket(connect, socket); + socketConnect.dataset['options'] = options; + this.handleUpgrade(socketConnect); + return socketConnect.done; + } else { + var socketConnect = new SocketConnect(connect); + socketConnect.dataset['options'] = options; + this.handleRequest(socketConnect); + return socketConnect.done; + } }, preceding: true); } @@ -448,16 +455,18 @@ class Server extends Engine { static abortConnection(SocketConnect connect, code) { var socket = connect.websocket; - if (socket.readyState == HttpStatus.OK) { + if (socket.readyState == HttpStatus.ok) { var message = ServerErrorMessages.containsKey(code) - ? ServerErrorMessages[code] : code; - var length = UTF8 - .encode(message) - .length; - socket.add('HTTP/1.1 400 Bad Request\r\n' + 'Connection: close\r\n' + - 'Content-type: text/html\r\n' + 'Content-Length: $length\r\n' + - '\r\n' + message); + ? ServerErrorMessages[code] + : code; + var length = utf8.encode(message).length; + socket.add('HTTP/1.1 400 Bad Request\r\n' + + 'Connection: close\r\n' + + 'Content-type: text/html\r\n' + + 'Content-Length: $length\r\n' + + '\r\n' + + message); } socket.close(); } -} \ No newline at end of file +} diff --git a/lib/src/engine/socket.dart b/lib/src/engine/socket.dart index fa0c400..15894f4 100644 --- a/lib/src/engine/socket.dart +++ b/lib/src/engine/socket.dart @@ -73,12 +73,13 @@ class Socket extends EventEmitter { // sends an `open` packet this.transport.sid = this.id; - this.sendPacket('open', data: JSON.encode({ - 'sid': this.id, - 'upgrades': this.getAvailableUpgrades(), - 'pingInterval': this.server.pingInterval, - 'pingTimeout': this.server.pingTimeout - })); + this.sendPacket('open', + data: json.encode({ + 'sid': this.id, + 'upgrades': this.getAvailableUpgrades(), + 'pingInterval': this.server.pingInterval, + 'pingTimeout': this.server.pingTimeout + })); // if (this.server.initialPacket != null) { // this.sendPacket('message', data: this.server.initialPacket); @@ -146,8 +147,10 @@ class Socket extends EventEmitter { if (this.pingTimeoutTimer != null) { this.pingTimeoutTimer.cancel(); } - this.pingTimeoutTimer = new Timer(new Duration( - milliseconds: this.server.pingInterval + this.server.pingTimeout), () { + this.pingTimeoutTimer = new Timer( + new Duration( + milliseconds: this.server.pingInterval + this.server.pingTimeout), + () { this.onClose('ping timeout'); }); } @@ -189,14 +192,14 @@ class Socket extends EventEmitter { * @api private */ maybeUpgrade(transport) { - _logger.fine('might upgrade socket transport from ${this.transport - .name} to ${transport.name}'); + _logger.fine( + 'might upgrade socket transport from ${this.transport.name} to ${transport.name}'); this.upgrading = true; Map cleanupFn = {}; // set transport upgrade timer this.upgradeTimeoutTimer = - new Timer(new Duration(milliseconds: this.server.upgradeTimeout), () { + new Timer(new Duration(milliseconds: this.server.upgradeTimeout), () { _logger.fine('client did not complete upgrade - closing transport'); cleanupFn['cleanup'](); if ('open' == transport.readyState) { @@ -208,19 +211,23 @@ class Socket extends EventEmitter { var check = () { if ('polling' == this.transport.name && this.transport.writable == true) { _logger.fine('writing a noop packet to polling for fast upgrade'); - this.transport.send([{ 'type': 'noop'}]); + this.transport.send([ + {'type': 'noop'} + ]); } }; var onPacket = (packet) { if ('ping' == packet['type'] && 'probe' == packet['data']) { - transport.send([{ 'type': 'pong', 'data': 'probe'}]); + transport.send([ + {'type': 'pong', 'data': 'probe'} + ]); this.emit('upgrading', transport); if (this.checkIntervalTimer != null) { this.checkIntervalTimer.cancel(); } this.checkIntervalTimer = - new Timer.periodic(new Duration(milliseconds: 100), (_) => check()); + new Timer.periodic(new Duration(milliseconds: 100), (_) => check()); } else if ('upgrade' == packet['type'] && this.readyState != 'closed') { _logger.fine('got upgrade packet - upgrading'); cleanupFn['cleanup'](); @@ -257,7 +264,6 @@ class Socket extends EventEmitter { onError('socket closed'); }; - var cleanup = () { this.upgrading = false; this.checkIntervalTimer?.cancel(); @@ -343,7 +349,8 @@ class Socket extends EventEmitter { if (seqFn is Function) { _logger.fine('executing send callback'); seqFn(this.transport); - } /** else if (Array.isArray(seqFn)) { + } + /** else if (Array.isArray(seqFn)) { _logger.fine('executing batch send callback'); for (var l = seqFn.length, i = 0; i < l; i++) { if ('function' === typeof seqFn[i]) { @@ -372,7 +379,8 @@ class Socket extends EventEmitter { */ send(data, options, [callback]) => write(data, options, callback); write(data, options, [callback]) { - this.sendPacket('message', data: data, options: options, callback: callback); + this.sendPacket('message', + data: data, options: options, callback: callback); return this; } @@ -412,7 +420,8 @@ class Socket extends EventEmitter { * @api private */ flush() { - if ('closed' != this.readyState && this.transport.writable == true && + if ('closed' != this.readyState && + this.transport.writable == true && this.writeBuffer.length > 0) { _logger.fine('flushing buffer to transport'); this.emit('flush', this.writeBuffer); @@ -478,4 +487,4 @@ class Socket extends EventEmitter { if (discard == true) this.transport.discard(); this.transport.close(() => this.onClose('forced close')); } -} \ No newline at end of file +} diff --git a/lib/src/engine/transport/jsonp_transport.dart b/lib/src/engine/transport/jsonp_transport.dart index 71d3e37..969a44c 100644 --- a/lib/src/engine/transport/jsonp_transport.dart +++ b/lib/src/engine/transport/jsonp_transport.dart @@ -11,16 +11,17 @@ * Copyright (C) 2017 Potix Corporation. All Rights Reserved. */ import 'dart:convert'; -import 'dart:io'; import 'package:socket_io/src/engine/connect.dart'; import 'package:socket_io/src/engine/transport/polling_transport.dart'; class JSONPTransport extends PollingTransport { String head; String foot; - JSONPTransport(SocketConnect connect): super(connect) { - - this.head = '___eio[' + (connect.request.uri.queryParameters['j'] ?? '').replaceAll(new RegExp('[^0-9]'), '') + ']('; + JSONPTransport(SocketConnect connect) : super(connect) { + this.head = '___eio[' + + (connect.request.uri.queryParameters['j'] ?? '') + .replaceAll(new RegExp('[^0-9]'), '') + + ']('; this.foot = ');'; } @@ -38,7 +39,6 @@ class JSONPTransport extends PollingTransport { // client will send already escaped newlines as \\\\n and newlines as \\n // \\n must be replaced with \n and \\\\n with \\n data = data.replaceAllMapped(new RegExp(r'(\\)?\\n'), (match) { - // TODO: need to verify the case. throw new UnimplementedError('Not implemented yet'); // print(match); // match @@ -56,7 +56,8 @@ class JSONPTransport extends PollingTransport { doWrite(data, options, [callback]) { // we must output valid javascript, not valid json // see: http://timelessrepo.com/json-isnt-a-javascript-subset - var js = JSON.encode(data) + var js = json + .encode(data) .replaceAll(new RegExp(r'\u2028'), '\\u2028') .replaceAll(new RegExp(r'\u2029'), '\\u2029'); @@ -83,4 +84,4 @@ class JSONPTransport extends PollingTransport { return result; } -} \ No newline at end of file +} diff --git a/lib/src/engine/transport/polling_transport.dart b/lib/src/engine/transport/polling_transport.dart index 44388c7..4aff834 100644 --- a/lib/src/engine/transport/polling_transport.dart +++ b/lib/src/engine/transport/polling_transport.dart @@ -25,7 +25,8 @@ class PollingTransport extends Transport { @override bool get supportsFraming => false; - static final Logger _logger = new Logger('socket_io:transport.PollingTransport'); + static final Logger _logger = + new Logger('socket_io:transport.PollingTransport'); int closeTimeout; Function shouldClose; SocketConnect dataReq; @@ -48,6 +49,7 @@ class PollingTransport extends Transport { res.close(); } } + Map _reqCleanups = {}; Map _reqCloses = {}; @@ -58,7 +60,7 @@ class PollingTransport extends Transport { */ onPollRequest(SocketConnect connect) { if (this.connect != null) { - _logger.fine('request overlap'); + _logger.fine('request overlap'); // assert: this.res, '.req and .res should be (un)set together' this.onError('overlap from client'); this.connect.response.statusCode = 500; @@ -66,7 +68,7 @@ class PollingTransport extends Transport { return; } - _logger.fine('setting request'); + _logger.fine('setting request'); this.connect = connect; @@ -82,14 +84,15 @@ class PollingTransport extends Transport { _reqCleanups[connect] = cleanup; _reqCloses[connect] = onClose; - this.writable = true; this.emit('drain'); // if we're still writable but had a pending close, trigger an empty send if (this.writable && this.shouldClose != null) { - _logger.fine('triggering empty send to append close packet'); - this.send([{ 'type': 'noop' }]); + _logger.fine('triggering empty send to append close packet'); + this.send([ + {'type': 'noop'} + ]); } } @@ -107,7 +110,8 @@ class PollingTransport extends Transport { return; } - var isBinary = 'application/octet-stream' == connect.request.headers.value('content-type'); + var isBinary = 'application/octet-stream' == + connect.request.headers.value('content-type'); this.dataReq = connect; @@ -122,23 +126,19 @@ class PollingTransport extends Transport { self.dataReq = null; }; - var onClose = () { - cleanup(); - self.onError('data request connection closed prematurely'); - }; - var onData = (List data) { var contentLength; if (data is String) { chunks += data; - contentLength = UTF8 - .encode(chunks) - .length; + contentLength = utf8.encode(chunks).length; } else { if (chunks is String) { chunks += new String.fromCharCodes(data); } else { - chunks.addAll(new String.fromCharCodes(data).split(',').map((s) => int.parse(s)).toList()); + chunks.addAll(new String.fromCharCodes(data) + .split(',') + .map((s) => int.parse(s)) + .toList()); } contentLength = chunks.length; } @@ -152,10 +152,7 @@ class PollingTransport extends Transport { var onEnd = () { self.onData(chunks); - var headers = { - 'Content-Type': 'text/html', - 'Content-Length': 2 - }; + var headers = {'Content-Type': 'text/html', 'Content-Length': 2}; HttpResponse res = connect.response; @@ -172,12 +169,10 @@ class PollingTransport extends Transport { cleanup(); }; - subscription = connect.request.listen( - onData, - onDone: onEnd); + subscription = connect.request.listen(onData, onDone: onEnd); if (!isBinary) { - connect.response.headers.contentType - = ContentType.TEXT; // for encoding utf-8 + connect.response.headers.contentType = + ContentType.text; // for encoding utf-8 } } @@ -193,7 +188,7 @@ class PollingTransport extends Transport { messageHandler.handle(this, data); } else { var self = this; - var callback = (Map packet, [foo, bar]) { + var callback = (packet, [foo, bar]) { if ('close' == packet['type']) { _logger.fine('got xhr close packet'); self.onClose(); @@ -215,7 +210,9 @@ class PollingTransport extends Transport { onClose() { if (this.writable == true) { // close pending poll request - this.send([{ 'type': 'noop' }]); + this.send([ + {'type': 'noop'} + ]); } super.onClose(); } @@ -231,15 +228,15 @@ class PollingTransport extends Transport { if (this.shouldClose != null) { _logger.fine('appending close packet to payload'); - packets.add({ 'type': 'close' }); + packets.add({'type': 'close'}); this.shouldClose(); this.shouldClose = null; } var self = this; - PacketParser.encodePayload( - packets, supportsBinary: this.supportsBinary, callback: (data) { - var compress = packets.any((Map packet) { + PacketParser.encodePayload(packets, supportsBinary: this.supportsBinary, + callback: (data) { + var compress = packets.any((packet) { var opt = packet['options']; return opt != null && opt['compress'] == true; }); @@ -258,8 +255,7 @@ class PollingTransport extends Transport { _logger.fine('writing "$data"'); this.doWrite(data, options, () { Function fn = _reqCleanups.remove(this.connect); - if (fn != null) - fn(); + if (fn != null) fn(); }); } @@ -273,16 +269,14 @@ class PollingTransport extends Transport { // explicit UTF-8 is required for pages not served under utf var isString = data is String; - var contentType = isString - ? 'text/plain; charset=UTF-8' - : 'application/octet-stream'; + var contentType = + isString ? 'text/plain; charset=UTF-8' : 'application/octet-stream'; - var headers = { - 'Content-Type': contentType - }; + var headers = {'Content-Type': contentType}; var respond = (data) { - headers[HttpHeaders.CONTENT_LENGTH] = data is String ? UTF8.encode(data).length : data.length; + headers[HttpHeaders.contentLengthHeader] = + data is String ? utf8.encode(data).length : data.length; HttpResponse res = self.connect.response; res.statusCode = 200; @@ -292,21 +286,19 @@ class PollingTransport extends Transport { }); try { if (data is String) { - res - .write(data); + res.write(data); connect.close(); } else { - if (headers.containsKey(HttpHeaders.CONTENT_ENCODING)) { + if (headers.containsKey(HttpHeaders.contentEncodingHeader)) { res.add(data); } else { res.write(new String.fromCharCodes(data)); } - connect.close(); + connect.close(); } } catch (e) { Function fn = _reqCloses.remove(connect); - if (fn != null) - fn(); + if (fn != null) fn(); rethrow; } callback(); @@ -317,20 +309,20 @@ class PollingTransport extends Transport { return; } - var len = isString ? UTF8.encode(data).length : data.length; + var len = isString ? utf8.encode(data).length : data.length; if (len < this.httpCompression['threshold']) { respond(data); return; } - - var encodings = this.connect.request.headers.value(HttpHeaders.ACCEPT_ENCODING); - var gzip = encodings.contains('gzip'); - if (!gzip && !encodings.contains('deflate')) { + var encodings = + this.connect.request.headers.value(HttpHeaders.acceptEncodingHeader); + var hasGzip = encodings.contains('gzip'); + if (!hasGzip && !encodings.contains('deflate')) { respond(data); return; } - var encoding = gzip ? 'gzip' : 'deflate'; + var encoding = hasGzip ? 'gzip' : 'deflate'; // this.compress(data, encoding, (err, data) { // if (err != null) { // self.req.response..statusCode = 500..close(); @@ -338,8 +330,11 @@ class PollingTransport extends Transport { // return; // } - headers[HttpHeaders.CONTENT_ENCODING] = encoding; - respond(gzip ? GZIP.encode(UTF8.encode(data is List ? new String.fromCharCodes(data as List) : data)) : data); + headers[HttpHeaders.contentEncodingHeader] = encoding; + respond(hasGzip + ? gzip.encode(utf8.encode( + data is List ? new String.fromCharCodes(data as List) : data)) + : data); // }); } @@ -355,29 +350,29 @@ class PollingTransport extends Transport { Timer closeTimeoutTimer; if (this.dataReq != null) { - _logger.fine('aborting ongoing data request'); + _logger.fine('aborting ongoing data request'); this.dataReq = null; } - var onClose = () { - if (closeTimeoutTimer != null) - closeTimeoutTimer.cancel(); - if (fn != null) - fn(); + if (closeTimeoutTimer != null) closeTimeoutTimer.cancel(); + if (fn != null) fn(); self.onClose(); }; if (this.writable == true) { - _logger.fine('transport writable - closing right away'); - this.send([{ 'type': 'close' }]); + _logger.fine('transport writable - closing right away'); + this.send([ + {'type': 'close'} + ]); onClose(); } else if (this.discarded) { - _logger.fine('transport discarded - closing right away'); + _logger.fine('transport discarded - closing right away'); onClose(); } else { - _logger.fine('transport not writable - buffering orderly close'); + _logger.fine('transport not writable - buffering orderly close'); this.shouldClose = onClose; - closeTimeoutTimer = new Timer(new Duration(milliseconds: this.closeTimeout), onClose); + closeTimeoutTimer = + new Timer(new Duration(milliseconds: this.closeTimeout), onClose); } } @@ -394,11 +389,12 @@ class PollingTransport extends Transport { // prevent XSS warnings on IE // https://github.com/LearnBoost/socket.io/pull/1333 var ua = connect.request.headers.value('user-agent'); - if (ua != null && (ua.indexOf(';MSIE') >= 0 || ua.indexOf('Trident/') >= 0)) { + if (ua != null && + (ua.indexOf(';MSIE') >= 0 || ua.indexOf('Trident/') >= 0)) { headers['X-XSS-Protection'] = '0'; } this.emit('headers', headers); return headers; } -} \ No newline at end of file +} diff --git a/lib/src/engine/transport/transports.dart b/lib/src/engine/transport/transports.dart index 1dbc0eb..ed71bb8 100644 --- a/lib/src/engine/transport/transports.dart +++ b/lib/src/engine/transport/transports.dart @@ -1,4 +1,3 @@ -import 'dart:collection'; /** * transports.dart * @@ -11,8 +10,6 @@ import 'dart:collection'; * * Copyright (C) 2017 Potix Corporation. All Rights Reserved. */ -import 'dart:io'; - import 'package:logging/logging.dart'; import 'package:socket_io/src/engine/connect.dart'; import 'package:socket_io/src/engine/parser/parser.dart'; @@ -20,7 +17,6 @@ import 'package:socket_io/src/engine/transport/jsonp_transport.dart'; import 'package:socket_io/src/engine/transport/websocket_transport.dart'; import 'package:socket_io/src/engine/transport/xhr_transport.dart'; import 'package:socket_io/src/util/event_emitter.dart'; -import 'dart:async'; class Transports { static List upgradesTo(String from) { @@ -33,7 +29,7 @@ class Transports { static Transport newInstance(String name, SocketConnect connect) { if ('websocket' == name) { return new WebSocketTransport(connect); - } else if ('polling' == name ) { + } else if ('polling' == name) { if (connect.request.uri.queryParameters.containsKey('j')) { return new JSONPTransport(connect); } else { @@ -64,7 +60,9 @@ abstract class Transport extends EventEmitter { this.discarded = false; var options = connect.dataset['options']; if (options != null) { - messageHandler = options.containsKey('messageHandlerFactory') ? options['messageHandlerFactory'](this, connect) : null; + messageHandler = options.containsKey('messageHandlerFactory') + ? options['messageHandlerFactory'](this, connect) + : null; } } @@ -114,9 +112,8 @@ abstract class Transport extends EventEmitter { bool get supportsFraming; bool get handlesUpgrades; - } abstract class MessageHandler { void handle(Transport transport, /*String|List*/ message); -} \ No newline at end of file +} diff --git a/lib/src/engine/transport/websocket_transport.dart b/lib/src/engine/transport/websocket_transport.dart index 2094893..8235738 100644 --- a/lib/src/engine/transport/websocket_transport.dart +++ b/lib/src/engine/transport/websocket_transport.dart @@ -20,10 +20,11 @@ class WebSocketTransport extends Transport { bool get handlesUpgrades => true; bool get supportsFraming => true; StreamSubscription subscription; - WebSocketTransport(connect): super(connect) { + WebSocketTransport(connect) : super(connect) { this.name = 'websocket'; this.connect = connect; - subscription = connect.websocket.listen(this.onData, onError: this.onError, onDone: this.onClose); + subscription = connect.websocket + .listen(this.onData, onError: this.onError, onDone: this.onClose); writable = true; } @@ -55,9 +56,12 @@ class WebSocketTransport extends Transport { // } for (var i = 0; i < packets.length; i++) { var packet = packets[i]; - PacketParser.encodePacket(packet, supportsBinary: this.supportsBinary, callback: (_) => send(_, packet)); + PacketParser.encodePacket(packet, + supportsBinary: this.supportsBinary, + callback: (_) => send(_, packet)); } } + void onClose() { super.onClose(); @@ -67,9 +71,9 @@ class WebSocketTransport extends Transport { subscription = null; } } + void doClose([fn]) { this.connect.websocket.close(); - if (fn != null) - fn(); + if (fn != null) fn(); } -} \ No newline at end of file +} diff --git a/lib/src/engine/transport/xhr_transport.dart b/lib/src/engine/transport/xhr_transport.dart index 15de118..7888ba2 100644 --- a/lib/src/engine/transport/xhr_transport.dart +++ b/lib/src/engine/transport/xhr_transport.dart @@ -15,7 +15,7 @@ import 'package:socket_io/src/engine/connect.dart'; import 'package:socket_io/src/engine/transport/polling_transport.dart'; class XHRTransport extends PollingTransport { - XHRTransport(SocketConnect connect): super(connect); + XHRTransport(SocketConnect connect) : super(connect); /** * Overrides `onRequest` to handle `OPTIONS`.. @@ -49,13 +49,13 @@ class XHRTransport extends PollingTransport { */ headers(SocketConnect connect, [Map headers]) { headers = headers ?? {}; - var req = connect.request; - if (req.headers.value('origin') != null) { - headers['Access-Control-Allow-Credentials'] = 'true'; - headers['Access-Control-Allow-Origin'] = req.headers.value('origin'); - } else { - headers['Access-Control-Allow-Origin'] = '*'; - } + var req = connect.request; + if (req.headers.value('origin') != null) { + headers['Access-Control-Allow-Credentials'] = 'true'; + headers['Access-Control-Allow-Origin'] = req.headers.value('origin'); + } else { + headers['Access-Control-Allow-Origin'] = '*'; + } return super.headers(connect, headers); } -} \ No newline at end of file +} diff --git a/lib/src/namespace.dart b/lib/src/namespace.dart index 06c48a2..16184dd 100644 --- a/lib/src/namespace.dart +++ b/lib/src/namespace.dart @@ -23,8 +23,9 @@ import 'package:socket_io/src/util/event_emitter.dart'; * Blacklisted events. */ -List events = ['connect', // for symmetry with client -'connection', 'newListener' +List events = [ + 'connect', // for symmetry with client + 'connection', 'newListener' ]; /** @@ -188,8 +189,6 @@ class Namespace extends EventEmitter { if (events.contains(ev)) { super.emit(ev, arg); } else { - // set up packet object - var parserType = EVENT; // default // @todo check how to handle it with Dart // if (hasBin(args)) { parserType = ParserType.binaryEvent; } // binary @@ -197,10 +196,9 @@ class Namespace extends EventEmitter { Map packet = {'type': EVENT, 'data': data}; - this.adapter.broadcast(packet, { - 'rooms': this.rooms, - 'flags': this.flags - }); + this + .adapter + .broadcast(packet, {'rooms': this.rooms, 'flags': this.flags}); this.rooms = null; this.flags = null; diff --git a/lib/src/parser/binary.dart b/lib/src/parser/binary.dart index 1c65638..6969ab3 100644 --- a/lib/src/parser/binary.dart +++ b/lib/src/parser/binary.dart @@ -1,26 +1,21 @@ -// Copyright (C) 2018 Potix Corporation. All Rights Reserved +// Copyright (C) 2018 Potix Corporation. All Rights Reserved // History: 2018/6/1 12:31 PM // Author: jumperchen import 'dart:typed_data'; class Binary { - - static final String KEY_PLACEHOLDER = "_placeholder"; + static final String KEY_PLACEHOLDER = "_placeholder"; static final String KEY_NUM = "num"; - static Map deconstructPacket(Map packet) { List buffers = []; packet['data'] = _deconstructPacket(packet['data'], buffers); packet['attachments'] = buffers.length; - final result = { - 'packet': packet, - 'buffers': buffers - }; + final result = {'packet': packet, 'buffers': buffers}; return result; } @@ -35,7 +30,7 @@ class Binary { final newData = []; final _data = data; int len = _data.length; - for (int i = 0; i < len; i ++) { + for (int i = 0; i < len; i++) { newData.add(_deconstructPacket(_data[i], buffers)); } return newData; @@ -68,7 +63,7 @@ class Binary { final _data = data; if ('${_data[KEY_PLACEHOLDER]}'.toLowerCase() == 'true') { final knum = _data[KEY_NUM]; - int num = knum is int ? knum : int.parse(_data[KEY_NUM], onError: (_) => -1).toInt(); + int num = knum is int ? knum : int.parse(_data[KEY_NUM]).toInt(); return num >= 0 && num < buffers.length ? buffers[num] : null; } data.forEach((key, value) { @@ -78,4 +73,4 @@ class Binary { } return data; } -} \ No newline at end of file +} diff --git a/lib/src/parser/parser.dart b/lib/src/parser/parser.dart index 686d8a2..2193d59 100644 --- a/lib/src/parser/parser.dart +++ b/lib/src/parser/parser.dart @@ -30,18 +30,17 @@ const int BINARY_ACK = 6; * @api public */ -List PacketTypes = [ -'CONNECT', -'DISCONNECT', -'EVENT', -'ACK', -'ERROR', -'BINARY_EVENT', -'BINARY_ACK' +List PacketTypes = [ + 'CONNECT', + 'DISCONNECT', + 'EVENT', + 'ACK', + 'ERROR', + 'BINARY_EVENT', + 'BINARY_ACK' ]; class Encoder { - static final Logger _logger = new Logger('socket_io:parser.Encoder'); /** @@ -78,9 +77,9 @@ class Encoder { var str = '${obj['type']}'; // attachments if we have them - if (BINARY_EVENT == obj['type'] || BINARY_ACK == obj['type']) { - str += '${obj['attachments']}-'; - } + if (BINARY_EVENT == obj['type'] || BINARY_ACK == obj['type']) { + str += '${obj['attachments']}-'; + } // if we have a namespace other than `/` // we append it followed by a comma `,` @@ -95,7 +94,7 @@ class Encoder { // json data if (null != obj['data']) { - str += JSON.encode(obj['data']); + str += json.encode(obj['data']); } _logger.fine('encoded $obj as $str'); @@ -112,20 +111,19 @@ class Encoder { * @api private */ -static encodeAsBinary(obj, callback) { - - var writeEncoding = (bloblessData) { - var deconstruction = Binary.deconstructPacket(bloblessData); - var pack = encodeAsString(deconstruction['packet']); - var buffers = deconstruction['buffers']; + static encodeAsBinary(obj, callback) { + var writeEncoding = (bloblessData) { + var deconstruction = Binary.deconstructPacket(bloblessData); + var pack = encodeAsString(deconstruction['packet']); + var buffers = deconstruction['buffers']; - // add packet info to beginning of data list - callback([pack]..addAll(buffers)); // write all the buffers - }; + // add packet info to beginning of data list + callback([pack]..addAll(buffers)); // write all the buffers + }; // // binary.removeBlobs(obj, writeEncoding); - writeEncoding(obj); -} + writeEncoding(obj); + } } /** @@ -148,25 +146,29 @@ class Decoder extends EventEmitter { var packet; if (obj is String) { packet = decodeString(obj); - if (BINARY_EVENT == packet['type'] || - BINARY_ACK == packet['type']) { // binary packet's json + if (BINARY_EVENT == packet['type'] || BINARY_ACK == packet['type']) { + // binary packet's json this.reconstructor = new BinaryReconstructor(packet); // no attachments, labeled binary but no binary data to follow if (this.reconstructor.reconPack['attachments'] == 0) { this.emit('decoded', packet); } - } else { // non-binary full packet + } else { + // non-binary full packet this.emit('decoded', packet); } - } else if (obj is ByteBuffer || obj is Uint8List || - obj is Map && obj['base64'] != null) { // raw binary data + } else if (obj is ByteBuffer || + obj is Uint8List || + obj is Map && obj['base64'] != null) { + // raw binary data if (this.reconstructor == null) { throw new UnsupportedError( 'got binary data when not reconstructing a packet'); } else { packet = this.reconstructor.takeBinaryData(obj); - if (packet != null) { // received final buffer + if (packet != null) { + // received final buffer this.reconstructor = null; this.emit('decoded', packet); } @@ -188,9 +190,7 @@ class Decoder extends EventEmitter { var i = 0; var endLen = str.length - 1; // look up type - var p = { - 'type': num.parse(str[0]) - }; + var p = {'type': num.parse(str[0])}; if (null == PacketTypes[p['type']]) return error(); @@ -201,7 +201,7 @@ class Decoder extends EventEmitter { buf += str[i]; if (i == endLen) break; } - if (buf != '${num.parse(buf, (_) => -1)}' || str[i] != '-') { + if (buf != '${num.parse(buf)}' || str[i] != '-') { throw new ArgumentError('Illegal attachments'); } p['attachments'] = num.parse(buf); @@ -222,22 +222,22 @@ class Decoder extends EventEmitter { // look up id var next = i < endLen - 1 ? str[i + 1] : null; - if (next?.isNotEmpty == true && '${num.parse(next, (e) => null)}' == next) { - p['id'] = ''; - while (++i > 0) { - var c = str[i]; - if (null == c || '${num.parse(c, (e) => null)}' != c ) { - --i; - break; + if (next?.isNotEmpty == true && '${num.parse(next)}' == next) { + p['id'] = ''; + while (++i > 0) { + var c = str[i]; + if (null == c || '${num.parse(c)}' != c) { + --i; + break; + } + p['id'] += str[i]; + if (i == endLen - 1) break; } - p['id'] += str[i]; - if (i == endLen - 1) break; - } // p['id'] = p['id']; } // look up json data - if (i < endLen - 1 && str[++i]?.isNotEmpty) { + if (i < endLen - 1 && str[++i]?.isNotEmpty == true) { p = tryParse(p, str.substring(i)); } @@ -245,17 +245,15 @@ class Decoder extends EventEmitter { return p; } - static tryParse(p, str) { try { - p['data'] = JSON.decode(str); - } catch(e){ + p['data'] = json.decode(str); + } catch (e) { return error(); } return p; } - /** * Deallocates a parser's resources * @@ -297,8 +295,8 @@ class BinaryReconstructor { */ takeBinaryData(binData) { this.buffers.add(binData); - if (this.buffers.length == - this.reconPack['attachments']) { // done with buffer list + if (this.buffers.length == this.reconPack['attachments']) { + // done with buffer list var packet = Binary.reconstructPacket(this.reconPack, this.buffers); this.finishedReconstruction(); return packet; @@ -317,8 +315,5 @@ class BinaryReconstructor { } Map error() { - return { - 'type': ERROR, - 'data': 'parser error' - }; -} \ No newline at end of file + return {'type': ERROR, 'data': 'parser error'}; +} diff --git a/lib/src/server.dart b/lib/src/server.dart index a1a1b70..db65d70 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -17,6 +17,7 @@ import 'package:socket_io/src/engine/engine.dart'; import 'package:socket_io/src/namespace.dart'; import 'package:socket_io/src/parser/parser.dart'; import 'package:stream/stream.dart'; + /** * Socket.IO client source. */ @@ -56,7 +57,8 @@ class Server { this.nsps = {}; this.path(options.containsKey('path') ? options['path'] : '/socket.io'); this.serveClient(false != options['serveClient']); - this.adapter = options.containsKey('adapter') ? options['adapter'] : 'default'; + this.adapter = + options.containsKey('adapter') ? options['adapter'] : 'default'; this.origins(options.containsKey('origins') ? options['origins'] : '*:*'); this.encoder = new Encoder(); this.sockets = this.of('/'); @@ -72,8 +74,9 @@ class Server { * @param {Function} callback to be called with the result: `fn(err, success)` */ checkRequest(HttpRequest req, [Function fn]) { - String origin = req.headers.value('origin') != null ? req.headers.value( - 'origin') : req.headers.value('referer'); + String origin = req.headers.value('origin') != null + ? req.headers.value('origin') + : req.headers.value('referer'); // file:// URLs produce a null Origin which can't be authorized via echo-back if (origin == null || origin.isEmpty) { @@ -93,9 +96,10 @@ class Server { Uri parts = Uri.parse(origin); int defaultPort = 'https:' == parts.scheme ? 443 : 80; int port = parts.port != null ? parts.port : defaultPort; - bool ok = this._origins.indexOf(parts.host + ':' + port.toString()) >= - 0 || this._origins.indexOf(parts.host + ':*') >= 0 || - this._origins.indexOf('*:' + port.toString()) >= 0; + bool ok = + this._origins.indexOf(parts.host + ':' + port.toString()) >= 0 || + this._origins.indexOf(parts.host + ':*') >= 0 || + this._origins.indexOf('*:' + port.toString()) >= 0; return fn(null, ok); } catch (ex) {} @@ -131,7 +135,8 @@ class Server { val(socket.request, (err, authorized) { if (err) { return next(new Exception(err)); - }; + } + ; if (!authorized) { return next(new Exception('Not authorized')); } @@ -253,28 +258,28 @@ class Server { //// response.close(); //// }); - var connectPacket = { 'type': CONNECT, 'nsp': '/'}; - this.encoder.encode(connectPacket, (encodedPacket) { - // the CONNECT packet will be merged with Engine.IO handshake, - // to reduce the number of round trips - opts['initialPacket'] = encodedPacket; + var connectPacket = {'type': CONNECT, 'nsp': '/'}; + this.encoder.encode(connectPacket, (encodedPacket) { + // the CONNECT packet will be merged with Engine.IO handshake, + // to reduce the number of round trips + opts['initialPacket'] = encodedPacket; - _logger.fine('creating engine.io instance with opts $opts'); - // initialize engine - this.engine = Engine.attach(server, opts); + _logger.fine('creating engine.io instance with opts $opts'); + // initialize engine + this.engine = Engine.attach(server, opts); - // attach static file serving + // attach static file serving // if (self._serveClient) self.attachServe(srv); - // Export http server - this.httpServer = server; + // Export http server + this.httpServer = server; - // bind to engine events - this.bind(this.engine); - }); + // bind to engine events + this.bind(this.engine); + }); // }); } else { - var connectPacket = { 'type': CONNECT, 'nsp': '/'}; + var connectPacket = {'type': CONNECT, 'nsp': '/'}; this.encoder.encode(connectPacket, (encodedPacket) { // the CONNECT packet will be merged with Engine.IO handshake, // to reduce the number of round trips @@ -429,4 +434,3 @@ class Server { once(event, handler) => sockets.once(event, handler); off(event, handler) => sockets.off(event, handler); } - diff --git a/lib/src/socket.dart b/lib/src/socket.dart index 169e4ed..356bc7e 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -29,7 +29,12 @@ import 'package:socket_io/src/util/event_emitter.dart'; * @api public */ -List events = ['error', 'connect', 'disconnect', 'newListener', 'removeListener' +List events = [ + 'error', + 'connect', + 'disconnect', + 'newListener', + 'removeListener' ]; /** @@ -40,13 +45,14 @@ List events = ['error', 'connect', 'disconnect', 'newListener', 'removeListener' List flags = ['json', 'volatile', 'broadcast']; const List EVENTS = const [ -'error', -'connect', -'disconnect', -'disconnecting', -'newListener', -'removeListener' + 'error', + 'connect', + 'disconnect', + 'disconnecting', + 'newListener', + 'removeListener' ]; + class Socket extends EventEmitter { // ignore: undefined_class Namespace nsp; @@ -82,18 +88,19 @@ class Socket extends EventEmitter { * @api private */ buildHandshake(query) { - final buildQuery = () { var requestQuery = this.request.uri.queryParameters; //if socket-specific query exist, replace query strings in requestQuery - return query != null ? (new Map.from(query)..addAll(requestQuery)) : requestQuery; + return query != null + ? (new Map.from(query)..addAll(requestQuery)) + : requestQuery; }; return { 'headers': this.request.headers, 'time': new DateTime.now().toString(), 'address': this.conn.remoteAddress, 'xdomain': this.request.headers.value('origin') != null, - // TODO 'secure': ! !this.request.connectionInfo.encrypted, + // TODO 'secure': ! !this.request.connectionInfo.encrypted, 'issued': new DateTime.now().millisecondsSinceEpoch, 'url': this.request.uri.path, 'query': buildQuery() @@ -132,7 +139,8 @@ class Socket extends EventEmitter { * @return {Socket} self * @api public */ - void emitWithAck(String event, dynamic data, {Function ack, bool binary = false}) { + void emitWithAck(String event, dynamic data, + {Function ack, bool binary = false}) { if (EVENTS.contains(event)) { super.emit(event, data); } else { @@ -143,7 +151,8 @@ class Socket extends EventEmitter { if (ack != null) { if (this.roomList.isNotEmpty || flags['broadcast'] == true) { - throw new UnsupportedError('Callbacks are not supported when broadcasting'); + throw new UnsupportedError( + 'Callbacks are not supported when broadcasting'); } this.acks['${this.nsp.ids}'] = ack; @@ -153,14 +162,16 @@ class Socket extends EventEmitter { packet['type'] = binary ? BINARY_EVENT : EVENT; packet['data'] = sendData; - if (this.roomList.isNotEmpty || flags['broadcast'] == true) { - this.adapter.broadcast( - packet, {'except': [this.id], 'rooms': this.roomList, 'flags': flags}); + this.adapter.broadcast(packet, { + 'except': [this.id], + 'rooms': this.roomList, + 'flags': flags + }); } else { // dispatch packet - this.packet( - packet, {'volatile': flags['volatile'], compress: flags['compress']}); + this.packet(packet, + {'volatile': flags['volatile'], compress: flags['compress']}); } // // reset flags @@ -190,7 +201,7 @@ class Socket extends EventEmitter { * @api public */ send(_) { - this.write(_); + this.write(_); } write(List data) { @@ -206,7 +217,6 @@ class Socket extends EventEmitter { * @api private */ packet(packet, [opts]) { - // ignore preEncoded = true. if (packet is Map) { packet['nsp'] = this.nsp.name; @@ -234,8 +244,7 @@ class Socket extends EventEmitter { if (err != null) return fn?.call(err); // _logger.info('joined room %s', room); this.roomMap[room] = room; - if (fn != null) - fn(null); + if (fn != null) fn(null); }); return this; } @@ -281,7 +290,7 @@ class Socket extends EventEmitter { // debug('socket connected - writing packet'); this.nsp.connected[this.id] = this; this.join(this.id); - this.packet({ 'type': CONNECT}); + this.packet({'type': CONNECT}); } /** @@ -356,8 +365,12 @@ class Socket extends EventEmitter { // var args = Array.prototype.slice.call(arguments); // debug('sending ack %j', args); - var type = /*hasBin(args) ? parser.BINARY_ACK : parser.*/ACK; - packet({'id': id, 'type': type, 'data': [_]}); + var type = /*hasBin(args) ? parser.BINARY_ACK : parser.*/ ACK; + packet({ + 'id': id, + 'type': type, + 'data': [_] + }); sent = true; }; } @@ -393,8 +406,7 @@ class Socket extends EventEmitter { * @api private */ onerror(err) { - if (this - .hasListeners('error')) { + if (this.hasListeners('error')) { this.emit('error', err); } else { // console.error('Missing error handler on `socket`.'); @@ -429,7 +441,7 @@ class Socket extends EventEmitter { * @api private */ error(err) { - this.packet({ 'type': ERROR, 'data': err}); + this.packet({'type': ERROR, 'data': err}); } /** @@ -445,7 +457,7 @@ class Socket extends EventEmitter { if (close == true) { this.client.disconnect(); } else { - this.packet({ 'type': DISCONNECT}); + this.packet({'type': DISCONNECT}); this.onclose('server namespace disconnect'); } return this; @@ -464,15 +476,3 @@ class Socket extends EventEmitter { return this; } } - - - - - - - - - - - - diff --git a/lib/src/util/event_emitter.dart b/lib/src/util/event_emitter.dart index b4abca8..bb952b0 100644 --- a/lib/src/util/event_emitter.dart +++ b/lib/src/util/event_emitter.dart @@ -35,7 +35,7 @@ class EventEmitter { * Constructor */ EventEmitter() { - this._events = new HashMap>(); + this._events = new HashMap>(); this._eventsOnce = new HashMap>(); } @@ -48,7 +48,7 @@ class EventEmitter { // todo: try to optimize this. Maybe remember the off() handlers and remove later? // handler might be off() inside handler; make a copy first final list = list0 != null ? new List.from(list0) : null; - list?.forEach((EventHandler handler) { + list?.forEach((handler) { handler(data); }); diff --git a/pubspec.yaml b/pubspec.yaml index 6bc1b4a..9fa2656 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,12 +5,11 @@ author: jumperchen homepage: https://www.zkoss.org environment: - sdk: '>=1.0.0' + sdk: ">=2.0.0-dev.68.0 <3.0.0" dependencies: - logging: '>=0.11.3+1 <0.12.0' - stream: '>=1.6.6+1 <2.0.0' - uuid: '>=0.5.3 <0.6.0' + logging: ^0.11.3+2 + stream: ^2.1.0 + uuid: "1.0.3" dev_dependencies: - unittest: any - test: '>=0.12.0 <0.13.0' + test: ">=1.3.0 <2.0.0" diff --git a/test/socket.test.dart b/test/socket.test.dart index be0a636..a13e920 100644 --- a/test/socket.test.dart +++ b/test/socket.test.dart @@ -17,24 +17,23 @@ import 'package:socket_io/socket_io.dart'; main() { group('Socket IO', () { test('Start standalone server', () async { - - var io = new Server(); - var nsp = io.of('/some'); - nsp.on('connection', (Socket client) { - print('connection /some'); - client.on('msg', (data) { - print('data from /some => $data'); - client.emit('fromServer', "ok 2"); - }); + var io = new Server(); + var nsp = io.of('/some'); + nsp.on('connection', (client) { + print('connection /some'); + client.on('msg', (data) { + print('data from /some => $data'); + client.emit('fromServer', "ok 2"); }); - io.on('connection', (Socket client) { - print('connection default namespace'); - client.on('msg', (data) { - print('data from default => $data'); - client.emit('fromServer', "ok"); - }); + }); + io.on('connection', (client) { + print('connection default namespace'); + client.on('msg', (data) { + print('data from default => $data'); + client.emit('fromServer', "ok"); }); - io.listen(3000); + }); + io.listen(3000); }); }); -} \ No newline at end of file +} From e3bf03d4efe4109cf4379ce9f2b21f6e7a12700f Mon Sep 17 00:00:00 2001 From: Jumper Chen Date: Tue, 20 Nov 2018 12:38:08 +0800 Subject: [PATCH 2/2] fix type error at runtime. --- lib/src/client.dart | 6 +++--- lib/src/engine/parser/parser.dart | 2 +- lib/src/engine/socket.dart | 2 +- lib/src/engine/transport/polling_transport.dart | 2 +- lib/src/parser/parser.dart | 6 +++--- lib/src/socket.dart | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index 0f1284c..6bd995e 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -64,7 +64,7 @@ class Client { connect(name, [query]) { _logger.fine('connecting to namespace $name'); if (!this.server.nsps.containsKey(name)) { - this.packet({'type': ERROR, 'nsp': name, 'data': 'Invalid namespace'}); + this.packet({'type': ERROR, 'nsp': name, 'data': 'Invalid namespace'}); return; } var nsp = this.server.of(name); @@ -174,8 +174,8 @@ class Client { // try/catch is needed for protocol violations (GH-1880) try { this.decoder.add(data); - } catch (e) { - _logger.severe(e, (e as Error).stackTrace); + } catch (e, st) { + _logger.severe(e, st); this.onerror(e); } } diff --git a/lib/src/engine/parser/parser.dart b/lib/src/engine/parser/parser.dart index 81cbe00..a62bd64 100644 --- a/lib/src/engine/parser/parser.dart +++ b/lib/src/engine/parser/parser.dart @@ -256,7 +256,7 @@ class PacketParser { continue; } - if (length.isEmpty || (length != '${(n = num.parse(length))}')) { + if (length.isEmpty || (length != '${(n = num.tryParse(length))}')) { // parser error - ignoring payload return callback(ERROR, 0, 1); } diff --git a/lib/src/engine/socket.dart b/lib/src/engine/socket.dart index 15894f4..e3f76be 100644 --- a/lib/src/engine/socket.dart +++ b/lib/src/engine/socket.dart @@ -96,7 +96,7 @@ class Socket extends EventEmitter { * @api private */ - onPacket(Map packet) { + onPacket(packet) { if ('open' == this.readyState) { // export packet event _logger.fine('packet'); diff --git a/lib/src/engine/transport/polling_transport.dart b/lib/src/engine/transport/polling_transport.dart index 4aff834..5c1b51e 100644 --- a/lib/src/engine/transport/polling_transport.dart +++ b/lib/src/engine/transport/polling_transport.dart @@ -272,7 +272,7 @@ class PollingTransport extends Transport { var contentType = isString ? 'text/plain; charset=UTF-8' : 'application/octet-stream'; - var headers = {'Content-Type': contentType}; + final Map headers = {'Content-Type': contentType}; var respond = (data) { headers[HttpHeaders.contentLengthHeader] = diff --git a/lib/src/parser/parser.dart b/lib/src/parser/parser.dart index 2193d59..34af93b 100644 --- a/lib/src/parser/parser.dart +++ b/lib/src/parser/parser.dart @@ -201,7 +201,7 @@ class Decoder extends EventEmitter { buf += str[i]; if (i == endLen) break; } - if (buf != '${num.parse(buf)}' || str[i] != '-') { + if (buf != '${num.tryParse(buf) ?? -1}' || str[i] != '-') { throw new ArgumentError('Illegal attachments'); } p['attachments'] = num.parse(buf); @@ -222,11 +222,11 @@ class Decoder extends EventEmitter { // look up id var next = i < endLen - 1 ? str[i + 1] : null; - if (next?.isNotEmpty == true && '${num.parse(next)}' == next) { + if (next?.isNotEmpty == true && '${num.tryParse(next)}' == next) { p['id'] = ''; while (++i > 0) { var c = str[i]; - if (null == c || '${num.parse(c)}' != c) { + if (null == c || '${num.tryParse(c)}' != c) { --i; break; } diff --git a/lib/src/socket.dart b/lib/src/socket.dart index 356bc7e..162dde6 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -290,7 +290,7 @@ class Socket extends EventEmitter { // debug('socket connected - writing packet'); this.nsp.connected[this.id] = this; this.join(this.id); - this.packet({'type': CONNECT}); + this.packet({'type': CONNECT}); } /** @@ -366,7 +366,7 @@ class Socket extends EventEmitter { // debug('sending ack %j', args); var type = /*hasBin(args) ? parser.BINARY_ACK : parser.*/ ACK; - packet({ + packet({ 'id': id, 'type': type, 'data': [_] @@ -441,7 +441,7 @@ class Socket extends EventEmitter { * @api private */ error(err) { - this.packet({'type': ERROR, 'data': err}); + this.packet({'type': ERROR, 'data': err}); } /** @@ -457,7 +457,7 @@ class Socket extends EventEmitter { if (close == true) { this.client.disconnect(); } else { - this.packet({'type': DISCONNECT}); + this.packet({'type': DISCONNECT}); this.onclose('server namespace disconnect'); } return this;