Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
f7c2490f
Commit
f7c2490f
authored
Jul 15, 2016
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove connection cache causing errors when reusing
parent
3ff60c1d
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
171 additions
and
116 deletions
+171
-116
ConnectionManagerTests.cs
Tests/Titanium.Web.Proxy.UnitTests/ConnectionManagerTests.cs
+0
-85
Titanium.Web.Proxy.UnitTests.csproj
...m.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
+0
-1
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+2
-2
TcpConnection.cs
Titanium.Web.Proxy/Network/TcpConnection.cs
+8
-2
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/TcpConnectionFactory.cs
+146
-0
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+2
-10
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+11
-14
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+2
-2
No files found.
Tests/Titanium.Web.Proxy.UnitTests/ConnectionManagerTests.cs
deleted
100644 → 0
View file @
3ff60c1d
using
System
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
Titanium.Web.Proxy.Network
;
using
System.Threading.Tasks
;
using
System.Collections.Generic
;
using
System.Diagnostics
;
namespace
Titanium.Web.Proxy.UnitTests
{
[
TestClass
]
public
class
ConnectionManagerTests
{
private
readonly
static
string
[]
hostNames
=
new
string
[]
{
"facebook.com"
,
"youtube.com"
,
"google.com"
,
"bing.com"
,
"yahoo.com"
};
private
readonly
Random
random
=
new
Random
();
[
TestMethod
]
public
async
Task
Simple_Create_Connection_Stress_Test
()
{
var
tasks
=
new
List
<
Task
>();
var
mgr
=
new
TcpConnectionManager
();
mgr
.
ClearIdleConnections
(
1
);
for
(
int
i
=
0
;
i
<
1000
;
i
++)
{
foreach
(
var
host
in
hostNames
)
{
tasks
.
Add
(
Task
.
Run
(
async
()
=>
{
await
Task
.
Delay
(
random
.
Next
(
0
,
10
)
*
1000
);
//get the connection
var
httpConnection
=
await
mgr
.
GetClient
(
host
,
80
,
false
,
new
Version
(
1
,
1
),
null
,
null
,
8096
,
System
.
Security
.
Authentication
.
SslProtocols
.
Default
,
120
,
null
,
null
);
//simulate a work with the connection
await
Task
.
Delay
(
random
.
Next
(
0
,
10
)
*
1000
);
//print total number of connections on cache
Debug
.
WriteLine
(
mgr
.
connectionCache
.
Count
);
Assert
.
IsNotNull
(
httpConnection
);
Assert
.
IsNotNull
(
httpConnection
.
TcpClient
);
Assert
.
IsTrue
(
httpConnection
.
TcpClient
.
Connected
);
//release
await
mgr
.
ReleaseClient
(
httpConnection
);
}));
tasks
.
Add
(
Task
.
Run
(
async
()
=>
{
await
Task
.
Delay
(
random
.
Next
(
0
,
10
)
*
1000
);
//get the connection
var
httpsConnection
=
await
mgr
.
GetClient
(
host
,
443
,
true
,
new
Version
(
1
,
1
),
null
,
null
,
8096
,
System
.
Security
.
Authentication
.
SslProtocols
.
Default
,
120
,
null
,
null
);
//simulate a work with the connection
await
Task
.
Delay
(
random
.
Next
(
0
,
10
)
*
1000
);
//print total number of connections on cache
Debug
.
WriteLine
(
mgr
.
connectionCache
.
Count
);
Assert
.
IsNotNull
(
httpsConnection
);
Assert
.
IsNotNull
(
httpsConnection
.
TcpClient
);
Assert
.
IsTrue
(
httpsConnection
.
TcpClient
.
Connected
);
//release
await
mgr
.
ReleaseClient
(
httpsConnection
);
}));
}
}
await
Task
.
WhenAll
(
tasks
.
ToArray
());
mgr
.
StopClearIdleConnections
();
}
}
}
Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
View file @
f7c2490f
...
...
@@ -51,7 +51,6 @@
</Choose>
<ItemGroup>
<Compile
Include=
"CertificateManagerTests.cs"
/>
<Compile
Include=
"ConnectionManagerTests.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
</ItemGroup>
<ItemGroup>
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
f7c2490f
...
...
@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Connection to server
/// </summary>
internal
Cached
TcpConnection
ServerConnection
{
get
;
set
;
}
internal
TcpConnection
ServerConnection
{
get
;
set
;
}
public
Request
Request
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
...
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
/// Set the tcp connection to server used by this webclient
/// </summary>
/// <param name="Connection"></param>
internal
void
SetConnection
(
Cached
TcpConnection
Connection
)
internal
void
SetConnection
(
TcpConnection
Connection
)
{
Connection
.
LastAccess
=
DateTime
.
Now
;
ServerConnection
=
Connection
;
...
...
Titanium.Web.Proxy/Network/
Cached
TcpConnection.cs
→
Titanium.Web.Proxy/Network/TcpConnection.cs
View file @
f7c2490f
...
...
@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// An object that holds TcpConnection to a particular server & port
/// </summary>
public
class
CachedTcpConnection
public
class
TcpConnection
:
IDisposable
{
internal
string
HostName
{
get
;
set
;
}
internal
int
port
{
get
;
set
;
}
...
...
@@ -37,9 +37,15 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal
DateTime
LastAccess
{
get
;
set
;
}
internal
Cached
TcpConnection
()
internal
TcpConnection
()
{
LastAccess
=
DateTime
.
Now
;
}
public
void
Dispose
()
{
Stream
.
Dispose
();
TcpClient
.
Client
.
Dispose
();
}
}
}
Titanium.Web.Proxy/Network/TcpConnection
Manager
.cs
→
Titanium.Web.Proxy/Network/TcpConnection
Factory
.cs
View file @
f7c2490f
...
...
@@ -9,7 +9,6 @@ using System.Net.Security;
using
Titanium.Web.Proxy.Helpers
;
using
System.Threading
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Authentication
;
...
...
@@ -18,18 +17,8 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
internal
class
TcpConnection
Manager
internal
class
TcpConnection
Factory
{
/// <summary>
/// Connection cache
/// </summary>
internal
Dictionary
<
string
,
List
<
CachedTcpConnection
>>
connectionCache
=
new
Dictionary
<
string
,
List
<
CachedTcpConnection
>>();
/// <summary>
/// A lock to manage concurrency
/// </summary>
SemaphoreSlim
connectionAccessLock
=
new
SemaphoreSlim
(
1
);
/// <summary>
/// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version
/// </summary>
...
...
@@ -38,76 +27,18 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
async
Task
<
Cached
TcpConnection
>
GetClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
internal
async
Task
<
TcpConnection
>
GetClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
ExternalProxy
upStreamHttpProxy
,
ExternalProxy
upStreamHttpsProxy
,
int
bufferSize
,
SslProtocols
supportedSslProtocols
,
int
connectionTimeOutSeconds
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallBack
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallBack
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
)
{
List
<
CachedTcpConnection
>
cachedConnections
=
null
;
CachedTcpConnection
cached
=
null
;
//Get a unique string to identify this connection
var
key
=
GetConnectionKey
(
hostname
,
port
,
isHttps
,
version
);
{
//not in cache so create and return
return
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
connectionTimeOutSeconds
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
while
(
true
)
{
await
connectionAccessLock
.
WaitAsync
();
try
{
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
if
(
cachedConnections
!=
null
&&
cachedConnections
.
Count
>
0
)
{
cached
=
cachedConnections
.
First
();
cachedConnections
.
Remove
(
cached
);
}
else
{
cached
=
null
;
}
}
finally
{
connectionAccessLock
.
Release
();
}
if
(
cached
!=
null
&&
!
cached
.
TcpClient
.
Client
.
IsConnected
())
{
cached
.
TcpClient
.
Client
.
Dispose
();
cached
.
TcpClient
.
Close
();
continue
;
}
if
(
cached
==
null
)
{
break
;
}
}
if
(
cached
==
null
)
{
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
connectionTimeOutSeconds
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
}
return
cached
;
}
/// <summary>
/// Get a string to identfiy the connection to a particular host, port
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
string
GetConnectionKey
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
{
return
string
.
Format
(
"{0}:{1}:{2}:{3}:{4}"
,
hostname
.
ToLower
(),
port
,
isHttps
,
version
.
Major
,
version
.
Minor
);
}
/// <summary>
/// Create connection to a particular host/port optionally with SSL and a particular HTTP version
...
...
@@ -117,7 +48,7 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
private
async
Task
<
Cached
TcpConnection
>
CreateClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
int
connectionTimeOutSeconds
,
private
async
Task
<
TcpConnection
>
CreateClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
int
connectionTimeOutSeconds
,
ExternalProxy
upStreamHttpProxy
,
ExternalProxy
upStreamHttpsProxy
,
int
bufferSize
,
SslProtocols
supportedSslProtocols
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallBack
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
)
{
...
...
@@ -194,11 +125,11 @@ namespace Titanium.Web.Proxy.Network
stream
=
client
.
GetStream
();
}
}
client
.
ReceiveTimeout
=
connectionTimeOutSeconds
*
1000
;
client
.
SendTimeout
=
connectionTimeOutSeconds
*
1000
;
return
new
Cached
TcpConnection
()
return
new
TcpConnection
()
{
HostName
=
hostname
,
port
=
port
,
...
...
@@ -210,80 +141,6 @@ namespace Titanium.Web.Proxy.Network
};
}
/// <summary>
/// Returns a Tcp Connection back to cache for reuse by other requests
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
internal
async
Task
ReleaseClient
(
CachedTcpConnection
connection
)
{
connection
.
LastAccess
=
DateTime
.
Now
;
var
key
=
GetConnectionKey
(
connection
.
HostName
,
connection
.
port
,
connection
.
IsHttps
,
connection
.
Version
);
await
connectionAccessLock
.
WaitAsync
();
try
{
List
<
CachedTcpConnection
>
cachedConnections
;
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
if
(
cachedConnections
!=
null
)
{
cachedConnections
.
Add
(
connection
);
}
else
{
connectionCache
.
Add
(
key
,
new
List
<
CachedTcpConnection
>()
{
connection
});
}
}
finally
{
connectionAccessLock
.
Release
();
}
}
private
bool
clearConenctions
{
get
;
set
;
}
/// <summary>
/// Stop clearing idle connections
/// </summary>
internal
void
StopClearIdleConnections
()
{
clearConenctions
=
false
;
}
/// <summary>
/// A method to clear idle connections
/// </summary>
internal
async
void
ClearIdleConnections
(
int
connectionCacheTimeOutMinutes
)
{
clearConenctions
=
true
;
while
(
clearConenctions
)
{
await
connectionAccessLock
.
WaitAsync
();
try
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
connectionCacheTimeOutMinutes
);
connectionCache
.
SelectMany
(
x
=>
x
.
Value
)
.
Where
(
x
=>
x
.
LastAccess
<
cutOff
)
.
ToList
()
.
ForEach
(
x
=>
x
.
TcpClient
.
Close
());
connectionCache
.
ToList
().
ForEach
(
x
=>
x
.
Value
.
RemoveAll
(
y
=>
y
.
LastAccess
<
cutOff
));
}
finally
{
connectionAccessLock
.
Release
();
}
//every minute run this
await
Task
.
Delay
(
1000
*
60
);
}
}
}
}
Titanium.Web.Proxy/ProxyServer.cs
View file @
f7c2490f
...
...
@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// A object that manages tcp connection cache to server
/// </summary>
private
TcpConnection
Manager
tcpConnectionCacheManager
{
get
;
set
;
}
private
TcpConnection
Factory
tcpConnectionCacheManager
{
get
;
set
;
}
/// <summary>
/// Manage system proxy settings
...
...
@@ -66,11 +66,6 @@ namespace Titanium.Web.Proxy
/// </summary>
public
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
/// <summary>
/// Minutes TCP connection cache to servers to be kept alive from last time it was used
/// </summary>
public
int
ServerConnectionCacheTimeOutMinutes
{
get
;
set
;
}
/// <summary>
/// Minutes certificates should be kept in cache when not used
/// </summary>
...
...
@@ -128,11 +123,10 @@ namespace Titanium.Web.Proxy
{
//default values
ConnectionTimeOutSeconds
=
120
;
ServerConnectionCacheTimeOutMinutes
=
3
;
CertificateCacheTimeOutMinutes
=
60
;
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
tcpConnectionCacheManager
=
new
TcpConnection
Manager
();
tcpConnectionCacheManager
=
new
TcpConnection
Factory
();
systemProxySettingsManager
=
new
SystemProxyManager
();
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
...
...
@@ -279,7 +273,6 @@ namespace Titanium.Web.Proxy
Listen
(
endPoint
);
}
tcpConnectionCacheManager
.
ClearIdleConnections
(
ServerConnectionCacheTimeOutMinutes
);
certificateCacheManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
proxyRunning
=
true
;
...
...
@@ -312,7 +305,6 @@ namespace Titanium.Web.Proxy
ProxyEndPoints
.
Clear
();
tcpConnectionCacheManager
.
StopClearIdleConnections
();
certificateCacheManager
.
StopClearIdleCertificates
();
proxyRunning
=
false
;
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
f7c2490f
...
...
@@ -88,14 +88,6 @@ namespace Titanium.Web.Proxy
try
{
//create the Tcp Connection to server and then release it to connection cache
//Just doing what CONNECT request is asking as to do
var
tunnelClient
=
await
tcpConnectionCacheManager
.
GetClient
(
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
true
,
version
,
UpStreamHttpProxy
,
UpStreamHttpsProxy
,
BUFFER_SIZE
,
SupportedSslProtocols
,
ConnectionTimeOutSeconds
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
),
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
));
await
tcpConnectionCacheManager
.
ReleaseClient
(
tunnelClient
);
sslStream
=
new
SslStream
(
clientStream
,
true
);
var
certificate
=
await
certificateCacheManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
...
...
@@ -218,7 +210,7 @@ namespace Titanium.Web.Proxy
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
)
{
Cached
TcpConnection
connection
=
null
;
TcpConnection
connection
=
null
;
//Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client)
...
...
@@ -327,11 +319,11 @@ namespace Titanium.Web.Proxy
await
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
IsHttps
,
SupportedSslProtocols
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
break
;
}
//construct the web request that we are going to issue on behalf of the client.
connection
=
await
tcpConnectionCacheManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
,
connection
=
connection
!=
null
?
connection
:
await
tcpConnectionCacheManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
,
UpStreamHttpProxy
,
UpStreamHttpsProxy
,
BUFFER_SIZE
,
SupportedSslProtocols
,
ConnectionTimeOutSeconds
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
),
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
));
...
...
@@ -411,11 +403,10 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
break
;
}
//send the tcp connection to server back to connection cache for reuse
await
tcpConnectionCacheManager
.
ReleaseClient
(
connection
);
// read the next request
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
...
...
@@ -429,6 +420,12 @@ namespace Titanium.Web.Proxy
}
if
(
connection
!=
null
)
{
//dispose
connection
.
Dispose
();
}
}
/// <summary>
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
f7c2490f
...
...
@@ -77,8 +77,8 @@
<Compile
Include=
"Http\Request.cs"
/>
<Compile
Include=
"Http\Response.cs"
/>
<Compile
Include=
"Models\ExternalProxy.cs"
/>
<Compile
Include=
"Network\
Cached
TcpConnection.cs"
/>
<Compile
Include=
"Network\TcpConnection
Manager
.cs"
/>
<Compile
Include=
"Network\TcpConnection.cs"
/>
<Compile
Include=
"Network\TcpConnection
Factory
.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
<Compile
Include=
"Http\HttpWebClient.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment