Commit 65be519e authored by titanium007's avatar titanium007

Issue #27

Improve performance by avoiding new Tasks for each requests
parent ca13d730
......@@ -14,27 +14,28 @@ namespace Titanium.Web.Proxy.Helpers
internal string ReadLine()
{
var buf = new char[1];
var readBuffer = new StringBuilder();
try
{
var lastChar = new char();
var lastChar = default(char);
while ((Read(buf, 0, 1)) > 0)
while (true)
{
if (lastChar == '\r' && buf[0] == '\n')
var buf = ReadChar();
if (lastChar == '\r' && buf == '\n')
{
return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
}
if (buf[0] == '\0')
if (buf == '\0')
{
return readBuffer.ToString();
}
readBuffer.Append(buf[0]);
readBuffer.Append(buf);
lastChar = buf[0];
lastChar = buf;
}
return readBuffer.ToString();
}
catch (IOException)
{
......@@ -42,7 +43,6 @@ namespace Titanium.Web.Proxy.Helpers
}
}
internal List<string> ReadAllLines()
{
string tmpLine;
......
......@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy
{
ServicePointManager.Expect100Continue = false;
WebRequest.DefaultWebProxy = null;
ServicePointManager.DefaultConnectionLimit = 10;
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000; //3 minutes
ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000;
......
......@@ -97,10 +97,8 @@ namespace Titanium.Web.Proxy
}
//Now create the request
Task.Factory.StartNew(
() =>
HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null));
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null);
}
catch
{
......@@ -111,6 +109,8 @@ namespace Titanium.Web.Proxy
private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
{
while (true)
{
if (string.IsNullOrEmpty(httpCmd))
{
......@@ -172,9 +172,8 @@ namespace Titanium.Web.Proxy
}
}
//construct the web request that we are going to issue on behalf of the client.
args.ProxyRequest = (HttpWebRequest) WebRequest.Create(httpRemoteUri);
args.ProxyRequest = (HttpWebRequest)WebRequest.Create(httpRemoteUri);
args.ProxyRequest.Proxy = null;
args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = httpMethod;
......@@ -186,11 +185,10 @@ namespace Titanium.Web.Proxy
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
args.RequestUrl = args.ProxyRequest.RequestUri.OriginalString;
args.ClientPort = ((IPEndPoint) client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint) client.Client.RemoteEndPoint).Address;
args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
args.RequestHttpVersion = version;
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
args.ProxyRequest.ConnectionGroupName = args.RequestHostname;
args.ProxyRequest.AllowWriteStreamBuffering = true;
......@@ -217,8 +215,6 @@ namespace Titanium.Web.Proxy
args.ProxyRequest.ContentLength = args.RequestBody.Length;
var newStream = args.ProxyRequest.GetRequestStream();
newStream.Write(args.RequestBody, 0, args.RequestBody.Length);
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
}
else
{
......@@ -227,22 +223,31 @@ namespace Titanium.Web.Proxy
{
SendClientRequestBody(args);
}
//Http request body sent, now wait asynchronously for response
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
}
HandleHttpSessionResponse(args);
if (args.ResponseHeaders.Any(x => x.Name.ToLower() == "proxy-connection" && x.Value.ToLower() == "close"))
{
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
//If client is pipeling the request, this will be immediately hit before response for previous request was made
httpCmd = clientStreamReader.ReadLine();
//Http request body sent, now wait for next request
Task.Factory.StartNew(
() =>
HandleHttpSessionRequest(args.Client, httpCmd, args.ClientStream, args.ClientStreamReader,
args.ClientStreamWriter, secureTunnelHostName));
client = args.Client;
clientStream = args.ClientStream;
clientStreamReader = args.ClientStreamReader;
args.ClientStreamWriter = clientStreamWriter;
}
catch
{
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
throw;
}
}
}
......@@ -250,7 +255,7 @@ namespace Titanium.Web.Proxy
{
clientStreamWriter.WriteLine(httpVersion + " 200 Connection established");
clientStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
clientStreamWriter.WriteLine("connection:close");
//clientStreamWriter.WriteLine("connection:close");
clientStreamWriter.WriteLine();
clientStreamWriter.Flush();
}
......@@ -302,6 +307,8 @@ namespace Titanium.Web.Proxy
case "proxy-connection":
if (requestHeaders[i].Value.ToLower() == "keep-alive")
webRequest.KeepAlive = true;
else if (requestHeaders[i].Value.ToLower() == "close")
webRequest.KeepAlive = false;
break;
case "range":
var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
......@@ -359,18 +366,18 @@ namespace Titanium.Web.Proxy
int bytesToRead;
if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
{
bytesToRead = (int) args.ProxyRequest.ContentLength;
bytesToRead = (int)args.ProxyRequest.ContentLength;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < (int) args.ProxyRequest.ContentLength)
while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
{
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
var remainingBytes = (int) args.ProxyRequest.ContentLength - totalbytesRead;
var remainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
if (remainingBytes < bytesToRead)
{
bytesToRead = remainingBytes;
......@@ -414,7 +421,6 @@ namespace Titanium.Web.Proxy
}
}
postStream.Close();
}
catch
......
......@@ -15,13 +15,12 @@ namespace Titanium.Web.Proxy
partial class ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
private static void HandleHttpSessionResponse(IAsyncResult asynchronousResult)
private static void HandleHttpSessionResponse(SessionEventArgs args)
{
var args = (SessionEventArgs)asynchronousResult.AsyncState;
try
{
args.ServerResponse = (HttpWebResponse)args.ProxyRequest.EndGetResponse(asynchronousResult);
args.ServerResponse = (HttpWebResponse)args.ProxyRequest.GetResponse();
}
catch (WebException webEx)
{
......@@ -132,6 +131,8 @@ namespace Titanium.Web.Proxy
{
if (headers != null)
{
FixProxyHeaders(headers);
foreach (var header in headers)
{
responseWriter.WriteLine(header.ToString());
......@@ -141,10 +142,24 @@ namespace Titanium.Web.Proxy
responseWriter.WriteLine();
responseWriter.Flush();
}
private static void FixProxyHeaders(List<HttpHeader> headers)
{
//If proxy-connection close was returned inform to close the connection
if (headers.Any(x => x.Name.ToLower() == "proxy-connection" && x.Value.ToLower() == "close"))
if (headers.Any(x => x.Name.ToLower() == "connection") == false)
{
headers.Add(new HttpHeader("connection", "close"));
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
else
headers.Find(x => x.Name.ToLower() == "connection").Value = "close";
}
private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length,
bool isChunked)
{
FixProxyHeaders(headers);
if (!isChunked)
{
if (headers.Any(x => x.Name.ToLower() == "content-length") == false)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment