From 6ca0d2126a1aae03e196837c167c7f3451dba234 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Fri, 10 Aug 2018 22:08:44 -0400 Subject: [PATCH] Dart 2 fixes -> 1.1.1 --- .idea/body_parser.iml | 1 + .idea/libraries/Dart_Packages.xml | 237 ++++++++++++++++-------------- .travis.yml | 5 +- CHANGELOG.md | 3 + analysis_options.yaml | 3 +- example/main.dart | 13 +- lib/src/body_parse_result.dart | 2 +- lib/src/chunk.dart | 7 +- lib/src/file_upload_info.dart | 8 +- lib/src/get_value.dart | 30 ++-- lib/src/map_from_uri.dart | 2 +- lib/src/parse_body.dart | 27 +++- pubspec.yaml | 6 +- test/form_data_test.dart | 45 +++--- test/server_test.dart | 66 ++++++--- 15 files changed, 260 insertions(+), 195 deletions(-) diff --git a/.idea/body_parser.iml b/.idea/body_parser.iml index 0fd729f3..ae9af975 100644 --- a/.idea/body_parser.iml +++ b/.idea/body_parser.iml @@ -3,6 +3,7 @@ + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 83757bd2..3a4aead0 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,408 +5,417 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - + - - - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index de2210c9..a9e2c109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1 +1,4 @@ -language: dart \ No newline at end of file +language: dart +dart: + - dev + - stable \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d27178a..2304947d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,5 @@ +# 1.1.1 +* Dart 2 updates; should fix Angel in Travis. + # 1.1.0 * Add `parseBodyFromStream` \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index 518eb901..eae1e42a 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,2 +1,3 @@ analyzer: - strong-mode: true \ No newline at end of file + strong-mode: + implicit-casts: false \ No newline at end of file diff --git a/example/main.dart b/example/main.dart index 791d0524..ce0af703 100644 --- a/example/main.dart +++ b/example/main.dart @@ -5,32 +5,33 @@ import 'dart:isolate'; import 'package:body_parser/body_parser.dart'; main() async { - var address = InternetAddress.LOOPBACK_IP_V4; + var address = '127.0.0.1'; var port = 3000; var futures = []; for (int i = 1; i < Platform.numberOfProcessors; i++) { - futures.add(Isolate.spawn(start, [address.address, port, i])); + futures.add(Isolate.spawn(start, [address, port, i])); } Future.wait(futures).then((_) { print('All instances started.'); print( 'Test with "wrk -t12 -c400 -d30s -s ./example/post.lua http://localhost:3000" or similar'); - start([address.address, port, 0]); + start([address, port, 0]); }); } void start(List args) { - var address = new InternetAddress(args[0]); + var address = new InternetAddress(args[0] as String); int port = args[1], id = args[2]; HttpServer.bind(address, port, shared: true).then((server) { server.listen((request) async { + // ignore: deprecated_member_use var body = await parseBody(request); request.response - ..headers.contentType = ContentType.JSON - ..write(JSON.encode(body.body)) + ..headers.contentType = new ContentType('application', 'json') + ..write(json.encode(body.body)) ..close(); }); diff --git a/lib/src/body_parse_result.dart b/lib/src/body_parse_result.dart index 4fa826e1..806335c3 100644 --- a/lib/src/body_parse_result.dart +++ b/lib/src/body_parse_result.dart @@ -12,7 +12,7 @@ abstract class BodyParseResult { List get files; /// The original body bytes sent with this request. - /// + /// /// You must set [storeOriginalBuffer] to `true` to see this. List get originalBuffer; diff --git a/lib/src/chunk.dart b/lib/src/chunk.dart index 2dd36d0b..58776ca0 100644 --- a/lib/src/chunk.dart +++ b/lib/src/chunk.dart @@ -1,8 +1,7 @@ import 'file_upload_info.dart'; -List getFileDataFromChunk(String chunk, String boundary, - String fileUploadName, - Map body) { +List getFileDataFromChunk( + String chunk, String boundary, String fileUploadName, Map body) { List result = []; return result; -} \ No newline at end of file +} diff --git a/lib/src/file_upload_info.dart b/lib/src/file_upload_info.dart index 85be74dd..5db8b785 100644 --- a/lib/src/file_upload_info.dart +++ b/lib/src/file_upload_info.dart @@ -2,12 +2,16 @@ class FileUploadInfo { /// The MIME type of the uploaded file. String mimeType; + /// The name of the file field from the request. String name; + /// The filename of the file. String filename; + /// The bytes that make up this file. List data; - FileUploadInfo({this.mimeType, this.name, this.filename, this.data: const []}) {} -} \ No newline at end of file + FileUploadInfo( + {this.mimeType, this.name, this.filename, this.data: const []}) {} +} diff --git a/lib/src/get_value.dart b/lib/src/get_value.dart index 73e01507..d3c6c3f1 100644 --- a/lib/src/get_value.dart +++ b/lib/src/get_value.dart @@ -1,14 +1,20 @@ -import 'dart:convert'; +import 'package:dart2_constant/convert.dart'; getValue(String value) { - num numValue = num.parse(value, (_) => double.NAN); - if (!numValue.isNaN) - return numValue; - else if (value.startsWith('[') && value.endsWith(']')) - return JSON.decode(value); - else if (value.startsWith('{') && value.endsWith('}')) - return JSON.decode(value); - else if (value.trim().toLowerCase() == 'null') - return null; - else return value; -} \ No newline at end of file + try { + num numValue = num.parse(value); + if (!numValue.isNaN) + return numValue; + else + return value; + } on FormatException { + if (value.startsWith('[') && value.endsWith(']')) + return json.decode(value); + else if (value.startsWith('{') && value.endsWith('}')) + return json.decode(value); + else if (value.trim().toLowerCase() == 'null') + return null; + else + return value; + } +} diff --git a/lib/src/map_from_uri.dart b/lib/src/map_from_uri.dart index 15ca9f4b..97f1d56c 100644 --- a/lib/src/map_from_uri.dart +++ b/lib/src/map_from_uri.dart @@ -30,7 +30,7 @@ buildMapFromUri(Map map, String body) { for (int i = 1; i < keys.length; i++) { if (i < keys.length - 1) { targetMap[keys[i]] = targetMap[keys[i]] ?? {}; - targetMap = targetMap[keys[i]]; + targetMap = targetMap[keys[i]] as Map; } else { targetMap[keys[i]] = getValue(value); } diff --git a/lib/src/parse_body.dart b/lib/src/parse_body.dart index cca4456e..00dcf663 100644 --- a/lib/src/parse_body.dart +++ b/lib/src/parse_body.dart @@ -1,9 +1,11 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:io'; + +import 'package:dart2_constant/convert.dart'; import 'package:http_parser/http_parser.dart'; import 'package:http_server/http_server.dart'; import 'package:mime/mime.dart'; + import 'body_parse_result.dart'; import 'file_upload_info.dart'; import 'map_from_uri.dart'; @@ -44,10 +46,10 @@ Future parseBodyFromStream( if (storeOriginalBuffer) { return getBytes().then((bytes) { result.originalBuffer = bytes; - return UTF8.decode(bytes); + return utf8.decode(bytes); }); } else - return data.transform(UTF8.decoder).join(); + return data.transform(utf8.decoder).join(); } try { @@ -70,14 +72,17 @@ Future parseBodyFromStream( .transform(new MimeMultipartTransformer( contentType.parameters['boundary'])) .map((part) => - HttpMultipartFormData.parse(part, defaultEncoding: UTF8)); + HttpMultipartFormData.parse(part, defaultEncoding: utf8)); await for (HttpMultipartFormData part in parts) { if (part.isBinary || part.contentDisposition.parameters.containsKey("filename")) { BytesBuilder builder = await part.fold( new BytesBuilder(copy: false), - (BytesBuilder b, d) => b..add(d is! String ? d : d.codeUnits)); + (BytesBuilder b, d) => b + ..add(d is! String + ? (d as List) + : (d as String).codeUnits)); var upload = new FileUploadInfo( mimeType: part.contentType.mimeType, name: part.contentDisposition.parameters['name'], @@ -91,8 +96,9 @@ Future parseBodyFromStream( '${part.contentDisposition.parameters["name"]}=$text'); } } - } else if (contentType.mimeType == ContentType.JSON.mimeType) { - result.body.addAll(JSON.decode(await getBody())); + } else if (contentType.mimeType == 'application/json') { + result.body + .addAll(_foldToStringDynamic(json.decode(await getBody()) as Map)); } else if (contentType.mimeType == 'application/x-www-form-urlencoded') { String body = await getBody(); buildMapFromUri(result.body, body); @@ -135,3 +141,10 @@ class _BodyParseResultImpl implements BodyParseResult { @override StackTrace stack = null; } + +Map _foldToStringDynamic(Map map) { + return map == null + ? null + : map.keys.fold>( + {}, (out, k) => out..[k.toString()] = map[k]); +} diff --git a/pubspec.yaml b/pubspec.yaml index 424d74ab..e07c6368 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,13 @@ name: body_parser author: Tobe O -version: 1.1.0 +version: 1.1.1 description: Parse request bodies and query strings in Dart. Supports JSON, URL-encoded, and multi-part bodies. homepage: https://github.com/angel-dart/body_parser dependencies: + dart2_constant: ^1.0.0 http_parser: ">=3.1.1 <4.0.0" http_server: ">=0.9.6 <1.0.0" mime: ">=0.9.3 <1.0.0" dev_dependencies: http: ">=0.11.3 <0.12.0" - json_god: ">=2.0.0-beta <3.0.0" - test: ">=0.12.15 <0.13.0" \ No newline at end of file + test: ">=0.12.15" \ No newline at end of file diff --git a/test/form_data_test.dart b/test/form_data_test.dart index 496279cc..354c42db 100644 --- a/test/form_data_test.dart +++ b/test/form_data_test.dart @@ -1,8 +1,9 @@ import 'dart:io'; import 'package:body_parser/body_parser.dart'; +import 'package:dart2_constant/convert.dart'; import 'package:http/http.dart' as http; -import 'package:json_god/json_god.dart' as god; import 'package:test/test.dart'; +import 'server_test.dart'; main() { HttpServer server; @@ -10,10 +11,11 @@ main() { http.Client client; setUp(() async { - server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0); + server = await HttpServer.bind('127.0.0.1', 0); server.listen((HttpRequest request) async { //Server will simply return a JSON representation of the parsed body - request.response.write(god.serialize(await parseBody(request))); + // ignore: deprecated_member_use + request.response.write(jsonEncodeBody(await parseBody(request))); await request.response.close(); }); url = 'http://localhost:${server.port}'; @@ -31,8 +33,8 @@ main() { test('No upload', () async { String boundary = 'myBoundary'; - Map headers = { - HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary' + Map headers = { + 'content-type': 'multipart/form-data; boundary=$boundary' }; String postData = ''' --$boundary @@ -47,16 +49,21 @@ world 'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}'); var response = await client.post(url, headers: headers, body: postData); print('Response: ${response.body}'); - Map json = god.deserialize(response.body); - List files = json['files']; + Map jsons = json.decode(response.body); + var files = jsons['files'].map((map) { + return map == null + ? null + : map.keys.fold>( + {}, (out, k) => out..[k.toString()] = map[k]); + }); expect(files.length, equals(0)); - expect(json['body']['hello'], equals('world')); + expect(jsons['body']['hello'], equals('world')); }); test('Single upload', () async { String boundary = 'myBoundary'; - Map headers = { - HttpHeaders.CONTENT_TYPE: new ContentType("multipart", "form-data", + Map headers = { + 'content-type': new ContentType("multipart", "form-data", parameters: {"boundary": boundary}).toString() }; String postData = ''' @@ -77,20 +84,20 @@ Hello world 'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}'); var response = await client.post(url, headers: headers, body: postData); print('Response: ${response.body}'); - Map json = god.deserialize(response.body); - List files = json['files']; + Map jsons = json.decode(response.body); + var files = jsons['files']; expect(files.length, equals(1)); expect(files[0]['name'], equals('file')); expect(files[0]['mimeType'], equals('application/dart')); expect(files[0]['data'].length, equals(11)); expect(files[0]['filename'], equals('app.dart')); - expect(json['body']['hello'], equals('world')); + expect(jsons['body']['hello'], equals('world')); }); test('Multiple upload', () async { String boundary = 'myBoundary'; - Map headers = { - HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary' + Map headers = { + 'content-type': 'multipart/form-data; boundary=$boundary' }; String postData = ''' --$boundary @@ -121,15 +128,15 @@ function main() { 'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}'); var response = await client.post(url, headers: headers, body: postData); print('Response: ${response.body}'); - Map json = god.deserialize(response.body); - List files = json['files']; + Map jsons = json.decode(response.body); + var files = jsons['files']; expect(files.length, equals(2)); expect(files[0]['name'], equals('file')); expect(files[0]['mimeType'], equals('text/plain')); expect(files[0]['data'].length, equals(11)); expect(files[1]['name'], equals('entry-point')); expect(files[1]['mimeType'], equals('text/javascript')); - expect(json['body']['json'], equals('god')); - expect(json['body']['num'], equals(14.5)); + expect(jsons['body']['json'], equals('god')); + expect(jsons['body']['num'], equals(14.5)); }); } diff --git a/test/server_test.dart b/test/server_test.dart index 91288491..277ff495 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -1,24 +1,43 @@ -import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show HttpRequest, HttpServer; + import 'package:body_parser/body_parser.dart'; +import 'package:dart2_constant/convert.dart'; import 'package:http/http.dart' as http; -import 'package:json_god/json_god.dart' as god; import 'package:test/test.dart'; const TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxMjcuMC4wLjEiLCJleHAiOi0xLCJpYXQiOiIyMDE2LTEyLTIyVDEyOjQ5OjUwLjM2MTQ0NiIsImlzcyI6ImFuZ2VsX2F1dGgiLCJzdWIiOiIxMDY2OTQ4Mzk2MDIwMjg5ODM2NTYifQ==.PYw7yUb-cFWD7N0sSLztP7eeRvO44nu1J2OgDNyT060='; +String jsonEncodeBody(BodyParseResult result) { + return json.encode({ + 'query': result.query, + 'body': result.body, + 'error': result.error?.toString(), + 'files': result.files.map((f) { + return { + 'name': f.name, + 'mimeType': f.mimeType, + 'filename': f.filename, + 'data': f.data, + }; + }).toList(), + 'originalBuffer': result.originalBuffer, + 'stack': null, //result.stack.toString(), + }); +} + main() { HttpServer server; String url; http.Client client; setUp(() async { - server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0); + server = await HttpServer.bind('127.0.0.1', 0); server.listen((HttpRequest request) async { //Server will simply return a JSON representation of the parsed body request.response.write( - god.serialize(await parseBody(request, storeOriginalBuffer: true))); + // ignore: deprecated_member_use + jsonEncodeBody(await parseBody(request, storeOriginalBuffer: true))); await request.response.close(); }); url = 'http://localhost:${server.port}'; @@ -38,7 +57,7 @@ main() { print('GET $url/?hello=world'); var response = await client.get('$url/?hello=world'); print('Response: ${response.body}'); - var result = JSON.decode(response.body); + var result = json.decode(response.body); expect(result['body'], equals({})); expect(result['query'], equals({'hello': 'world'})); expect(result['files'], equals([])); @@ -46,12 +65,12 @@ main() { }); test('GET Complex', () async { - var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - - 1}&map.foo.bar=baz'; + var postData = + 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz'; print('Body: $postData'); var response = await client.get('$url/?$postData'); print('Response: ${response.body}'); - var query = god.deserialize(response.body)['query']; + var query = json.decode(response.body)['query']; expect(query['hello'], equals('world')); expect(query['nums'][2], equals(2)); expect(query['map'] is Map, equals(true)); @@ -63,21 +82,21 @@ main() { print('Body: $postData'); var response = await client.get('$url/?$postData'); print('Response: ${response.body}'); - var query = god.deserialize(response.body)['query']; + var query = json.decode(response.body)['query']; expect(query['token'], equals(TOKEN)); }); }); group('urlencoded', () { Map headers = { - HttpHeaders.CONTENT_TYPE: 'application/x-www-form-urlencoded' + 'content-type': 'application/x-www-form-urlencoded' }; test('POST Simple', () async { print('Body: hello=world'); var response = await client.post(url, headers: headers, body: 'hello=world'); print('Response: ${response.body}'); - var result = JSON.decode(response.body); + var result = json.decode(response.body); expect(result['query'], equals({})); expect(result['body'], equals({'hello': 'world'})); expect(result['files'], equals([])); @@ -86,10 +105,11 @@ main() { }); test('Post Complex', () async { - var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - - 1}&map.foo.bar=baz'; + var postData = + 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz'; var response = await client.post(url, headers: headers, body: postData); - var body = god.deserialize(response.body)['body']; + print('Response: ${response.body}'); + var body = json.decode(response.body)['body']; expect(body['hello'], equals('world')); expect(body['nums'][2], equals(2)); expect(body['map'] is Map, equals(true)); @@ -99,21 +119,19 @@ main() { test('JWT', () async { var postData = 'token=$TOKEN'; var response = await client.post(url, headers: headers, body: postData); - var body = god.deserialize(response.body)['body']; + var body = json.decode(response.body)['body']; expect(body['token'], equals(TOKEN)); }); }); - group('JSON', () { - Map headers = { - HttpHeaders.CONTENT_TYPE: ContentType.JSON.toString() - }; + group('json', () { + Map headers = {'content-type': 'application/json'}; test('Post Simple', () async { - var postData = god.serialize({'hello': 'world'}); + var postData = json.encode({'hello': 'world'}); print('Body: $postData'); var response = await client.post(url, headers: headers, body: postData); print('Response: ${response.body}'); - var result = JSON.decode(response.body); + var result = json.decode(response.body); expect(result['body'], equals({'hello': 'world'})); expect(result['query'], equals({})); expect(result['files'], equals([])); @@ -121,7 +139,7 @@ main() { }); test('Post Complex', () async { - var postData = god.serialize({ + var postData = json.encode({ 'hello': 'world', 'nums': [1, 2.0, 3 - 1], 'map': { @@ -131,7 +149,7 @@ main() { print('Body: $postData'); var response = await client.post(url, headers: headers, body: postData); print('Response: ${response.body}'); - var body = god.deserialize(response.body)['body']; + var body = json.decode(response.body)['body']; expect(body['hello'], equals('world')); expect(body['nums'][2], equals(2)); expect(body['map'] is Map, equals(true));