/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; return(handleClient(endPoint, clientConnection, endPoint.Port, cancellationTokenSource, cancellationToken)); }
public IBinaryConnection Create(BinaryConnectionConfig config, IMessageValidator validator) { IBinaryConnection connection = null; if (config is TcpClientConfig) { connection = new TcpClientConnection(validator) { Logger = _logger } } ; if (config is TcpListenerConfig) { connection = new TcpListenerConnection(validator) { Logger = _logger } } ; connection?.Initialize(config); return(connection); }
protected override async Task handleClient(TcpClient tcpClient, ProxyEndPoint endPoint) { tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.LingerState = new LingerOption(true, TcpTimeWaitSeconds); using (var requestState = new TRequestState()) { await InvokeClientConnectionCreateEvent(tcpClient); var clientConnection = new TcpClientConnection(this, tcpClient); requestState.server = this; requestState.clientConnection = clientConnection; if (endPoint is TransparentProxyEndPoint tep) { await handleClient(tep, requestState); } else { await handleClient((ExplicitProxyEndPoint)endPoint, requestState); } } }
public async Task WhenReceivingData_TriggerDataReceivedEvent() { var pause = new ManualResetEvent(false); var data = "test"; var dataReceived = string.Empty; using (var tcpClient = new TcpClientConnection()) { tcpClient.DataReceived += (s, e) => { dataReceived = e.Data; pause.Set(); }; await tcpClient.ConnectAsync(HOST, PORT); using (var server = await connectionFixture.TcpListener.AcceptTcpClientAsync()) { using (var stream = new StreamWriter(server.GetStream())) { await stream.WriteLineAsync(data); await stream.FlushAsync(); // Wait for the client to receive the data if necessary Assert.True(pause.WaitOne(60000)); } } } Assert.Equal(data, dataReceived); }
private void ProcessRequest(TcpClientConnection client) { EventHandler <TcpClientEventArgs> handler = OnDataRecieved; if (handler == null) { client.Close(); } else { if (client.BytesDesired <= client.BytesAvailable) { client.BytesDesired = 0; handler(this, client); } } if (client.ReadOffset < ushort.MaxValue / 2 && client.ReadBuffer.Length > ushort.MaxValue) { Array.Resize(ref client.ReadBuffer, client.ReadOffset + 1024); } if (!client.IsClosed) { try { client.FlushWrite(); } catch { client.Close(); } } }
public async Task WhenServerDisconnects_TrigerDisconnectedEvent() { var pauseConnected = new ManualResetEvent(false); var pauseDisconnected = new ManualResetEvent(false); var pauseDataReceived = new ManualResetEvent(false); using (var tcpClient = new TcpClientConnection()) { tcpClient.Connected += (s, e) => pauseConnected.Set(); tcpClient.Disconnected += (s, e) => pauseDisconnected.Set(); tcpClient.DataReceived += (s, e) => pauseDataReceived.Set(); await tcpClient.ConnectAsync(HOST, PORT); using (var server = await connectionFixture.TcpListener.AcceptTcpClientAsync()) { // Wait for the client to be connected if necessary Assert.True(pauseConnected.WaitOne(60000)); using (var stream = new StreamWriter(server.GetStream())) { await stream.WriteLineAsync("test"); await stream.FlushAsync(); // Wait for the client to receive the data if necessary Assert.True(pauseDataReceived.WaitOne(60000)); } } } Assert.True(pauseDisconnected.WaitOne(60000)); }
private Boolean CloseConnection() { StopRequested = true; TcpClientConnection.GetStream().Close(); return(true); }
/// <summary> /// Read all CURRENTLY available data (in the kernel) from the Stream. Keep in mind, that there might be more data than this method returns. /// </summary> /// <returns>A bunch of data which arrived at the kernel.</returns> public Byte[] GetAllAvailableData() { #region Data Definition NetworkStream networkStream = TcpClientConnection.GetStream(); Byte[] ReadBuffer = new Byte[1024]; Int32 BytesRead = 0; List <Byte> FirstBytesList = new List <Byte>(); #endregion #region Read the FirstBytes until no Data is available or we read more than we can store in a List of Bytes do { BytesRead = networkStream.Read(ReadBuffer, 0, ReadBuffer.Length); if (BytesRead == ReadBuffer.Length) { FirstBytesList.AddRange(ReadBuffer); } else { Byte[] Temp = new Byte[BytesRead]; Array.Copy(ReadBuffer, 0, Temp, 0, BytesRead); FirstBytesList.AddRange(Temp); } } while (networkStream.DataAvailable && BytesRead > 0 && FirstBytesList.Count < (Int32.MaxValue - ReadBuffer.Length)); #endregion return(FirstBytesList.ToArray()); }
private void conn_DataReceived(TcpClientConnection<HttpConnectionState> conn, HttpConnectionState state, BufferData data) { HttpResponseParser parser = state.ResponseParser; string response = parser.Parse(data);//info:noexception if (response == null) return; conn.Close();//info:noexception TriggerCompleted(new HttpFetchResult(state.Url, response: response)); }
/// <summary> /// constructor of SettingModel /// </summary> public SettingModel() { handler = new ObservableCollection <string>(); clientConnection = TcpClientConnection.Instance; Thread.Sleep(1000); BindingOperations.EnableCollectionSynchronization(handler, new Object()); clientConnection.MessageReceived += onGetConfig; }
public void TcpClientConnection_Constructor_WithParameters() { var connection = new TcpClientConnection(ip, 3030); //Assert.AreEqual(100, connection.ReadTimeout); //Assert.AreEqual(100, connection.WriteTimeout); Assert.AreEqual(ip + ":3030", connection.Name); }
/// <summary> /// Creates a connection for TCP network services. /// </summary> public override TcpConnection Create() { var connection = new TcpClientConnection(); connection.TcpClient.NoDelay = true; connection.TcpClient.SendBufferSize = 1024 * 8; connection.TcpClient.ReceiveBufferSize = 1024 * 8; return(connection); }
/// <summary> /// Creates a new connection for the tunnel. /// </summary> /// <param name="session">The session that will own the connection.</param> /// <param name="connectionId"></param> /// <returns> /// The <see cref="T:BlueBoxMoon.LocalSubway.Connections.Connection" /> that can now be added to the tunnel. /// </returns> public override async Task <Connection> CreateConnectionAsync(ClientSession session, Guid connectionId) { var socket = new SubwayTcpClient(_hostname, _port); var connection = new TcpClientConnection(connectionId, Id, session, socket); await connection.StartAsync(); return(connection); }
public void TcpClientConnection_OpenAndClose() { var connection = new TcpClientConnection(ip); connection.Open(); connection.Close(); connection.Open(); connection.Close(); connection.Dispose(); }
/// <summary> /// when we click on the button, this function happen. /// in our case- the choose itrm remove from the list /// </summary> /// <param name="obj"></param> private void OnRemove(object obj) { if (chooseItem != null) { DataInfo remove = new DataInfo(CommandEnum.CloseCommand, this.chooseItem); TcpClientConnection client = TcpClientConnection.Instance; client.WriteToServer(remove.toJson()); this.chooseItem = null; } }
/// <summary> /// Starts the TCP server loop listening for client connections on the Server Socket, then /// communicating with the client on that client's TCP Connection Socket. /// </summary> public override void Start() { ListenSocket = Transport.GetSocket(IPAddress.Any.AddressFamily); ListenSocket.Bind(IpEndPoint); ListenSocket.Listen(10); Console.WriteLine("TCP Server Socket awaiting connection from client"); Console.WriteLine("Press ESC to stop this server"); var shutdownToken = new CancellationTokenSource(); var socketTasks = new ConcurrentBag<Task>(); var serverSocketTask = Task.Run(() => { //loop to listen for TCP connections while token isn't while (!shutdownToken.IsCancellationRequested) { try { Console.WriteLine("\r\nTCP Server Socket waiting at {0}", ListenSocket.LocalEndPoint); var newClientSocket = ListenSocket.Accept(); Connections++; Console.WriteLine("\r\nConnections: {0}", Connections); var client = new TcpClientConnection(newClientSocket, Transport.BufferSize); var clientTask = Task.Factory.StartNew(() => { client.Execute(); Task toRemove; socketTasks.TryTake(out toRemove); //remove from concurrent bag Connections--; Console.WriteLine("\r\nConnections: {0}", Connections); }, shutdownToken.Token); socketTasks.Add(clientTask); } catch (OperationCanceledException) { //time to shutdown } } }, shutdownToken.Token); //cancel this task when token is flagged socketTasks.Add(serverSocketTask); //wait for connections while (Console.ReadKey(true).Key != ConsoleKey.Escape) { } //no more waiting... shutdown Console.WriteLine("Stopping... closing open TCP connections"); shutdownToken.CancelAfter(1000); //give tasks 1000ms to finish - then throw them if necessary Task.WaitAll(socketTasks.ToArray(), 1000); //wait up to 5 seconds for all tasks to end, then give up Stop(); }
public SimpleClient(string host, int port) { Contract.Requires(!string.IsNullOrEmpty(host)); Contract.Requires(0 < port && port < 65536); var address = host == "localhost" ? IPAddress.Loopback : IPAddress.Parse(host); connection = new TcpClientConnection(new IPEndPoint(address, port)); connection.SocketDisconnected += SocketDisconnected; connection.DataReceived += DataReceived; }
/// <summary> /// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class. /// </summary> private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint, TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest?connectRequest, Request request, CancellationTokenSource cancellationTokenSource) { BufferPool = server.BufferPool; ExceptionFunc = server.ExceptionFunc; TimeLine["Session Created"] = DateTime.Now; CancellationTokenSource = cancellationTokenSource; ClientConnection = clientConnection; ClientStream = clientStream; HttpClient = new HttpWebClient(connectRequest, request, new Lazy <int>(() => clientConnection.GetProcessId(endPoint))); LocalEndPoint = endPoint; EnableWinAuth = server.EnableWinAuth && isWindowsAuthenticationSupported; }
public async Task WhenConnected_TriggerConnectedEvent() { var pause = new ManualResetEvent(false); using (var tcpClient = new TcpClientConnection()) { tcpClient.Connected += (s, e) => pause.Set(); await tcpClient.ConnectAsync(HOST, PORT); await connectionFixture.TcpListener.AcceptTcpClientAsync(); } Assert.True(pause.WaitOne(500)); }
public async Task WhenReceivingDataWithNoDataReceivedHandler_ItShouldBeOK() { using (var tcpClient = new TcpClientConnection()) { await tcpClient.ConnectAsync(HOST, PORT); using (var server = await connectionFixture.TcpListener.AcceptTcpClientAsync()) { using (var stream = new StreamWriter(server.GetStream())) { await stream.WriteLineAsync("test"); await stream.FlushAsync(); } } } }
/// <summary> /// Wait until new StreamData is available timeout or server shutdown /// </summary> /// <returns>True: if new StreamData is available. False: if timeout or server shutdown</returns> public Boolean WaitForStreamDataAvailable() { #region Timeout var Start = DateTime.Now; if (TcpClientConnection == null) { return(false); } var stream = TcpClientConnection.GetStream(); if (stream == null) { return(false); } while (!StopRequested && TcpClientConnection.Connected && !stream.DataAvailable && ((Timeout == System.Threading.Timeout.Infinite) || (DateTime.Now.Subtract(Start).TotalMilliseconds < Timeout))) { Thread.Sleep(1); } #endregion if (StopRequested || !TcpClientConnection.Connected) { Debug.WriteLine("[ATcpSocketConnection][StreamDataAvailableTimeout] Stop requested"); return(false); } // If we have any DataAvailable than proceed, even if StopRequested is true if (stream.DataAvailable) { return(true); } if (DateTime.Now.Subtract(Start).TotalMilliseconds >= Timeout) { Debug.WriteLine("[ATcpSocketConnection][StreamDataAvailableTimeout] timedout after " + Timeout + "ms"); } return(false); }
private void DataRecieved(IAsyncResult ar) { TcpClientConnection client = ar.AsyncState as TcpClientConnection; if (client == null) { return; } bool close = false; try { int count = client.Stream.EndRead(ar); if (count <= 0) { close = true; } else { client.ReadOffset += count; client.AsyncRead = null; lock (_queue) { _queue.Enqueue(client); _ready.Set(); } } } catch { close = true; } if (close) { using (client.Client) { lock (_clients) _clients.Remove(client); } } }
public async Task WhenSendingData_ServerShouldReceiveIt() { var data = "test"; var dataReceived = string.Empty; using (var tcpClient = new TcpClientConnection()) { await tcpClient.ConnectAsync(HOST, PORT); using (var server = await connectionFixture.TcpListener.AcceptTcpClientAsync()) { using (var stream = new StreamReader(server.GetStream())) { await tcpClient.SendAsync(data); dataReceived = await stream.ReadLineAsync(); } } } Assert.Equal(data, dataReceived); }
private void button1_Click(object sender, EventArgs e) { using (TcpClientConnection client = new TcpClientConnection()) { client.NetworkStream = new NetworkStream(); client.TimeOut = 60000; client.Open(HostResolver.GetIPAddress("127.0.0.1"), 2110); MessageBox.Show("Client connected"); using (StringStream data = new StringStream("Data to be sent")) { client.WriteData(data); data.SetLength(0); client.IsReadUntilClose = true; client.ReadData(data); MessageBox.Show(data.DataString); } client.Close(true); MessageBox.Show("Client disconnected"); } }
/// <summary> /// Handle the client. /// </summary> /// <param name="tcpClient">The client.</param> /// <param name="endPoint">The proxy endpoint.</param> /// <returns>The task.</returns> private async Task handleClient(TcpClient tcpClient, ProxyEndPoint endPoint) { tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.SendBufferSize = BufferSize; tcpClient.ReceiveBufferSize = BufferSize; await InvokeConnectionCreateEvent(tcpClient, true); using (var clientConnection = new TcpClientConnection(this, tcpClient)) { if (endPoint is TransparentProxyEndPoint) { TransparentProxyEndPoint tep = endPoint as TransparentProxyEndPoint; await handleClient(tep, clientConnection); } else { await handleClient((ExplicitProxyEndPoint)endPoint, clientConnection); } } }
private void HandleRequests() { try { while (!_stop.WaitOne(0, false)) { var context = _listener.BeginAcceptTcpClient(null, null); if (0 == WaitHandle.WaitAny(new[] { _stop, context.AsyncWaitHandle })) { return; } try { TcpClientConnection client = new TcpClientConnection(this, _listener.EndAcceptTcpClient(context)); EventHandler <TcpClientEventArgs> handler = OnClientConnect; if (handler != null) { handler(this, client); } lock (_clients) { _clients.Add(client); } lock (_queue) { _queue.Enqueue(client); _ready.Set(); } } catch { return; } } } catch { _stop.Set(); } }
public MainWindow() { ModalWindow modalWindow = new ModalWindow(); modalWindow.ShowDialog(); _currentСlient = ModalWindow._currentСlient; if (_currentСlient == null) { System.Windows.Application.Current.Shutdown(); } else { InitializeComponent(); _common = new BLL.Common(); Conversations = new ObservableCollection <ConversationModel>(); Messages = new ObservableCollection <MessageEventArgsModel>(); _clientTcp = new TcpClientConnection(); _clientTcp.OnMessage += SetMessage; _clientTcp.SentStartMessage += SentStartMessage; UpdateСlientData(); _clientTcp.StartTcpClient(_portNumber); } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); Task <TcpServerConnection> prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; SslStream sslStream = null; try { string connectHostname = null; TunnelConnectSessionEventArgs connectArgs = null; // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1) { // read the first line HTTP command string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (string.IsNullOrEmpty(httpCmd)) { return; } Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version); var httpRemoteUri = new Uri("http://" + httpUrl); connectHostname = httpRemoteUri.Host; var connectRequest = new ConnectRequest { RequestUri = httpRemoteUri, OriginalUrl = httpUrl, HttpVersion = version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, cancellationTokenSource); connectArgs.ProxyClient.Connection = clientConnection; connectArgs.ProxyClient.ClientStream = clientStream; await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(version); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isClientHello = clientHelloInfo != null; if (isClientHello) { connectRequest.TunnelType = TunnelType.Https; connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && isClientHello) { connectRequest.RequestUri = new Uri("https://" + httpUrl); bool http2Supported = false; var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support try { // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; //release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } catch (Exception) { // ignore } } if (EnableTcpServerConnectionPrefetch) { IPAddress[] ipAddresses = null; try { //make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { //don't pass cancellation token here //it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect: true, applicationProtocols: null, noCache: false, cancellationToken: CancellationToken.None); } } X509Certificate2 certificate = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (EnableHttp2 && http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETCOREAPP2_1 clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); } if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == -1) { decryptSsl = false; } if (!decryptSsl) { await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } // Hostname is excluded or it is not an HTTPS connect if (!decryptSsl || !isClientHello) { if (!isClientHello) { connectRequest.TunnelType = TunnelType.Websocket; } // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { await clientStream.ReadAsync(data, 0, available, cancellationToken); // clientStream.Available should be at most BufferSize because it is using the same buffer size await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, connectArgs.CancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1) { // todo string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { connectArgs.HttpClient.ConnectRequest.TunnelType = TunnelType.Http2; // HTTP/2 Connection Preface string line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); await connection.StreamWriter.WriteLineAsync("SM", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); #if NETCOREAPP2_1 await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, () => new SessionEventArgs(this, endPoint, cancellationTokenSource) { ProxyClient = { Connection = clientConnection }, HttpClient = { ConnectRequest = connectArgs?.HttpClient.ConnectRequest }, UserData = connectArgs?.UserData }, async args => { await invokeBeforeRequest(args); }, async args => { await invokeBeforeResponse(args); }, connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } calledRequestHandler = true; // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } sslStream?.Dispose(); clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); Task <TcpServerConnection>?prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; try { TunnelConnectSessionEventArgs?connectArgs = null; var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (method == KnownMethod.Connect) { // read the first line HTTP command var requestLine = await clientStream.ReadRequestLine(cancellationToken); if (requestLine.IsEmpty()) { return; } var connectRequest = new ConnectRequest(requestLine.RequestUri) { RequestUriString8 = requestLine.RequestUri, HttpVersion = requestLine.Version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, clientStream, cancellationTokenSource); clientStream.DataRead += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; bool sendRawData = !decryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(requestLine.Version); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStream.WriteResponseAsync(response, cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } bool isClientHello = clientHelloInfo != null; if (clientHelloInfo != null) { connectRequest.TunnelType = TunnelType.Https; connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && clientHelloInfo != null) { connectRequest.IsHttps = true; // todo: move this line to the previous "if" clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol; bool http2Supported = false; if (EnableHttp2) { var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support try { // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, cancellationToken); http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; // release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } catch (Exception) { // ignore } } } if (EnableTcpServerConnectionPrefetch) { IPAddress[]? ipAddresses = null; try { // make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { // don't pass cancellation token here // it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, false, CancellationToken.None); } } string connectHostname = requestLine.RequestUri.GetString(); int idx = connectHostname.IndexOf(":"); if (idx >= 0) { connectHostname = connectHostname.Substring(0, idx); } X509Certificate2?certificate = null; SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (EnableHttp2 && http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETSTANDARD2_1 clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count); } catch (Exception e) { sslStream?.Dispose(); var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); } method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } if (method == KnownMethod.Invalid) { sendRawData = true; await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } else if (clientHelloInfo == null) { method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (method == KnownMethod.Invalid) { sendRawData = true; } // Hostname is excluded or it is not an HTTPS connect if (sendRawData) { // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, true, cancellationToken); try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(); try { // clientStream.Available should be at most BufferSize because it is using the same buffer size int read = await clientStream.ReadAsync(data, 0, available, cancellationToken); if (read != available) { throw new Exception("Internal error."); } await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } if (!clientStream.IsClosed && !connection.Stream.IsClosed) { await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, null, null, connectArgs.CancellationTokenSource, ExceptionFunc); } } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && method == KnownMethod.Pri) { // todo string?httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { connectArgs.HttpClient.ConnectRequest !.TunnelType = TunnelType.Http2; // HTTP/2 Connection Preface string?line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, cancellationToken); try { #if NETSTANDARD2_1 var connectionPreface = new ReadOnlyMemory <byte>(Http2Helper.ConnectionPreface); await connection.Stream.WriteAsync(connectionPreface, cancellationToken); await Http2Helper.SendHttp2(clientStream, connection.Stream, () => new SessionEventArgs(this, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource) { UserData = connectArgs?.UserData }, async args => { await onBeforeRequest(args); }, async args => { await onBeforeResponse(args); }, connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } calledRequestHandler = true; // Now create the request await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } clientStream.Dispose(); } }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); Task <TcpServerConnection> prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isHttps = clientHelloInfo != null; string httpsHostName = null; if (isHttps) { httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource) { SniHostName = httpsHostName }; await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { if (EnableTcpServerConnectionPrefetch) { //don't pass cancellation token here //it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false, proxyServer: this, session: null, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy, noCache: false, cancellationToken: CancellationToken.None); } SslStream sslStream = null; //do client authentication using fake certificate try { sslStream = new SslStream(clientStream); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName); // Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { sslStream?.Dispose(); throw new ProxyConnectException( $"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e, null); } } else { var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, httpVersion : null, isHttps : false, applicationProtocols : null, isConnect : true, proxyServer : this, session : null, upStreamEndPoint : UpStreamEndPoint, externalProxy : UpStreamHttpsProxy, noCache : true, cancellationToken : cancellationToken); try { CustomBufferedStream serverStream = null; int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { // clientStream.Available sbould be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); serverStream = connection.Stream; await serverStream.WriteAsync(data, 0, available, cancellationToken); await serverStream.FlushAsync(cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize, null, null, cancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } calledRequestHandler = true; // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, isHttps?httpsHostName : null, null, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
/// <summary> /// This is the core request handler method for a particular connection from client. /// Will create new session (request/response) sequence until /// client/server abruptly terminates connection or by normal HTTP termination. /// </summary> /// <param name="endPoint">The proxy endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <param name="clientStream">The client stream.</param> /// <param name="clientStreamWriter">The client stream writer.</param> /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param> /// <param name="httpsConnectHostname"> /// The https hostname as appeared in CONNECT request if this is a HTTPS request from /// explicit endpoint. /// </param> /// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param> private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection, CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter, CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest) { var cancellationToken = cancellationTokenSource.Token; TcpServerConnection serverConnection = null; bool serverConnectionClose = false; try { // Loop through each subsequest request on this particular client connection // (assuming HTTP connection is kept alive by client) while (true) { // read the request line string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (string.IsNullOrEmpty(httpCmd)) { return; } var args = new SessionEventArgs(BufferSize, endPoint, cancellationTokenSource, ExceptionFunc) { ProxyClient = { ClientConnection = clientConnection }, WebSession = { ConnectRequest = connectRequest } }; try { try { Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version); // Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers, cancellationToken); Uri httpRemoteUri; if (uriSchemeRegex.IsMatch(httpUrl)) { try { httpRemoteUri = new Uri(httpUrl); } catch (Exception ex) { throw new Exception($"Invalid URI: '{httpUrl}'", ex); } } else { string host = args.WebSession.Request.Host ?? httpsConnectHostname; string hostAndPath = host; if (httpUrl.StartsWith("/")) { hostAndPath += httpUrl; } string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", hostAndPath); try { httpRemoteUri = new Uri(url); } catch (Exception ex) { throw new Exception($"Invalid URI: '{url}'", ex); } } var request = args.WebSession.Request; request.RequestUri = httpRemoteUri; request.OriginalUrl = httpUrl; request.Method = httpMethod; request.HttpVersion = version; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamWriter = clientStreamWriter; if (!args.IsTransparent) { // proxy authorization check if (httpsConnectHostname == null && await CheckAuthorization(args) == false) { await InvokeBeforeResponse(args); // send the response await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, cancellationToken : cancellationToken); return; } PrepareRequestHeaders(request.Headers); request.Host = request.RequestUri.Authority; } // if win auth is enabled // we need a cache of request body // so that we can send it after authentication in WinAuthHandler.cs if (isWindowsAuthenticationEnabledAndSupported && request.HasBody) { await args.GetRequestBody(cancellationToken); } request.OriginalHasBody = request.HasBody; // If user requested interception do it await InvokeBeforeRequest(args); var response = args.WebSession.Response; if (request.CancelRequest) { // syphon out the request body from client before setting the new body await args.SyphonOutBodyAsync(true, cancellationToken); await HandleHttpSessionResponse(args); if (!response.KeepAlive) { return; } continue; } // create a new connection if hostname/upstream end point changes if (serverConnection != null && (!serverConnection.HostName.EqualsIgnoreCase(request.RequestUri.Host) || args.WebSession.UpStreamEndPoint?.Equals(serverConnection.UpStreamEndPoint) == false)) { tcpConnectionFactory.Release(serverConnection, true); serverConnection = null; } if (serverConnection == null) { serverConnection = await GetServerConnection(args, false, clientConnection.NegotiatedApplicationProtocol, cancellationToken); } // if upgrading to websocket then relay the requet without reading the contents if (request.UpgradeToWebSocket) { // prepare the prefix content await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken); await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers, cancellationToken : cancellationToken); string httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken); Response.ParseResponseLine(httpStatus, out var responseVersion, out int responseStatusCode, out string responseStatusDescription); response.HttpVersion = responseVersion; response.StatusCode = responseStatusCode; response.StatusDescription = responseStatusDescription; await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers, cancellationToken); if (!args.IsTransparent) { await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); } // If user requested call back then do it if (!args.WebSession.Response.Locked) { await InvokeBeforeResponse(args); } await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferSize, (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }, cancellationTokenSource, ExceptionFunc); return; } // construct the web request that we are going to issue on behalf of the client. await HandleHttpSessionRequestInternal(serverConnection, args); if (args.WebSession.ServerConnection == null) { return; } // if connection is closing exit if (!response.KeepAlive) { serverConnectionClose = true; return; } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session request", e, args); } } catch (Exception e) { args.Exception = e; serverConnectionClose = true; throw; } finally { await InvokeAfterResponse(args); args.Dispose(); } } } finally { tcpConnectionFactory.Release(serverConnection, serverConnectionClose || !EnableConnectionPool); } }
public static void CheckIn(TcpClientConnection<HttpConnectionState> conn) { //todo:把链接入池 }
public ClientDisconnectedState(TcpClientConnection context, StateMap stateMap) : base(context, stateMap, BinaryConnectionState.Disconnected) { }
private void conn_Connected(TcpClientConnection<HttpConnectionState> conn, HttpConnectionState state) { HttpRequest request = state.Request; conn.SendData(request.GetBytes());//info:noexception }
private void conn_Error(TcpClientConnection<HttpConnectionState> conn, HttpConnectionState state, Exception error) { TriggerCompleted(new HttpFetchResult(state.Url, error: error)); }
private void HandleRequests() { try { while (!_stop.WaitOne(0, false)) { var context = _listener.BeginAcceptTcpClient(null, null); if (0 == WaitHandle.WaitAny(new[] { _stop, context.AsyncWaitHandle })) return; try { TcpClientConnection client = new TcpClientConnection(this, _listener.EndAcceptTcpClient(context)); EventHandler<TcpClientEventArgs> handler = OnClientConnect; if (handler != null) handler(this, client); lock (_clients) { _clients.Add(client); } lock (_queue) { _queue.Enqueue(client); _ready.Set(); } } catch { return; } } } catch { _stop.Set(); } }
private void ProcessRequest(TcpClientConnection client) { EventHandler<TcpClientEventArgs> handler = OnDataRecieved; if (handler == null) client.Close(); else { if (client.BytesDesired <= client.BytesAvailable) { client.BytesDesired = 0; handler(this, client); } } if (client.ReadOffset < ushort.MaxValue / 2 && client.ReadBuffer.Length > ushort.MaxValue) Array.Resize(ref client.ReadBuffer, client.ReadOffset + 1024); if (!client.IsClosed) { try { client.FlushWrite(); } catch { client.Close(); } } }