public override async Task <GenericLoopbackConnection> EstablishGenericConnectionAsync() { Socket socket = await _listenSocket.AcceptAsync().ConfigureAwait(false); Stream stream = new NetworkStream(socket, ownsSocket: true); var options = new GenericLoopbackOptions() { Address = _options.Address, SslProtocols = _options.SslProtocols, UseSsl = false, ListenBacklog = _options.ListenBacklog }; GenericLoopbackConnection connection = null; try { if (_options.UseSsl) { var sslStream = new SslStream(stream, false, delegate { return(true); }); using (X509Certificate2 cert = Configuration.Certificates.GetServerCertificate()) { SslServerAuthenticationOptions sslOptions = new SslServerAuthenticationOptions(); sslOptions.EnabledSslProtocols = _options.SslProtocols; sslOptions.ApplicationProtocols = _options.SslApplicationProtocols; sslOptions.ServerCertificate = cert; await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None).ConfigureAwait(false); } stream = sslStream; if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2) { // Do not pass original options so the CreateConnectionAsync won't try to do ALPN again. return(connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http11 || sslStream.NegotiatedApplicationProtocol == default) { // Do not pass original options so the CreateConnectionAsync won't try to do ALPN again. return(connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } else { throw new Exception($"Unsupported negotiated protocol {sslStream.NegotiatedApplicationProtocol}"); } } if (_options.ClearTextVersion is null) { throw new Exception($"HTTP server does not accept clear text connections, either set '{nameof(HttpAgnosticOptions.UseSsl)}' or set up '{nameof(HttpAgnosticOptions.ClearTextVersion)}' in server options."); } var buffer = new byte[24]; var position = 0; while (position < buffer.Length) { var readBytes = await stream.ReadAsync(buffer, position, buffer.Length - position).ConfigureAwait(false); if (readBytes == 0) { break; } position += readBytes; } var memory = new Memory <byte>(buffer, 0, position); stream = new ReturnBufferStream(stream, memory); var prefix = Text.Encoding.ASCII.GetString(memory.Span); if (prefix == Http2LoopbackConnection.Http2Prefix) { if (_options.ClearTextVersion == HttpVersion.Version20 || _options.ClearTextVersion == HttpVersion.Unknown) { return(connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } } else { if (_options.ClearTextVersion == HttpVersion.Version11 || _options.ClearTextVersion == HttpVersion.Unknown) { return(connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } } throw new Exception($"HTTP/{_options.ClearTextVersion} server cannot establish connection due to unexpected data: '{prefix}'"); } catch { connection?.Dispose(); connection = null; stream.Dispose(); throw; } finally { if (connection != null) { await connection.InitializeConnectionAsync().ConfigureAwait(false); } } }
public override async Task <GenericLoopbackConnection> EstablishGenericConnectionAsync() { Socket socket = await _listenSocket.AcceptAsync().ConfigureAwait(false); Stream stream = new NetworkStream(socket, ownsSocket: true); var options = new GenericLoopbackOptions() { Address = _options.Address, SslProtocols = _options.SslProtocols, UseSsl = false, ListenBacklog = _options.ListenBacklog }; GenericLoopbackConnection connection = null; try { if (_options.UseSsl) { var sslStream = new SslStream(stream, false, delegate { return(true); }); using (X509Certificate2 cert = Configuration.Certificates.GetServerCertificate()) { SslServerAuthenticationOptions sslOptions = new SslServerAuthenticationOptions(); sslOptions.EnabledSslProtocols = _options.SslProtocols; sslOptions.ApplicationProtocols = _options.SslApplicationProtocols; sslOptions.ServerCertificate = cert; await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None).ConfigureAwait(false); } stream = sslStream; if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2) { // Do not pass original options so the CreateConnectionAsync won't try to do ALPN again. return(connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http11 || sslStream.NegotiatedApplicationProtocol == default) { // Do not pass original options so the CreateConnectionAsync won't try to do ALPN again. return(connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } else { throw new Exception($"Unsupported negotiated protocol {sslStream.NegotiatedApplicationProtocol}"); } } if (_options.ClearTextVersion == HttpVersion.Version11) { return(connection = await Http11LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } else if (_options.ClearTextVersion == HttpVersion.Version20) { return(connection = await Http2LoopbackServerFactory.Singleton.CreateConnectionAsync(socket, stream, options).ConfigureAwait(false)); } else { throw new Exception($"Invalid ClearTextVersion={_options.ClearTextVersion} specified"); } } catch { connection?.Dispose(); connection = null; stream.Dispose(); throw; } finally { if (connection != null) { await connection.InitializeConnectionAsync().ConfigureAwait(false); } } }