+5
This commit is contained in:
parent
331e7aa14c
commit
1acfeeee24
6 changed files with 77 additions and 24 deletions
|
@ -1,5 +1,5 @@
|
||||||
# Body Parser
|
# Body Parser
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
**NOT YET PRODUCTION READY**
|
**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:
|
Feel free to follow me on Twitter:
|
||||||
|
|
||||||
[@_wapaa_](http://twitter.com/_wapaa_)
|
[@thosakwe](http://twitter.com/thosakwe)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
/// A library for parsing HTTP request bodies and queries.
|
/// A library for parsing HTTP request bodies and queries.
|
||||||
library body_parser;
|
library body_parser;
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
export 'src/body_parser.dart';
|
export 'src/body_parser.dart';
|
||||||
export 'src/body_parse_result.dart';
|
export 'src/body_parse_result.dart';
|
||||||
export 'src/file_upload_info.dart';
|
export 'src/file_upload_info.dart';
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import 'file_upload_info.dart';
|
import 'file_upload_info.dart';
|
||||||
|
|
||||||
/// A representation of data from an incoming request.
|
/// A representation of data from an incoming request.
|
||||||
class BodyParseResult {
|
abstract class BodyParseResult {
|
||||||
/// The parsed body.
|
/// The parsed body.
|
||||||
Map body = {};
|
Map<String, dynamic> get body;
|
||||||
|
|
||||||
/// The parsed query string.
|
/// The parsed query string.
|
||||||
Map query = {};
|
Map<String, dynamic> get query;
|
||||||
|
|
||||||
/// All files uploaded within this request.
|
/// 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'dart:io';
|
||||||
import 'package:http_server/http_server.dart';
|
import 'package:http_server/http_server.dart';
|
||||||
import 'package:mime/mime.dart';
|
import 'package:mime/mime.dart';
|
||||||
import 'body_parse_result.dart';
|
import 'body_parse_result.dart';
|
||||||
import 'chunk.dart';
|
|
||||||
import 'file_upload_info.dart';
|
import 'file_upload_info.dart';
|
||||||
import 'map_from_uri.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
|
/// 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
|
/// as files. Anything else is put in the body. You can change the upload file name
|
||||||
/// via the *fileUploadName* parameter. :)
|
/// 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 {
|
try {
|
||||||
if (request.headers.contentType != null) {
|
if (request.headers.contentType != null) {
|
||||||
if (request.headers.contentType.primaryType == 'multipart' &&
|
if (request.headers.contentType.primaryType == 'multipart' &&
|
||||||
request.headers.contentType.parameters.containsKey('boundary')) {
|
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(
|
.transform(new MimeMultipartTransformer(
|
||||||
request.headers.contentType.parameters['boundary']))
|
request.headers.contentType.parameters['boundary']))
|
||||||
.map((part) =>
|
.map((part) =>
|
||||||
|
@ -47,11 +73,10 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
|
||||||
}
|
}
|
||||||
} else if (request.headers.contentType.mimeType ==
|
} else if (request.headers.contentType.mimeType ==
|
||||||
ContentType.JSON.mimeType) {
|
ContentType.JSON.mimeType) {
|
||||||
result.body
|
result.body.addAll(JSON.decode(await getBody()));
|
||||||
.addAll(JSON.decode(await request.transform(UTF8.decoder).join()));
|
|
||||||
} else if (request.headers.contentType.mimeType ==
|
} else if (request.headers.contentType.mimeType ==
|
||||||
'application/x-www-form-urlencoded') {
|
'application/x-www-form-urlencoded') {
|
||||||
String body = await request.transform(UTF8.decoder).join();
|
String body = await getBody();
|
||||||
buildMapFromUri(result.body, body);
|
buildMapFromUri(result.body, body);
|
||||||
}
|
}
|
||||||
} else if (request.uri.hasQuery) {
|
} else if (request.uri.hasQuery) {
|
||||||
|
@ -63,3 +88,17 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _BodyParseResultImpl implements BodyParseResult {
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> body = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<FileUploadInfo> files = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<int> originalBuffer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> query = {};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: body_parser
|
name: body_parser
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
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.
|
description: Parse request bodies and query strings in Dart.
|
||||||
homepage: https://github.com/thosakwe/body_parser
|
homepage: https://github.com/thosakwe/body_parser
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:body_parser/body_parser.dart';
|
import 'package:body_parser/body_parser.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
@ -16,7 +17,8 @@ main() {
|
||||||
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
|
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
|
||||||
server.listen((HttpRequest request) async {
|
server.listen((HttpRequest request) async {
|
||||||
//Server will simply return a JSON representation of the parsed body
|
//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();
|
await request.response.close();
|
||||||
});
|
});
|
||||||
url = 'http://localhost:${server.port}';
|
url = 'http://localhost:${server.port}';
|
||||||
|
@ -36,8 +38,11 @@ main() {
|
||||||
print('GET $url/?hello=world');
|
print('GET $url/?hello=world');
|
||||||
var response = await client.get('$url/?hello=world');
|
var response = await client.get('$url/?hello=world');
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response.body,
|
var result = JSON.decode(response.body);
|
||||||
equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
|
expect(result['body'], equals({}));
|
||||||
|
expect(result['query'], equals({'hello': 'world'}));
|
||||||
|
expect(result['files'], equals([]));
|
||||||
|
expect(result['originalBuffer'], isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET Complex', () async {
|
test('GET Complex', () async {
|
||||||
|
@ -72,8 +77,12 @@ main() {
|
||||||
var response =
|
var response =
|
||||||
await client.post(url, headers: headers, body: 'hello=world');
|
await client.post(url, headers: headers, body: 'hello=world');
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response.body,
|
var result = JSON.decode(response.body);
|
||||||
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
|
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 {
|
test('Post Complex', () async {
|
||||||
|
@ -104,8 +113,11 @@ main() {
|
||||||
print('Body: $postData');
|
print('Body: $postData');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response = await client.post(url, headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response.body,
|
var result = JSON.decode(response.body);
|
||||||
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
|
expect(result['body'], equals({'hello': 'world'}));
|
||||||
|
expect(result['query'], equals({}));
|
||||||
|
expect(result['files'], equals([]));
|
||||||
|
expect(result['originalBuffer'], allOf(isList, isNotEmpty));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Post Complex', () async {
|
test('Post Complex', () async {
|
||||||
|
|
Loading…
Reference in a new issue