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
33d50f32
Commit
33d50f32
authored
May 11, 2018
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix -ive server connection count
parent
e662451f
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
159 additions
and
119 deletions
+159
-119
ExplicitClientHandler.cs
Titanium.Web.Proxy/ExplicitClientHandler.cs
+4
-2
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+26
-17
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+125
-98
TransparentClientHandler.cs
Titanium.Web.Proxy/TransparentClientHandler.cs
+4
-2
No files found.
Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
33d50f32
...
@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy
...
@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy
Task
<
TcpServerConnection
>
prefetchConnectionTask
=
null
;
Task
<
TcpServerConnection
>
prefetchConnectionTask
=
null
;
bool
closeServerConnection
=
false
;
bool
closeServerConnection
=
false
;
bool
calledRequestHandler
=
false
;
try
try
{
{
...
@@ -289,7 +290,7 @@ namespace Titanium.Web.Proxy
...
@@ -289,7 +290,7 @@ namespace Titanium.Web.Proxy
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
}
}
}
}
calledRequestHandler
=
true
;
// Now create the request
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
,
connectHostname
,
connectArgs
?.
WebSession
.
ConnectRequest
,
prefetchConnectionTask
);
cancellationTokenSource
,
connectHostname
,
connectArgs
?.
WebSession
.
ConnectRequest
,
prefetchConnectionTask
);
...
@@ -316,7 +317,8 @@ namespace Titanium.Web.Proxy
...
@@ -316,7 +317,8 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
if
(
prefetchConnectionTask
!=
null
)
if
(!
calledRequestHandler
&&
prefetchConnectionTask
!=
null
)
{
{
var
connection
=
await
prefetchConnectionTask
;
var
connection
=
await
prefetchConnectionTask
;
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
33d50f32
...
@@ -42,6 +42,29 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -42,6 +42,29 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal
ProxyServer
server
{
get
;
set
;
}
internal
ProxyServer
server
{
get
;
set
;
}
internal
string
GetConnectionCacheKey
(
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
bool
isConnect
,
ProxyServer
proxyServer
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
)
{
var
cacheKeyBuilder
=
new
StringBuilder
(
$"
{
remoteHostName
}
-
{
remotePort
}
"
+
$"-
{(
httpVersion
==
null
?
string
.
Empty
:
httpVersion
.
ToString
())}
"
+
$"-
{
isHttps
}
-
{
isConnect
}
-"
);
if
(
applicationProtocols
!=
null
)
{
foreach
(
var
protocol
in
applicationProtocols
)
{
cacheKeyBuilder
.
Append
(
$"
{
protocol
}
-"
);
}
}
cacheKeyBuilder
.
Append
(
upStreamEndPoint
!=
null
?
$"
{
upStreamEndPoint
.
Address
}
-
{
upStreamEndPoint
.
Port
}
-"
:
string
.
Empty
);
cacheKeyBuilder
.
Append
(
externalProxy
!=
null
?
$"
{
externalProxy
.
GetCacheKey
()}
-"
:
string
.
Empty
);
return
cacheKeyBuilder
.
ToString
();
}
/// <summary>
/// <summary>
/// Gets a TCP connection to server from connection pool.
/// Gets a TCP connection to server from connection pool.
/// </summary>
/// </summary>
...
@@ -61,23 +84,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -61,23 +84,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
ProxyServer
proxyServer
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
ProxyServer
proxyServer
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
CancellationToken
cancellationToken
)
CancellationToken
cancellationToken
)
{
{
var
cacheKeyBuilder
=
new
StringBuilder
(
$"
{
remoteHostName
}
-
{
remotePort
}
"
+
var
cacheKey
=
GetConnectionCacheKey
(
remoteHostName
,
remotePort
,
$"-
{(
httpVersion
==
null
?
string
.
Empty
:
httpVersion
.
ToString
())}
"
+
httpVersion
,
isHttps
,
applicationProtocols
,
isConnect
,
$"-
{
isHttps
}
-
{
isConnect
}
-"
);
proxyServer
,
upStreamEndPoint
,
externalProxy
);
if
(
applicationProtocols
!=
null
)
{
foreach
(
var
protocol
in
applicationProtocols
)
{
cacheKeyBuilder
.
Append
(
$"
{
protocol
}
-"
);
}
}
cacheKeyBuilder
.
Append
(
upStreamEndPoint
!=
null
?
$"
{
upStreamEndPoint
.
Address
}
-
{
upStreamEndPoint
.
Port
}
-"
:
string
.
Empty
);
cacheKeyBuilder
.
Append
(
externalProxy
!=
null
?
$"
{
externalProxy
.
GetCacheKey
()}
-"
:
string
.
Empty
);
string
cacheKey
=
cacheKeyBuilder
.
ToString
();
if
(
proxyServer
.
EnableConnectionPool
)
if
(
proxyServer
.
EnableConnectionPool
)
{
{
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
33d50f32
...
@@ -189,11 +189,11 @@ namespace Titanium.Web.Proxy
...
@@ -189,11 +189,11 @@ namespace Titanium.Web.Proxy
newConnection
=
true
;
newConnection
=
true
;
}
}
// create a new connection if
hostname/upstream end point
changes
// create a new connection if
cache key
changes
if
(
serverConnection
!=
null
if
(
serverConnection
!=
null
&&
(
!
serverConnection
.
HostName
.
EqualsIgnoreCase
(
request
.
RequestUri
.
Host
)
&&
(
await
getConnectionCacheKey
(
args
,
false
,
||
args
.
WebSession
.
UpStreamEndPoint
?.
Equals
(
serverConnection
.
UpStreamEndPoint
)
==
clientConnection
.
NegotiatedApplicationProtocol
)
false
))
!=
serverConnection
.
CacheKey
))
{
{
await
tcpConnectionFactory
.
Release
(
serverConnection
);
await
tcpConnectionFactory
.
Release
(
serverConnection
);
serverConnection
=
null
;
serverConnection
=
null
;
...
@@ -263,16 +263,14 @@ namespace Titanium.Web.Proxy
...
@@ -263,16 +263,14 @@ namespace Titanium.Web.Proxy
throw
new
Exception
(
"Session was terminated by user."
);
throw
new
Exception
(
"Session was terminated by user."
);
}
}
//TODO find why enabling this cause server connection count to go -ive
//TODO find why enabling this causes invalid httpCmd exception occationally
//With connection pool get connection for each HTTP session instead of per client connection.
//With connection pool get connection for each HTTP session instead of per client connection.
//That will be more efficient especially when client is holding connection but not using it
//That will be more efficient especially when client is holding connection but not using it
//
if (EnableConnectionPool)
if
(
EnableConnectionPool
)
//
{
{
//
await tcpConnectionFactory.Release(serverConnection);
await
tcpConnectionFactory
.
Release
(
serverConnection
);
//
serverConnection = null;
serverConnection
=
null
;
//
prefetchTask = null;
prefetchTask
=
null
;
//
}
}
}
}
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
...
@@ -294,17 +292,10 @@ namespace Titanium.Web.Proxy
...
@@ -294,17 +292,10 @@ namespace Titanium.Web.Proxy
}
}
}
}
finally
finally
{
//don't release prefetched connection here.
//it will be handled by the parent method which created it.
if
(
prefetchConnectionTask
==
null
||
serverConnection
!=
await
prefetchConnectionTask
)
{
{
await
tcpConnectionFactory
.
Release
(
serverConnection
,
await
tcpConnectionFactory
.
Release
(
serverConnection
,
closeServerConnection
);
closeServerConnection
);
}
}
}
}
}
/// <summary>
/// <summary>
...
@@ -386,54 +377,59 @@ namespace Titanium.Web.Proxy
...
@@ -386,54 +377,59 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// <summary>
///
Create a server connection.
///
Handle upgrade to websocket
/// </summary>
/// </summary>
/// <param name="args">The session event arguments.</param>
private
async
Task
handleWebSocketUpgrade
(
string
httpCmd
,
/// <param name="isConnect">Is this a CONNECT request.</param>
SessionEventArgs
args
,
Request
request
,
Response
response
,
/// <param name="applicationProtocol"></param>
CustomBufferedStream
clientStream
,
HttpResponseWriter
clientStreamWriter
,
/// <param name="cancellationToken">The cancellation token for this async task.</param>
TcpServerConnection
serverConnection
,
/// <returns></returns>
CancellationTokenSource
cancellationTokenSource
,
CancellationToken
cancellationToken
)
private
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
SslApplicationProtocol
applicationProtocol
,
CancellationToken
cancellationToken
)
{
{
List
<
SslApplicationProtocol
>
applicationProtocols
=
null
;
// prepare the prefix content
if
(
applicationProtocol
!=
default
)
await
serverConnection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
,
cancellationToken
);
await
serverConnection
.
StreamWriter
.
WriteHeadersAsync
(
request
.
Headers
,
cancellationToken
:
cancellationToken
);
string
httpStatus
;
try
{
{
applicationProtocols
=
new
List
<
SslApplicationProtocol
>
{
applicationProtocol
};
httpStatus
=
await
serverConnection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
if
(
httpStatus
==
null
)
{
throw
new
ServerConnectionException
(
"Server connection was closed."
);
}
}
return
getServerConnection
(
args
,
isConnect
,
applicationProtocols
,
cancellationToken
);
}
}
catch
(
Exception
e
)
when
(!(
e
is
ServerConnectionException
))
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocols"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private
async
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
CancellationToken
cancellationToken
)
{
{
ExternalProxy
customUpStreamProxy
=
null
;
throw
new
ServerConnectionException
(
"Server connection was closed."
,
e
);
}
bool
isHttps
=
args
.
IsHttps
;
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
if
(
GetCustomUpStreamProxyFunc
!=
null
)
out
int
responseStatusCode
,
out
string
responseStatusDescription
);
response
.
HttpVersion
=
responseVersion
;
response
.
StatusCode
=
responseStatusCode
;
response
.
StatusDescription
=
responseStatusDescription
;
await
HeaderParser
.
ReadHeaders
(
serverConnection
.
Stream
,
response
.
Headers
,
cancellationToken
);
if
(!
args
.
IsTransparent
)
{
{
customUpStreamProxy
=
await
GetCustomUpStreamProxyFunc
(
args
);
await
clientStreamWriter
.
WriteResponseAsync
(
response
,
cancellationToken
:
cancellationToken
);
}
}
args
.
CustomUpStreamProxyUsed
=
customUpStreamProxy
;
// If user requested call back then do it
if
(!
args
.
WebSession
.
Response
.
Locked
)
{
await
invokeBeforeResponse
(
args
);
}
return
await
tcpConnectionFactory
.
GetClient
(
await
TcpHelper
.
SendRaw
(
clientStream
,
serverConnection
.
Stream
,
BufferPool
,
BufferSize
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
args
.
WebSession
.
Request
.
HttpVersion
,
cancellationTokenSource
,
ExceptionFunc
);
isHttps
,
applicationProtocols
,
isConnect
,
this
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
customUpStreamProxy
??
(
isHttps
?
UpStreamHttpsProxy
:
UpStreamHttpProxy
),
cancellationToken
);
}
}
/// <summary>
/// <summary>
...
@@ -462,62 +458,93 @@ namespace Titanium.Web.Proxy
...
@@ -462,62 +458,93 @@ namespace Titanium.Web.Proxy
requestHeaders
.
FixProxyHeaders
();
requestHeaders
.
FixProxyHeaders
();
}
}
/// <summary>
/// <summary>
///
Handle upgrade to websocket
///
Gets the connection cache key.
/// </summary>
/// </summary>
private
async
Task
handleWebSocketUpgrade
(
string
httpCmd
,
/// <param name="args">The session event arguments.</param>
SessionEventArgs
args
,
Request
request
,
Response
response
,
/// <param name="isConnect">Is this a CONNECT request.</param>
CustomBufferedStream
clientStream
,
HttpResponseWriter
clientStreamWriter
,
/// <param name="applicationProtocol"></param>
TcpServerConnection
serverConnection
,
/// <returns></returns>
CancellationTokenSource
cancellationTokenSource
,
CancellationToken
cancellationToken
)
private
async
Task
<
string
>
getConnectionCacheKey
(
SessionEventArgsBase
args
,
bool
isConnect
,
{
SslApplicationProtocol
applicationProtocol
)
// prepare the prefix content
await
serverConnection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
,
cancellationToken
);
await
serverConnection
.
StreamWriter
.
WriteHeadersAsync
(
request
.
Headers
,
cancellationToken
:
cancellationToken
);
string
httpStatus
;
try
{
{
httpStatus
=
await
serverConnection
.
Stream
.
ReadLineAsync
(
cancellationToken
)
;
List
<
SslApplicationProtocol
>
applicationProtocols
=
null
;
if
(
httpStatus
==
null
)
if
(
applicationProtocol
!=
default
)
{
{
throw
new
ServerConnectionException
(
"Server connection was closed."
);
applicationProtocols
=
new
List
<
SslApplicationProtocol
>
{
applicationProtocol
};
}
}
}
catch
(
Exception
e
)
when
(!(
e
is
ServerConnectionException
))
ExternalProxy
customUpStreamProxy
=
null
;
bool
isHttps
=
args
.
IsHttps
;
if
(
GetCustomUpStreamProxyFunc
!=
null
)
{
{
throw
new
ServerConnectionException
(
"Server connection was closed."
,
e
);
customUpStreamProxy
=
await
GetCustomUpStreamProxyFunc
(
args
);
}
}
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
args
.
CustomUpStreamProxyUsed
=
customUpStreamProxy
;
out
int
responseStatusCode
,
out
string
responseStatusDescription
);
response
.
HttpVersion
=
responseVersion
;
response
.
StatusCode
=
responseStatusCode
;
response
.
StatusDescription
=
responseStatusDescription
;
await
HeaderParser
.
ReadHeaders
(
serverConnection
.
Stream
,
response
.
Headers
,
return
tcpConnectionFactory
.
GetConnectionCacheKey
(
cancellationToken
);
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
isHttps
,
applicationProtocols
,
isConnect
,
this
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
customUpStreamProxy
??
(
isHttps
?
UpStreamHttpsProxy
:
UpStreamHttpProxy
));
}
if
(!
args
.
IsTransparent
)
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocol"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
SslApplicationProtocol
applicationProtocol
,
CancellationToken
cancellationToken
)
{
{
await
clientStreamWriter
.
WriteResponseAsync
(
response
,
List
<
SslApplicationProtocol
>
applicationProtocols
=
null
;
cancellationToken
:
cancellationToken
);
if
(
applicationProtocol
!=
default
)
{
applicationProtocols
=
new
List
<
SslApplicationProtocol
>
{
applicationProtocol
};
}
}
// If user requested call back then do it
return
getServerConnection
(
args
,
isConnect
,
applicationProtocols
,
cancellationToken
);
if
(!
args
.
WebSession
.
Response
.
Locked
)
{
await
invokeBeforeResponse
(
args
);
}
}
await
TcpHelper
.
SendRaw
(
clientStream
,
serverConnection
.
Stream
,
BufferPool
,
BufferSize
,
/// <summary>
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
/// Create a server connection.
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
/// </summary>
cancellationTokenSource
,
ExceptionFunc
);
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocols"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private
async
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
CancellationToken
cancellationToken
)
{
ExternalProxy
customUpStreamProxy
=
null
;
bool
isHttps
=
args
.
IsHttps
;
if
(
GetCustomUpStreamProxyFunc
!=
null
)
{
customUpStreamProxy
=
await
GetCustomUpStreamProxyFunc
(
args
);
}
}
args
.
CustomUpStreamProxyUsed
=
customUpStreamProxy
;
return
await
tcpConnectionFactory
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
isHttps
,
applicationProtocols
,
isConnect
,
this
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
customUpStreamProxy
??
(
isHttps
?
UpStreamHttpsProxy
:
UpStreamHttpProxy
),
cancellationToken
);
}
/// <summary>
/// <summary>
/// Invoke before request handler if it is set.
/// Invoke before request handler if it is set.
...
...
Titanium.Web.Proxy/TransparentClientHandler.cs
View file @
33d50f32
...
@@ -35,6 +35,7 @@ namespace Titanium.Web.Proxy
...
@@ -35,6 +35,7 @@ namespace Titanium.Web.Proxy
Task
<
TcpServerConnection
>
prefetchConnectionTask
=
null
;
Task
<
TcpServerConnection
>
prefetchConnectionTask
=
null
;
bool
closeServerConnection
=
false
;
bool
closeServerConnection
=
false
;
bool
calledRequestHandler
=
false
;
try
try
{
{
...
@@ -127,7 +128,7 @@ namespace Titanium.Web.Proxy
...
@@ -127,7 +128,7 @@ namespace Titanium.Web.Proxy
}
}
}
}
calledRequestHandler
=
true
;
// HTTPS server created - we can now decrypt the client's traffic
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
...
@@ -155,7 +156,8 @@ namespace Titanium.Web.Proxy
...
@@ -155,7 +156,8 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
if
(
prefetchConnectionTask
!=
null
)
if
(!
calledRequestHandler
&&
prefetchConnectionTask
!=
null
)
{
{
var
connection
=
await
prefetchConnectionTask
;
var
connection
=
await
prefetchConnectionTask
;
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
...
...
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