titanium-web-proxy
titanium-web-proxy copied to clipboard
Error ocurred whilst handling session request: Server connection was closed.
App used: BasicClient from this Github.
I am having problems with persistent connections that remain inactive for more than a minute. When the web client makes a new request for this persistent connection and the proxy detects that the connection is not open to the server and trigger Retry to create another one and then send the request, it crashes.
I also tried to activate the connection pool but it returns the same error:
SessionEventArgs.TimeLine: Session Created: 04/06/2020 15:52:44 Request Received: 04/06/2020 15:52:44 Connection Ready: 04/06/2020 15:52:44 Request Sent: 04/06/2020 15:52:44 Error ocurred whilst handling session request: Server connection was closed.
This code is Original from this Git, and following the TimeLine, all steps are working perfectly.
private async Task<RetryResult> handleHttpSessionRequest(SessionEventArgs args,
TcpServerConnection? serverConnection, SslApplicationProtocol sslApplicationProtocol,
CancellationToken cancellationToken, CancellationTokenSource cancellationTokenSource)
{
args.HttpClient.Request.Locked = true;
// do not cache server connections for WebSockets
bool noCache = args.HttpClient.Request.UpgradeToWebSocket;
if (noCache)
{
serverConnection = null;
}
// a connection generator task with captured parameters via closure.
Func<Task<TcpServerConnection>> generator = () =>
tcpConnectionFactory.GetServerConnection(this,
args,
false,
sslApplicationProtocol,
noCache,
cancellationToken);
// for connection pool, retry fails until cache is exhausted.
return await retryPolicy<ServerConnectionException>().ExecuteAsync(async connection =>
{
// set the connection and send request headers
args.HttpClient.SetConnection(connection);
args.TimeLine["Connection Ready"] = DateTime.UtcNow;
if (args.HttpClient.Request.UpgradeToWebSocket)
{
// connectRequest can be null for SOCKS connection
if (args.HttpClient.ConnectRequest != null)
{
args.HttpClient.ConnectRequest!.TunnelType = TunnelType.Websocket;
}
// if upgrading to websocket then relay the request without reading the contents
await handleWebSocketUpgrade(args, args.ClientStream, connection, cancellationTokenSource, cancellationToken);
return false;
}
// construct the web request that we are going to issue on behalf of the client.
await handleHttpSessionRequest(args);
return true;
}, generator, serverConnection);
}
private async Task handleHttpSessionRequest(SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
var request = args.HttpClient.Request;
var body = request.CompressBodyAndUpdateContentLength();
await args.HttpClient.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
cancellationToken);
// If a successful 100 continue request was made, inform that to the client and reset response
if (request.ExpectationSucceeded)
{
var writer = args.ClientStream;
var response = args.HttpClient.Response;
var headerBuilder = new HeaderBuilder();
headerBuilder.WriteResponseLine(response.HttpVersion, response.StatusCode, response.StatusDescription);
headerBuilder.WriteHeaders(response.Headers);
await writer.WriteHeadersAsync(headerBuilder, cancellationToken);
await args.ClearResponse(cancellationToken);
}
// send body to server if available
if (request.HasBody)
{
if (request.IsBodyRead)
{
await args.HttpClient.Connection.Stream.WriteBodyAsync(body!, request.IsChunked, cancellationToken);
}
else if (!request.ExpectationFailed)
{
// get the request body unless an unsuccessful 100 continue request was made
await args.CopyRequestBodyAsync(args.HttpClient.Connection.Stream, TransformationMode.None, cancellationToken);
}
}
args.TimeLine["Request Sent"] = DateTime.UtcNow;
// parse and send response
await handleHttpSessionResponse(args);
}
Edit: The handler is not detecting the connection is closed, i did a test for check purposes only, and the error is "fixed":
private async Task handleHttpSessionRequest
if (args.HttpClient.Request.RequestUri.Host.Contains("pdc"))
{
connection = null;
Console.WriteLine("Connection set to null");
}
var result = await handleHttpSessionRequest(args, connection,
clientStream.Connection.NegotiatedApplicationProtocol,
cancellationToken, cancellationTokenSource);
Now we have to understand why the handler can't figure out the connection is closed
I have added another flag to Connection problem, and now i can detect when the connection is closed in all my cases, BUT...
Seems the Request is sent with the same connection what i have Released with: await tcpConnectionFactory.Release(connection, true); Like not waiting for the release.
On next request a New Tunel is fired and all works again while connection dont sleep for a minute.
if (connection != null)
{
var socket = connection.TcpSocket;
bool part1 = socket.Poll(1000, SelectMode.SelectRead);
bool part2 = socket.Available == 0;
bool part3 = socket.Connected;
if (part1 && part2 && part3)
{
//connection is closed
await tcpConnectionFactory.Release(connection, true);
connection = null;
}
}
OK, restored all code to original and only changed this:
if (args.HttpClient.Request.RequestUri.Host.Contains("pdc"))
{
connection = null;
Console.WriteLine("Connection set to null");
}
var result = await handleHttpSessionRequest(args, connection,
clientStream.Connection.NegotiatedApplicationProtocol,
cancellationToken, cancellationTokenSource);
Is fully working now, but i could not figure out what's happen here...