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.
|
/// The parsed query string.
|
||||||
Map query = {};
|
Map query = {};
|
||||||
|
|
||||||
|
/// All files uploaded within this request.
|
||||||
|
List<Map> files = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grabs data from an incoming request.
|
/// Grabs data from an incoming request.
|
||||||
|
@ -39,14 +42,48 @@ Future<BodyParseResult> parseBody(HttpRequest request) async {
|
||||||
buildMapFromUri(result.query, queryMatch.group(1));
|
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;
|
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!**
|
/// Parses a URI-encoded string into real data! **Wow!**
|
||||||
///
|
///
|
||||||
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
|
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
|
||||||
buildMapFromUri(Map map, String body) {
|
buildMapFromUri(Map map, String body) {
|
||||||
RegExp parseArray = new RegExp(r'^(.+)\[\]$');
|
RegExp parseArrayRgx = new RegExp(r'^(.+)\[\]$');
|
||||||
|
|
||||||
for (String keyValuePair in body.split('&')) {
|
for (String keyValuePair in body.split('&')) {
|
||||||
if (keyValuePair.contains('=')) {
|
if (keyValuePair.contains('=')) {
|
||||||
|
@ -54,15 +91,15 @@ buildMapFromUri(Map map, String body) {
|
||||||
String key = Uri.decodeQueryComponent(split[0]);
|
String key = Uri.decodeQueryComponent(split[0]);
|
||||||
String value = Uri.decodeQueryComponent(split[1]);
|
String value = Uri.decodeQueryComponent(split[1]);
|
||||||
|
|
||||||
if (parseArray.hasMatch(key)) {
|
if (parseArrayRgx.hasMatch(key)) {
|
||||||
Match queryMatch = parseArray.firstMatch(key);
|
Match queryMatch = parseArrayRgx.firstMatch(key);
|
||||||
key = queryMatch.group(1);
|
key = queryMatch.group(1);
|
||||||
if (!(map[key] is List)) {
|
if (!(map[key] is List)) {
|
||||||
map[key] = [];
|
map[key] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
map[key].add(getValue(value));
|
map[key].add(getValue(value));
|
||||||
} else if(key.contains('.')) {
|
} else if (key.contains('.')) {
|
||||||
// i.e. map.foo.bar => [map, foo, bar]
|
// i.e. map.foo.bar => [map, foo, bar]
|
||||||
List<String> keys = key.split('.');
|
List<String> keys = key.split('.');
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ 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, equals('{"body":{},"query":{"hello":"world"}}'));
|
expect(response.body, equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET Complex', () async {
|
test('GET Complex', () async {
|
||||||
|
@ -64,7 +64,7 @@ main() {
|
||||||
var response = await client.post(
|
var response = await client.post(
|
||||||
url, headers: headers, body: 'hello=world');
|
url, headers: headers, body: 'hello=world');
|
||||||
print('Response: ${response.body}');
|
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 {
|
test('Post Complex', () async {
|
||||||
|
@ -91,7 +91,7 @@ main() {
|
||||||
var response = await client.post(
|
var response = await client.post(
|
||||||
url, headers: headers, body: postData);
|
url, headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
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 {
|
test('Post Complex', () async {
|
||||||
|
@ -114,5 +114,28 @@ main() {
|
||||||
expect(body['map']['foo'], equals({'bar': 'baz'}));
|
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