blob: 243ed8a8ffab937aa1c8eeb7413e74531ac5f749 [file] [log] [blame]
// Copyright (c) 2018, 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.
import "dart:async";
import "dart:io" show Directory, File, Platform;
import "dart:typed_data";
import "package:http_io/http_io.dart";
import "package:test/test.dart";
// Platform.script may refer to a AOT or JIT snapshot, which are significantly
// larger.
File scriptSource;
void testServerRequest(void handler(server, request),
{int bytes, bool closeClient}) {
HttpServer.bind("127.0.0.1", 0).then((server) {
server.defaultResponseHeaders.clear();
server.listen((request) {
handler(server, request);
});
var client = new HttpClient();
// We only close the client on either
// - Bad response headers
// - Response done (with optional errors in between).
client
.get("127.0.0.1", server.port, "/")
.then((request) => request.close())
.then((response) {
int received = 0;
StreamSubscription subscription;
subscription = response.listen((data) {
if (closeClient == true) {
subscription.cancel();
client.close();
} else {
received += data.length;
}
}, onDone: () {
if (bytes != null) expect(received, equals(bytes));
client.close();
}, onError: (error) {
expect(error is HttpException, isTrue);
});
}).catchError((error) {
client.close();
}, test: (e) => e is HttpException);
});
}
Future<List> testResponseDone() {
final completers = new List<Future<Null>>();
final completer = new Completer<Null>();
testServerRequest((server, request) {
request.response.close();
request.response.done.then((response) {
expect(request.response, equals(response));
server.close();
completer.complete();
});
});
completers.add(completer.future);
final completer2 = new Completer<Null>();
testServerRequest((server, request) {
new File("__nonexistent_file_")
.openRead()
.cast<List<int>>()
.pipe(request.response)
.catchError((e) {
server.close();
completer2.complete();
});
});
completers.add(completer2.future);
final completer3 = new Completer<Null>();
testServerRequest((server, request) {
request.response.done.then((_) {
server.close();
completer3.complete();
});
request.response.contentLength = 0;
request.response.close();
});
completers.add(completer3.future);
return Future.wait(completers);
}
Future<List> testResponseAddStream() {
File file = scriptSource;
int bytes = file.lengthSync();
final completers = new List<Future<Null>>();
final completer = new Completer<Null>();
testServerRequest((server, request) {
request.response.addStream(file.openRead()).then((response) {
response.close();
response.done.then((_) {
server.close();
completer.complete();
});
});
}, bytes: bytes);
completers.add(completer.future);
final completer2 = new Completer<Null>();
testServerRequest((server, request) {
request.response.addStream(file.openRead()).then((response) {
request.response.addStream(file.openRead()).then((response) {
response.close();
response.done.then((_) {
server.close();
completer2.complete();
});
});
});
}, bytes: bytes * 2);
completers.add(completer2.future);
final completer3 = new Completer<Null>();
testServerRequest((server, request) {
var controller = new StreamController<List<int>>(sync: true);
request.response.addStream(controller.stream).then((response) {
response.close();
response.done.then((_) {
server.close();
completer3.complete();
});
});
controller.close();
}, bytes: 0);
completers.add(completer3.future);
final completer4 = new Completer<Null>();
testServerRequest((server, request) {
request.response
.addStream(new File("__nonexistent_file_").openRead())
.catchError((e) {
server.close();
completer4.complete();
});
});
completers.add(completer4.future);
final completer5 = new Completer<Null>();
testServerRequest((server, request) {
new File("__nonexistent_file_")
.openRead()
.cast<List<int>>()
.pipe(request.response)
.catchError((e) {
server.close();
completer5.complete();
});
});
completers.add(completer5.future);
return Future.wait(completers);
}
Future<Null> testResponseAddStreamClosed() {
final completer = new Completer<Null>();
File file = scriptSource;
testServerRequest((server, request) {
request.response
.addStream(file.openRead().cast<List<int>>())
.then((response) {
response.close();
response.done.then((_) => server.close());
});
}, closeClient: true);
testServerRequest((server, request) {
int count = 0;
write() {
request.response.addStream(file.openRead()).then((response) {
request.response.write("sync data");
count++;
if (count < 1000) {
write();
} else {
response.close();
response.done.then((_) {
server.close();
completer.complete();
});
}
});
}
write();
}, closeClient: true);
return completer.future;
}
Future<List> testResponseAddClosed() {
File file = scriptSource;
final completers = new List<Future<Null>>();
final completer = new Completer<Null>();
testServerRequest((server, request) {
request.response.add(file.readAsBytesSync());
request.response.close();
request.response.done.then((_) {
server.close();
completer.complete();
});
}, closeClient: true);
completers.add(completer.future);
final completer2 = new Completer<Null>();
testServerRequest((server, request) {
for (int i = 0; i < 1000; i++) {
request.response.add(file.readAsBytesSync());
}
request.response.close();
request.response.done.then((_) {
server.close();
completer2.complete();
});
}, closeClient: true);
completers.add(completer2.future);
final completer3 = new Completer<Null>();
testServerRequest((server, request) {
int count = 0;
write() {
request.response.add(file.readAsBytesSync());
Timer.run(() {
count++;
if (count < 1000) {
write();
} else {
request.response.close();
request.response.done.then((_) {
server.close();
completer3.complete();
});
}
});
}
write();
}, closeClient: true);
completers.add(completer3.future);
return Future.wait(completers);
}
Future<List> testBadResponseAdd() {
final completers = new List<Future<Null>>();
final completer = new Completer<Null>();
testServerRequest((server, request) {
request.response.contentLength = 0;
request.response.add([0]);
request.response.close();
request.response.done.catchError((error) {
server.close();
completer.complete();
}, test: (e) => e is HttpException);
});
completers.add(completer.future);
final completer2 = new Completer<Null>();
testServerRequest((server, request) {
request.response.contentLength = 5;
request.response.add([0, 0, 0]);
request.response.add([0, 0, 0]);
request.response.close();
request.response.done.catchError((error) {
server.close();
completer2.complete();
}, test: (e) => e is HttpException);
});
completers.add(completer2.future);
final completer3 = new Completer<Null>();
testServerRequest((server, request) {
request.response.contentLength = 0;
request.response.add(new Uint8List(64 * 1024));
request.response.add(new Uint8List(64 * 1024));
request.response.add(new Uint8List(64 * 1024));
request.response.close();
request.response.done.catchError((error) {
server.close();
completer3.complete();
}, test: (e) => e is HttpException);
});
completers.add(completer3.future);
return Future.wait(completers);
}
Future<List> testBadResponseClose() {
final completers = new List<Future<Null>>();
final completer = new Completer<Null>();
testServerRequest((server, request) {
request.response.contentLength = 5;
request.response.close();
request.response.done.catchError((error) {
server.close();
completer.complete();
}, test: (e) => e is HttpException);
});
completers.add(completer.future);
final completer2 = new Completer<Null>();
testServerRequest((server, request) {
request.response.contentLength = 5;
request.response.add([0]);
request.response.close();
request.response.done.catchError((error) {
server.close();
completer2.complete();
}, test: (e) => e is HttpException);
});
completers.add(completer2.future);
return Future.wait(completers);
}
Future<Null> testIgnoreRequestData() {
final completer = new Completer<Null>();
HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
// Ignore request data.
request.response.write("all-okay");
request.response.close();
});
var client = new HttpClient();
client.get("127.0.0.1", server.port, "/").then((request) {
request.contentLength = 1024 * 1024;
request.add(new Uint8List(1024 * 1024));
return request.close();
}).then((response) {
response.fold(0, (s, b) => s + b.length).then((bytes) {
expect(8, equals(bytes));
server.close();
completer.complete();
});
});
});
return completer.future;
}
Future<Null> testWriteCharCode() {
final completer = new Completer<Null>();
testServerRequest((server, request) {
// Test that default is latin-1 (only 2 bytes).
request.response.writeCharCode(0xFF);
request.response.writeCharCode(0xFF);
request.response.close().then((_) {
server.close();
completer.complete();
});
}, bytes: 2);
return completer.future;
}
void main() {
scriptSource =
new File('${Directory.current.path}/test/http_server_response_test.dart');
if (!scriptSource.existsSync()) {
// If we can't find the file relative to the cwd, then look relative
// to Platform.script.
scriptSource = new File(
Platform.script.resolve('http_server_response_test.dart').toFilePath());
}
test('responseDone', () => testResponseDone());
test('responseAddStream', () => testResponseAddStream());
test('responseAddStreamClosed', () => testResponseAddStreamClosed());
test('responseAddClosed', () => testResponseAddClosed());
test('badResponseAdd', () => testBadResponseAdd());
test('badResponseClose', () => testBadResponseClose());
test('ignoreRequestData', () => testIgnoreRequestData());
test('writeCharCode', () => testWriteCharCode());
}