public static Http11ProtocolOwinAdapter CreateHttp11Adapter(DuplexStream duplexStream, Func<IDictionary<string, object>, Task> appFunc) { var headers = "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: Upgrade\r\n" + "Upgrade: " + Protocols.Http2 + "\r\n" + "HTTP2-Settings: \r\n" + // TODO send any valid parameters "\r\n"; var requestBytes = Encoding.UTF8.GetBytes(headers); var mock = Mock.Get(duplexStream ?? CreateStream()); int position = 0; var modifyBufferData = new Action<byte[], int, int>((buffer, offset, count) => { for (int i = offset; count > 0; --count, ++i) { buffer[i] = requestBytes[position]; ++position; } }); mock.Setup(stream => stream.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>())).Callback(modifyBufferData) .Returns<byte[], int, int>((buffer, offset, count) => count); // read our requestBytes mock.Setup(stream => stream.CanRead).Returns(true); return new Http11ProtocolOwinAdapter(mock.Object, SecureProtocol.Tls1, appFunc); }
/// <summary> /// Initializes a new instance of the <see cref="Http2OwinMessageHandler"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="end"></param> /// <param name="transportInfo">The transport information.</param> /// <param name="next">The next layer delegate.</param> /// <param name="cancel">The cancellation token.</param> public Http2OwinMessageHandler(DuplexStream stream, ConnectionEnd end, TransportInformation transportInfo, AppFunc next, CancellationToken cancel) : base(stream, end, stream.IsSecure, transportInfo, cancel) { _next = next; stream.OnClose += delegate { Dispose(); }; }
public Http2ClientMessageHandler(DuplexStream stream, ConnectionEnd end, TransportInformation transportInfo, CancellationToken cancel) : base(stream, end, stream.IsSecure, transportInfo, cancel) { _fileHelper = new FileHelper(ConnectionEnd.Client); stream.OnClose += delegate { Dispose(); }; }
public bool Connect(Uri connectUri) { _path = connectUri.PathAndQuery; _version = Protocols.Http2; _scheme = connectUri.Scheme; _host = connectUri.Host; _port = connectUri.Port; ServerUri = connectUri.Authority; if (_sessionAdapter != null) { return false; } try { int port = connectUri.Port; int securePort; if (!int.TryParse(ConfigurationManager.AppSettings["securePort"], out securePort)) { Http2Logger.LogError("Incorrect port in the config file!"); return false; } //Connect alpn extension, set known protocols var extensions = new[] {ExtensionType.Renegotiation, ExtensionType.ALPN}; Options = port == securePort ? new SecurityOptions(SecureProtocol.Tls1, extensions, new[] { Protocols.Http1, Protocols.Http2 }, ConnectionEnd.Client) : new SecurityOptions(SecureProtocol.None, extensions, new[] { Protocols.Http1, Protocols.Http2 }, ConnectionEnd.Client); Options.VerificationType = CredentialVerification.None; Options.Certificate = Org.Mentalis.Security.Certificates.Certificate.CreateFromCerFile(CertificatePath); Options.Flags = SecurityFlags.Default; Options.AllowedAlgorithms = SslAlgorithms.RSA_AES_256_SHA | SslAlgorithms.NULL_COMPRESSION; var socket = new SecureSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, Options); using (var monitor = new ALPNExtensionMonitor()) { monitor.OnProtocolSelected += (o, args) => { _selectedProtocol = args.SelectedProtocol; }; socket.Connect(new DnsEndPoint(connectUri.Host, connectUri.Port), monitor); _clientStream = new DuplexStream(socket, true); if (_useHandshake) { MakeHandshakeEnvironment(); //Handshake manager determines what handshake must be used: upgrade or secure if (socket.SecureProtocol != SecureProtocol.None) { socket.MakeSecureHandshake(Options); _selectedProtocol = socket.SelectedProtocol; } if (socket.SecureProtocol == SecureProtocol.None || _selectedProtocol == Protocols.Http1) { try { var handshakeResult = new UpgradeHandshaker(_environment).Handshake(); _environment.Add(HandshakeKeys.Result, handshakeResult); _useHttp20 = handshakeResult[HandshakeKeys.Successful] as string == HandshakeKeys.True; if (!_useHttp20) { Dispose(false); return true; } } catch (Http2HandshakeFailed ex) { if (ex.Reason == HandshakeFailureReason.InternalError) { _useHttp20 = false; } else { Http2Logger.LogError("Specified server did not respond"); Dispose(true); return false; } } } } } Http2Logger.LogDebug("Handshake finished"); if (_useHttp20) { //TODO provide transport info _sessionAdapter = new Http2ClientMessageHandler(_clientStream, ConnectionEnd.Client, default(TransportInformation), CancellationToken.None); } } catch (SocketException) { Http2Logger.LogError("Check if any server listens port " + connectUri.Port); Dispose(true); return false; } catch (Exception ex) { Http2Logger.LogError("Unknown connection exception was caught: " + ex.Message); Dispose(true); return false; } return true; }
private void HandleAcceptedClient(SecureSocket incomingClient, ALPNExtensionMonitor monitor) { bool backToHttp11 = false; string selectedProtocol = Protocols.Http1; if (_useHandshake) { try { if (_options.Protocol != SecureProtocol.None) { incomingClient.MakeSecureHandshake(_options); selectedProtocol = incomingClient.SelectedProtocol; } } catch (SecureHandshakeException ex) { switch (ex.Reason) { case SecureHandshakeFailureReason.HandshakeInternalError: backToHttp11 = true; break; case SecureHandshakeFailureReason.HandshakeTimeout: incomingClient.Close(); Http2Logger.LogError("Handshake timeout. Client was disconnected."); return; default: incomingClient.Close(); Http2Logger.LogError("Unknown error occurred during secure handshake"); return; } } catch (Exception e) { Http2Logger.LogError("Exception occurred. Closing client's socket. " + e.Message); incomingClient.Close(); return; } } var clientStream = new DuplexStream(incomingClient, true); var transportInfo = GetTransportInfo(incomingClient); monitor.Dispose(); try { HandleRequest(clientStream, selectedProtocol, transportInfo, backToHttp11); } catch (Exception e) { Http2Logger.LogError("Exception occurred. Closing client's socket. " + e.Message); incomingClient.Close(); } }
private async void OpenHttp2Session(DuplexStream incomingClientStream, TransportInformation transportInformation) { Http2Logger.LogDebug("Handshake successful"); using (var messageHandler = new Http2OwinMessageHandler(incomingClientStream, ConnectionEnd.Server, transportInformation, _next, _cancelClientHandling.Token)) { try { await messageHandler.StartSessionAsync(); } catch (Exception) { Http2Logger.LogError("Client was disconnected"); } } GC.Collect(); }
private void HandleRequest(DuplexStream incomingClient, string alpnSelectedProtocol, TransportInformation transportInformation, bool backToHttp11) { //Server checks selected protocol and calls http2 or http11 layer if (backToHttp11 || alpnSelectedProtocol == Protocols.Http1) { if (incomingClient.IsSecure) Http2Logger.LogDebug("Ssl chose http11"); new Http11ProtocolOwinAdapter(incomingClient, _options.Protocol, _next).ProcessRequest(); return; } //ALPN selected http2. No need to perform upgrade handshake. OpenHttp2Session(incomingClient, transportInformation); }
public static void SendSessionHeader(DuplexStream stream) { stream.Write(ClientSessionHeader); stream.Flush(); }