Move MimeMultipartTransformer and HttpBodyHandler to mime and http_server packages.

BUG=
R=whesse@google.com

Review URL: https://codereview.chromium.org//18438005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@24991 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ajohnsen@google.com 2013-07-15 08:40:36 +00:00
parent 88d1ae1957
commit 40c7d89d66
14 changed files with 119 additions and 89 deletions

View file

@ -6,9 +6,14 @@ library http_server;
import 'dart:async';
import 'dart:io';
import 'dart:json' as JSON;
import 'package:mime/mime.dart';
part 'src/http_body.dart';
part 'src/http_body_impl.dart';
part 'src/http_multipart_form_data.dart';
part 'src/http_multipart_form_data_impl.dart';
part 'src/virtual_directory.dart';
part 'src/virtual_host.dart';

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
part of http_server;
/**

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
part of http_server;
class _HttpBodyHandlerTransformer
extends StreamEventTransformer<HttpRequest, HttpRequestBody> {
@ -150,6 +150,24 @@ class _HttpBodyHandler {
return asBinary();
}
// Utility function to synchronously decode a list of bytes.
static String _decodeString(List<int> bytes,
[Encoding encoding = Encoding.UTF_8]) {
if (bytes.length == 0) return "";
var string;
var error;
var controller = new StreamController(sync: true);
controller.stream
.transform(new StringDecoder(encoding))
.listen((data) => string = data,
onError: (e) => error = e);
controller.add(bytes);
controller.close();
if (error != null) throw error;
assert(string != null);
return string;
}
}
class _HttpBodyFileUpload implements HttpBodyFileUpload {

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
part of http_server;
/**

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
part of http_server;
class _HttpMultipartFormData extends Stream implements HttpMultipartFormData {
@ -136,4 +136,3 @@ class _HttpMultipartFormData extends Stream implements HttpMultipartFormData {
return buffer.toString();
}
}

View file

@ -5,7 +5,8 @@
import 'dart:io';
import 'dart:utf';
import 'package:expect/expect.dart';
import 'package:http_server/http_server.dart';
import 'package:unittest/unittest.dart';
void testHttpClientResponseBody() {
void test(String mimeType,
@ -30,20 +31,17 @@ void testHttpClientResponseBody() {
.then((request) => request.close())
.then(HttpBodyHandler.processResponse)
.then((body) {
if (shouldFail) Expect.fail("Error expected");
Expect.equals(type, body.type);
Expect.isNotNull(body.response);
expect(shouldFail, isFalse);
expect(body.type, equals(type));
expect(body.response, isNotNull);
switch (type) {
case "text":
Expect.equals(expectedBody, body.body);
break;
case "json":
Expect.mapEquals(expectedBody, body.body);
expect(body.body, equals(expectedBody));
break;
default:
Expect.fail("bad body type");
fail("bad body type");
}
}, onError: (error) {
if (!shouldFail) throw error;
@ -95,52 +93,49 @@ void testHttpServerRequestBody() {
HttpServer.bind("127.0.0.1", 0).then((server) {
server.transform(new HttpBodyHandler(defaultEncoding: defaultEncoding))
.listen((body) {
if (shouldFail) Expect.fail("Error expected");
Expect.equals(type, body.type);
expect(shouldFail, isFalse);
expect(body.type, equals(type));
switch (type) {
case "text":
Expect.equals(body.contentType.mimeType, "text/plain");
Expect.equals(expectedBody, body.body);
expect(body.contentType.mimeType, equals("text/plain"));
expect(body.body, equals(expectedBody));
break;
case "json":
Expect.equals(body.contentType.mimeType, "application/json");
Expect.mapEquals(expectedBody, body.body);
expect(body.contentType.mimeType, equals("application/json"));
expect(body.body, equals(expectedBody));
break;
case "binary":
Expect.equals(body.contentType, null);
Expect.listEquals(expectedBody, body.body);
expect(body.contentType, isNull);
expect(body.body, equals(expectedBody));
break;
case "form":
var mimeType = body.contentType.mimeType;
Expect.isTrue(
mimeType == 'multipart/form-data' ||
mimeType == 'application/x-www-form-urlencoded');
Expect.setEquals(expectedBody.keys.toSet(),
body.body.keys.toSet());
expect(mimeType,
anyOf(equals('multipart/form-data'),
equals('application/x-www-form-urlencoded')));
expect(body.body.keys.toSet(),
equals(expectedBody.keys.toSet()));
for (var key in expectedBody.keys) {
if (body.body[key] is HttpBodyFileUpload) {
Expect.equals(expectedBody[key]['contentType'],
body.body[key].contentType.toString());
Expect.equals(expectedBody[key]['filename'],
body.body[key].filename);
if (body.body[key].content is String) {
Expect.equals(expectedBody[key]['content'],
body.body[key].content);
} else {
Expect.listEquals(expectedBody[key]['content'],
body.body[key].content);
}
var found = body.body[key];
var expected = expectedBody[key];
if (found is HttpBodyFileUpload) {
expect(found.contentType.toString(),
equals(expected['contentType']));
expect(found.filename,
equals(expected['filename']));
expect(found.content,
equals(expected['content']));
} else {
Expect.equals(expectedBody[key], body.body[key]);
expect(found, equals(expected));
}
}
break;
default:
Expect.fail("bad body type");
throw "bad body type";
}
body.response.close();
}, onError: (error) {
@ -159,7 +154,7 @@ void testHttpServerRequestBody() {
})
.then((response) {
if (shouldFail) {
Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode);
expect(response.statusCode, equals(HttpStatus.BAD_REQUEST));
}
response.fold(null, (x, y) {});
client.close();

View file

@ -1,13 +1,10 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write
import "package:expect/expect.dart";
import "package:http_server/http_server.dart";
import "package:mime/mime.dart";
import "package:unittest/unittest.dart";
import 'dart:async';
import 'dart:io';
@ -76,7 +73,7 @@ void postDataTest(List<int> message,
.fold([], (l, f) => l..add(f))
.then(Future.wait)
.then((fields) {
Expect.listEquals(expectedFields, fields);
expect(fields, equals(expectedFields));
request.response.close().then((_) => server.close());
});
});

View file

@ -4,6 +4,10 @@
library mime;
import 'dart:async';
import 'dart:typed_data';
part 'src/mime_type.dart';
part 'src/extension_map.dart';
part 'src/magic_number.dart';
part 'src/mime_multipart_transformer.dart';

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
part of mime;
/**
@ -30,6 +30,21 @@ class _MimeMultipart extends MimeMultipart {
}
}
class _Const {
// Bytes for '()<>@,;:\\"/[]?={} \t'.
static const SEPARATORS = const [40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47,
91, 93, 63, 61, 123, 125, 32, 9];
}
class _CharCode {
static const int HT = 9;
static const int LF = 10;
static const int CR = 13;
static const int SP = 32;
static const int DASH = 45;
static const int COLON = 58;
}
/**
* Parser for MIME multipart types of data as described in RFC 2046
* section 5.1.1. The data is transformed into [MimeMultipart] objects, each
@ -398,7 +413,7 @@ class MimeMultipartTransformer
}
class MimeMultipartException implements IOException {
class MimeMultipartException implements Exception {
const MimeMultipartException([String this.message = ""]);
String toString() => "MimeMultipartException: $message";
final String message;

View file

@ -2,44 +2,43 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
import "package:unittest/unittest.dart";
import "package:mime/mime.dart";
import 'dart:async';
import 'dart:math';
import 'dart:io';
import 'dart:isolate';
void testParse(String message,
String boundary,
[List<Map> expectedHeaders,
List expectedParts,
bool expectError = false]) {
void testWrite(List<int> data, [int chunkSize = -1]) {
List expectedParts,
bool expectError = false]) {
Future testWrite(List<int> data, [int chunkSize = -1]) {
StreamController controller = new StreamController(sync: true);
var stream = controller.stream.transform(
new MimeMultipartTransformer(boundary));
int i = 0;
var port = new ReceivePort();
var completer = new Completer();
var futures = [];
stream.listen((multipart) {
int part = i++;
if (expectedHeaders != null) {
Expect.mapEquals(expectedHeaders[part], multipart.headers);
expect(multipart.headers, equals(expectedHeaders[part]));
}
var partPort = new ReceivePort();
multipart.fold([], (buffer, data) => buffer..addAll(data))
futures.add(multipart.fold([], (buffer, data) => buffer..addAll(data))
.then((data) {
if (expectedParts[part] != null) {
Expect.listEquals(expectedParts[part].codeUnits, data);
expect(data, equals(expectedParts[part].codeUnits));
}
partPort.close();
});
}));
}, onError: (error) {
if (!expectError) throw error;
}, onDone: () {
if (expectedParts != null) {
Expect.equals(expectedParts.length, i);
expect(i, equals(expectedParts.length));
}
port.close();
Future.wait(futures).then(completer.complete);
});
if (chunkSize == -1) chunkSize = data.length;
@ -52,15 +51,19 @@ void testParse(String message,
written += writeLength;
}
controller.close();
return completer.future;
}
// Test parsing the data three times delivering the data in
// different chunks.
List<int> data = message.codeUnits;
testWrite(data);
testWrite(data, 10);
testWrite(data, 2);
testWrite(data, 1);
expect(Future.wait([
testWrite(data),
testWrite(data, 10),
testWrite(data, 2),
testWrite(data, 1)]),
completes);
}
void testParseValid() {

View file

@ -35,14 +35,16 @@ _getHttpRequestResponseCode() => _httpRequestResponseCode;
_getHttpRequestStatusString() => _httpRequestStatusString;
_getHttpRequestResponse() => _httpRequestResponse;
void _requestCompleted(HttpClientResponseBody body) {
_httpRequestResponseCode = body.statusCode;
_httpRequestStatusString = '${body.statusCode} ${body.reasonPhrase}';
void _requestCompleted(List<int> data, HttpClientResponse response) {
_httpRequestResponseCode = response.statusCode;
_httpRequestStatusString = '${response.statusCode} ${response.reasonPhrase}';
_httpRequestResponse = null;
if (body.statusCode != 200 || body.type == 'json') {
if (response.statusCode != 200 ||
(response.headers.contentType != null &&
response.headers.contentType.mimeType == 'application/json')) {
return;
}
_httpRequestResponse = body.body;
_httpRequestResponse = data;
}
@ -61,9 +63,12 @@ void _makeHttpRequest(String uri) {
Uri requestUri = Uri.parse(uri);
_client.getUrl(requestUri)
.then((HttpClientRequest request) => request.close())
.then(HttpBodyHandler.processResponse)
.then((HttpClientResponseBody body) {
_requestCompleted(body);
.then((HttpClientResponse response) {
return response
.fold(new BytesBuilder(), (b, d) => b..add(d))
.then((builder) {
_requestCompleted(builder.takeBytes(), response);
});
}).catchError((error) {
_requestFailed(error);
});

View file

@ -503,7 +503,6 @@ bool isUserFacingException(error) {
error is HttpException ||
error is HttpException ||
error is LinkException ||
error is MimeMultipartException ||
error is OSError ||
error is ProcessException ||
error is SocketException ||

View file

@ -34,18 +34,13 @@ part 'file.dart';
part 'file_impl.dart';
part 'file_system_entity.dart';
part 'http.dart';
part 'http_body.dart';
part 'http_body_impl.dart';
part 'http_date.dart';
part 'http_headers.dart';
part 'http_impl.dart';
part 'http_multipart_form_data.dart';
part 'http_multipart_form_data_impl.dart';
part 'http_parser.dart';
part 'http_session.dart';
part 'io_sink.dart';
part 'link.dart';
part 'mime_multipart_parser.dart';
part 'options.dart';
part 'path.dart';
part 'path_impl.dart';

View file

@ -15,18 +15,13 @@
'file_impl.dart',
'file_system_entity.dart',
'http.dart',
'http_body.dart',
'http_body_impl.dart',
'http_date.dart',
'http_headers.dart',
'http_impl.dart',
'http_multipart_form_data.dart',
'http_multipart_form_data_impl.dart',
'http_parser.dart',
'http_session.dart',
'io_sink.dart',
'link.dart',
'mime_multipart_parser.dart',
'options.dart',
'path.dart',
'path_impl.dart',