Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Commit 65be519

Browse files
committed
Issue #27
Improve performance by avoiding new Tasks for each requests
1 parent ca13d73 commit 65be519

File tree

4 files changed

+148
-127
lines changed

4 files changed

+148
-127
lines changed

Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,35 @@ internal CustomBinaryReader(Stream stream, Encoding encoding)
1414

1515
internal string ReadLine()
1616
{
17-
var buf = new char[1];
1817
var readBuffer = new StringBuilder();
18+
1919
try
2020
{
21-
var lastChar = new char();
21+
var lastChar = default(char);
2222

23-
while ((Read(buf, 0, 1)) > 0)
23+
while (true)
2424
{
25-
if (lastChar == '\r' && buf[0] == '\n')
25+
var buf = ReadChar();
26+
if (lastChar == '\r' && buf == '\n')
2627
{
2728
return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
2829
}
29-
if (buf[0] == '\0')
30+
if (buf == '\0')
3031
{
3132
return readBuffer.ToString();
3233
}
33-
readBuffer.Append(buf[0]);
34+
readBuffer.Append(buf);
3435

35-
lastChar = buf[0];
36+
lastChar = buf;
3637
}
37-
return readBuffer.ToString();
38+
3839
}
3940
catch (IOException)
4041
{
4142
return readBuffer.ToString();
4243
}
4344
}
4445

