platform/lib/src/parse_body.dart

138 lines
4.2 KiB
Dart
Raw Normal View History

import 'dart:async';
import 'dart:convert';
import 'dart:io';
2018-03-04 22:32:14 +00:00
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';
2018-03-04 22:32:14 +00:00
/// Forwards to [parseBodyFromStream].
@deprecated
Future<BodyParseResult> parseBody(HttpRequest request,
{bool storeOriginalBuffer: false}) {
return parseBodyFromStream(
request,
request.headers.contentType != null
? new MediaType.parse(request.headers.contentType.toString())
: null,
request.uri,
storeOriginalBuffer: storeOriginalBuffer);
}
/// Grabs data from an incoming request.
///
/// Supports URL-encoded and JSON, as well as multipart/* forms.
/// 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. :)
2017-01-14 13:50:02 +00:00
///
/// Use [storeOriginalBuffer] to add the original request bytes to the result.
2018-03-04 22:32:14 +00:00
Future<BodyParseResult> parseBodyFromStream(
Stream<List<int>> data, MediaType contentType, Uri requestUri,
2017-01-14 13:50:02 +00:00
{bool storeOriginalBuffer: false}) async {
var result = new _BodyParseResultImpl();
2017-10-12 02:32:42 +00:00
Future<List<int>> getBytes() {
2018-03-04 22:32:14 +00:00
return data
2017-10-12 02:32:42 +00:00
.fold<BytesBuilder>(new BytesBuilder(copy: false), (a, b) => a..add(b))
.then((b) => b.takeBytes());
2017-01-14 13:50:02 +00:00
}
2017-10-12 02:32:42 +00:00
Future<String> getBody() {
2017-01-14 13:50:02 +00:00
if (storeOriginalBuffer) {
2017-10-12 02:32:42 +00:00
return getBytes().then((bytes) {
result.originalBuffer = bytes;
return UTF8.decode(bytes);
});
2017-01-14 13:50:02 +00:00
} else
2018-03-04 22:32:14 +00:00
return data.transform(UTF8.decoder).join();
2017-01-14 13:50:02 +00:00
}
2016-12-05 02:31:25 +00:00
try {
2018-03-04 22:32:14 +00:00
if (contentType != null) {
if (contentType.type == 'multipart' &&
contentType.parameters.containsKey('boundary')) {
2017-01-14 13:50:02 +00:00
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 {
2018-03-04 22:32:14 +00:00
stream = data;
2017-01-14 13:50:02 +00:00
}
var parts = stream
2016-12-05 02:31:25 +00:00
.transform(new MimeMultipartTransformer(
2018-03-04 22:32:14 +00:00
contentType.parameters['boundary']))
2016-12-05 02:31:25 +00:00
.map((part) =>
HttpMultipartFormData.parse(part, defaultEncoding: UTF8));
2016-12-05 02:31:25 +00:00
await for (HttpMultipartFormData part in parts) {
if (part.isBinary ||
part.contentDisposition.parameters.containsKey("filename")) {
2017-10-12 02:32:42 +00:00
BytesBuilder builder = await part.fold(
new BytesBuilder(copy: false),
2016-12-05 02:31:25 +00:00
(BytesBuilder b, d) => b..add(d is! String ? d : d.codeUnits));
var upload = new FileUploadInfo(
mimeType: part.contentType.mimeType,
name: part.contentDisposition.parameters['name'],
filename:
part.contentDisposition.parameters['filename'] ?? 'file',
data: builder.takeBytes());
result.files.add(upload);
} else if (part.isText) {
var text = await part.join();
buildMapFromUri(result.body,
'${part.contentDisposition.parameters["name"]}=$text');
}
}
2018-03-04 22:32:14 +00:00
} else if (contentType.mimeType == ContentType.JSON.mimeType) {
2017-01-14 13:50:02 +00:00
result.body.addAll(JSON.decode(await getBody()));
2018-03-04 22:32:14 +00:00
} else if (contentType.mimeType == 'application/x-www-form-urlencoded') {
2017-01-14 13:50:02 +00:00
String body = await getBody();
2016-12-05 02:31:25 +00:00
buildMapFromUri(result.body, body);
2017-07-19 21:20:57 +00:00
} else if (storeOriginalBuffer == true) {
result.originalBuffer = await getBytes();
}
} else {
2018-03-04 22:32:14 +00:00
if (requestUri.hasQuery) {
buildMapFromUri(result.query, requestUri.query);
2017-07-19 21:20:57 +00:00
}
if (storeOriginalBuffer == true) {
result.originalBuffer = await getBytes();
}
}
2017-07-19 21:20:57 +00:00
} catch (e, st) {
result.error = e;
result.stack = st;
}
return result;
}
2017-01-14 13:50:02 +00:00
class _BodyParseResultImpl implements BodyParseResult {
@override
Map<String, dynamic> body = {};
@override
List<FileUploadInfo> files = [];
@override
List<int> originalBuffer;
@override
Map<String, dynamic> query = {};
2017-07-19 21:20:57 +00:00
@override
var error = null;
@override
StackTrace stack = null;
2017-01-14 13:50:02 +00:00
}