|  | // 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 "dart:async"; | 
|  | import "dart:io"; | 
|  | import "dart:isolate"; | 
|  | import "package:expect/expect.dart"; | 
|  |  | 
|  | Future sendData(List<int> data, int port) { | 
|  | return Socket.connect("127.0.0.1", port).then((socket) { | 
|  | socket.listen((data) { | 
|  | Expect.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; | 
|  | bool calledOnDone = false; | 
|  | ReceivePort port = new ReceivePort(); | 
|  | var requestCompleter = new Completer(); | 
|  | server.listen((request) { | 
|  | Expect.isTrue(expectRequest); | 
|  | Expect.isFalse(calledOnError); | 
|  | Expect.isFalse(calledOnRequest, "onRequest called multiple times"); | 
|  | calledOnRequest = true; | 
|  | request.listen((_) {}, onDone: () { | 
|  | requestCompleter.complete(); | 
|  | }, onError: (error) { | 
|  | Expect.isFalse(calledOnError); | 
|  | Expect.equals(exception, error.message); | 
|  | calledOnError = true; | 
|  | if (exception != null) port.close(); | 
|  | }); | 
|  | }, onDone: () { | 
|  | Expect.equals(expectRequest, calledOnRequest); | 
|  | calledOnDone = true; | 
|  | 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) Expect.fail("Invalid data"); | 
|  | sendData(d!, server.port).then((_) { | 
|  | if (!expectRequest) requestCompleter.complete(); | 
|  | requestCompleter.future.then((_) => server.close()); | 
|  | }); | 
|  |  | 
|  | return c.future; | 
|  | }); | 
|  | } | 
|  |  | 
|  | final data; | 
|  | final String? exception; | 
|  | final bool expectRequest; | 
|  | } | 
|  |  | 
|  | void testEarlyClose1() { | 
|  | List<EarlyCloseTest> tests = <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); | 
|  |  | 
|  | void runTest(Iterator it) { | 
|  | if (it.moveNext()) { | 
|  | it.current.execute().then((_) { | 
|  | runTest(it); | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | runTest(tests.iterator); | 
|  | } | 
|  |  | 
|  | testEarlyClose2() { | 
|  | HttpServer.bind("127.0.0.1", 0).then((server) { | 
|  | server.listen((request) { | 
|  | String name = Platform.script.toFilePath(); | 
|  | new File(name) | 
|  | .openRead() | 
|  | .cast<List<int>>() | 
|  | .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); | 
|  | } | 
|  | }); | 
|  | }); | 
|  | } | 
|  |  | 
|  | makeRequest(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void testEarlyClose3() { | 
|  | 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(); | 
|  | }); | 
|  | }); | 
|  | 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((_) {}); | 
|  | }); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void main() { | 
|  | testEarlyClose1(); | 
|  | testEarlyClose2(); | 
|  | testEarlyClose3(); | 
|  | } |