45-
4646
internal List<string> ReadAllLines()
4747
{
4848
string tmpLine;

Titanium.Web.Proxy/ProxyServer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static void Initialize()
6161
{
6262
ServicePointManager.Expect100Continue = false;
6363
WebRequest.DefaultWebProxy = null;
64-
ServicePointManager.DefaultConnectionLimit = 10;
64+
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
6565
ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000; //3 minutes
6666
ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000;
6767

Titanium.Web.Proxy/RequestHandler.cs

+120-114
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,8 @@ private static void HandleClient(TcpClient client)
9797
}
9898

9999
//Now create the request
100-
Task.Factory.StartNew(
101-
() =>
102-
HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
103-
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null));
100+
HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
101+
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null);
104102
}
105103
catch
106104
{
@@ -112,145 +110,152 @@ private static void HandleClient(TcpClient client)
112110
private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
113111
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
114112
{
115-
if (string.IsNullOrEmpty(httpCmd))
113+
while (true)
116114
{
117-
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
118-
return;
119-
}
120-
121-
var args = new SessionEventArgs(BUFFER_SIZE);
122-
args.Client = client;
123-
115+
if (string.IsNullOrEmpty(httpCmd))
116+
{
117+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
118+
return;
119+
}
124120

125-
try
126-
{
127-
//break up the line into three components (method, remote URL & Http Version)
128-
var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);
121+
var args = new SessionEventArgs(BUFFER_SIZE);
122+
args.Client = client;
129123

130-
var httpMethod = httpCmdSplit[0];
131-
var httpRemoteUri =
132-
new Uri(secureTunnelHostName == null ? httpCmdSplit[1] : (secureTunnelHostName + httpCmdSplit[1]));
133-
var httpVersion = httpCmdSplit[2];
134124

135-
Version version;
136-
if (httpVersion == "HTTP/1.1")
137-
{
138-
version = new Version(1, 1);
139-
}
140-
else
125+
try
141126
{
142-
version = new Version(1, 0);
143-
}
127+
//break up the line into three components (method, remote URL & Http Version)
128+
var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);
144129

145-
if (httpRemoteUri.Scheme == Uri.UriSchemeHttps)
146-
{
147-
args.IsHttps = true;
148-
}
130+
var httpMethod = httpCmdSplit[0];
131+
var httpRemoteUri =
132+
new Uri(secureTunnelHostName == null ? httpCmdSplit[1] : (secureTunnelHostName + httpCmdSplit[1]));
133+
var httpVersion = httpCmdSplit[2];
149134

150-
args.RequestHeaders = new List<HttpHeader>();
135+
Version version;
136+
if (httpVersion == "HTTP/1.1")
137+
{
138+
version = new Version(1, 1);
139+
}
140+
else
141+
{
142+
version = new Version(1, 0);
143+
}
151144

152-
string tmpLine;
145+
if (httpRemoteUri.Scheme == Uri.UriSchemeHttps)
146+
{
147+
args.IsHttps = true;
148+
}
153149

154-
while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
155-
{
156-
var header = tmpLine.Split(ColonSpaceSplit, 2, StringSplitOptions.None);
157-
args.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
158-
}
150+
args.RequestHeaders = new List<HttpHeader>();
159151

160-
for (var i = 0; i < args.RequestHeaders.Count; i++)
161-
{
162-
var rawHeader = args.RequestHeaders[i];
152+
string tmpLine;
163153

154+
while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
155+
{
156+
var header = tmpLine.Split(ColonSpaceSplit, 2, StringSplitOptions.None);
157+
args.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
158+
}
164159

165-
//if request was upgrade to web-socket protocol then relay the request without proxying
166-
if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
160+
for (var i = 0; i < args.RequestHeaders.Count; i++)
167161
{
168-
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders,
169-
httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
170-
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
171-
return;
162+
var rawHeader = args.RequestHeaders[i];
163+
164+
165+
//if request was upgrade to web-socket protocol then relay the request without proxying
166+
if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
167+
{
168+
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders,
169+
httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
170+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
171+
return;
172+
}
172173
}
173-
}
174174

175+
//construct the web request that we are going to issue on behalf of the client.
176+
args.ProxyRequest = (HttpWebRequest)WebRequest.Create(httpRemoteUri);
177+
args.ProxyRequest.Proxy = null;
178+
args.ProxyRequest.UseDefaultCredentials = true;
179+
args.ProxyRequest.Method = httpMethod;
180+
args.ProxyRequest.ProtocolVersion = version;
181+
args.ClientStream = clientStream;
182+
args.ClientStreamReader = clientStreamReader;
183+
args.ClientStreamWriter = clientStreamWriter;
184+
args.ProxyRequest.AllowAutoRedirect = false;
185+
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
186+
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
187+
args.RequestUrl = args.ProxyRequest.RequestUri.OriginalString;
188+
args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
189+
args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
190+
args.RequestHttpVersion = version;
191+
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
192+
args.ProxyRequest.AllowWriteStreamBuffering = true;
193+
194+
195+
//If requested interception
196+
if (BeforeRequest != null)
197+
{
198+
args.RequestEncoding = args.ProxyRequest.GetEncoding();
199+
BeforeRequest(null, args);
200+
}
175201

176-
//construct the web request that we are going to issue on behalf of the client.
177-
args.ProxyRequest = (HttpWebRequest) WebRequest.Create(httpRemoteUri);
178-
args.ProxyRequest.Proxy = null;
179-
args.ProxyRequest.UseDefaultCredentials = true;
180-
args.ProxyRequest.Method = httpMethod;
181-
args.ProxyRequest.ProtocolVersion = version;
182-
args.ClientStream = clientStream;
183-
args.ClientStreamReader = clientStreamReader;
184-
args.ClientStreamWriter = clientStreamWriter;
185-
args.ProxyRequest.AllowAutoRedirect = false;
186-
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
187-
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
188-
args.RequestUrl = args.ProxyRequest.RequestUri.OriginalString;
189-
args.ClientPort = ((IPEndPoint) client.Client.RemoteEndPoint).Port;
190-
args.ClientIpAddress = ((IPEndPoint) client.Client.RemoteEndPoint).Address;
191-
args.RequestHttpVersion = version;
192-
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
193-
args.ProxyRequest.ConnectionGroupName = args.RequestHostname;
194-
args.ProxyRequest.AllowWriteStreamBuffering = true;
202+
args.RequestLocked = true;
195203

204+
if (args.CancelRequest)
205+
{
206+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
207+
return;
208+
}
196209

197-
//If requested interception
198-
if (BeforeRequest != null)
199-
{
200-
args.RequestEncoding = args.ProxyRequest.GetEncoding();
201-
BeforeRequest(null, args);
202-
}
210+
SetRequestHeaders(args.RequestHeaders, args.ProxyRequest);
203211

204-
args.RequestLocked = true;
212+
//If request was modified by user
213+
if (args.RequestBodyRead)
214+
{
215+
args.ProxyRequest.ContentLength = args.RequestBody.Length;
216+
var newStream = args.ProxyRequest.GetRequestStream();
217+
newStream.Write(args.RequestBody, 0, args.RequestBody.Length);
218+
}
219+
else
220+
{
221+
//If its a post/put request, then read the client html body and send it to server
222+
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
223+
{
224+
SendClientRequestBody(args);
225+
}
226+
}
205227

206-
if (args.CancelRequest)
207-
{
208-
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
209-
return;
210-
}
228+
HandleHttpSessionResponse(args);
211229

212-
SetRequestHeaders(args.RequestHeaders, args.ProxyRequest);
230+
if (args.ResponseHeaders.Any(x => x.Name.ToLower() == "proxy-connection" && x.Value.ToLower() == "close"))
231+
{
232+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
233+
return;
234+
}
235+
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
236+
//If client is pipeling the request, this will be immediately hit before response for previous request was made
237+
httpCmd = clientStreamReader.ReadLine();
238+
//Http request body sent, now wait for next request
213239

214-
//If request was modified by user
215-
if (args.RequestBodyRead)
216-
{
217-
args.ProxyRequest.ContentLength = args.RequestBody.Length;
218-
var newStream = args.ProxyRequest.GetRequestStream();
219-
newStream.Write(args.RequestBody, 0, args.RequestBody.Length);
240+
client = args.Client;
241+
clientStream = args.ClientStream;
242+
clientStreamReader = args.ClientStreamReader;
243+
args.ClientStreamWriter = clientStreamWriter;
220244

221-
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
222245
}
223-
else
246+
catch
224247
{
225-
//If its a post/put request, then read the client html body and send it to server
226-
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
227-
{
228-
SendClientRequestBody(args);
229-
}
230-
//Http request body sent, now wait asynchronously for response
231-
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
248+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
249+
throw;
232250
}
233-
234-
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
235-
//If client is pipeling the request, this will be immediately hit before response for previous request was made
236-
httpCmd = clientStreamReader.ReadLine();
237-
//Http request body sent, now wait for next request
238-
Task.Factory.StartNew(
239-
() =>
240-
HandleHttpSessionRequest(args.Client, httpCmd, args.ClientStream, args.ClientStreamReader,
241-
args.ClientStreamWriter, secureTunnelHostName));
242-
}
243-
catch
244-
{
245-
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
246251
}
247252
}
248253

