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
02ea4aec
Unverified
Commit
02ea4aec
authored
May 15, 2018
by
justcoding121
Committed by
GitHub
May 15, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #445 from justcoding121/master
Use polly for retries
parents
17a1aabe
fc3a9308
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
152 additions
and
118 deletions
+152
-118
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+41
-27
ExplicitClientHandler.cs
Titanium.Web.Proxy/ExplicitClientHandler.cs
+24
-21
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+3
-2
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+29
-3
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+41
-54
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+1
-0
Titanium.Web.Proxy.nuspec
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
+1
-0
TransparentClientHandler.cs
Titanium.Web.Proxy/TransparentClientHandler.cs
+8
-8
packages.config
Titanium.Web.Proxy/packages.config
+1
-0
Titanium.Web.Proxy.ProxyServer.html
docs/api/Titanium.Web.Proxy.ProxyServer.html
+2
-2
index.json
docs/index.json
+1
-1
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
02ea4aec
...
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
...
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
...
@@ -14,7 +15,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -14,7 +15,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
{
public
class
ProxyTestController
public
class
ProxyTestController
{
{
private
readonly
object
lockObj
=
new
object
(
);
private
readonly
SemaphoreSlim
@lock
=
new
SemaphoreSlim
(
1
);
private
readonly
ProxyServer
proxyServer
;
private
readonly
ProxyServer
proxyServer
;
...
@@ -23,34 +24,41 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -23,34 +24,41 @@ namespace Titanium.Web.Proxy.Examples.Basic
public
ProxyTestController
()
public
ProxyTestController
()
{
{
proxyServer
=
new
ProxyServer
();
proxyServer
=
new
ProxyServer
();
//proxyServer.EnableConnectionPool = fals
e;
proxyServer
.
EnableConnectionPool
=
tru
e
;
// generate root certificate without storing it in file system
// generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
proxyServer
.
ExceptionFunc
=
exception
=>
proxyServer
.
ExceptionFunc
=
async
exception
=>
{
{
lock
(
lockObj
)
await
@lock
.
WaitAsync
();
try
{
var
color
=
Console
.
ForegroundColor
;
Console
.
ForegroundColor
=
ConsoleColor
.
Red
;
if
(
exception
is
ProxyHttpException
phex
)
{
Console
.
WriteLine
(
exception
.
Message
+
": "
+
phex
.
InnerException
?.
Message
);
}
else
{
Console
.
WriteLine
(
exception
.
Message
);
}
Console
.
ForegroundColor
=
color
;
}
finally
{
{
var
color
=
Console
.
ForegroundColor
;
@lock
.
Release
();
Console
.
ForegroundColor
=
ConsoleColor
.
Red
;
if
(
exception
is
ProxyHttpException
phex
)
{
Console
.
WriteLine
(
exception
.
Message
+
": "
+
phex
.
InnerException
?.
Message
);
}
else
{
Console
.
WriteLine
(
exception
.
Message
);
}
Console
.
ForegroundColor
=
color
;
}
}
};
};
proxyServer
.
ForwardToUpstreamGateway
=
true
;
proxyServer
.
ForwardToUpstreamGateway
=
true
;
proxyServer
.
CertificateManager
.
SaveFakeCertificates
=
true
;
proxyServer
.
CertificateManager
.
SaveFakeCertificates
=
true
;
// optionally set the Certificate Engine
// optionally set the Certificate Engine
// Under Mono or Non-Windows runtimes only BouncyCastle will be supported
// Under Mono or Non-Windows runtimes only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
...
@@ -122,7 +130,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -122,7 +130,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
Stop
();
proxyServer
.
Stop
();
// remove the generated certificates
// remove the generated certificates
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
}
}
...
@@ -130,7 +138,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -130,7 +138,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
{
{
string
hostname
=
e
.
WebSession
.
Request
.
RequestUri
.
Host
;
string
hostname
=
e
.
WebSession
.
Request
.
RequestUri
.
Host
;
WriteToConsole
(
"Tunnel to: "
+
hostname
);
await
WriteToConsole
(
"Tunnel to: "
+
hostname
);
if
(
hostname
.
Contains
(
"dropbox.com"
))
if
(
hostname
.
Contains
(
"dropbox.com"
))
{
{
...
@@ -148,8 +156,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -148,8 +156,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
// intecept & cancel redirect or update requests
// intecept & cancel redirect or update requests
private
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
private
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
WriteToConsole
(
"Active Client Connections:"
+
((
ProxyServer
)
sender
).
ClientConnectionCount
);
await
WriteToConsole
(
"Active Client Connections:"
+
((
ProxyServer
)
sender
).
ClientConnectionCount
);
WriteToConsole
(
e
.
WebSession
.
Request
.
Url
);
await
WriteToConsole
(
e
.
WebSession
.
Request
.
Url
);
// store it in the UserData property
// store it in the UserData property
// It can be a simple integer, Guid, or any type
// It can be a simple integer, Guid, or any type
...
@@ -187,19 +195,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -187,19 +195,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
}
// Modify response
// Modify response
private
void
MultipartRequestPartSent
(
object
sender
,
MultipartRequestPartSentEventArgs
e
)
private
async
Task
MultipartRequestPartSent
(
object
sender
,
MultipartRequestPartSentEventArgs
e
)
{
{
var
session
=
(
SessionEventArgs
)
sender
;
var
session
=
(
SessionEventArgs
)
sender
;
WriteToConsole
(
"Multipart form data headers:"
);
await
WriteToConsole
(
"Multipart form data headers:"
);
foreach
(
var
header
in
e
.
Headers
)
foreach
(
var
header
in
e
.
Headers
)
{
{
WriteToConsole
(
header
.
ToString
());
await
WriteToConsole
(
header
.
ToString
());
}
}
}
}
private
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
private
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
{
WriteToConsole
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
await
WriteToConsole
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsolutePath
);
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsolutePath
);
...
@@ -271,12 +279,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -271,12 +279,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
private
void
WriteToConsole
(
string
message
)
private
async
Task
WriteToConsole
(
string
message
)
{
{
lock
(
lockObj
)
await
@lock
.
WaitAsync
();
try
{
{
Console
.
WriteLine
(
message
);
Console
.
WriteLine
(
message
);
}
}
finally
{
@lock
.
Release
();
}
}
}
///// <summary>
///// <summary>
...
...
Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
02ea4aec
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
...
@@ -140,17 +141,17 @@ namespace Titanium.Web.Proxy
...
@@ -140,17 +141,17 @@ namespace Titanium.Web.Proxy
// test server HTTP/2 support
// test server HTTP/2 support
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
var
connection
=
await
getServerConnection
(
connectArgs
,
true
,
var
connection
=
await
getServerConnection
(
connectArgs
,
true
,
SslExtensions
.
Http2ProtocolAsList
,
cancellationToken
);
SslExtensions
.
Http2ProtocolAsList
,
true
,
cancellationToken
);
http2Supported
=
connection
.
NegotiatedApplicationProtocol
==
SslApplicationProtocol
.
Http2
;
http2Supported
=
connection
.
NegotiatedApplicationProtocol
==
SslApplicationProtocol
.
Http2
;
//release connection back to pool intead of closing when connection pool is enabled.
//release connection back to pool intead of closing when connection pool is enabled.
await
tcpConnectionFactory
.
Release
(
connection
);
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
}
}
SslStream
sslStream
=
null
;
SslStream
sslStream
=
null
;
prefetchConnectionTask
=
getServerConnection
(
connectArgs
,
true
,
prefetchConnectionTask
=
getServerConnection
(
connectArgs
,
true
,
null
,
cancellationToken
);
null
,
false
,
cancellationToken
);
try
try
{
{
sslStream
=
new
SslStream
(
clientStream
);
sslStream
=
new
SslStream
(
clientStream
);
...
@@ -209,8 +210,8 @@ namespace Titanium.Web.Proxy
...
@@ -209,8 +210,8 @@ namespace Titanium.Web.Proxy
// create new connection to server.
// create new connection to server.
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// this connection should not be HTTPS.
// this connection should not be HTTPS.
var
connection
=
await
getServerConnection
(
connectArgs
,
true
,
var
connection
=
await
getServerConnection
(
connectArgs
,
null
,
cancellationToken
);
true
,
SslExtensions
.
Http2ProtocolAsList
,
true
,
cancellationToken
);
try
try
{
{
...
@@ -224,10 +225,9 @@ namespace Titanium.Web.Proxy
...
@@ -224,10 +225,9 @@ namespace Titanium.Web.Proxy
try
try
{
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await
clientStream
.
ReadAsync
(
data
,
0
,
available
,
cancellationToken
);
await
clientStream
.
ReadAsync
(
data
,
0
,
available
,
cancellationToken
);
await
connection
.
StreamWriter
.
WriteAsync
(
data
,
0
,
available
,
true
,
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
cancellationToken
);
await
connection
.
StreamWriter
.
WriteAsync
(
data
,
0
,
available
,
true
,
cancellationToken
);
}
}
finally
finally
{
{
...
@@ -235,8 +235,7 @@ namespace Titanium.Web.Proxy
...
@@ -235,8 +235,7 @@ namespace Titanium.Web.Proxy
}
}
}
}
var
serverHelloInfo
=
var
serverHelloInfo
=
await
SslTools
.
PeekServerHello
(
connection
.
Stream
,
BufferPool
,
cancellationToken
);
await
SslTools
.
PeekServerHello
(
connection
.
Stream
,
BufferPool
,
cancellationToken
);
((
ConnectResponse
)
connectArgs
.
WebSession
.
Response
).
ServerHelloInfo
=
serverHelloInfo
;
((
ConnectResponse
)
connectArgs
.
WebSession
.
Response
).
ServerHelloInfo
=
serverHelloInfo
;
}
}
...
@@ -244,11 +243,14 @@ namespace Titanium.Web.Proxy
...
@@ -244,11 +243,14 @@ namespace Titanium.Web.Proxy
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
connectArgs
.
CancellationTokenSource
,
ExceptionFunc
);
connectArgs
.
CancellationTokenSource
,
ExceptionFunc
);
}
}
finally
finally
{
{
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
}
}
calledRequestHandler
=
true
;
return
;
return
;
}
}
}
}
...
@@ -278,22 +280,22 @@ namespace Titanium.Web.Proxy
...
@@ -278,22 +280,22 @@ namespace Titanium.Web.Proxy
throw
new
Exception
(
$"HTTP/2 Protocol violation. Empty string expected, '
{
line
}
' received"
);
throw
new
Exception
(
$"HTTP/2 Protocol violation. Empty string expected, '
{
line
}
' received"
);
}
}
// create new connection
var
connection
=
await
getServerConnection
(
connectArgs
,
true
,
var
connection
=
await
getServerConnection
(
connectArgs
,
true
,
SslExtensions
.
Http2ProtocolAsList
,
SslExtensions
.
Http2ProtocolAsList
,
true
,
cancellationToken
);
cancellationToken
);
try
try
{
{
await
connection
.
StreamWriter
.
WriteLineAsync
(
"PRI * HTTP/2.0"
,
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
"PRI * HTTP/2.0"
,
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
"SM"
,
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
"SM"
,
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
cancellationToken
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
cancellationToken
);
#if NETCOREAPP2_1
#if NETCOREAPP2_1
await
Http2Helper
.
SendHttp2
(
clientStream
,
connection
.
Stream
,
BufferSize
,
await
Http2Helper
.
SendHttp2
(
clientStream
,
connection
.
Stream
,
BufferSize
,
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
connectArgs
.
CancellationTokenSource
,
clientConnection
.
Id
,
ExceptionFunc
);
connectArgs
.
CancellationTokenSource
,
clientConnection
.
Id
,
ExceptionFunc
);
#endif
#endif
}
}
finally
finally
{
{
...
@@ -301,6 +303,7 @@ namespace Titanium.Web.Proxy
...
@@ -301,6 +303,7 @@ namespace Titanium.Web.Proxy
}
}
}
}
}
}
calledRequestHandler
=
true
;
calledRequestHandler
=
true
;
// Now create the request
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
...
@@ -328,19 +331,19 @@ namespace Titanium.Web.Proxy
...
@@ -328,19 +331,19 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
if
(!
calledRequestHandler
&&
prefetchConnectionTask
!=
null
)
{
var
connection
=
await
prefetchConnectionTask
;
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
}
clientStream
.
Dispose
();
clientStream
.
Dispose
();
if
(!
cancellationTokenSource
.
IsCancellationRequested
)
if
(!
cancellationTokenSource
.
IsCancellationRequested
)
{
{
cancellationTokenSource
.
Cancel
();
cancellationTokenSource
.
Cancel
();
}
}
if
(!
calledRequestHandler
&&
prefetchConnectionTask
!=
null
)
{
var
connection
=
await
prefetchConnectionTask
;
await
tcpConnectionFactory
.
Release
(
connection
,
closeServerConnection
);
}
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
02ea4aec
...
@@ -81,18 +81,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -81,18 +81,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="noCache">Not from cache/create new connection.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
/// <returns></returns>
internal
async
Task
<
TcpServerConnection
>
GetClient
(
string
remoteHostName
,
int
remotePort
,
internal
async
Task
<
TcpServerConnection
>
GetClient
(
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
bool
isConnect
,
Version
httpVersion
,
bool
isHttps
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
bool
isConnect
,
ProxyServer
proxyServer
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
ProxyServer
proxyServer
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
CancellationToken
cancellationToken
)
bool
noCache
,
CancellationToken
cancellationToken
)
{
{
var
cacheKey
=
GetConnectionCacheKey
(
remoteHostName
,
remotePort
,
var
cacheKey
=
GetConnectionCacheKey
(
remoteHostName
,
remotePort
,
isHttps
,
applicationProtocols
,
isHttps
,
applicationProtocols
,
proxyServer
,
upStreamEndPoint
,
externalProxy
);
proxyServer
,
upStreamEndPoint
,
externalProxy
);
if
(
proxyServer
.
EnableConnectionPool
)
if
(
proxyServer
.
EnableConnectionPool
&&
!
noCache
)
{
{
if
(
cache
.
TryGetValue
(
cacheKey
,
out
var
existingConnections
))
if
(
cache
.
TryGetValue
(
cacheKey
,
out
var
existingConnections
))
{
{
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
02ea4aec
...
@@ -7,6 +7,7 @@ using System.Security.Authentication;
...
@@ -7,6 +7,7 @@ using System.Security.Authentication;
using
System.Security.Cryptography.X509Certificates
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Polly
;
using
StreamExtended
;
using
StreamExtended
;
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
...
@@ -123,6 +124,9 @@ namespace Titanium.Web.Proxy
...
@@ -123,6 +124,9 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
//Number of exception retries when connection pool is enabled.
private
int
retries
=>
EnableConnectionPool
?
MaxCachedConnections
+
1
:
0
;
/// <summary>
/// <summary>
/// Is the proxy currently running?
/// Is the proxy currently running?
/// </summary>
/// </summary>
...
@@ -197,7 +201,7 @@ namespace Titanium.Web.Proxy
...
@@ -197,7 +201,7 @@ namespace Titanium.Web.Proxy
/// Realm used during Proxy Basic Authentication.
/// Realm used during Proxy Basic Authentication.
/// </summary>
/// </summary>
public
string
ProxyRealm
{
get
;
set
;
}
=
"TitaniumProxy"
;
public
string
ProxyRealm
{
get
;
set
;
}
=
"TitaniumProxy"
;
/// <summary>
/// <summary>
/// List of supported Ssl versions.
/// List of supported Ssl versions.
/// </summary>
/// </summary>
...
@@ -252,7 +256,8 @@ namespace Titanium.Web.Proxy
...
@@ -252,7 +256,8 @@ namespace Titanium.Web.Proxy
public
ExceptionHandler
ExceptionFunc
public
ExceptionHandler
ExceptionFunc
{
{
get
=>
exceptionFunc
??
defaultExceptionFunc
;
get
=>
exceptionFunc
??
defaultExceptionFunc
;
set
{
set
{
exceptionFunc
=
value
;
exceptionFunc
=
value
;
CertificateManager
.
ExceptionFunc
=
value
;
CertificateManager
.
ExceptionFunc
=
value
;
}
}
...
@@ -274,7 +279,7 @@ namespace Titanium.Web.Proxy
...
@@ -274,7 +279,7 @@ namespace Titanium.Web.Proxy
{
{
Stop
();
Stop
();
}
}
CertificateManager
?.
Dispose
();
CertificateManager
?.
Dispose
();
BufferPool
?.
Dispose
();
BufferPool
?.
Dispose
();
}
}
...
@@ -800,5 +805,26 @@ namespace Titanium.Web.Proxy
...
@@ -800,5 +805,26 @@ namespace Titanium.Web.Proxy
await
OnServerConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
await
OnServerConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
}
}
}
}
/// <summary>
/// Connection retry policy when using connection pool.
/// </summary>
private
Policy
retryPolicy
<
T
>()
where
T
:
Exception
{
return
Policy
.
Handle
<
T
>()
.
RetryAsync
(
retries
,
onRetryAsync
:
async
(
ex
,
i
,
context
)
=>
{
if
(
context
.
ContainsKey
(
"connection"
))
{
//close connection on error
var
connection
=
(
TcpServerConnection
)
context
[
"connection"
];
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
context
.
Remove
(
"connection"
);
}
});
}
}
}
}
}
Titanium.Web.Proxy/RequestHandler.cs
View file @
02ea4aec
...
@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy
...
@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy
var
cancellationToken
=
cancellationTokenSource
.
Token
;
var
cancellationToken
=
cancellationTokenSource
.
Token
;
var
prefetchTask
=
prefetchConnectionTask
;
var
prefetchTask
=
prefetchConnectionTask
;
TcpServerConnection
serverC
onnection
=
null
;
TcpServerConnection
c
onnection
=
null
;
bool
closeServerConnection
=
false
;
bool
closeServerConnection
=
false
;
try
try
...
@@ -186,70 +186,57 @@ namespace Titanium.Web.Proxy
...
@@ -186,70 +186,57 @@ namespace Titanium.Web.Proxy
}
}
//If prefetch task is available.
//If prefetch task is available.
if
(
serverC
onnection
==
null
&&
prefetchTask
!=
null
)
if
(
c
onnection
==
null
&&
prefetchTask
!=
null
)
{
{
serverC
onnection
=
await
prefetchTask
;
c
onnection
=
await
prefetchTask
;
prefetchTask
=
null
;
prefetchTask
=
null
;
}
}
// create a new connection if cache key changes.
// create a new connection if cache key changes.
// only gets hit when connection pool is disabled.
// only gets hit when connection pool is disabled.
// or when prefetch task has a unexpectedly different connection.
// or when prefetch task has a unexpectedly different connection.
if
(
serverC
onnection
!=
null
if
(
c
onnection
!=
null
&&
(
await
getConnectionCacheKey
(
args
,
&&
(
await
getConnectionCacheKey
(
args
,
clientConnection
.
NegotiatedApplicationProtocol
)
clientConnection
.
NegotiatedApplicationProtocol
)
!=
serverC
onnection
.
CacheKey
))
!=
c
onnection
.
CacheKey
))
{
{
await
tcpConnectionFactory
.
Release
(
serverC
onnection
);
await
tcpConnectionFactory
.
Release
(
c
onnection
);
serverC
onnection
=
null
;
c
onnection
=
null
;
}
}
//create
var
contextData
=
new
Dictionary
<
string
,
object
>();
if
(
serverConnection
=
=
null
)
if
(
connection
!
=
null
)
{
{
serverConnection
=
await
getServerConnection
(
args
,
false
,
contextData
.
Add
(
"connection"
,
connection
);
clientConnection
.
NegotiatedApplicationProtocol
,
cancellationToken
);
}
}
//for connection pool retry fails until cache is exhausted
//for connection pool retry fails until cache is exhausted
int
attempt
=
0
;
await
retryPolicy
<
ServerConnectionException
>().
ExecuteAsync
(
async
(
context
)
=>
while
(
attempt
<
MaxCachedConnections
+
1
)
{
{
try
{
connection
=
context
.
ContainsKey
(
"connection"
)?
// if upgrading to websocket then relay the request without reading the contents
(
TcpServerConnection
)
context
[
"connection"
]
if
(
request
.
UpgradeToWebSocket
)
:
await
getServerConnection
(
args
,
false
,
{
clientConnection
.
NegotiatedApplicationProtocol
,
await
handleWebSocketUpgrade
(
httpCmd
,
args
,
request
,
false
,
cancellationToken
);
response
,
clientStream
,
clientStreamWriter
,
serverConnection
,
cancellationTokenSource
,
cancellationToken
);
context
[
"connection"
]
=
connection
;
closeServerConnection
=
true
;
return
;
// if upgrading to websocket then relay the request without reading the contents
}
if
(
request
.
UpgradeToWebSocket
)
// construct the web request that we are going to issue on behalf of the client.
await
handleHttpSessionRequestInternal
(
serverConnection
,
args
);
}
//connection pool retry
catch
(
ServerConnectionException
)
{
{
attempt
++;
await
handleWebSocketUpgrade
(
httpCmd
,
args
,
request
,
if
(!
EnableConnectionPool
||
attempt
==
MaxCachedConnections
+
1
)
response
,
clientStream
,
clientStreamWriter
,
{
connection
,
cancellationTokenSource
,
cancellationToken
);
throw
;
closeServerConnection
=
true
;
}
return
;
//get new connection from pool
await
tcpConnectionFactory
.
Release
(
serverConnection
,
true
);
serverConnection
=
null
;
serverConnection
=
await
getServerConnection
(
args
,
false
,
clientConnection
.
NegotiatedApplicationProtocol
,
cancellationToken
);
continue
;
}
}
break
;
// construct the web request that we are going to issue on behalf of the client.
}
await
handleHttpSessionRequestInternal
(
connection
,
args
);
},
contextData
);
//user requested
//user requested
if
(
args
.
WebSession
.
CloseServerConnection
)
if
(
args
.
WebSession
.
CloseServerConnection
)
...
@@ -275,8 +262,8 @@ namespace Titanium.Web.Proxy
...
@@ -275,8 +262,8 @@ namespace Titanium.Web.Proxy
//between sessions without using it.
//between sessions without using it.
if
(
EnableConnectionPool
)
if
(
EnableConnectionPool
)
{
{
await
tcpConnectionFactory
.
Release
(
serverC
onnection
);
await
tcpConnectionFactory
.
Release
(
c
onnection
);
serverConnection
=
null
;
connection
=
null
;
}
}
}
}
...
@@ -300,10 +287,10 @@ namespace Titanium.Web.Proxy
...
@@ -300,10 +287,10 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
await
tcpConnectionFactory
.
Release
(
serverC
onnection
,
await
tcpConnectionFactory
.
Release
(
c
onnection
,
closeServerConnection
);
closeServerConnection
);
if
(
prefetchTask
!=
null
)
if
(
prefetchTask
!=
null
)
{
{
await
tcpConnectionFactory
.
Release
(
await
prefetchTask
,
await
tcpConnectionFactory
.
Release
(
await
prefetchTask
,
closeServerConnection
);
closeServerConnection
);
...
@@ -515,7 +502,7 @@ namespace Titanium.Web.Proxy
...
@@ -515,7 +502,7 @@ namespace Titanium.Web.Proxy
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
/// <returns></returns>
private
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
private
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
SslApplicationProtocol
applicationProtocol
,
CancellationToken
cancellationToken
)
SslApplicationProtocol
applicationProtocol
,
bool
noCache
,
CancellationToken
cancellationToken
)
{
{
List
<
SslApplicationProtocol
>
applicationProtocols
=
null
;
List
<
SslApplicationProtocol
>
applicationProtocols
=
null
;
if
(
applicationProtocol
!=
default
)
if
(
applicationProtocol
!=
default
)
...
@@ -523,7 +510,7 @@ namespace Titanium.Web.Proxy
...
@@ -523,7 +510,7 @@ namespace Titanium.Web.Proxy
applicationProtocols
=
new
List
<
SslApplicationProtocol
>
{
applicationProtocol
};
applicationProtocols
=
new
List
<
SslApplicationProtocol
>
{
applicationProtocol
};
}
}
return
getServerConnection
(
args
,
isConnect
,
applicationProtocols
,
cancellationToken
);
return
getServerConnection
(
args
,
isConnect
,
applicationProtocols
,
noCache
,
cancellationToken
);
}
}
/// <summary>
/// <summary>
...
@@ -535,7 +522,7 @@ namespace Titanium.Web.Proxy
...
@@ -535,7 +522,7 @@ namespace Titanium.Web.Proxy
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
private
async
Task
<
TcpServerConnection
>
getServerConnection
(
SessionEventArgsBase
args
,
bool
isConnect
,
List
<
SslApplicationProtocol
>
applicationProtocols
,
CancellationToken
cancellationToken
)
List
<
SslApplicationProtocol
>
applicationProtocols
,
bool
noCache
,
CancellationToken
cancellationToken
)
{
{
ExternalProxy
customUpStreamProxy
=
null
;
ExternalProxy
customUpStreamProxy
=
null
;
...
@@ -554,7 +541,7 @@ namespace Titanium.Web.Proxy
...
@@ -554,7 +541,7 @@ namespace Titanium.Web.Proxy
isHttps
,
applicationProtocols
,
isConnect
,
isHttps
,
applicationProtocols
,
isConnect
,
this
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
this
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
customUpStreamProxy
??
(
isHttps
?
UpStreamHttpsProxy
:
UpStreamHttpProxy
),
customUpStreamProxy
??
(
isHttps
?
UpStreamHttpsProxy
:
UpStreamHttpProxy
),
cancellationToken
);
noCache
,
cancellationToken
);
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
02ea4aec
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
</PropertyGroup>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<PackageReference Include="Polly" Version="6.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="StreamExtended" Version="1.0.175-beta" />
<PackageReference Include="StreamExtended" Version="1.0.175-beta" />
</ItemGroup>
</ItemGroup>
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
View file @
02ea4aec
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
<dependencies>
<dependencies>
<dependency
id=
"StreamExtended"
version=
"1.0.175-beta"
/>
<dependency
id=
"StreamExtended"
version=
"1.0.175-beta"
/>
<dependency
id=
"Portable.BouncyCastle"
version=
"1.8.2"
/>
<dependency
id=
"Portable.BouncyCastle"
version=
"1.8.2"
/>
<dependency
id=
"Polly"
version=
"6.0.1"
/>
</dependencies>
</dependencies>
</metadata>
</metadata>
<files>
<files>
...
...
Titanium.Web.Proxy/TransparentClientHandler.cs
View file @
02ea4aec
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
...
@@ -63,8 +64,8 @@ namespace Titanium.Web.Proxy
...
@@ -63,8 +64,8 @@ namespace Titanium.Web.Proxy
if
(
endPoint
.
DecryptSsl
&&
args
.
DecryptSsl
)
if
(
endPoint
.
DecryptSsl
&&
args
.
DecryptSsl
)
{
{
prefetchConnectionTask
=
tcpConnectionFactory
.
GetClient
(
httpsHostName
,
endPoint
.
Port
,
prefetchConnectionTask
=
tcpConnectionFactory
.
GetClient
(
httpsHostName
,
endPoint
.
Port
,
null
,
true
,
null
,
null
,
true
,
null
,
false
,
this
,
false
,
this
,
UpStreamEndPoint
,
UpStreamHttpsProxy
,
cancellationToken
);
UpStreamEndPoint
,
UpStreamHttpsProxy
,
false
,
cancellationToken
);
SslStream
sslStream
=
null
;
SslStream
sslStream
=
null
;
...
@@ -93,25 +94,24 @@ namespace Titanium.Web.Proxy
...
@@ -93,25 +94,24 @@ namespace Titanium.Web.Proxy
}
}
else
else
{
{
// create new connection
var
connection
=
await
tcpConnectionFactory
.
GetClient
(
httpsHostName
,
endPoint
.
Port
,
var
connection
=
await
tcpConnectionFactory
.
GetClient
(
httpsHostName
,
endPoint
.
Port
,
null
,
false
,
null
,
null
,
false
,
null
,
true
,
this
,
UpStreamEndPoint
,
UpStreamHttpsProxy
,
cancellationToken
);
true
,
this
,
UpStreamEndPoint
,
UpStreamHttpsProxy
,
true
,
cancellationToken
);
try
try
{
{
var
serverStream
=
connection
.
Stream
;
CustomBufferedStream
serverStream
=
null
;
int
available
=
clientStream
.
Available
;
int
available
=
clientStream
.
Available
;
if
(
available
>
0
)
if
(
available
>
0
)
{
{
// send the buffered data
// send the buffered data
var
data
=
BufferPool
.
GetBuffer
(
BufferSize
);
var
data
=
BufferPool
.
GetBuffer
(
BufferSize
);
try
try
{
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await
clientStream
.
ReadAsync
(
data
,
0
,
available
,
cancellationToken
);
await
clientStream
.
ReadAsync
(
data
,
0
,
available
,
cancellationToken
);
serverStream
=
connection
.
Stream
;
await
serverStream
.
WriteAsync
(
data
,
0
,
available
,
cancellationToken
);
await
serverStream
.
WriteAsync
(
data
,
0
,
available
,
cancellationToken
);
await
serverStream
.
FlushAsync
(
cancellationToken
);
await
serverStream
.
FlushAsync
(
cancellationToken
);
}
}
...
...
Titanium.Web.Proxy/packages.config
View file @
02ea4aec
...
@@ -3,4 +3,5 @@
...
@@ -3,4 +3,5 @@
<
packages
>
<
packages
>
<
package
id
=
"Portable.BouncyCastle"
version
=
"1.8.2"
targetFramework
=
"net45"
/>
<
package
id
=
"Portable.BouncyCastle"
version
=
"1.8.2"
targetFramework
=
"net45"
/>
<
package
id
=
"StreamExtended"
version
=
"1.0.175-beta"
targetFramework
=
"net45"
/>
<
package
id
=
"StreamExtended"
version
=
"1.0.175-beta"
targetFramework
=
"net45"
/>
<
package
id
=
"Polly"
version
=
"6.0.1"
targetFramework
=
"net45"
/>
</
packages
>
</
packages
>
\ No newline at end of file
docs/api/Titanium.Web.Proxy.ProxyServer.html
View file @
02ea4aec
...
@@ -450,8 +450,8 @@ Defaults to false.</p>
...
@@ -450,8 +450,8 @@ Defaults to false.</p>
<a
id=
"Titanium_Web_Proxy_ProxyServer_EnableConnectionPool_"
data-uid=
"Titanium.Web.Proxy.ProxyServer.EnableConnectionPool*"
></a>
<a
id=
"Titanium_Web_Proxy_ProxyServer_EnableConnectionPool_"
data-uid=
"Titanium.Web.Proxy.ProxyServer.EnableConnectionPool*"
></a>
<h4
id=
"Titanium_Web_Proxy_ProxyServer_EnableConnectionPool"
data-uid=
"Titanium.Web.Proxy.ProxyServer.EnableConnectionPool"
>
EnableConnectionPool
</h4>
<h4
id=
"Titanium_Web_Proxy_ProxyServer_EnableConnectionPool"
data-uid=
"Titanium.Web.Proxy.ProxyServer.EnableConnectionPool"
>
EnableConnectionPool
</h4>
<div
class=
"markdown level1 summary"
><p>
Should we enable server connection pool?
<div
class=
"markdown level1 summary"
><p>
Should we enable
experimental
server connection pool?
Defaults to
tru
e.
</p>
Defaults to
disabl
e.
</p>
</div>
</div>
<div
class=
"markdown level1 conceptual"
></div>
<div
class=
"markdown level1 conceptual"
></div>
<h5
class=
"decalaration"
>
Declaration
</h5>
<h5
class=
"decalaration"
>
Declaration
</h5>
...
...
docs/index.json
View file @
02ea4aec
This diff is collapsed.
Click to expand it.
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