| Index: tests/standalone/io/http_parser_test.dart
|
| diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
|
| index fe4018a91bf84410536243bec18f40f0c9589c22..173fec4410da150a51ad1fb842deaaf9cdc4f4ee 100644
|
| --- a/tests/standalone/io/http_parser_test.dart
|
| +++ b/tests/standalone/io/http_parser_test.dart
|
| @@ -1,14 +1,19 @@
|
| -// 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.
|
|
|
| import 'dart:async';
|
| import 'dart:math';
|
| import 'dart:scalarlist';
|
| +import 'dart:isolate';
|
| +import 'dart:uri';
|
|
|
| +part '../../../sdk/lib/io/io_stream_consumer.dart';
|
| part '../../../sdk/lib/io/http.dart';
|
| +part '../../../sdk/lib/io/http_impl.dart';
|
| part '../../../sdk/lib/io/http_headers.dart';
|
| part '../../../sdk/lib/io/http_parser.dart';
|
| +part '../../../sdk/lib/io/socket.dart';
|
|
|
| class HttpParserTest {
|
| static void runAllTests() {
|
| @@ -21,7 +26,7 @@ class HttpParserTest {
|
| static void _testParseRequest(String request,
|
| String expectedMethod,
|
| String expectedUri,
|
| - {int expectedContentLength: 0,
|
| + {int expectedTransferLength: 0,
|
| int expectedBytesReceived: 0,
|
| Map expectedHeaders: null,
|
| bool chunked: false,
|
| @@ -29,88 +34,93 @@ class HttpParserTest {
|
| int unparsedLength: 0,
|
| bool connectionClose: false,
|
| String expectedVersion: "1.1"}) {
|
| - _HttpParser httpParser;
|
| - bool headersCompleteCalled;
|
| - bool dataEndCalled;
|
| - String method;
|
| - String uri;
|
| - String version;
|
| - HttpHeaders headers;
|
| - int contentLength;
|
| - int bytesReceived;
|
| -
|
| + StreamController controller;
|
| void reset() {
|
| - httpParser = new _HttpParser.requestParser();
|
| - httpParser.requestStart = (m, u, v, h, b) {
|
| - method = m;
|
| - uri = u;
|
| - version = v;
|
| - headers = h;
|
| - headersCompleteCalled = true;
|
| + _HttpParser httpParser = new _HttpParser.requestParser();
|
| + controller = new StreamController();
|
| + var port1 = new ReceivePort();
|
| + var port2 = new ReceivePort();
|
| +
|
| + String method;
|
| + Uri uri;
|
| + HttpHeaders headers;
|
| + int contentLength;
|
| + int bytesReceived;
|
| + int unparsedBytesReceived;
|
| + bool upgraded;
|
| +
|
| + controller.stream.pipe(httpParser);
|
| + var subscription = httpParser.listen((incoming) {
|
| + method = incoming.method;
|
| + uri = incoming.uri;
|
| + headers = incoming.headers;
|
| + upgraded = incoming.upgraded;
|
| + Expect.equals(upgrade, upgraded);
|
| +
|
| if (!chunked) {
|
| - Expect.equals(expectedContentLength, httpParser.contentLength);
|
| + Expect.equals(expectedTransferLength, incoming.transferLength);
|
| } else {
|
| - Expect.equals(-1, httpParser.contentLength);
|
| + Expect.equals(-1, incoming.transferLength);
|
| }
|
| if (expectedHeaders != null) {
|
| expectedHeaders.forEach(
|
| (String name, String value) =>
|
| Expect.equals(value, headers[name][0]));
|
| }
|
| - Expect.equals(upgrade, httpParser.upgrade);
|
| - Expect.equals(connectionClose, !httpParser.persistentConnection);
|
| - headersCompleteCalled = true;
|
| - };
|
| - httpParser.responseStart = (s, r, v, h, b) {
|
| - Expect.fail("Expected request");
|
| - };
|
| - httpParser.dataReceived = (List<int> data) {
|
| - Expect.isTrue(headersCompleteCalled);
|
| - bytesReceived += data.length;
|
| - };
|
| - httpParser.dataEnd = (close) {
|
| - Expect.isFalse(close);
|
| - dataEndCalled = true;
|
| - };
|
| - httpParser.closed = () { };
|
| + incoming.listen(
|
| + (List<int> data) {
|
| + Expect.isFalse(upgraded);
|
| + bytesReceived += data.length;
|
| + },
|
| + onDone: () {
|
| + Expect.isFalse(upgraded);
|
| + port2.close();
|
| + });
|
| +
|
| + if (upgraded) {
|
| + port1.close();
|
| + httpParser.detachIncoming().listen(
|
| + (List<int> data) {
|
| + unparsedBytesReceived += data.length;
|
| + },
|
| + onDone: () {
|
| + Expect.equals(unparsedLength, unparsedBytesReceived);
|
| + port2.close();
|
| + });
|
| + }
|
| +
|
| + incoming.dataDone.then((_) {
|
| + port1.close();
|
| + Expect.isFalse(upgraded);
|
| + Expect.equals(expectedMethod, method);
|
| + Expect.stringEquals(expectedUri, uri.toString());
|
| + Expect.equals(expectedVersion, headers.protocolVersion);
|
| + if (upgrade) {
|
| + Expect.equals(0, bytesReceived);
|
| + // port1 is closed by the listener on the detached data.
|
| + } else {
|
| + Expect.equals(expectedBytesReceived, bytesReceived);
|
| + }
|
| + });
|
| + });
|
|
|
| - headersCompleteCalled = false;
|
| - dataEndCalled = false;
|
| method = null;
|
| uri = null;
|
| headers = null;
|
| bytesReceived = 0;
|
| + unparsedBytesReceived = 0;
|
| + upgraded = false;
|
| }
|
|
|
| void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
| if (chunkSize == -1) chunkSize = requestData.length;
|
| reset();
|
| - int written = 0;
|
| - int unparsed;
|
| for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
| int remaining = requestData.length - pos;
|
| int writeLength = min(chunkSize, remaining);
|
| - written += writeLength;
|
| - httpParser.streamData(requestData.getRange(pos, writeLength));
|
| - unparsed = httpParser.readUnparsedData().length;
|
| - if (httpParser.upgrade) {
|
| - unparsed += requestData.length - written;
|
| - break;
|
| - } else {
|
| - Expect.equals(0, unparsed);
|
| - }
|
| - }
|
| - Expect.equals(expectedMethod, method);
|
| - Expect.equals(expectedUri, uri);
|
| - Expect.equals(expectedVersion, version);
|
| - Expect.isTrue(headersCompleteCalled);
|
| - Expect.equals(expectedBytesReceived, bytesReceived);
|
| - if (!upgrade) Expect.isTrue(dataEndCalled);
|
| - if (unparsedLength == 0) {
|
| - Expect.equals(0, unparsed);
|
| - } else {
|
| - Expect.equals(unparsedLength, unparsed);
|
| + controller.add(requestData.getRange(pos, writeLength));
|
| }
|
| + controller.close();
|
| }
|
|
|
| // Test parsing the request three times delivering the data in
|
| @@ -124,17 +134,23 @@ class HttpParserTest {
|
| static void _testParseInvalidRequest(String request) {
|
| _HttpParser httpParser;
|
| bool errorCalled;
|
| + StreamController controller;
|
|
|
| void reset() {
|
| httpParser = new _HttpParser.requestParser();
|
| - httpParser.responseStart = (s, r, v, h, b) {
|
| + controller = new StreamController();
|
| + var port = new ReceivePort();
|
| + controller.stream.pipe(httpParser);
|
| + var subscription = httpParser.listen((incoming) {
|
| Expect.fail("Expected request");
|
| - };
|
| - httpParser.error = (e) {
|
| + });
|
| + subscription.onError((e) {
|
| errorCalled = true;
|
| - };
|
| - httpParser.closed = () { };
|
| -
|
| + });
|
| + subscription.onDone(() {
|
| + port.close();
|
| + Expect.isTrue(errorCalled);
|
| + });
|
| errorCalled = false;
|
| }
|
|
|
| @@ -146,9 +162,9 @@ class HttpParserTest {
|
| pos += chunkSize) {
|
| int remaining = requestData.length - pos;
|
| int writeLength = min(chunkSize, remaining);
|
| - httpParser.streamData(requestData.getRange(pos, writeLength));
|
| + controller.add(requestData.getRange(pos, writeLength));
|
| }
|
| - Expect.isTrue(errorCalled);
|
| + controller.close();
|
| }
|
|
|
| // Test parsing the request three times delivering the data in
|
| @@ -162,7 +178,7 @@ class HttpParserTest {
|
| static void _testParseResponse(String response,
|
| int expectedStatusCode,
|
| String expectedReasonPhrase,
|
| - {int expectedContentLength: -1,
|
| + {int expectedTransferLength: 0,
|
| int expectedBytesReceived: 0,
|
| Map expectedHeaders: null,
|
| bool chunked: false,
|
| @@ -178,29 +194,27 @@ class HttpParserTest {
|
| bool dataEndClose;
|
| int statusCode;
|
| String reasonPhrase;
|
| - String version;
|
| HttpHeaders headers;
|
| int contentLength;
|
| int bytesReceived;
|
| + StreamController controller;
|
| + bool upgraded;
|
|
|
| void reset() {
|
| httpParser = new _HttpParser.responseParser();
|
| - if (responseToMethod != null) {
|
| - httpParser.responseToMethod = responseToMethod;
|
| - }
|
| - httpParser.requestStart = (m, u, v, h, b) {
|
| - Expect.fail("Expected response");
|
| - };
|
| - httpParser.responseStart = (s, r, v, h, b) {
|
| - statusCode = s;
|
| - reasonPhrase = r;
|
| - version = v;
|
| - headers = h;
|
| + controller = new StreamController();
|
| + var port = new ReceivePort();
|
| + controller.stream.pipe(httpParser);
|
| + var subscription = httpParser.listen((incoming) {
|
| + port.close();
|
| + statusCode = incoming.statusCode;
|
| + reasonPhrase = incoming.reasonPhrase;
|
| + headers = incoming.headers;
|
| Expect.isFalse(headersCompleteCalled);
|
| if (!chunked && !close) {
|
| - Expect.equals(expectedContentLength, httpParser.contentLength);
|
| + Expect.equals(expectedTransferLength, incoming.transferLength);
|
| } else {
|
| - Expect.equals(-1, httpParser.contentLength);
|
| + Expect.equals(-1, incoming.transferLength);
|
| }
|
| if (expectedHeaders != null) {
|
| expectedHeaders.forEach((String name, String value) {
|
| @@ -209,16 +223,29 @@ class HttpParserTest {
|
| }
|
| Expect.equals(upgrade, httpParser.upgrade);
|
| headersCompleteCalled = true;
|
| - };
|
| - httpParser.dataReceived = (List<int> data) {
|
| + incoming.listen(
|
| + (List<int> data) {
|
| + Expect.isTrue(headersCompleteCalled);
|
| + bytesReceived += data.length;
|
| + },
|
| + onDone: () {
|
| + dataEndCalled = true;
|
| + dataEndClose = close;
|
| + });
|
| + });
|
| +
|
| + subscription.onDone(() {
|
| + Expect.equals(expectedVersion, headers.protocolVersion);
|
| + Expect.equals(expectedStatusCode, statusCode);
|
| + Expect.equals(expectedReasonPhrase, reasonPhrase);
|
| Expect.isTrue(headersCompleteCalled);
|
| - bytesReceived += data.length;
|
| - };
|
| - httpParser.dataEnd = (close) {
|
| - dataEndCalled = true;
|
| - dataEndClose = close;
|
| - };
|
| - httpParser.closed = () { };
|
| + Expect.equals(expectedBytesReceived, bytesReceived);
|
| + if (!upgrade) {
|
| + Expect.isTrue(dataEndCalled);
|
| + if (close) Expect.isTrue(dataEndClose);
|
| + Expect.equals(dataEndClose, connectionClose);
|
| + }
|
| + });
|
|
|
| headersCompleteCalled = false;
|
| dataEndCalled = false;
|
| @@ -232,37 +259,13 @@ class HttpParserTest {
|
| void testWrite(List<int> requestData, [int chunkSize = -1]) {
|
| if (chunkSize == -1) chunkSize = requestData.length;
|
| reset();
|
| - int written = 0;
|
| - int unparsed;
|
| for (int pos = 0; pos < requestData.length; pos += chunkSize) {
|
| int remaining = requestData.length - pos;
|
| int writeLength = min(chunkSize, remaining);
|
| - written += writeLength;
|
| - httpParser.streamData(requestData.getRange(pos, writeLength));
|
| - unparsed = httpParser.readUnparsedData().length;
|
| - if (httpParser.upgrade) {
|
| - unparsed += requestData.length - written;
|
| - break;
|
| - } else {
|
| - Expect.equals(0, unparsed);
|
| - }
|
| - }
|
| - if (close) httpParser.streamDone();
|
| - Expect.equals(expectedVersion, version);
|
| - Expect.equals(expectedStatusCode, statusCode);
|
| - Expect.equals(expectedReasonPhrase, reasonPhrase);
|
| - Expect.isTrue(headersCompleteCalled);
|
| - Expect.equals(expectedBytesReceived, bytesReceived);
|
| - if (!upgrade) {
|
| - Expect.isTrue(dataEndCalled);
|
| - if (close) Expect.isTrue(dataEndClose);
|
| - Expect.equals(dataEndClose, connectionClose);
|
| - }
|
| - if (unparsedLength == 0) {
|
| - Expect.equals(0, unparsed);
|
| - } else {
|
| - Expect.equals(unparsedLength, unparsed);
|
| + controller.add(requestData.getRange(pos, writeLength));
|
| +
|
| }
|
| + if (close) controller.close();
|
| }
|
|
|
| // Test parsing the request three times delivering the data in
|
| @@ -276,15 +279,29 @@ class HttpParserTest {
|
| static void _testParseInvalidResponse(String response, [bool close = false]) {
|
| _HttpParser httpParser;
|
| bool errorCalled;
|
| + StreamController controller;
|
|
|
| void reset() {
|
| httpParser = new _HttpParser.responseParser();
|
| - httpParser.requestStart = (m, u, v, h, b) {
|
| - Expect.fail("Expected response");
|
| - };
|
| - httpParser.error = (e) => errorCalled = true;
|
| - httpParser.closed = () { };
|
| -
|
| + controller = new StreamController();
|
| + var port = new ReceivePort();
|
| + controller.stream.pipe(httpParser);
|
| + var subscription = httpParser.listen((incoming) {
|
| + incoming.listen(
|
| + (data) {},
|
| + onError: (e) {
|
| + Expect.isFalse(errorCalled);
|
| + errorCalled = true;
|
| + });
|
| + });
|
| + subscription.onError((e) {
|
| + Expect.isFalse(errorCalled);
|
| + errorCalled = true;
|
| + });
|
| + subscription.onDone(() {
|
| + port.close();
|
| + Expect.isTrue(errorCalled);
|
| + });
|
| errorCalled = false;
|
| }
|
|
|
| @@ -296,10 +313,9 @@ class HttpParserTest {
|
| pos += chunkSize) {
|
| int remaining = requestData.length - pos;
|
| int writeLength = min(chunkSize, remaining);
|
| - httpParser.streamData(requestData.getRange(pos, writeLength));
|
| + controller.add(requestData.getRange(pos, writeLength));
|
| }
|
| - if (close) httpParser.streamDone();
|
| - Expect.isTrue(errorCalled);
|
| + controller.close();
|
| }
|
|
|
| // Test parsing the request three times delivering the data in
|
| @@ -329,6 +345,7 @@ class HttpParserTest {
|
| _testParseRequest(request, method, "/index.html");
|
| });
|
|
|
| +
|
| request = "GET / HTTP/1.0\r\n\r\n";
|
| _testParseRequest(request, "GET", "/",
|
| expectedVersion: "1.0",
|
| @@ -406,7 +423,7 @@ Content-Length: 10\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: 10,
|
| + expectedTransferLength: 10,
|
| expectedBytesReceived: 10);
|
|
|
| // Test connection close header.
|
| @@ -426,7 +443,7 @@ Transfer-Encoding: chunked\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 10,
|
| chunked: true);
|
|
|
| @@ -445,7 +462,7 @@ Transfer-Encoding: chunked\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 10,
|
| chunked: true);
|
|
|
| @@ -464,7 +481,7 @@ Content-Length: 3\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 10,
|
| chunked: true);
|
|
|
| @@ -481,7 +498,7 @@ Transfer-Encoding: chunked\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 60,
|
| chunked: true);
|
|
|
| @@ -498,7 +515,7 @@ Transfer-Encoding: chunked\r
|
| _testParseRequest(request,
|
| "POST",
|
| "/test",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 60,
|
| chunked: true);
|
|
|
| @@ -586,13 +603,16 @@ Sec-WebSocket-Version: 13\r
|
| String response;
|
| Map headers;
|
| response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
|
| - _testParseResponse(response, 100, "Continue", expectedContentLength: 0);
|
| + _testParseResponse(response, 100, "Continue");
|
| +
|
| + response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
|
| + _testParseResponse(response, 100, "Continue");
|
|
|
| response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n";
|
| _testParseResponse(response,
|
| 100,
|
| "Continue",
|
| - expectedContentLength: 10,
|
| + expectedTransferLength: 10,
|
| expectedBytesReceived: 0);
|
|
|
| response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n"
|
| @@ -600,14 +620,12 @@ Sec-WebSocket-Version: 13\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: 0,
|
| connectionClose: true);
|
|
|
| response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n";
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: 0,
|
| expectedVersion: "1.0",
|
| connectionClose: true);
|
|
|
| @@ -616,31 +634,30 @@ Sec-WebSocket-Version: 13\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: 0,
|
| expectedVersion: "1.0");
|
|
|
| response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n";
|
| _testParseResponse(response,
|
| 204,
|
| "No Content",
|
| - expectedContentLength: 11,
|
| + expectedTransferLength: 11,
|
| expectedBytesReceived: 0);
|
|
|
| response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n";
|
| _testParseResponse(response,
|
| 304,
|
| "Not Modified",
|
| - expectedContentLength: 12,
|
| + expectedTransferLength: 12,
|
| expectedBytesReceived: 0);
|
|
|
| response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
|
| - _testParseResponse(response, 200, "OK", expectedContentLength: 0);
|
| + _testParseResponse(response, 200, "OK");
|
|
|
| response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n";
|
| - _testParseResponse(response, 404, "Not found", expectedContentLength: 0);
|
| + _testParseResponse(response, 404, "Not found");
|
|
|
| response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n";
|
| - _testParseResponse(response, 500, "Server error", expectedContentLength: 0);
|
| + _testParseResponse(response, 500, "Server error");
|
|
|
| // Test response to HEAD request.
|
| response = """
|
| @@ -655,7 +672,7 @@ Content-Type: text/html\r
|
| 200,
|
| "OK",
|
| responseToMethod: "HEAD",
|
| - expectedContentLength: 20,
|
| + expectedTransferLength: 20,
|
| expectedBytesReceived: 0,
|
| expectedHeaders: headers);
|
|
|
| @@ -668,7 +685,7 @@ Content-Length: 20\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: 20,
|
| + expectedTransferLength: 20,
|
| expectedBytesReceived: 20);
|
|
|
| // Test upper and lower case hex digits in chunked encoding.
|
| @@ -684,7 +701,7 @@ Transfer-Encoding: chunked\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 57,
|
| chunked: true);
|
|
|
| @@ -697,7 +714,6 @@ Connection: close\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: 0,
|
| connectionClose: true);
|
|
|
| // Test HTTP response without any transfer length indications
|
| @@ -711,7 +727,7 @@ HTTP/1.1 200 OK\r
|
| _testParseResponse(response,
|
| 200,
|
| "OK",
|
| - expectedContentLength: -1,
|
| + expectedTransferLength: -1,
|
| expectedBytesReceived: 59,
|
| close: true,
|
| connectionClose: true);
|
|
|