mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 15:21:31 +00:00
5aa86eb123
Issue https://github.com/dart-lang/sdk/issues/36097 Change-Id: I0b7eca744bc49ab5ba09da3ce2a9286b1ed3c70f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126340 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
428 lines
14 KiB
Dart
428 lines
14 KiB
Dart
// 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=--enable-isolate-groups
|
|
// VMOptions=--no-enable-isolate-groups
|
|
//
|
|
// VMOptions=
|
|
// VMOptions=--short_socket_read
|
|
// VMOptions=--short_socket_write
|
|
// VMOptions=--short_socket_read --short_socket_write
|
|
|
|
import "package:expect/expect.dart";
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'dart:isolate';
|
|
|
|
class IsolatedHttpServer {
|
|
IsolatedHttpServer()
|
|
: _statusPort = new ReceivePort(),
|
|
_serverPort = null;
|
|
|
|
void setServerStartedHandler(void startedCallback(int port)) {
|
|
_startedCallback = startedCallback;
|
|
}
|
|
|
|
void start() {
|
|
ReceivePort receivePort = new ReceivePort();
|
|
var remote = Isolate.spawn(startIsolatedHttpServer, receivePort.sendPort);
|
|
receivePort.first.then((port) {
|
|
_serverPort = port;
|
|
|
|
// Send server start message to the server.
|
|
var command = new IsolatedHttpServerCommand.start();
|
|
port.send([command, _statusPort.sendPort]);
|
|
});
|
|
|
|
// Handle status messages from the server.
|
|
_statusPort.listen((var status) {
|
|
if (status.isStarted) {
|
|
_startedCallback(status.port);
|
|
}
|
|
});
|
|
}
|
|
|
|
void shutdown() {
|
|
// Send server stop message to the server.
|
|
_serverPort
|
|
.send([new IsolatedHttpServerCommand.stop(), _statusPort.sendPort]);
|
|
_statusPort.close();
|
|
}
|
|
|
|
void chunkedEncoding() {
|
|
// Send chunked encoding message to the server.
|
|
_serverPort.send([
|
|
new IsolatedHttpServerCommand.chunkedEncoding(),
|
|
_statusPort.sendPort
|
|
]);
|
|
}
|
|
|
|
ReceivePort _statusPort; // Port for receiving messages from the server.
|
|
SendPort _serverPort; // Port for sending messages to the server.
|
|
var _startedCallback;
|
|
}
|
|
|
|
class IsolatedHttpServerCommand {
|
|
static const START = 0;
|
|
static const STOP = 1;
|
|
static const CHUNKED_ENCODING = 2;
|
|
|
|
IsolatedHttpServerCommand.start() : _command = START;
|
|
IsolatedHttpServerCommand.stop() : _command = STOP;
|
|
IsolatedHttpServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING;
|
|
|
|
bool get isStart => _command == START;
|
|
bool get isStop => _command == STOP;
|
|
bool get isChunkedEncoding => _command == CHUNKED_ENCODING;
|
|
|
|
int _command;
|
|
}
|
|
|
|
class IsolatedHttpServerStatus {
|
|
static const STARTED = 0;
|
|
static const STOPPED = 1;
|
|
static const ERROR = 2;
|
|
|
|
IsolatedHttpServerStatus.started(this._port) : _state = STARTED;
|
|
IsolatedHttpServerStatus.stopped() : _state = STOPPED;
|
|
IsolatedHttpServerStatus.error() : _state = ERROR;
|
|
|
|
bool get isStarted => _state == STARTED;
|
|
bool get isStopped => _state == STOPPED;
|
|
bool get isError => _state == ERROR;
|
|
|
|
int get port => _port;
|
|
|
|
int _state;
|
|
int _port;
|
|
}
|
|
|
|
void startIsolatedHttpServer(Object replyToObj) {
|
|
SendPort replyTo = replyToObj;
|
|
var server = new TestServer();
|
|
server.init();
|
|
replyTo.send(server.dispatchSendPort);
|
|
}
|
|
|
|
class TestServer {
|
|
// Return a 404.
|
|
void _notFoundHandler(HttpRequest request) {
|
|
var response = request.response;
|
|
response.statusCode = HttpStatus.notFound;
|
|
response.headers.set("Content-Type", "text/html; charset=UTF-8");
|
|
response.write("Page not found");
|
|
response.close();
|
|
}
|
|
|
|
// Check the "Host" header.
|
|
void _hostHandler(HttpRequest request) {
|
|
var response = request.response;
|
|
Expect.equals(1, request.headers["Host"].length);
|
|
Expect.equals("www.dartlang.org:1234", request.headers["Host"][0]);
|
|
Expect.equals("www.dartlang.org", request.headers.host);
|
|
Expect.equals(1234, request.headers.port);
|
|
response.statusCode = HttpStatus.ok;
|
|
response.close();
|
|
}
|
|
|
|
// Set the "Expires" header using the expires property.
|
|
void _expires1Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
DateTime date = new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0);
|
|
response.headers.expires = date;
|
|
Expect.equals(date, response.headers.expires);
|
|
response.close();
|
|
}
|
|
|
|
// Set the "Expires" header.
|
|
void _expires2Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
response.headers.set("Expires", "Fri, 11 Jun 1999 18:46:53 GMT");
|
|
DateTime date = new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0);
|
|
Expect.equals(date, response.headers.expires);
|
|
response.close();
|
|
}
|
|
|
|
void _contentType1Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
Expect.equals("text/html", request.headers.contentType.value);
|
|
Expect.equals("text", request.headers.contentType.primaryType);
|
|
Expect.equals("html", request.headers.contentType.subType);
|
|
Expect.equals("utf-8", request.headers.contentType.parameters["charset"]);
|
|
|
|
ContentType contentType = new ContentType("text", "html", charset: "utf-8");
|
|
response.headers.contentType = contentType;
|
|
response.close();
|
|
}
|
|
|
|
void _contentType2Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
Expect.equals("text/html", request.headers.contentType.value);
|
|
Expect.equals("text", request.headers.contentType.primaryType);
|
|
Expect.equals("html", request.headers.contentType.subType);
|
|
Expect.equals("utf-8", request.headers.contentType.parameters["charset"]);
|
|
|
|
response.headers
|
|
.set(HttpHeaders.contentTypeHeader, "text/html; charset = utf-8");
|
|
response.close();
|
|
}
|
|
|
|
void _cookie1Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
|
|
// No cookies passed with this request.
|
|
Expect.equals(0, request.cookies.length);
|
|
|
|
Cookie cookie1 = new Cookie("name1", "value1");
|
|
DateTime date = new DateTime.utc(2014, DateTime.january, 5, 23, 59, 59, 0);
|
|
cookie1.expires = date;
|
|
cookie1.domain = "www.example.com";
|
|
cookie1.httpOnly = true;
|
|
response.cookies.add(cookie1);
|
|
Cookie cookie2 = new Cookie("name2", "value2");
|
|
cookie2.maxAge = 100;
|
|
cookie2.domain = ".example.com";
|
|
cookie2.path = "/shop";
|
|
response.cookies.add(cookie2);
|
|
response.close();
|
|
}
|
|
|
|
void _cookie2Handler(HttpRequest request) {
|
|
var response = request.response;
|
|
|
|
// Two cookies passed with this request.
|
|
Expect.equals(2, request.cookies.length);
|
|
response.close();
|
|
}
|
|
|
|
void init() {
|
|
// Setup request handlers.
|
|
_requestHandlers = new Map();
|
|
_requestHandlers["/host"] = _hostHandler;
|
|
_requestHandlers["/expires1"] = _expires1Handler;
|
|
_requestHandlers["/expires2"] = _expires2Handler;
|
|
_requestHandlers["/contenttype1"] = _contentType1Handler;
|
|
_requestHandlers["/contenttype2"] = _contentType2Handler;
|
|
_requestHandlers["/cookie1"] = _cookie1Handler;
|
|
_requestHandlers["/cookie2"] = _cookie2Handler;
|
|
_dispatchPort = new ReceivePort();
|
|
_dispatchPort.listen(dispatch);
|
|
}
|
|
|
|
SendPort get dispatchSendPort => _dispatchPort.sendPort;
|
|
|
|
void dispatch(message) {
|
|
IsolatedHttpServerCommand command = message[0];
|
|
SendPort replyTo = message[1];
|
|
if (command.isStart) {
|
|
try {
|
|
HttpServer.bind("127.0.0.1", 0).then((server) {
|
|
_server = server;
|
|
_server.listen(_requestReceivedHandler);
|
|
replyTo.send(new IsolatedHttpServerStatus.started(_server.port));
|
|
});
|
|
} catch (e) {
|
|
replyTo.send(new IsolatedHttpServerStatus.error());
|
|
}
|
|
} else if (command.isStop) {
|
|
_server.close();
|
|
_dispatchPort.close();
|
|
replyTo.send(new IsolatedHttpServerStatus.stopped());
|
|
} else if (command.isChunkedEncoding) {
|
|
_chunkedEncoding = true;
|
|
}
|
|
}
|
|
|
|
void _requestReceivedHandler(HttpRequest request) {
|
|
var requestHandler = _requestHandlers[request.uri.path];
|
|
if (requestHandler != null) {
|
|
requestHandler(request);
|
|
} else {
|
|
_notFoundHandler(request);
|
|
}
|
|
}
|
|
|
|
HttpServer _server; // HTTP server instance.
|
|
ReceivePort _dispatchPort;
|
|
Map _requestHandlers;
|
|
bool _chunkedEncoding = false;
|
|
}
|
|
|
|
Future testHost() {
|
|
Completer completer = new Completer();
|
|
IsolatedHttpServer server = new IsolatedHttpServer();
|
|
server.setServerStartedHandler((int port) {
|
|
HttpClient httpClient = new HttpClient();
|
|
httpClient.get("127.0.0.1", port, "/host").then((request) {
|
|
Expect.equals("127.0.0.1:$port", request.headers["host"][0]);
|
|
request.headers.host = "www.dartlang.com";
|
|
Expect.equals("www.dartlang.com:$port", request.headers["host"][0]);
|
|
Expect.equals("www.dartlang.com", request.headers.host);
|
|
Expect.equals(port, request.headers.port);
|
|
request.headers.port = 1234;
|
|
Expect.equals("www.dartlang.com:1234", request.headers["host"][0]);
|
|
Expect.equals(1234, request.headers.port);
|
|
request.headers.port = HttpClient.defaultHttpPort;
|
|
Expect.equals(HttpClient.defaultHttpPort, request.headers.port);
|
|
Expect.equals("www.dartlang.com", request.headers["host"][0]);
|
|
request.headers.set("Host", "www.dartlang.org");
|
|
Expect.equals("www.dartlang.org", request.headers.host);
|
|
Expect.equals(HttpClient.defaultHttpPort, request.headers.port);
|
|
request.headers.set("Host", "www.dartlang.org:");
|
|
Expect.equals("www.dartlang.org", request.headers.host);
|
|
Expect.equals(HttpClient.defaultHttpPort, request.headers.port);
|
|
request.headers.set("Host", "www.dartlang.org:1234");
|
|
Expect.equals("www.dartlang.org", request.headers.host);
|
|
Expect.equals(1234, request.headers.port);
|
|
return request.close();
|
|
}).then((response) {
|
|
Expect.equals(HttpStatus.ok, response.statusCode);
|
|
response.listen((_) {}, onDone: () {
|
|
httpClient.close();
|
|
server.shutdown();
|
|
completer.complete(true);
|
|
});
|
|
});
|
|
});
|
|
server.start();
|
|
return completer.future;
|
|
}
|
|
|
|
Future testExpires() {
|
|
Completer completer = new Completer();
|
|
IsolatedHttpServer server = new IsolatedHttpServer();
|
|
server.setServerStartedHandler((int port) {
|
|
int responses = 0;
|
|
HttpClient httpClient = new HttpClient();
|
|
|
|
void processResponse(HttpClientResponse response) {
|
|
Expect.equals(HttpStatus.ok, response.statusCode);
|
|
Expect.equals(
|
|
"Fri, 11 Jun 1999 18:46:53 GMT", response.headers["expires"][0]);
|
|
Expect.equals(new DateTime.utc(1999, DateTime.june, 11, 18, 46, 53, 0),
|
|
response.headers.expires);
|
|
response.listen((_) {}, onDone: () {
|
|
responses++;
|
|
if (responses == 2) {
|
|
httpClient.close();
|
|
server.shutdown();
|
|
completer.complete(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
httpClient
|
|
.get("127.0.0.1", port, "/expires1")
|
|
.then((request) => request.close())
|
|
.then(processResponse);
|
|
httpClient
|
|
.get("127.0.0.1", port, "/expires2")
|
|
.then((request) => request.close())
|
|
.then(processResponse);
|
|
});
|
|
server.start();
|
|
return completer.future;
|
|
}
|
|
|
|
Future testContentType() {
|
|
Completer completer = new Completer();
|
|
IsolatedHttpServer server = new IsolatedHttpServer();
|
|
server.setServerStartedHandler((int port) {
|
|
int responses = 0;
|
|
HttpClient httpClient = new HttpClient();
|
|
|
|
void processResponse(HttpClientResponse response) {
|
|
Expect.equals(HttpStatus.ok, response.statusCode);
|
|
Expect.equals(
|
|
"text/html; charset=utf-8", response.headers.contentType.toString());
|
|
Expect.equals("text/html", response.headers.contentType.value);
|
|
Expect.equals("text", response.headers.contentType.primaryType);
|
|
Expect.equals("html", response.headers.contentType.subType);
|
|
Expect.equals(
|
|
"utf-8", response.headers.contentType.parameters["charset"]);
|
|
response.listen((_) {}, onDone: () {
|
|
responses++;
|
|
if (responses == 2) {
|
|
httpClient.close();
|
|
server.shutdown();
|
|
completer.complete(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
httpClient.get("127.0.0.1", port, "/contenttype1").then((request) {
|
|
request.headers.contentType =
|
|
new ContentType("text", "html", charset: "utf-8");
|
|
return request.close();
|
|
}).then(processResponse);
|
|
|
|
httpClient.get("127.0.0.1", port, "/contenttype2").then((request) {
|
|
request.headers
|
|
.set(HttpHeaders.contentTypeHeader, "text/html; charset = utf-8");
|
|
return request.close();
|
|
}).then(processResponse);
|
|
});
|
|
server.start();
|
|
return completer.future;
|
|
}
|
|
|
|
Future testCookies() {
|
|
Completer completer = new Completer();
|
|
IsolatedHttpServer server = new IsolatedHttpServer();
|
|
server.setServerStartedHandler((int port) {
|
|
int responses = 0;
|
|
HttpClient httpClient = new HttpClient();
|
|
|
|
httpClient
|
|
.get("127.0.0.1", port, "/cookie1")
|
|
.then((request) => request.close())
|
|
.then((response) {
|
|
Expect.equals(2, response.cookies.length);
|
|
response.cookies.forEach((cookie) {
|
|
if (cookie.name == "name1") {
|
|
Expect.equals("value1", cookie.value);
|
|
DateTime date =
|
|
new DateTime.utc(2014, DateTime.january, 5, 23, 59, 59, 0);
|
|
Expect.equals(date, cookie.expires);
|
|
Expect.equals("www.example.com", cookie.domain);
|
|
Expect.isTrue(cookie.httpOnly);
|
|
} else if (cookie.name == "name2") {
|
|
Expect.equals("value2", cookie.value);
|
|
Expect.equals(100, cookie.maxAge);
|
|
Expect.equals(".example.com", cookie.domain);
|
|
Expect.equals("/shop", cookie.path);
|
|
} else {
|
|
Expect.fail("Unexpected cookie");
|
|
}
|
|
});
|
|
|
|
response.listen((_) {}, onDone: () {
|
|
httpClient.get("127.0.0.1", port, "/cookie2").then((request) {
|
|
request.cookies.add(response.cookies[0]);
|
|
request.cookies.add(response.cookies[1]);
|
|
return request.close();
|
|
}).then((response) {
|
|
response.listen((_) {}, onDone: () {
|
|
httpClient.close();
|
|
server.shutdown();
|
|
completer.complete(true);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
server.start();
|
|
return completer.future;
|
|
}
|
|
|
|
void main() {
|
|
testHost().then((_) {
|
|
return testExpires().then((_) {
|
|
return testContentType().then((_) {
|
|
return testCookies();
|
|
});
|
|
});
|
|
});
|
|
}
|