Migrated http_server_early_client_close_test from the SDK (#35)

* Migrated http_server_early_client_close_test from the SDK
diff --git a/test/http_server_early_client_close_test.dart b/test/http_server_early_client_close_test.dart
new file mode 100644
index 0000000..f16ae44
--- /dev/null
+++ b/test/http_server_early_client_close_test.dart
@@ -0,0 +1,165 @@
+// 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, Socket;
+import "dart:isolate";
+
+import 'package:http_io/http_io.dart';
+import 'package:test/test.dart';
+
+Future sendData(List<int> data, int port) {
+  return Socket.connect("127.0.0.1", port).then((socket) {
+    socket.listen((data) {
+      fail("No data response was expected");
+    });
+    socket.add(data);
+    return socket.close().then((_) {
+      socket.destroy();
+    });
+  });
+}
+
+class EarlyCloseTest {
+  EarlyCloseTest(this.data, [this.exception, this.expectRequest = false]);
+
+  Future execute() {
+    return HttpServer.bind("127.0.0.1", 0).then((server) {
+      Completer c = new Completer();
+
+      bool calledOnRequest = false;
+      bool calledOnError = false;
+      ReceivePort port = new ReceivePort();
+      var requestCompleter = new Completer();
+      server.listen((request) {
+        expect(expectRequest, isTrue);
+        expect(calledOnError, isFalse);
+        expect(calledOnRequest, isFalse);
+        calledOnRequest = true;
+        request.listen((_) {}, onDone: () {
+          requestCompleter.complete();
+        }, onError: (error) {
+          expect(calledOnError, isFalse);
+          expect(exception, equals(error.message));
+          calledOnError = true;
+          if (exception != null) port.close();
+        });
+      }, onDone: () {
+        expect(expectRequest, equals(calledOnRequest));
+        if (exception == null) port.close();
+        c.complete(null);
+      });
+
+      List<int> d;
+      if (data is List<int>) d = data;
+      if (data is String) d = data.codeUnits;
+      if (d == null) fail("Invalid data");
+      sendData(d, server.port).then((_) {
+        if (!expectRequest) requestCompleter.complete();
+        requestCompleter.future.then((_) => server.close());
+      });
+
+      return c.future;
+    });
+  }
+
+  final dynamic data;
+  final String exception;
+  final bool expectRequest;
+}
+
+Future<Null> testEarlyClose1() async {
+  List<EarlyCloseTest> tests = new List<EarlyCloseTest>();
+  void add(Object data, [String exception, bool expectRequest = false]) {
+    tests.add(new EarlyCloseTest(data, exception, expectRequest));
+  }
+  // The empty packet is valid.
+
+  // Close while sending header
+  add("G");
+  add("GET /");
+  add("GET / HTTP/1.1");
+  add("GET / HTTP/1.1\r\n");
+
+  // Close while sending content
+  add("GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n",
+      "Connection closed while receiving data", true);
+  add("GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n1",
+      "Connection closed while receiving data", true);
+
+  for (final t in tests) {
+    await t.execute();
+  }
+}
+
+Future<Null> testEarlyClose2() {
+  final completer = new Completer<Null>();
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen((request) {
+      String name =
+          "${Directory.current.path}/test/http_server_early_client_close_test.dart";
+      if (!new File(name).existsSync()) {
+        name = Platform.script.toFilePath();
+      }
+      new File(name)
+          .openRead()
+          .pipe(request.response)
+          .catchError((e) {/* ignore */});
+    });
+
+    var count = 0;
+    makeRequest() {
+      Socket.connect("127.0.0.1", server.port).then((socket) {
+        var data = "GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n";
+        socket.write(data);
+        socket.close();
+        socket.done.then((_) {
+          socket.destroy();
+          if (++count < 10) {
+            makeRequest();
+          } else {
+            scheduleMicrotask(() {
+              server.close();
+              completer.complete();
+            });
+          }
+        });
+      });
+    }
+
+    makeRequest();
+  });
+  return completer.future;
+}
+
+Future<Null> testEarlyClose3() {
+  final completer = new Completer<Null>();
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen((request) {
+      var subscription;
+      subscription = request.listen((_) {}, onError: (error) {
+        // subscription.cancel should not trigger an error.
+        subscription.cancel();
+        server.close();
+        completer.complete();
+      });
+    });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.write("GET / HTTP/1.1\r\n");
+      socket.write("Content-Length: 10\r\n");
+      socket.write("\r\n");
+      socket.write("data");
+      socket.close();
+      socket.listen((_) {}, onError: (_) {});
+      socket.done.catchError((_) {});
+    });
+  });
+  return completer.future;
+}
+
+void main() {
+  test('testEarlyClose1', testEarlyClose1);
+  test('testEarlyClose2', testEarlyClose2);
+  test('testEarlyClose3', testEarlyClose3);
+}