run method

Future<int> run ({String privateKeyFilename, String certificateName, String certChainFilename })

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;
}