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
99e3b575
Commit
99e3b575
authored
Jul 19, 2017
by
justcoding121
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into beta
parents
dd688aa1
38116fb9
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
959 additions
and
944 deletions
+959
-944
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+4
-2
TunnelConnectEventArgs.cs
Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
+4
-2
DotNet45Extensions.cs
Titanium.Web.Proxy/Extensions/DotNet45Extensions.cs
+1
-1
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+2
-2
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+0
-28
HttpRequestWriter.cs
Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs
+2
-1
HttpResponseWriter.cs
Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs
+2
-1
HttpWriter.cs
Titanium.Web.Proxy/Helpers/HttpWriter.cs
+2
-1
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+4
-3
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+11
-2
TcpConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
+6
-0
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+11
-7
AssemblyInfo.cs
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
+2
-2
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+871
-868
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+32
-22
Titanium.Web.Proxy.Standard.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.Standard.csproj
+4
-1
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+1
-1
No files found.
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
99e3b575
...
@@ -98,13 +98,15 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -98,13 +98,15 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// <summary>
/// Constructor to initialize the proxy
/// Constructor to initialize the proxy
/// </summary>
/// </summary>
internal
SessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
)
internal
SessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
)
{
{
this
.
bufferSize
=
bufferSize
;
this
.
bufferSize
=
bufferSize
;
this
.
httpResponseHandler
=
httpResponseHandler
;
this
.
httpResponseHandler
=
httpResponseHandler
;
ProxyClient
=
new
ProxyClient
();
ProxyClient
=
new
ProxyClient
();
WebSession
=
new
HttpWebClient
();
WebSession
=
new
HttpWebClient
(
bufferSize
);
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
{
{
...
...
Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
View file @
99e3b575
using
Titanium.Web.Proxy.Models
;
using
System.Net
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.EventArguments
namespace
Titanium.Web.Proxy.EventArguments
{
{
...
@@ -6,7 +7,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -6,7 +7,8 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
public
bool
IsHttpsConnect
{
get
;
set
;
}
public
bool
IsHttpsConnect
{
get
;
set
;
}
public
TunnelConnectSessionEventArgs
(
ProxyEndPoint
endPoint
)
:
base
(
0
,
endPoint
,
null
)
public
TunnelConnectSessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
)
:
base
(
bufferSize
,
endPoint
,
null
)
{
{
}
}
...
...
Titanium.Web.Proxy/Extensions/DotNet
Standard
Extensions.cs
→
Titanium.Web.Proxy/Extensions/DotNet
45
Extensions.cs
View file @
99e3b575
...
@@ -3,7 +3,7 @@ using System.Security.Cryptography.X509Certificates;
...
@@ -3,7 +3,7 @@ using System.Security.Cryptography.X509Certificates;
namespace
Titanium.Web.Proxy.Extensions
namespace
Titanium.Web.Proxy.Extensions
{
{
internal
static
class
DotNet
Standard
Extensions
internal
static
class
DotNet
45
Extensions
{
{
#if NET45
#if NET45
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
99e3b575
...
@@ -17,9 +17,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -17,9 +17,9 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="input"></param>
/// <param name="input"></param>
/// <param name="output"></param>
/// <param name="output"></param>
/// <param name="onCopy"></param>
/// <param name="onCopy"></param>
internal
static
async
Task
CopyToAsync
(
this
Stream
input
,
Stream
output
,
Action
<
byte
[],
int
,
int
>
onCopy
)
internal
static
async
Task
CopyToAsync
(
this
Stream
input
,
Stream
output
,
Action
<
byte
[],
int
,
int
>
onCopy
,
int
bufferSize
)
{
{
byte
[]
buffer
=
new
byte
[
81920
];
byte
[]
buffer
=
new
byte
[
bufferSize
];
while
(
true
)
while
(
true
)
{
{
int
num
=
await
input
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
).
ConfigureAwait
(
false
);
int
num
=
await
input
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
).
ConfigureAwait
(
false
);
...
...
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
99e3b575
...
@@ -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/Helpers/HttpRequestWriter.cs
View file @
99e3b575
...
@@ -4,7 +4,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -4,7 +4,8 @@ namespace Titanium.Web.Proxy.Helpers
{
{
sealed
class
HttpRequestWriter
:
HttpWriter
sealed
class
HttpRequestWriter
:
HttpWriter
{
{
public
HttpRequestWriter
(
Stream
stream
)
:
base
(
stream
,
true
)
public
HttpRequestWriter
(
Stream
stream
,
int
bufferSize
)
:
base
(
stream
,
bufferSize
,
true
)
{
{
}
}
}
}
...
...
Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs
View file @
99e3b575
...
@@ -12,7 +12,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -12,7 +12,8 @@ namespace Titanium.Web.Proxy.Helpers
{
{
sealed
class
HttpResponseWriter
:
HttpWriter
sealed
class
HttpResponseWriter
:
HttpWriter
{
{
public
HttpResponseWriter
(
Stream
stream
)
:
base
(
stream
,
true
)
public
HttpResponseWriter
(
Stream
stream
,
int
bufferSize
)
:
base
(
stream
,
bufferSize
,
true
)
{
{
}
}
...
...
Titanium.Web.Proxy/Helpers/HttpWriter.cs
View file @
99e3b575
...
@@ -8,7 +8,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -8,7 +8,8 @@ namespace Titanium.Web.Proxy.Helpers
{
{
abstract
class
HttpWriter
:
StreamWriter
abstract
class
HttpWriter
:
StreamWriter
{
{
protected
HttpWriter
(
Stream
stream
,
bool
leaveOpen
)
:
base
(
stream
,
Encoding
.
ASCII
,
1024
,
leaveOpen
)
protected
HttpWriter
(
Stream
stream
,
int
bufferSize
,
bool
leaveOpen
)
:
base
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
leaveOpen
)
{
{
NewLine
=
ProxyConstants
.
NewLine
;
NewLine
=
ProxyConstants
.
NewLine
;
}
}
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
99e3b575
...
@@ -116,12 +116,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -116,12 +116,13 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onDataSend"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="onDataReceive"></param>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
SendRaw
(
Stream
clientStream
,
Stream
serverStream
,
Action
<
byte
[],
int
,
int
>
onDataSend
,
Action
<
byte
[],
int
,
int
>
onDataReceive
)
internal
static
async
Task
SendRaw
(
Stream
clientStream
,
Stream
serverStream
,
int
bufferSize
,
Action
<
byte
[],
int
,
int
>
onDataSend
,
Action
<
byte
[],
int
,
int
>
onDataReceive
)
{
{
//Now async relay all server=>client & client=>server data
//Now async relay all server=>client & client=>server data
var
sendRelay
=
clientStream
.
CopyToAsync
(
serverStream
,
onDataSend
);
var
sendRelay
=
clientStream
.
CopyToAsync
(
serverStream
,
onDataSend
,
bufferSize
);
var
receiveRelay
=
serverStream
.
CopyToAsync
(
clientStream
,
onDataReceive
);
var
receiveRelay
=
serverStream
.
CopyToAsync
(
clientStream
,
onDataReceive
,
bufferSize
);
await
Task
.
WhenAll
(
sendRelay
,
receiveRelay
);
await
Task
.
WhenAll
(
sendRelay
,
receiveRelay
);
}
}
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
99e3b575
...
@@ -13,6 +13,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -13,6 +13,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
class
HttpWebClient
:
IDisposable
public
class
HttpWebClient
:
IDisposable
{
{
private
int
bufferSize
;
/// <summary>
/// <summary>
/// Connection to server
/// Connection to server
/// </summary>
/// </summary>
...
@@ -23,6 +25,11 @@ namespace Titanium.Web.Proxy.Http
...
@@ -23,6 +25,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
Guid
RequestId
{
get
;
}
public
Guid
RequestId
{
get
;
}
/// <summary>
/// Override UpStreamEndPoint for this request; Local NIC via request is made
/// </summary>
public
IPEndPoint
UpStreamEndPoint
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Headers passed with Connect.
/// Headers passed with Connect.
/// </summary>
/// </summary>
...
@@ -49,8 +56,10 @@ namespace Titanium.Web.Proxy.Http
...
@@ -49,8 +56,10 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
bool
IsHttps
=>
Request
.
IsHttps
;
public
bool
IsHttps
=>
Request
.
IsHttps
;
internal
HttpWebClient
()
internal
HttpWebClient
(
int
bufferSize
)
{
{
this
.
bufferSize
=
bufferSize
;
RequestId
=
Guid
.
NewGuid
();
RequestId
=
Guid
.
NewGuid
();
Request
=
new
Request
();
Request
=
new
Request
();
Response
=
new
Response
();
Response
=
new
Response
();
...
@@ -77,7 +86,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -77,7 +86,7 @@ namespace Titanium.Web.Proxy.Http
byte
[]
requestBytes
;
byte
[]
requestBytes
;
using
(
var
ms
=
new
MemoryStream
())
using
(
var
ms
=
new
MemoryStream
())
using
(
var
writer
=
new
HttpRequestWriter
(
ms
))
using
(
var
writer
=
new
HttpRequestWriter
(
ms
,
bufferSize
))
{
{
var
upstreamProxy
=
ServerConnection
.
UpStreamHttpProxy
;
var
upstreamProxy
=
ServerConnection
.
UpStreamHttpProxy
;
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
View file @
99e3b575
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
System
;
using
System
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -25,6 +26,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -25,6 +26,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal
bool
UseUpstreamProxy
{
get
;
set
;
}
internal
bool
UseUpstreamProxy
{
get
;
set
;
}
/// <summary>
/// Local NIC via connection is made
/// </summary>
internal
IPEndPoint
UpStreamEndPoint
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Http version
/// Http version
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
99e3b575
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
System
;
using
System
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Text
;
...
@@ -17,19 +18,21 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -17,19 +18,21 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal
class
TcpConnectionFactory
internal
class
TcpConnectionFactory
{
{
/// <summary>
/// <summary>
/// Creates a TCP connection to server
///
Creates a TCP connection to server
/// </summary>
/// </summary>
/// <param name="server"></param>
/// <param name="server"></param>
/// <param name="remoteHostName"></param>
/// <param name="remoteHostName"></param>
/// <param name="remotePort"></param>
/// <param name="remotePort"></param>
/// <param name="httpVersion"></param>
/// <param name="httpVersion"></param>
/// <param name="isConnect"></param>
/// <param name="isHttps"></param>
/// <param name="isHttps"></param>
/// <param name="isConnect"></param>
/// <param name="upStreamEndPoint"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <returns></returns>
/// <returns></returns>
internal
async
Task
<
TcpConnection
>
CreateClient
(
ProxyServer
server
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
internal
async
Task
<
TcpConnection
>
CreateClient
(
ProxyServer
server
,
bool
isConnect
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
)
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
bool
isConnect
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
)
{
{
bool
useUpstreamProxy
=
false
;
bool
useUpstreamProxy
=
false
;
var
externalProxy
=
isHttps
?
externalHttpsProxy
:
externalHttpProxy
;
var
externalProxy
=
isHttps
?
externalHttpsProxy
:
externalHttpProxy
;
...
@@ -52,10 +55,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -52,10 +55,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
try
try
{
{
#if NET45
#if NET45
client
=
new
TcpClient
(
server
.
U
pStreamEndPoint
);
client
=
new
TcpClient
(
u
pStreamEndPoint
);
#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
...
@@ -72,7 +75,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -72,7 +75,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if
(
useUpstreamProxy
&&
(
isConnect
||
isHttps
))
if
(
useUpstreamProxy
&&
(
isConnect
||
isHttps
))
{
{
using
(
var
writer
=
new
HttpRequestWriter
(
stream
))
using
(
var
writer
=
new
HttpRequestWriter
(
stream
,
server
.
BufferSize
))
{
{
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
...
@@ -128,6 +131,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -128,6 +131,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
UpStreamHttpProxy
=
externalHttpProxy
,
UpStreamHttpProxy
=
externalHttpProxy
,
UpStreamHttpsProxy
=
externalHttpsProxy
,
UpStreamHttpsProxy
=
externalHttpsProxy
,
UpStreamEndPoint
=
upStreamEndPoint
,
HostName
=
remoteHostName
,
HostName
=
remoteHostName
,
Port
=
remotePort
,
Port
=
remotePort
,
IsHttps
=
isHttps
,
IsHttps
=
isHttps
,
...
...
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
View file @
99e3b575
...
@@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
...
@@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
// set of attributes. Change these attribute values to modify the information
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
// associated with an assembly.
[assembly: AssemblyTitle("Titanium.Web.Proxy
.Properties
")]
[assembly: AssemblyTitle("Titanium.Web.Proxy")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy
.Properties
")]
[assembly: AssemblyProduct("Titanium.Web.Proxy")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyCulture("")]
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
99e3b575
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 @
99e3b575
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy
var
clientStream
=
new
CustomBufferedStream
(
tcpClient
.
GetStream
(),
BufferSize
);
var
clientStream
=
new
CustomBufferedStream
(
tcpClient
.
GetStream
(),
BufferSize
);
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
var
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
);
var
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
,
BufferSize
);
Uri
httpRemoteUri
;
Uri
httpRemoteUri
;
...
@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy
...
@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
connectRequest
.
RequestHeaders
);
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
connectRequest
.
RequestHeaders
);
var
connectArgs
=
new
TunnelConnectSessionEventArgs
(
endPoint
);
var
connectArgs
=
new
TunnelConnectSessionEventArgs
(
BufferSize
,
endPoint
);
connectArgs
.
WebSession
.
Request
=
connectRequest
;
connectArgs
.
WebSession
.
Request
=
connectRequest
;
connectArgs
.
ProxyClient
.
TcpClient
=
tcpClient
;
connectArgs
.
ProxyClient
.
TcpClient
=
tcpClient
;
connectArgs
.
ProxyClient
.
ClientStream
=
clientStream
;
connectArgs
.
ProxyClient
.
ClientStream
=
clientStream
;
...
@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy
...
@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy
clientStreamReader
.
Dispose
();
clientStreamReader
.
Dispose
();
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
);
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
,
BufferSize
);
}
}
catch
catch
{
{
...
@@ -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
,
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
connectArgs
.
OnDataReceived
(
buffer
,
offset
,
count
);
});
UpdateServerConnectionCount
(
false
);
}
}
return
;
return
;
...
@@ -243,7 +249,7 @@ namespace Titanium.Web.Proxy
...
@@ -243,7 +249,7 @@ namespace Titanium.Web.Proxy
}
}
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
);
clientStreamWriter
=
new
HttpResponseWriter
(
clientStream
,
BufferSize
);
//now read the request line
//now read the request line
string
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
string
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
...
@@ -354,12 +360,15 @@ namespace Titanium.Web.Proxy
...
@@ -354,12 +360,15 @@ namespace Titanium.Web.Proxy
break
;
break
;
}
}
//create a new connection if hostname changes
//create a new connection if hostname/upstream end point changes
if
(
connection
!=
null
&&
!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
))
if
(
connection
!=
null
&&
(!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
)
||
(
args
.
WebSession
.
UpStreamEndPoint
!=
null
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
{
{
connection
.
Dispose
();
connection
.
Dispose
();
UpdateServerConnectionCount
(
false
);
connection
=
null
;
connection
=
null
;
UpdateServerConnectionCount
(
false
);
}
}
if
(
connection
==
null
)
if
(
connection
==
null
)
...
@@ -374,7 +383,7 @@ namespace Titanium.Web.Proxy
...
@@ -374,7 +383,7 @@ namespace Titanium.Web.Proxy
var
requestHeaders
=
args
.
WebSession
.
Request
.
RequestHeaders
;
var
requestHeaders
=
args
.
WebSession
.
Request
.
RequestHeaders
;
byte
[]
requestBytes
;
byte
[]
requestBytes
;
using
(
var
ms
=
new
MemoryStream
())
using
(
var
ms
=
new
MemoryStream
())
using
(
var
writer
=
new
HttpRequestWriter
(
ms
))
using
(
var
writer
=
new
HttpRequestWriter
(
ms
,
BufferSize
))
{
{
writer
.
WriteLine
(
httpCmd
);
writer
.
WriteLine
(
httpCmd
);
writer
.
WriteHeaders
(
requestHeaders
);
writer
.
WriteHeaders
(
requestHeaders
);
...
@@ -402,7 +411,7 @@ namespace Titanium.Web.Proxy
...
@@ -402,7 +411,7 @@ namespace Titanium.Web.Proxy
await
BeforeResponse
.
InvokeParallelAsync
(
this
,
args
,
ExceptionFunc
);
await
BeforeResponse
.
InvokeParallelAsync
(
this
,
args
,
ExceptionFunc
);
}
}
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
BufferSize
,
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
});
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
});
args
.
Dispose
();
args
.
Dispose
();
...
@@ -599,6 +608,7 @@ namespace Titanium.Web.Proxy
...
@@ -599,6 +608,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
IsHttps
,
isConnect
,
args
.
IsHttps
,
isConnect
,
args
.
WebSession
.
UpStreamEndPoint
??
UpStreamEndPoint
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
);
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
);
}
}
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.Standard.csproj
View file @
99e3b575
...
@@ -3,6 +3,10 @@
...
@@ -3,6 +3,10 @@
<PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
<RootNamespace>Titanium.Web.Proxy</RootNamespace>
<RootNamespace>Titanium.Web.Proxy</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
...
@@ -10,7 +14,6 @@
...
@@ -10,7 +14,6 @@
</PropertyGroup>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<Compile Remove="Properties\AssemblyInfo.cs" />
<Compile Remove="Helpers\WinHttp\NativeMethods.WinHttp.cs" />
<Compile Remove="Helpers\WinHttp\NativeMethods.WinHttp.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
99e3b575
...
@@ -84,7 +84,7 @@
...
@@ -84,7 +84,7 @@
<Compile
Include=
"Exceptions\ProxyException.cs"
/>
<Compile
Include=
"Exceptions\ProxyException.cs"
/>
<Compile
Include=
"Exceptions\ProxyHttpException.cs"
/>
<Compile
Include=
"Exceptions\ProxyHttpException.cs"
/>
<Compile
Include=
"Extensions\ByteArrayExtensions.cs"
/>
<Compile
Include=
"Extensions\ByteArrayExtensions.cs"
/>
<Compile
Include=
"Extensions\DotNet
Standard
Extensions.cs"
/>
<Compile
Include=
"Extensions\DotNet
45
Extensions.cs"
/>
<Compile
Include=
"Extensions\FuncExtensions.cs"
/>
<Compile
Include=
"Extensions\FuncExtensions.cs"
/>
<Compile
Include=
"Extensions\HttpWebRequestExtensions.cs"
/>
<Compile
Include=
"Extensions\HttpWebRequestExtensions.cs"
/>
<Compile
Include=
"Extensions\HttpWebResponseExtensions.cs"
/>
<Compile
Include=
"Extensions\HttpWebResponseExtensions.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment