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