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
58ec1bb3
Commit
58ec1bb3
authored
Jul 18, 2017
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix server connection count; fix UpstreamEndPoint
parent
494b0e6f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
892 additions
and
911 deletions
+892
-911
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+0
-28
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+1
-1
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+871
-868
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+20
-14
No files found.
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
58ec1bb3
...
@@ -5,34 +5,6 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -5,34 +5,6 @@ namespace Titanium.Web.Proxy.Extensions
{
{
internal
static
class
TcpExtensions
internal
static
class
TcpExtensions
{
{
/// <summary>
/// verifies if the underlying socket is connected before using a TcpClient connection
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
internal
static
bool
IsConnected
(
this
Socket
client
)
{
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
client
.
Blocking
;
try
{
var
tmp
=
new
byte
[
1
];
client
.
Blocking
=
false
;
client
.
Send
(
tmp
,
0
,
0
);
return
true
;
}
catch
(
SocketException
e
)
{
// 10035 == WSAEWOULDBLOCK
return
e
.
SocketErrorCode
==
SocketError
.
WouldBlock
;
}
finally
{
client
.
Blocking
=
blockingState
;
}
}
#if NET45
#if NET45
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
58ec1bb3
...
@@ -58,7 +58,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -58,7 +58,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
client
=
new
TcpClient
(
upStreamEndPoint
);
client
=
new
TcpClient
(
upStreamEndPoint
);
#else
#else
client
=
new
TcpClient
();
client
=
new
TcpClient
();
client
.
Client
.
Bind
(
server
.
U
pStreamEndPoint
);
client
.
Client
.
Bind
(
u
pStreamEndPoint
);
#endif
#endif
//If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
//If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
58ec1bb3
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Security.Authentication
;
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
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
#if NET45
#if NET45
using
Titanium.Web.Proxy.Helpers.WinHttp
;
using
Titanium.Web.Proxy.Helpers.WinHttp
;
#endif
#endif
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.Tcp
;
#if NET45
#if NET45
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
using
Titanium.Web.Proxy.Network.WinAuth.Security
;
#endif
#endif
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
/// <summary>
/// <summary>
/// Proxy Server Main class
/// Proxy Server Main class
/// </summary>
/// </summary>
public
partial
class
ProxyServer
:
IDisposable
public
partial
class
ProxyServer
:
IDisposable
{
{
#if NET45
#if NET45
internal
static
readonly
string
UriSchemeHttp
=
Uri
.
UriSchemeHttp
;
internal
static
readonly
string
UriSchemeHttp
=
Uri
.
UriSchemeHttp
;
internal
static
readonly
string
UriSchemeHttps
=
Uri
.
UriSchemeHttps
;
internal
static
readonly
string
UriSchemeHttps
=
Uri
.
UriSchemeHttps
;
#else
#else
internal
const
string
UriSchemeHttp
=
"http"
;
internal
const
string
UriSchemeHttp
=
"http"
;
internal
const
string
UriSchemeHttps
=
"https"
;
internal
const
string
UriSchemeHttps
=
"https"
;
#endif
#endif
/// <summary>
/// <summary>
/// Is the proxy currently running
/// Is the proxy currently running
/// </summary>
/// </summary>
private
bool
proxyRunning
{
get
;
set
;
}
private
bool
proxyRunning
{
get
;
set
;
}
/// <summary>
/// <summary>
/// An default exception log func
/// An default exception log func
/// </summary>
/// </summary>
private
readonly
Lazy
<
Action
<
Exception
>>
defaultExceptionFunc
=
new
Lazy
<
Action
<
Exception
>>(()
=>
(
e
=>
{
}));
private
readonly
Lazy
<
Action
<
Exception
>>
defaultExceptionFunc
=
new
Lazy
<
Action
<
Exception
>>(()
=>
(
e
=>
{
}));
/// <summary>
/// <summary>
/// backing exception func for exposed public property
/// backing exception func for exposed public property
/// </summary>
/// </summary>
private
Action
<
Exception
>
exceptionFunc
;
private
Action
<
Exception
>
exceptionFunc
;
/// <summary>
/// <summary>
/// Backing field for corresponding public property
/// Backing field for corresponding public property
/// </summary>
/// </summary>
private
bool
trustRootCertificate
;
private
bool
trustRootCertificate
;
/// <summary>
/// <summary>
/// Backing field for corresponding public property
/// Backing field for corresponding public property
/// </summary>
/// </summary>
private
int
clientConnectionCount
;
private
int
clientConnectionCount
;
/// <summary>
/// <summary>
/// Backing field for corresponding public property
/// Backing field for corresponding public property
/// </summary>
/// </summary>
private
int
serverConnectionCount
;
private
int
serverConnectionCount
;
/// <summary>
/// <summary>
/// A object that creates tcp connection to server
/// A object that creates tcp connection to server
/// </summary>
/// </summary>
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
}
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
}
#if NET45
#if NET45
private
WinHttpWebProxyFinder
systemProxyResolver
;
private
WinHttpWebProxyFinder
systemProxyResolver
;
/// <summary>
/// <summary>
/// Manage system proxy settings
/// Manage system proxy settings
/// </summary>
/// </summary>
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
/// <summary>
/// <summary>
/// Set firefox to use default system proxy
/// Set firefox to use default system proxy
/// </summary>
/// </summary>
private
readonly
FireFoxProxySettingsManager
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
private
readonly
FireFoxProxySettingsManager
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
#endif
#endif
/// <summary>
/// <summary>
/// Buffer size used throughout this proxy
/// Buffer size used throughout this proxy
/// </summary>
/// </summary>
public
int
BufferSize
{
get
;
set
;
}
=
8192
;
public
int
BufferSize
{
get
;
set
;
}
=
8192
;
/// <summary>
/// <summary>
/// Manages certificates used by this proxy
/// Manages certificates used by this proxy
/// </summary>
/// </summary>
public
CertificateManager
CertificateManager
{
get
;
}
public
CertificateManager
CertificateManager
{
get
;
}
/// <summary>
/// <summary>
/// The root certificate
/// The root certificate
/// </summary>
/// </summary>
public
X509Certificate2
RootCertificate
public
X509Certificate2
RootCertificate
{
{
get
{
return
CertificateManager
.
RootCertificate
;
}
get
{
return
CertificateManager
.
RootCertificate
;
}
set
{
CertificateManager
.
RootCertificate
=
value
;
}
set
{
CertificateManager
.
RootCertificate
=
value
;
}
}
}
/// <summary>
/// <summary>
/// Name of the root certificate issuer
/// Name of the root certificate issuer
/// (This is valid only when RootCertificate property is not set)
/// (This is valid only when RootCertificate property is not set)
/// </summary>
/// </summary>
public
string
RootCertificateIssuerName
public
string
RootCertificateIssuerName
{
{
get
{
return
CertificateManager
.
Issuer
;
}
get
{
return
CertificateManager
.
Issuer
;
}
set
{
CertificateManager
.
Issuer
=
value
;
}
set
{
CertificateManager
.
Issuer
=
value
;
}
}
}
/// <summary>
/// <summary>
/// Name of the root certificate
/// Name of the root certificate
/// (This is valid only when RootCertificate property is not set)
/// (This is valid only when RootCertificate property is not set)
/// If no certificate is provided then a default Root Certificate will be created and used
/// If no certificate is provided then a default Root Certificate will be created and used
/// The provided root certificate will be stored in proxy exe directory with the private key
/// The provided root certificate will be stored in proxy exe directory with the private key
/// Root certificate file will be named as "rootCert.pfx"
/// Root certificate file will be named as "rootCert.pfx"
/// </summary>
/// </summary>
public
string
RootCertificateName
public
string
RootCertificateName
{
{
get
{
return
CertificateManager
.
RootCertificateName
;
}
get
{
return
CertificateManager
.
RootCertificateName
;
}
set
{
CertificateManager
.
RootCertificateName
=
value
;
}
set
{
CertificateManager
.
RootCertificateName
=
value
;
}
}
}
/// <summary>
/// <summary>
/// Trust the RootCertificate used by this proxy server
/// Trust the RootCertificate used by this proxy server
/// Note that this do not make the client trust the certificate!
/// Note that this do not make the client trust the certificate!
/// This would import the root certificate to the certificate store of machine that runs this proxy server
/// This would import the root certificate to the certificate store of machine that runs this proxy server
/// </summary>
/// </summary>
public
bool
TrustRootCertificate
public
bool
TrustRootCertificate
{
{
get
{
return
trustRootCertificate
;
}
get
{
return
trustRootCertificate
;
}
set
set
{
{
trustRootCertificate
=
value
;
trustRootCertificate
=
value
;
if
(
value
)
if
(
value
)
{
{
EnsureRootCertificate
();
EnsureRootCertificate
();
}
}
}
}
}
}
/// <summary>
/// <summary>
/// Select Certificate Engine
/// Select Certificate Engine
/// Optionally set to BouncyCastle
/// Optionally set to BouncyCastle
/// Mono only support BouncyCastle and it is the default
/// Mono only support BouncyCastle and it is the default
/// </summary>
/// </summary>
public
CertificateEngine
CertificateEngine
public
CertificateEngine
CertificateEngine
{
{
get
{
return
CertificateManager
.
Engine
;
}
get
{
return
CertificateManager
.
Engine
;
}
set
{
CertificateManager
.
Engine
=
value
;
}
set
{
CertificateManager
.
Engine
=
value
;
}
}
}
/// <summary>
/// <summary>
/// Should we check for certificare revocation during SSL authentication to servers
/// Should we check for certificare revocation during SSL authentication to servers
/// Note: If enabled can reduce performance (Default disabled)
/// Note: If enabled can reduce performance (Default disabled)
/// </summary>
/// </summary>
public
bool
CheckCertificateRevocation
{
get
;
set
;
}
public
bool
CheckCertificateRevocation
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 contunue implementations on server/client may cause problems if enabled
/// Broken 100 contunue implementations on server/client may cause problems if enabled
/// </summary>
/// </summary>
public
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
public
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Minutes certificates should be kept in cache when not used
/// Minutes certificates should be kept in cache when not used
/// </summary>
/// </summary>
public
int
CertificateCacheTimeOutMinutes
{
get
;
set
;
}
public
int
CertificateCacheTimeOutMinutes
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Seconds client/server connection are to be kept alive when waiting for read/write to complete
/// Seconds client/server connection are to be kept alive when waiting for read/write to complete
/// </summary>
/// </summary>
public
int
ConnectionTimeOutSeconds
{
get
;
set
;
}
public
int
ConnectionTimeOutSeconds
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Intercept request to server
/// Intercept request to server
/// </summary>
/// </summary>
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
/// <summary>
/// <summary>
/// Intercept response from server
/// Intercept response from server
/// </summary>
/// </summary>
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeResponse
;
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeResponse
;
/// <summary>
/// <summary>
/// Intercept tunnel connect reques
/// Intercept tunnel connect reques
/// </summary>
/// </summary>
public
event
Func
<
object
,
TunnelConnectSessionEventArgs
,
Task
>
TunnelConnectRequest
;
public
event
Func
<
object
,
TunnelConnectSessionEventArgs
,
Task
>
TunnelConnectRequest
;
/// <summary>
/// <summary>
/// Intercept tunnel connect response
/// Intercept tunnel connect response
/// </summary>
/// </summary>
public
event
Func
<
object
,
TunnelConnectSessionEventArgs
,
Task
>
TunnelConnectResponse
;
public
event
Func
<
object
,
TunnelConnectSessionEventArgs
,
Task
>
TunnelConnectResponse
;
/// <summary>
/// <summary>
/// Occurs when client connection count changed.
/// Occurs when client connection count changed.
/// </summary>
/// </summary>
public
event
EventHandler
ClientConnectionCountChanged
;
public
event
EventHandler
ClientConnectionCountChanged
;
/// <summary>
/// <summary>
/// Occurs when server connection count changed.
/// Occurs when server connection count changed.
/// </summary>
/// </summary>
public
event
EventHandler
ServerConnectionCountChanged
;
public
event
EventHandler
ServerConnectionCountChanged
;
/// <summary>
/// <summary>
/// External proxy for Http
/// External proxy for Http
/// </summary>
/// </summary>
public
ExternalProxy
UpStreamHttpProxy
{
get
;
set
;
}
public
ExternalProxy
UpStreamHttpProxy
{
get
;
set
;
}
/// <summary>
/// <summary>
/// External proxy for Http
/// External proxy for Http
/// </summary>
/// </summary>
public
ExternalProxy
UpStreamHttpsProxy
{
get
;
set
;
}
public
ExternalProxy
UpStreamHttpsProxy
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Local adapter/NIC endpoint (where proxy makes request via)
/// Local adapter/NIC endpoint (where proxy makes request via)
/// default via any IP addresses of this machine
/// default via any IP addresses of this machine
/// </summary>
/// </summary>
public
IPEndPoint
UpStreamEndPoint
{
get
;
set
;
}
=
new
IPEndPoint
(
IPAddress
.
Any
,
0
);
public
IPEndPoint
UpStreamEndPoint
{
get
;
set
;
}
=
new
IPEndPoint
(
IPAddress
.
Any
,
0
);
/// <summary>
/// <summary>
/// Is the proxy currently running
/// Is the proxy currently running
/// </summary>
/// </summary>
public
bool
ProxyRunning
=>
proxyRunning
;
public
bool
ProxyRunning
=>
proxyRunning
;
/// <summary>
/// <summary>
/// Gets or sets a value indicating whether requests will be chained to upstream gateway.
/// Gets or sets a value indicating whether requests will be chained to upstream gateway.
/// </summary>
/// </summary>
public
bool
ForwardToUpstreamGateway
{
get
;
set
;
}
public
bool
ForwardToUpstreamGateway
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Enable disable Windows Authentication (NTLM/Kerberos)
/// Enable disable Windows Authentication (NTLM/Kerberos)
/// Note: NTLM/Kerberos will always send local credentials of current user
/// Note: NTLM/Kerberos will always send local credentials of current user
/// who is running the proxy process. This is because a man
/// who is running the proxy process. This is because a man
/// in middle attack is not currently supported
/// in middle attack is not currently supported
/// (which would require windows delegation enabled for this server process)
/// (which would require windows delegation enabled for this server process)
/// </summary>
/// </summary>
public
bool
EnableWinAuth
{
get
;
set
;
}
public
bool
EnableWinAuth
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// </summary>
/// </summary>
public
event
Func
<
object
,
CertificateValidationEventArgs
,
Task
>
ServerCertificateValidationCallback
;
public
event
Func
<
object
,
CertificateValidationEventArgs
,
Task
>
ServerCertificateValidationCallback
;
/// <summary>
/// <summary>
/// Callback tooverride client certificate during SSL mutual authentication
/// Callback tooverride client certificate during SSL mutual authentication
/// </summary>
/// </summary>
public
event
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>
ClientCertificateSelectionCallback
;
public
event
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>
ClientCertificateSelectionCallback
;
/// <summary>
/// <summary>
/// Callback for error events in proxy
/// Callback for error events in proxy
/// </summary>
/// </summary>
public
Action
<
Exception
>
ExceptionFunc
public
Action
<
Exception
>
ExceptionFunc
{
{
get
{
return
exceptionFunc
??
defaultExceptionFunc
.
Value
;
}
get
{
return
exceptionFunc
??
defaultExceptionFunc
.
Value
;
}
set
{
exceptionFunc
=
value
;
}
set
{
exceptionFunc
=
value
;
}
}
}
/// <summary>
/// <summary>
/// A callback to authenticate clients
/// A callback to authenticate clients
/// Parameters are username, password provided by client
/// Parameters are username, password provided by client
/// return true for successful authentication
/// return true for successful authentication
/// </summary>
/// </summary>
public
Func
<
string
,
string
,
Task
<
bool
>>
AuthenticateUserFunc
{
get
;
set
;
}
public
Func
<
string
,
string
,
Task
<
bool
>>
AuthenticateUserFunc
{
get
;
set
;
}
/// <summary>
/// <summary>
/// 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>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP requests
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP requests
/// return the ExternalProxy object with valid credentials
/// return the ExternalProxy object with valid credentials
/// </summary>
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpProxyFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpProxyFunc
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// return the ExternalProxy object with valid credentials
/// return the ExternalProxy object with valid credentials
/// </summary>
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A list of IpAddress and port this proxy is listening to
/// A list of IpAddress and port this proxy is listening to
/// </summary>
/// </summary>
public
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
public
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
/// <summary>
/// <summary>
/// List of supported Ssl versions
/// List of supported Ssl versions
/// </summary>
/// </summary>
#if NET45
#if NET45
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
#else
#else
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
;
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
;
#endif
#endif
/// <summary>
/// <summary>
/// Total number of active client connections
/// Total number of active client connections
/// </summary>
/// </summary>
public
int
ClientConnectionCount
=>
clientConnectionCount
;
public
int
ClientConnectionCount
=>
clientConnectionCount
;
/// <summary>
/// <summary>
/// Total number of active server connections
/// Total number of active server connections
/// </summary>
/// </summary>
public
int
ServerConnectionCount
=>
serverConnectionCount
;
public
int
ServerConnectionCount
=>
serverConnectionCount
;
/// <summary>
/// <summary>
/// Constructor
/// Constructor
/// </summary>
/// </summary>
public
ProxyServer
()
:
this
(
null
,
null
)
public
ProxyServer
()
:
this
(
null
,
null
)
{
{
}
}
/// <summary>
/// <summary>
/// Constructor.
/// Constructor.
/// </summary>
/// </summary>
/// <param name="rootCertificateName">Name of root certificate.</param>
/// <param name="rootCertificateName">Name of root certificate.</param>
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
{
//default values
//default values
ConnectionTimeOutSeconds
=
30
;
ConnectionTimeOutSeconds
=
30
;
CertificateCacheTimeOutMinutes
=
60
;
CertificateCacheTimeOutMinutes
=
60
;
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
tcpConnectionFactory
=
new
TcpConnectionFactory
();
tcpConnectionFactory
=
new
TcpConnectionFactory
();
#if NET45
#if NET45
if
(!
RunTime
.
IsRunningOnMono
)
if
(!
RunTime
.
IsRunningOnMono
)
{
{
systemProxySettingsManager
=
new
SystemProxyManager
();
systemProxySettingsManager
=
new
SystemProxyManager
();
}
}
#endif
#endif
CertificateManager
=
new
CertificateManager
(
ExceptionFunc
);
CertificateManager
=
new
CertificateManager
(
ExceptionFunc
);
if
(
rootCertificateName
!=
null
)
if
(
rootCertificateName
!=
null
)
{
{
RootCertificateName
=
rootCertificateName
;
RootCertificateName
=
rootCertificateName
;
}
}
if
(
rootCertificateIssuerName
!=
null
)
if
(
rootCertificateIssuerName
!=
null
)
{
{
RootCertificateIssuerName
=
rootCertificateIssuerName
;
RootCertificateIssuerName
=
rootCertificateIssuerName
;
}
}
}
}
/// <summary>
/// <summary>
/// Add a proxy end point
/// Add a proxy end point
/// </summary>
/// </summary>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
public
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
{
{
if
(
ProxyEndPoints
.
Any
(
x
=>
x
.
IpAddress
.
Equals
(
endPoint
.
IpAddress
)
&&
endPoint
.
Port
!=
0
&&
x
.
Port
==
endPoint
.
Port
))
if
(
ProxyEndPoints
.
Any
(
x
=>
x
.
IpAddress
.
Equals
(
endPoint
.
IpAddress
)
&&
endPoint
.
Port
!=
0
&&
x
.
Port
==
endPoint
.
Port
))
{
{
throw
new
Exception
(
"Cannot add another endpoint to same port & ip address"
);
throw
new
Exception
(
"Cannot add another endpoint to same port & ip address"
);
}
}
ProxyEndPoints
.
Add
(
endPoint
);
ProxyEndPoints
.
Add
(
endPoint
);
if
(
proxyRunning
)
if
(
proxyRunning
)
{
{
Listen
(
endPoint
);
Listen
(
endPoint
);
}
}
}
}
/// <summary>
/// <summary>
/// Remove a proxy end point
/// Remove a proxy end point
/// Will throw error if the end point does'nt exist
/// Will throw error if the end point does'nt exist
/// </summary>
/// </summary>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
public
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
{
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
{
throw
new
Exception
(
"Cannot remove endPoints not added to proxy"
);
throw
new
Exception
(
"Cannot remove endPoints not added to proxy"
);
}
}
ProxyEndPoints
.
Remove
(
endPoint
);
ProxyEndPoints
.
Remove
(
endPoint
);
if
(
proxyRunning
)
if
(
proxyRunning
)
{
{
QuitListen
(
endPoint
);
QuitListen
(
endPoint
);
}
}
}
}
#if NET45
#if NET45
/// <summary>
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// </summary>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
public
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
{
{
SetAsSystemProxy
(
endPoint
,
ProxyProtocolType
.
Http
);
SetAsSystemProxy
(
endPoint
,
ProxyProtocolType
.
Http
);
}
}
/// <summary>
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// </summary>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
SetAsSystemHttpsProxy
(
ExplicitProxyEndPoint
endPoint
)
public
void
SetAsSystemHttpsProxy
(
ExplicitProxyEndPoint
endPoint
)
{
{
SetAsSystemProxy
(
endPoint
,
ProxyProtocolType
.
Https
);
SetAsSystemProxy
(
endPoint
,
ProxyProtocolType
.
Https
);
}
}
/// <summary>
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// </summary>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
/// <param name="protocolType"></param>
/// <param name="protocolType"></param>
public
void
SetAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
,
ProxyProtocolType
protocolType
)
public
void
SetAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
,
ProxyProtocolType
protocolType
)
{
{
if
(
RunTime
.
IsRunningOnMono
)
if
(
RunTime
.
IsRunningOnMono
)
{
{
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
}
}
ValidateEndPointAsSystemProxy
(
endPoint
);
ValidateEndPointAsSystemProxy
(
endPoint
);
bool
isHttp
=
(
protocolType
&
ProxyProtocolType
.
Http
)
>
0
;
bool
isHttp
=
(
protocolType
&
ProxyProtocolType
.
Http
)
>
0
;
bool
isHttps
=
(
protocolType
&
ProxyProtocolType
.
Https
)
>
0
;
bool
isHttps
=
(
protocolType
&
ProxyProtocolType
.
Https
)
>
0
;
if
(
isHttps
)
if
(
isHttps
)
{
{
if
(!
endPoint
.
EnableSsl
)
if
(!
endPoint
.
EnableSsl
)
{
{
throw
new
Exception
(
"Endpoint do not support Https connections"
);
throw
new
Exception
(
"Endpoint do not support Https connections"
);
}
}
EnsureRootCertificate
();
EnsureRootCertificate
();
//If certificate was trusted by the machine
//If certificate was trusted by the machine
if
(!
CertificateManager
.
CertValidated
)
if
(!
CertificateManager
.
CertValidated
)
{
{
protocolType
=
protocolType
&
~
ProxyProtocolType
.
Https
;
protocolType
=
protocolType
&
~
ProxyProtocolType
.
Https
;
isHttps
=
false
;
isHttps
=
false
;
}
}
}
}
//clear any settings previously added
//clear any settings previously added
if
(
isHttp
)
if
(
isHttp
)
{
{
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpProxy
=
false
);
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpProxy
=
false
);
}
}
if
(
isHttps
)
if
(
isHttps
)
{
{
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpsProxy
=
false
);
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpsProxy
=
false
);
}
}
systemProxySettingsManager
.
SetProxy
(
systemProxySettingsManager
.
SetProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
,
endPoint
.
Port
,
protocolType
);
protocolType
);
if
(
isHttp
)
if
(
isHttp
)
{
{
endPoint
.
IsSystemHttpsProxy
=
true
;
endPoint
.
IsSystemHttpsProxy
=
true
;
}
}
if
(
isHttps
)
if
(
isHttps
)
{
{
endPoint
.
IsSystemHttpsProxy
=
true
;
endPoint
.
IsSystemHttpsProxy
=
true
;
}
}
firefoxProxySettingsManager
.
UseSystemProxy
();
firefoxProxySettingsManager
.
UseSystemProxy
();
string
proxyType
=
null
;
string
proxyType
=
null
;
switch
(
protocolType
)
switch
(
protocolType
)
{
{
case
ProxyProtocolType
.
Http
:
case
ProxyProtocolType
.
Http
:
proxyType
=
"HTTP"
;
proxyType
=
"HTTP"
;
break
;
break
;
case
ProxyProtocolType
.
Https
:
case
ProxyProtocolType
.
Https
:
proxyType
=
"HTTPS"
;
proxyType
=
"HTTPS"
;
break
;
break
;
case
ProxyProtocolType
.
AllHttp
:
case
ProxyProtocolType
.
AllHttp
:
proxyType
=
"HTTP and HTTPS"
;
proxyType
=
"HTTP and HTTPS"
;
break
;
break
;
}
}
if
(
protocolType
!=
ProxyProtocolType
.
None
)
if
(
protocolType
!=
ProxyProtocolType
.
None
)
{
{
Console
.
WriteLine
(
"Set endpoint at Ip {0} and port: {1} as System {2} Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
,
proxyType
);
Console
.
WriteLine
(
"Set endpoint at Ip {0} and port: {1} as System {2} Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
,
proxyType
);
}
}
}
}
/// <summary>
/// <summary>
/// Remove any HTTP proxy setting of current machien
/// Remove any HTTP proxy setting of current machien
/// </summary>
/// </summary>
public
void
DisableSystemHttpProxy
()
public
void
DisableSystemHttpProxy
()
{
{
DisableSystemProxy
(
ProxyProtocolType
.
Http
);
DisableSystemProxy
(
ProxyProtocolType
.
Http
);
}
}
/// <summary>
/// <summary>
/// Remove any HTTPS proxy setting for current machine
/// Remove any HTTPS proxy setting for current machine
/// </summary>
/// </summary>
public
void
DisableSystemHttpsProxy
()
public
void
DisableSystemHttpsProxy
()
{
{
DisableSystemProxy
(
ProxyProtocolType
.
Https
);
DisableSystemProxy
(
ProxyProtocolType
.
Https
);
}
}
/// <summary>
/// <summary>
/// Remove the specified proxy settings for current machine
/// Remove the specified proxy settings for current machine
/// </summary>
/// </summary>
public
void
DisableSystemProxy
(
ProxyProtocolType
protocolType
)
public
void
DisableSystemProxy
(
ProxyProtocolType
protocolType
)
{
{
if
(
RunTime
.
IsRunningOnMono
)
if
(
RunTime
.
IsRunningOnMono
)
{
{
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
}
}
systemProxySettingsManager
.
RemoveProxy
(
protocolType
);
systemProxySettingsManager
.
RemoveProxy
(
protocolType
);
}
}
/// <summary>
/// <summary>
/// Clear all proxy settings for current machine
/// Clear all proxy settings for current machine
/// </summary>
/// </summary>
public
void
DisableAllSystemProxies
()
public
void
DisableAllSystemProxies
()
{
{
if
(
RunTime
.
IsRunningOnMono
)
if
(
RunTime
.
IsRunningOnMono
)
{
{
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
}
}
systemProxySettingsManager
.
DisableAllProxy
();
systemProxySettingsManager
.
DisableAllProxy
();
}
}
#endif
#endif
/// <summary>
/// <summary>
/// Start this proxy server
/// Start this proxy server
/// </summary>
/// </summary>
public
void
Start
()
public
void
Start
()
{
{
if
(
proxyRunning
)
if
(
proxyRunning
)
{
{
throw
new
Exception
(
"Proxy is already running."
);
throw
new
Exception
(
"Proxy is already running."
);
}
}
#if NET45
#if NET45
//clear any system proxy settings which is pointing to our own endpoint
//clear any system proxy settings which is pointing to our own endpoint (causing a cycle)
//due to non gracious proxy shutdown before
//due to non gracious proxy shutdown before or something else
if
(
systemProxySettingsManager
!=
null
)
if
(
systemProxySettingsManager
!=
null
)
{
{
var
proxyInfo
=
systemProxySettingsManager
.
GetProxyInfoFromRegistry
();
var
proxyInfo
=
systemProxySettingsManager
.
GetProxyInfoFromRegistry
();
if
(
proxyInfo
.
Proxies
!=
null
)
if
(
proxyInfo
.
Proxies
!=
null
)
{
{
var
protocolToRemove
=
ProxyProtocolType
.
None
;
var
protocolToRemove
=
ProxyProtocolType
.
None
;
foreach
(
var
proxy
in
proxyInfo
.
Proxies
.
Values
)
foreach
(
var
proxy
in
proxyInfo
.
Proxies
.
Values
)
{
{
if
(
proxy
.
HostName
==
"127.0.0.1"
&&
ProxyEndPoints
.
Any
(
x
=>
x
.
Port
==
proxy
.
Port
))
if
((
proxy
.
HostName
==
"127.0.0.1"
{
||
proxy
.
HostName
.
Equals
(
"localhost"
,
StringComparison
.
OrdinalIgnoreCase
))
protocolToRemove
|=
proxy
.
ProtocolType
;
&&
ProxyEndPoints
.
Any
(
x
=>
x
.
Port
==
proxy
.
Port
))
}
{
}
protocolToRemove
|=
proxy
.
ProtocolType
;
}
if
(
protocolToRemove
!=
ProxyProtocolType
.
None
)
}
{
//do not restore to any of listening address when we quit
if
(
protocolToRemove
!=
ProxyProtocolType
.
None
)
systemProxySettingsManager
.
RemoveProxy
(
protocolToRemove
,
false
);
{
}
//do not restore to any of listening address when we quit
}
systemProxySettingsManager
.
RemoveProxy
(
protocolToRemove
,
false
);
}
}
}
if
(
ForwardToUpstreamGateway
}
&&
GetCustomUpStreamHttpProxyFunc
==
null
&&
GetCustomUpStreamHttpsProxyFunc
==
null
&&
systemProxySettingsManager
!=
null
)
if
(
ForwardToUpstreamGateway
{
&&
GetCustomUpStreamHttpProxyFunc
==
null
&&
GetCustomUpStreamHttpsProxyFunc
==
null
// Use WinHttp to handle PAC/WAPD scripts.
&&
systemProxySettingsManager
!=
null
)
systemProxyResolver
=
new
WinHttpWebProxyFinder
();
{
systemProxyResolver
.
LoadFromIE
();
// Use WinHttp to handle PAC/WAPD scripts.
systemProxyResolver
=
new
WinHttpWebProxyFinder
();
GetCustomUpStreamHttpProxyFunc
=
GetSystemUpStreamProxy
;
systemProxyResolver
.
LoadFromIE
();
GetCustomUpStreamHttpsProxyFunc
=
GetSystemUpStreamProxy
;
}
GetCustomUpStreamHttpProxyFunc
=
GetSystemUpStreamProxy
;
#endif
GetCustomUpStreamHttpsProxyFunc
=
GetSystemUpStreamProxy
;
}
foreach
(
var
endPoint
in
ProxyEndPoints
)
#endif
{
Listen
(
endPoint
);
foreach
(
var
endPoint
in
ProxyEndPoints
)
}
{
Listen
(
endPoint
);
CertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
}
#if NET45
CertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
if
(!
RunTime
.
IsRunningOnMono
)
{
#if NET45
//clear orphaned windows auth states every 2 minutes
if
(!
RunTime
.
IsRunningOnMono
)
WinAuthEndPoint
.
ClearIdleStates
(
2
);
{
}
//clear orphaned windows auth states every 2 minutes
#endif
WinAuthEndPoint
.
ClearIdleStates
(
2
);
}
proxyRunning
=
true
;
#endif
}
proxyRunning
=
true
;
}
/// <summary>
/// Stop this proxy server
/// </summary>
/// <summary>
public
void
Stop
()
/// Stop this proxy server
{
/// </summary>
if
(!
proxyRunning
)
public
void
Stop
()
{
{
throw
new
Exception
(
"Proxy is not running."
);
if
(!
proxyRunning
)
}
{
throw
new
Exception
(
"Proxy is not running."
);
#if NET45
}
if
(!
RunTime
.
IsRunningOnMono
)
{
#if NET45
bool
setAsSystemProxy
=
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemHttpProxy
||
x
.
IsSystemHttpsProxy
);
if
(!
RunTime
.
IsRunningOnMono
)
{
if
(
setAsSystemProxy
)
bool
setAsSystemProxy
=
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemHttpProxy
||
x
.
IsSystemHttpsProxy
);
{
systemProxySettingsManager
.
RestoreOriginalSettings
();
if
(
setAsSystemProxy
)
}
{
}
systemProxySettingsManager
.
RestoreOriginalSettings
();
#endif
}
}
foreach
(
var
endPoint
in
ProxyEndPoints
)
#endif
{
QuitListen
(
endPoint
);
foreach
(
var
endPoint
in
ProxyEndPoints
)
}
{
QuitListen
(
endPoint
);
ProxyEndPoints
.
Clear
();
}
CertificateManager
?.
StopClearIdleCertificates
();
ProxyEndPoints
.
Clear
();
proxyRunning
=
false
;
CertificateManager
?.
StopClearIdleCertificates
();
}
proxyRunning
=
false
;
/// <summary>
}
/// Handle dispose of a client/server session
/// </summary>
/// <summary>
/// <param name="clientStream"></param>
/// Handle dispose of a client/server session
/// <param name="clientStreamReader"></param>
/// </summary>
/// <param name="clientStreamWriter"></param>
/// <param name="clientStream"></param>
/// <param name="serverConnection"></param>
/// <param name="clientStreamReader"></param>
private
void
Dispose
(
CustomBufferedStream
clientStream
,
CustomBinaryReader
clientStreamReader
,
HttpResponseWriter
clientStreamWriter
,
TcpConnection
serverConnection
)
/// <param name="clientStreamWriter"></param>
{
/// <param name="serverConnection"></param>
clientStream
?.
Dispose
();
private
void
Dispose
(
CustomBufferedStream
clientStream
,
CustomBinaryReader
clientStreamReader
,
HttpResponseWriter
clientStreamWriter
,
TcpConnection
serverConnection
)
{
clientStreamReader
?.
Dispose
();
clientStream
?.
Dispose
();
clientStreamWriter
?.
Dispose
();
clientStreamReader
?.
Dispose
();
if
(
serverConnection
!=
null
)
clientStreamWriter
?.
Dispose
();
{
serverConnection
.
Dispose
();
if
(
serverConnection
!=
null
)
UpdateServerConnectionCount
(
false
);
{
}
serverConnection
.
Dispose
();
}
serverConnection
=
null
;
UpdateServerConnectionCount
(
false
);
/// <summary>
}
/// Dispose Proxy.
}
/// </summary>
public
void
Dispose
()
/// <summary>
{
/// Dispose Proxy.
if
(
proxyRunning
)
/// </summary>
{
public
void
Dispose
()
Stop
();
{
}
if
(
proxyRunning
)
{
CertificateManager
?.
Dispose
();
Stop
();
}
}
#if NET45
CertificateManager
?.
Dispose
();
/// <summary>
}
/// Listen on the given end point on local machine
/// </summary>
#if NET45
/// <param name="endPoint"></param>
/// <summary>
private
void
Listen
(
ProxyEndPoint
endPoint
)
/// Listen on the given end point on local machine
{
/// </summary>
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
/// <param name="endPoint"></param>
endPoint
.
Listener
.
Start
();
private
void
Listen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
// accept clients asynchronously
endPoint
.
Listener
.
Start
();
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
#else
// accept clients asynchronously
private
async
void
Listen
(
ProxyEndPoint
endPoint
)
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
{
}
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
#else
endPoint
.
Listener
.
Start
();
private
async
void
Listen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
Listener
.
Start
();
while
(
true
)
{
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
TcpClient
tcpClient
=
await
endPoint
.
Listener
.
AcceptTcpClientAsync
();
if
(
tcpClient
!=
null
)
while
(
true
)
Task
.
Run
(
async
()
=>
HandleClient
(
tcpClient
,
endPoint
));
{
}
TcpClient
tcpClient
=
await
endPoint
.
Listener
.
AcceptTcpClientAsync
();
if
(
tcpClient
!=
null
)
}
Task
.
Run
(
async
()
=>
HandleClient
(
tcpClient
,
endPoint
));
#endif
}
/// <summary>
}
/// Verifiy if its safe to set this end point as System proxy
#endif
/// </summary>
/// <param name="endPoint"></param>
/// <summary>
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
/// Verifiy if its safe to set this end point as System proxy
{
/// </summary>
if
(
endPoint
==
null
)
/// <param name="endPoint"></param>
throw
new
ArgumentNullException
(
nameof
(
endPoint
));
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
{
if
(
endPoint
==
null
)
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
throw
new
ArgumentNullException
(
nameof
(
endPoint
));
}
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
if
(!
proxyRunning
)
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
{
}
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
}
if
(!
proxyRunning
)
}
{
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
#if NET45
}
/// <summary>
}
/// Gets the system up stream proxy.
/// </summary>
#if NET45
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <summary>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
/// Gets the system up stream proxy.
private
Task
<
ExternalProxy
>
GetSystemUpStreamProxy
(
SessionEventArgs
sessionEventArgs
)
/// </summary>
{
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
var
proxy
=
systemProxyResolver
.
GetProxy
(
sessionEventArgs
.
WebSession
.
Request
.
RequestUri
);
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
return
Task
.
FromResult
(
proxy
);
private
Task
<
ExternalProxy
>
GetSystemUpStreamProxy
(
SessionEventArgs
sessionEventArgs
)
}
{
#endif
var
proxy
=
systemProxyResolver
.
GetProxy
(
sessionEventArgs
.
WebSession
.
Request
.
RequestUri
);
return
Task
.
FromResult
(
proxy
);
private
void
EnsureRootCertificate
()
}
{
#endif
if
(!
CertificateManager
.
CertValidated
)
{
private
void
EnsureRootCertificate
()
CertificateManager
.
CreateTrustedRootCertificate
();
{
if
(!
CertificateManager
.
CertValidated
)
if
(
TrustRootCertificate
)
{
{
CertificateManager
.
CreateTrustedRootCertificate
();
CertificateManager
.
TrustRootCertificate
();
}
if
(
TrustRootCertificate
)
}
{
}
CertificateManager
.
TrustRootCertificate
();
}
#if NET45
}
/// <summary>
}
/// When a connection is received from client act
/// </summary>
#if NET45
/// <param name="asyn"></param>
/// <summary>
private
void
OnAcceptConnection
(
IAsyncResult
asyn
)
/// When a connection is received from client act
{
/// </summary>
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
/// <param name="asyn"></param>
private
void
OnAcceptConnection
(
IAsyncResult
asyn
)
TcpClient
tcpClient
=
null
;
{
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
try
{
TcpClient
tcpClient
=
null
;
//based on end point type call appropriate request handlers
tcpClient
=
endPoint
.
Listener
.
EndAcceptTcpClient
(
asyn
);
try
}
{
catch
(
ObjectDisposedException
)
//based on end point type call appropriate request handlers
{
tcpClient
=
endPoint
.
Listener
.
EndAcceptTcpClient
(
asyn
);
// The listener was Stop()'d, disposing the underlying socket and
}
// triggering the completion of the callback. We're already exiting,
catch
(
ObjectDisposedException
)
// so just return.
{
return
;
// The listener was Stop()'d, disposing the underlying socket and
}
// triggering the completion of the callback. We're already exiting,
catch
// so just return.
{
return
;
//Other errors are discarded to keep proxy running
}
}
catch
{
if
(
tcpClient
!=
null
)
//Other errors are discarded to keep proxy running
{
}
Task
.
Run
(
async
()
=>
{
if
(
tcpClient
!=
null
)
await
HandleClient
(
tcpClient
,
endPoint
);
{
});
Task
.
Run
(
async
()
=>
}
{
await
HandleClient
(
tcpClient
,
endPoint
);
// Get the listener that handles the client request.
});
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
}
#endif
// Get the listener that handles the client request.
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
private
async
Task
HandleClient
(
TcpClient
tcpClient
,
ProxyEndPoint
endPoint
)
}
{
#endif
UpdateClientConnectionCount
(
true
);
private
async
Task
HandleClient
(
TcpClient
tcpClient
,
ProxyEndPoint
endPoint
)
tcpClient
.
ReceiveTimeout
=
ConnectionTimeOutSeconds
*
1000
;
{
tcpClient
.
SendTimeout
=
ConnectionTimeOutSeconds
*
1000
;
UpdateClientConnectionCount
(
true
);
try
tcpClient
.
ReceiveTimeout
=
ConnectionTimeOutSeconds
*
1000
;
{
tcpClient
.
SendTimeout
=
ConnectionTimeOutSeconds
*
1000
;
if
(
endPoint
.
GetType
()
==
typeof
(
TransparentProxyEndPoint
))
{
try
await
HandleClient
(
endPoint
as
TransparentProxyEndPoint
,
tcpClient
);
{
}
if
(
endPoint
.
GetType
()
==
typeof
(
TransparentProxyEndPoint
))
else
{
{
await
HandleClient
(
endPoint
as
TransparentProxyEndPoint
,
tcpClient
);
await
HandleClient
(
endPoint
as
ExplicitProxyEndPoint
,
tcpClient
);
}
}
else
}
{
finally
await
HandleClient
(
endPoint
as
ExplicitProxyEndPoint
,
tcpClient
);
{
}
UpdateClientConnectionCount
(
false
);
}
finally
try
{
{
UpdateClientConnectionCount
(
false
);
if
(
tcpClient
!=
null
)
{
try
//This line is important!
{
//contributors please don't remove it without discussion
if
(
tcpClient
!=
null
)
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
{
//due to default TCP CLOSE_WAIT timeout for 4 minutes
//This line is important!
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
0
);
//contributors please don't remove it without discussion
tcpClient
.
Dispose
();
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
}
//due to default TCP CLOSE_WAIT timeout for 4 minutes
}
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
0
);
catch
tcpClient
.
Dispose
();
{
}
}
}
}
catch
}
{
}
/// <summary>
}
/// Quit listening on the given end point
}
/// </summary>
/// <param name="endPoint"></param>
/// <summary>
private
void
QuitListen
(
ProxyEndPoint
endPoint
)
/// Quit listening on the given end point
{
/// </summary>
endPoint
.
Listener
.
Stop
();
/// <param name="endPoint"></param>
endPoint
.
Listener
.
Server
.
Dispose
();
private
void
QuitListen
(
ProxyEndPoint
endPoint
)
}
{
endPoint
.
Listener
.
Stop
();
internal
void
UpdateClientConnectionCount
(
bool
increment
)
endPoint
.
Listener
.
Server
.
Dispose
();
{
}
if
(
increment
)
{
internal
void
UpdateClientConnectionCount
(
bool
increment
)
Interlocked
.
Increment
(
ref
clientConnectionCount
);
{
}
if
(
increment
)
else
{
{
Interlocked
.
Increment
(
ref
clientConnectionCount
);
Interlocked
.
Decrement
(
ref
clientConnectionCount
);
}
}
else
{
ClientConnectionCountChanged
?.
Invoke
(
this
,
EventArgs
.
Empty
);
Interlocked
.
Decrement
(
ref
clientConnectionCount
);
}
}
internal
void
UpdateServerConnectionCount
(
bool
increment
)
ClientConnectionCountChanged
?.
Invoke
(
this
,
EventArgs
.
Empty
);
{
}
if
(
increment
)
{
internal
void
UpdateServerConnectionCount
(
bool
increment
)
Interlocked
.
Increment
(
ref
serverConnectionCount
);
{
}
if
(
increment
)
else
{
{
Interlocked
.
Increment
(
ref
serverConnectionCount
);
Interlocked
.
Decrement
(
ref
serverConnectionCount
);
}
}
else
{
ServerConnectionCountChanged
?.
Invoke
(
this
,
EventArgs
.
Empty
);
Interlocked
.
Decrement
(
ref
serverConnectionCount
);
}
}
}
}
ServerConnectionCountChanged
?.
Invoke
(
this
,
EventArgs
.
Empty
);
}
}
}
Titanium.Web.Proxy/RequestHandler.cs
View file @
58ec1bb3
...
@@ -164,24 +164,30 @@ namespace Titanium.Web.Proxy
...
@@ -164,24 +164,30 @@ namespace Titanium.Web.Proxy
//create new connection
//create new connection
using
(
var
connection
=
await
GetServerConnection
(
connectArgs
,
true
))
using
(
var
connection
=
await
GetServerConnection
(
connectArgs
,
true
))
{
{
if
(
isClientHello
)
try
{
{
if
(
clientStream
.
Available
>
0
)
if
(
isClientHello
)
{
{
//send the buffered data
if
(
clientStream
.
Available
>
0
)
var
data
=
new
byte
[
clientStream
.
Available
];
{
await
clientStream
.
ReadAsync
(
data
,
0
,
data
.
Length
);
//send the buffered data
await
connection
.
Stream
.
WriteAsync
(
data
,
0
,
data
.
Length
);
var
data
=
new
byte
[
clientStream
.
Available
];
await
connection
.
Stream
.
FlushAsync
();
await
clientStream
.
ReadAsync
(
data
,
0
,
data
.
Length
);
await
connection
.
Stream
.
WriteAsync
(
data
,
0
,
data
.
Length
);
await
connection
.
Stream
.
FlushAsync
();
}
var
serverHelloInfo
=
await
SslTools
.
PeekServerHello
(
connection
.
Stream
);
((
ConnectResponse
)
connectArgs
.
WebSession
.
Response
).
ServerHelloInfo
=
serverHelloInfo
;
}
}
var
serverHelloInfo
=
await
SslTools
.
PeekServerHello
(
connection
.
Stream
);
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
BufferSize
,
((
ConnectResponse
)
connectArgs
.
WebSession
.
Response
).
ServerHelloInfo
=
serverHelloInfo
;
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
});
}
finally
{
UpdateServerConnectionCount
(
false
);
}
}
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
BufferSize
,
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
});
UpdateServerConnectionCount
(
false
);
}
}
return
;
return
;
...
@@ -361,8 +367,8 @@ namespace Titanium.Web.Proxy
...
@@ -361,8 +367,8 @@ namespace Titanium.Web.Proxy
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
{
{
connection
.
Dispose
();
connection
.
Dispose
();
UpdateServerConnectionCount
(
false
);
connection
=
null
;
connection
=
null
;
UpdateServerConnectionCount
(
false
);
}
}
if
(
connection
==
null
)
if
(
connection
==
null
)
...
...
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