startConnect static method

Future<ConnectionTask<SecureSocket>> startConnect(
  1. Object host,
  2. int port, {
  3. SecurityContext? context,
  4. bool onBadCertificate(
    1. X509Certificate certificate
    )?,
  5. void keyLog(
    1. String line
    )?,
  6. List<String>? supportedProtocols,
})

Connects to host:port over TLS, as SecureSocket.startConnect does.

Hand it to HttpClient.connectionFactory for an https or wss uri with no proxy. A cancelled task completes ConnectionTask.socket with a SocketException at once and closes the socket.

Implementation

static Future<ConnectionTask<SecureSocket>> startConnect(
  Object host,
  int port, {
  SecurityContext? context,
  bool Function(X509Certificate certificate)? onBadCertificate,
  void Function(String line)? keyLog,
  List<String>? supportedProtocols,
}) async {
  final tcp = await RawSocket.startConnect(host, port);
  final cancelled = Completer<void>();
  RawSocket? raw;

  Future<SecureSocket> open() async {
    final socket = await tcp.socket;
    raw = socket;
    if (cancelled.isCompleted) {
      unawaited(socket.close());
      throw const SocketException('Connection attempt cancelled');
    }
    final handshake = RawSecureSocket.secure(
      socket,
      host: host,
      context: context,
      onBadCertificate: onBadCertificate,
      keyLog: keyLog,
      supportedProtocols: supportedProtocols,
    );
    // Closing the socket does not end a pending handshake future, so the
    // cancel is raced; a handshake that still completes is closed.
    unawaited(
      handshake.then((secure) {
        if (cancelled.isCompleted) secure.close();
      }, onError: (Object _) {}),
    );
    final secure = await Future.any([
      handshake,
      cancelled.future.then<RawSecureSocket>(
        (_) => throw const SocketException('Connection attempt cancelled'),
      ),
    ]);
    return _RawSecureSocketAdapter(secure);
  }

  return ConnectionTask.fromSocket(open(), () {
    if (cancelled.isCompleted) return;
    cancelled.complete();
    tcp.cancel();
    final socket = raw;
    if (socket != null) unawaited(socket.close());
  });
}