This commit is contained in:
thosakwe 2017-01-14 08:50:02 -05:00
parent 331e7aa14c
commit 1acfeeee24
6 changed files with 77 additions and 24 deletions

View file

@ -1,5 +1,5 @@
# Body Parser
![version 1.0.0-dev+3](https://img.shields.io/badge/version-1.0.0--dev+3-red.svg)
![version 1.0.0-dev+5](https://img.shields.io/badge/version-1.0.0--dev+5-red.svg)
![build status](https://travis-ci.org/thosakwe/body_parser.svg)
**NOT YET PRODUCTION READY**
@ -68,4 +68,4 @@ Thank you for using this library. I hope you like it.
Feel free to follow me on Twitter:
[@_wapaa_](http://twitter.com/_wapaa_)
[@thosakwe](http://twitter.com/thosakwe)

View file

@ -1,9 +1,6 @@
/// A library for parsing HTTP request bodies and queries.
library body_parser;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
export 'src/body_parser.dart';
export 'src/body_parse_result.dart';
export 'src/file_upload_info.dart';

View file

@ -1,13 +1,18 @@
import 'file_upload_info.dart';
/// A representation of data from an incoming request.
class BodyParseResult {
abstract class BodyParseResult {
/// The parsed body.
Map body = {};
Map<String, dynamic> get body;
/// The parsed query string.
Map query = {};
Map<String, dynamic> get query;
/// All files uploaded within this request.
List<FileUploadInfo> files = [];
List<FileUploadInfo> get files;
/// The original body bytes sent with this request.
///
/// You must set [storeOriginalBuffer] to `true` to see this.
List<int> get originalBuffer;
}

View file

@ -4,7 +4,6 @@ import 'dart:io';
import 'package:http_server/http_server.dart';
import 'package:mime/mime.dart';
import 'body_parse_result.dart';
import 'chunk.dart';
import 'file_upload_info.dart';
import 'map_from_uri.dart';
@ -14,14 +13,41 @@ import 'map_from_uri.dart';
/// On a file upload request, only fields with the name **'file'** are processed
/// as files. Anything else is put in the body. You can change the upload file name
/// via the *fileUploadName* parameter. :)
Future<BodyParseResult> parseBody(HttpRequest request) async {
var result = new BodyParseResult();
///
/// Use [storeOriginalBuffer] to add the original request bytes to the result.
Future<BodyParseResult> parseBody(HttpRequest request,
{bool storeOriginalBuffer: false}) async {
var result = new _BodyParseResultImpl();
Future<List<int>> getBytes() async {
return await request.fold(<int>[], (a, b) => a..addAll(b));
}
Future<String> getBody() async {
if (storeOriginalBuffer) {
List<int> bytes = await getBytes();
return UTF8.decode(result.originalBuffer = bytes);
} else
return await request.transform(UTF8.decoder).join();
}
try {
if (request.headers.contentType != null) {
if (request.headers.contentType.primaryType == 'multipart' &&
request.headers.contentType.parameters.containsKey('boundary')) {
var parts = request
Stream<List<int>> stream;
if (storeOriginalBuffer) {
var bytes = result.originalBuffer = await getBytes();
var ctrl = new StreamController<List<int>>()
..add(bytes)
..close();
stream = ctrl.stream;
} else {
stream = request;
}
var parts = stream
.transform(new MimeMultipartTransformer(
request.headers.contentType.parameters['boundary']))
.map((part) =>
@ -47,11 +73,10 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
}
} else if (request.headers.contentType.mimeType ==
ContentType.JSON.mimeType) {
result.body
.addAll(JSON.decode(await request.transform(UTF8.decoder).join()));
result.body.addAll(JSON.decode(await getBody()));
} else if (request.headers.contentType.mimeType ==
'application/x-www-form-urlencoded') {
String body = await request.transform(UTF8.decoder).join();
String body = await getBody();
buildMapFromUri(result.body, body);
}
} else if (request.uri.hasQuery) {
@ -63,3 +88,17 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
return result;
}
class _BodyParseResultImpl implements BodyParseResult {
@override
Map<String, dynamic> body = {};
@override
List<FileUploadInfo> files = [];
@override
List<int> originalBuffer;
@override
Map<String, dynamic> query = {};
}

View file

@ -1,6 +1,6 @@
name: body_parser
author: Tobe O <thosakwe@gmail.com>
version: 1.0.0-dev+4
version: 1.0.0-dev+5
description: Parse request bodies and query strings in Dart.
homepage: https://github.com/thosakwe/body_parser
dependencies:

View file

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:io';
import 'package:body_parser/body_parser.dart';
import 'package:http/http.dart' as http;
@ -16,7 +17,8 @@ main() {
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 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)));
request.response.write(
god.serialize(await parseBody(request, storeOriginalBuffer: true)));
await request.response.close();
});
url = 'http://localhost:${server.port}';
@ -36,8 +38,11 @@ main() {
print('GET $url/?hello=world');
var response = await client.get('$url/?hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
var result = JSON.decode(response.body);
expect(result['body'], equals({}));
expect(result['query'], equals({'hello': 'world'}));
expect(result['files'], equals([]));
expect(result['originalBuffer'], isNull);
});
test('GET Complex', () async {
@ -72,8 +77,12 @@ main() {
var response =
await client.post(url, headers: headers, body: 'hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
var result = JSON.decode(response.body);
expect(result['query'], equals({}));
expect(result['body'], equals({'hello': 'world'}));
expect(result['files'], equals([]));
expect(result['originalBuffer'], isList);
expect(result['originalBuffer'], isNotEmpty);
});
test('Post Complex', () async {
@ -104,8 +113,11 @@ main() {
print('Body: $postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
var result = JSON.decode(response.body);
expect(result['body'], equals({'hello': 'world'}));
expect(result['query'], equals({}));
expect(result['files'], equals([]));
expect(result['originalBuffer'], allOf(isList, isNotEmpty));
});
test('Post Complex', () async {