File support is nearly there.
This commit is contained in:
parent
0e74bc9d9b
commit
1f37cd1b70
2 changed files with 67 additions and 7 deletions
|
@ -12,6 +12,9 @@ class BodyParseResult {
|
|||
|
||||
/// The parsed query string.
|
||||
Map query = {};
|
||||
|
||||
/// All files uploaded within this request.
|
||||
List<Map> files = [];
|
||||
}
|
||||
|
||||
/// Grabs data from an incoming request.
|
||||
|
@ -39,14 +42,48 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
|
|||
buildMapFromUri(result.query, queryMatch.group(1));
|
||||
}
|
||||
|
||||
// Accept file
|
||||
if (contentType != null && request.method == 'POST') {
|
||||
RegExp parseBoundaryRgx = new RegExp(
|
||||
r'^multipart\/form-data;\s*boundary=(.+)$');
|
||||
if (parseBoundaryRgx.hasMatch(contentType.toString())) {
|
||||
Match boundaryMatch = parseBoundaryRgx.firstMatch(contentType.toString());
|
||||
String body = await request.transform(UTF8.decoder).join();
|
||||
for (String chunk in body.split(boundaryMatch.group(1))) {
|
||||
var fileData = getFileDataFromChunk(chunk);
|
||||
if (fileData != null)
|
||||
result.files.add(fileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Parses file data from a multipart/form-data chunk.
|
||||
Map getFileDataFromChunk(String chunk) {
|
||||
Map result = {};
|
||||
RegExp isFormDataRgx = new RegExp(
|
||||
r'Content-Dispositition:\s*form-data;\s*name="([^"]+)"');
|
||||
|
||||
if (isFormDataRgx.hasMatch(chunk)) {
|
||||
result['name'] = isFormDataRgx.firstMatch(chunk).group(1);
|
||||
|
||||
RegExp contentTypeRgx = new RegExp(r'Content-Type:\s*([^\n]+)');
|
||||
if (contentTypeRgx.hasMatch(chunk)) {
|
||||
result['type'] = contentTypeRgx.firstMatch(chunk).group(1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Parses a URI-encoded string into real data! **Wow!**
|
||||
///
|
||||
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
|
||||
buildMapFromUri(Map map, String body) {
|
||||
RegExp parseArray = new RegExp(r'^(.+)\[\]$');
|
||||
RegExp parseArrayRgx = new RegExp(r'^(.+)\[\]$');
|
||||
|
||||
for (String keyValuePair in body.split('&')) {
|
||||
if (keyValuePair.contains('=')) {
|
||||
|
@ -54,15 +91,15 @@ buildMapFromUri(Map map, String body) {
|
|||
String key = Uri.decodeQueryComponent(split[0]);
|
||||
String value = Uri.decodeQueryComponent(split[1]);
|
||||
|
||||
if (parseArray.hasMatch(key)) {
|
||||
Match queryMatch = parseArray.firstMatch(key);
|
||||
if (parseArrayRgx.hasMatch(key)) {
|
||||
Match queryMatch = parseArrayRgx.firstMatch(key);
|
||||
key = queryMatch.group(1);
|
||||
if (!(map[key] is List)) {
|
||||
map[key] = [];
|
||||
}
|
||||
|
||||
map[key].add(getValue(value));
|
||||
} else if(key.contains('.')) {
|
||||
} else if (key.contains('.')) {
|
||||
// i.e. map.foo.bar => [map, foo, bar]
|
||||
List<String> keys = key.split('.');
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ 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"}}'));
|
||||
expect(response.body, equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
|
||||
});
|
||||
|
||||
test('GET Complex', () async {
|
||||
|
@ -64,7 +64,7 @@ main() {
|
|||
var response = await client.post(
|
||||
url, headers: headers, body: 'hello=world');
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals('{"body":{"hello":"world"},"query":{}}'));
|
||||
expect(response.body, equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
|
||||
});
|
||||
|
||||
test('Post Complex', () async {
|
||||
|
@ -91,7 +91,7 @@ main() {
|
|||
var response = await client.post(
|
||||
url, headers: headers, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals('{"body":{"hello":"world"},"query":{}}'));
|
||||
expect(response.body, equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
|
||||
});
|
||||
|
||||
test('Post Complex', () async {
|
||||
|
@ -114,5 +114,28 @@ main() {
|
|||
expect(body['map']['foo'], equals({'bar': 'baz'}));
|
||||
});
|
||||
});
|
||||
|
||||
group('File', () {
|
||||
test('Single upload', () async {
|
||||
String boundary = '----myBoundary';
|
||||
Map headers = {
|
||||
HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary'
|
||||
};
|
||||
String postData = '''
|
||||
|
||||
$boundary
|
||||
Content-Dispositition: form-data; name="file"
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello world
|
||||
$boundary--
|
||||
''';
|
||||
|
||||
print('Form Data: \n$postData');
|
||||
var response = await client.post(url, headers: headers, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
var body = god.deserialize(response.body)['body'];
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue