run method
Starts the Web server.
By default a HTTP server is started.
s.run();
To create a secure HTTPS server, initialize the SecureSocket
database
and invoke this method with privateKeyFilename
, certificateName
and
certChainFilename
.
var certDb = Platform.script.resolve('pkcert').toFilePath();
SecureSocket.initialize(databse: certDb, password: "p@ssw0rd");
s.run(privateKeyFilename: "a.pvt", certificateName: "mycert", certChainFilename: "a.crt");
This method will return a Future whose value is the total number of requests processed by the server. This value is only available if/when the server is cleanly stopped. But normally a server listens for requests "forever" and never stops.
Throws a StateError
if the server is already running.
Implementation
Future<int> run(
{String privateKeyFilename,
String certificateName,
String certChainFilename}) async {
if (_svr != null) {
throw new StateError("server already running");
}
// Start the server
if (certificateName == null || certificateName.isEmpty) {
// Normal HTTP bind
_isSecure = false;
_svr = await HttpServer.bind(bindAddress, bindPort ?? 80, v6Only: v6Only);
} else {
// Secure HTTPS bind
//
// Note: this uses the TLS libraries in Dart 1.13 or later.
// https://dart-lang.github.io/server/tls-ssl.html
_isSecure = true;
final securityContext = new SecurityContext()
..useCertificateChain(certChainFilename)
..usePrivateKey(privateKeyFilename);
_svr = await HttpServer.bindSecure(
bindAddress, bindPort ?? 443, securityContext,
v6Only: v6Only, backlog: 5);
}
// Log that it started
final buf = new StringBuffer()
..write((_isSecure) ? "https://" : "http://")
..write((_svr.address.isLoopback) ? "localhost" : _svr.address.host);
if (_svr.port != null) {
buf.write(":${_svr.port}");
}
final url = buf.toString();
_logServer.fine(
"${(_isSecure) ? "HTTPS" : "HTTP"} server started: ${_svr.address} port ${_svr.port} <$url>");
// Listen for and process HTTP requests
var requestNo = 0;
final requestLoopCompleter = new Completer<int>();
// ignore: UNUSED_LOCAL_VARIABLE
final doNotWaitOnThis = runZoned(() async {
// The request processing loop
await for (var request in _svr) {
try {
// Note: although _handleRequest returns a Future that completes when
// the request is fully processed, this does NOT wait for it to
// complete, so that multiple requests can be handled in parallel.
//_logServer.info("HTTP Request: [$id${requestNo + 1}] starting handler");
final doNotWait = _handleRawRequest(request, "$id${++requestNo}");
assert(doNotWait != null);
//_logServer.info("HTTP Request: [$id$requestNo] handler started");
} catch (e, s) {
_logServer.shout(
"uncaught try/catch exception (${e.runtimeType}): $e", e, s);
}
}
requestLoopCompleter.complete(0);
}, onError: (Object e, StackTrace s) {
// The event processing code uses async try/catch, so something very wrong
// must have happened for an exception to have been thrown outside that.
_logServer.shout("uncaught onError (${e.runtimeType}): $e", e, s);
// Note: this can happen in situations where a handler uses both
// completeError() to set an error and also throws an exception.
// Will get a Bad state: Future already completed.
// Abort server?
//if (!requestLoopCompleter.isCompleted) {
// requestLoopCompleter.complete(0);
//}
});
await requestLoopCompleter.future;
// Finished: it only gets to here if the server stops running (see [stop] method)
_logServer.fine(
"${(_isSecure) ? "HTTPS" : "HTTP"} server stopped: $requestNo requests");
_svr = null;
_isSecure = null;
return requestNo;
}