249254
private static void WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion)
250255
{
251256
clientStreamWriter.WriteLine(httpVersion + " 200 Connection established");
252257
clientStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
253-
clientStreamWriter.WriteLine("connection:close");
258+
//clientStreamWriter.WriteLine("connection:close");
254259
clientStreamWriter.WriteLine();
255260
clientStreamWriter.Flush();
256261
}
@@ -302,6 +307,8 @@ private static void SetRequestHeaders(List<HttpHeader> requestHeaders, HttpWebRe
302307
case "proxy-connection":
303308
if (requestHeaders[i].Value.ToLower() == "keep-alive")
304309
webRequest.KeepAlive = true;
310+
else if (requestHeaders[i].Value.ToLower() == "close")
311+
webRequest.KeepAlive = false;
305312
break;
306313
case "range":
307314
var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
@@ -359,18 +366,18 @@ private static void SendClientRequestBody(SessionEventArgs args)
359366
int bytesToRead;
360367
if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
361368
{
362-
bytesToRead = (int) args.ProxyRequest.ContentLength;
369+
bytesToRead = (int)args.ProxyRequest.ContentLength;
363370
}
364371
else
365372
bytesToRead = BUFFER_SIZE;
366373

367374

368-
while (totalbytesRead < (int) args.ProxyRequest.ContentLength)
375+
while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
369376
{
370377
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
371378
totalbytesRead += buffer.Length;
372379

373-
var remainingBytes = (int) args.ProxyRequest.ContentLength - totalbytesRead;
380+
var remainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
374381
if (remainingBytes < bytesToRead)
375382
{
376383
bytesToRead = remainingBytes;
@@ -414,7 +421,6 @@ private static void SendClientRequestBody(SessionEventArgs args)
414421
}
415422
}
416423

417-
418424
postStream.Close();
419425
}
420426
catch

0 commit comments

Comments
 (0)