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
749fb44d
Commit
749fb44d
authored
Jun 17, 2016
by
justcoding121
Committed by
justcoding121
Jun 17, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make proxy server non-static object
parent
ec62c8be
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
291 additions
and
228 deletions
+291
-228
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+20
-15
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+2
-2
DefaultDecompression.cs
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
+1
-1
DeflateDecompression.cs
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
+2
-2
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+2
-2
IDecompression.cs
Titanium.Web.Proxy/Decompression/IDecompression.cs
+1
-1
ZlibDecompression.cs
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
+2
-2
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+31
-17
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+14
-14
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+5
-5
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+3
-3
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+14
-12
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+5
-4
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+4
-4
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+11
-4
TcpConnectionCache.cs
Titanium.Web.Proxy/Network/TcpConnectionCache.cs
+2
-2
TcpConnectionCacheManager.cs
Titanium.Web.Proxy/Network/TcpConnectionCacheManager.cs
+35
-27
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+98
-73
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+28
-23
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+8
-8
ProxyConstants.cs
Titanium.Web.Proxy/Shared/ProxyConstants.cs
+1
-5
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+2
-2
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
749fb44d
using
System
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Text.RegularExpressions
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
...
...
@@ -10,12 +8,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public
class
ProxyTestController
{
private
ProxyServer
proxyServer
;
public
ProxyTestController
()
{
proxyServer
=
new
ProxyServer
();
}
public
void
StartProxy
()
{
P
roxyServer
.
BeforeRequest
+=
OnRequest
;
P
roxyServer
.
BeforeResponse
+=
OnResponse
;
P
roxyServer
.
ServerCertificateValidationCallback
+=
OnCertificateValidation
;
P
roxyServer
.
ClientCertificateSelectionCallback
+=
OnCertificateSelection
;
p
roxyServer
.
BeforeRequest
+=
OnRequest
;
p
roxyServer
.
BeforeResponse
+=
OnResponse
;
p
roxyServer
.
ServerCertificateValidationCallback
+=
OnCertificateValidation
;
p
roxyServer
.
ClientCertificateSelectionCallback
+=
OnCertificateSelection
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
...
...
@@ -27,8 +32,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
//An explicit endpoint is where the client knows about the existance of a proxy
//So client sends request in a proxy friendly manner
P
roxyServer
.
AddEndPoint
(
explicitEndPoint
);
P
roxyServer
.
Start
();
p
roxyServer
.
AddEndPoint
(
explicitEndPoint
);
p
roxyServer
.
Start
();
//Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy)
...
...
@@ -41,26 +46,26 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
GenericCertificateName
=
"google.com"
};
P
roxyServer
.
AddEndPoint
(
transparentEndPoint
);
p
roxyServer
.
AddEndPoint
(
transparentEndPoint
);
//ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
foreach
(
var
endPoint
in
P
roxyServer
.
ProxyEndPoints
)
foreach
(
var
endPoint
in
p
roxyServer
.
ProxyEndPoints
)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
//Only explicit proxies can be set as system proxy!
P
roxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
P
roxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
p
roxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
p
roxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
}
public
void
Stop
()
{
P
roxyServer
.
BeforeRequest
-=
OnRequest
;
P
roxyServer
.
BeforeResponse
-=
OnResponse
;
p
roxyServer
.
BeforeRequest
-=
OnRequest
;
p
roxyServer
.
BeforeResponse
-=
OnResponse
;
P
roxyServer
.
Stop
();
p
roxyServer
.
Stop
();
}
//intecept & cancel, redirect or update requests
...
...
Titanium.Web.Proxy/CertificateHandler.cs
View file @
749fb44d
...
...
@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal
static
bool
ValidateServerCertificate
(
internal
bool
ValidateServerCertificate
(
object
sender
,
X509Certificate
certificate
,
X509Chain
chain
,
...
...
@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal
static
X509Certificate
SelectClientCertificate
(
internal
X509Certificate
SelectClientCertificate
(
object
sender
,
string
targetHost
,
X509CertificateCollection
localCertificates
,
...
...
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
View file @
749fb44d
...
...
@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal
class
DefaultDecompression
:
IDecompression
{
public
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
public
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
{
return
Task
.
FromResult
(
compressedArray
);
}
...
...
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
View file @
749fb44d
...
...
@@ -10,13 +10,13 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal
class
DeflateDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
{
var
stream
=
new
MemoryStream
(
compressedArray
);
using
(
var
decompressor
=
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
))
{
var
buffer
=
new
byte
[
ProxyConstants
.
BUFFER_SIZE
];
var
buffer
=
new
byte
[
bufferSize
];
using
(
var
output
=
new
MemoryStream
())
{
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
749fb44d
...
...
@@ -10,11 +10,11 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal
class
GZipDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
{
using
(
var
decompressor
=
new
GZipStream
(
new
MemoryStream
(
compressedArray
),
CompressionMode
.
Decompress
))
{
var
buffer
=
new
byte
[
ProxyConstants
.
BUFFER_SIZE
];
var
buffer
=
new
byte
[
bufferSize
];
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
...
...
Titanium.Web.Proxy/Decompression/IDecompression.cs
View file @
749fb44d
...
...
@@ -7,6 +7,6 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal
interface
IDecompression
{
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
);
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
);
}
}
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
View file @
749fb44d
...
...
@@ -10,12 +10,12 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal
class
ZlibDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
{
var
memoryStream
=
new
MemoryStream
(
compressedArray
);
using
(
var
decompressor
=
new
ZlibStream
(
memoryStream
,
CompressionMode
.
Decompress
))
{
var
buffer
=
new
byte
[
ProxyConstants
.
BUFFER_SIZE
];
var
buffer
=
new
byte
[
bufferSize
];
using
(
var
output
=
new
MemoryStream
())
{
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
749fb44d
...
...
@@ -20,14 +20,16 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
class
SessionEventArgs
:
EventArgs
,
IDisposable
{
/// <summary>
///
Constructor to initialize the proxy
///
Size of Buffers used by this object
/// </summary>
internal
SessionEventArgs
()
{
ProxyClient
=
new
ProxyClient
();
WebSession
=
new
HttpWebClient
();
}
private
readonly
int
bufferSize
;
/// <summary>
/// Holds a reference to proxy response handler method
/// </summary>
private
readonly
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
;
/// <summary>
/// Holds a reference to client
...
...
@@ -50,13 +52,18 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
///
implement any cleanup here
///
Constructor to initialize the proxy
/// </summary>
public
void
Dispose
(
)
internal
SessionEventArgs
(
int
bufferSize
,
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
)
{
this
.
bufferSize
=
bufferSize
;
this
.
httpResponseHandler
=
httpResponseHandler
;
ProxyClient
=
new
ProxyClient
();
WebSession
=
new
HttpWebClient
();
}
/// <summary>
/// Read request body content as bytes[] for current session
/// </summary>
...
...
@@ -80,7 +87,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
WebSession
.
Request
.
IsChunked
)
{
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
requestBodyStream
);
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
}
else
{
...
...
@@ -88,11 +95,11 @@ namespace Titanium.Web.Proxy.EventArguments
if
(
WebSession
.
Request
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
}
else
if
(
WebSession
.
Request
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Request
.
HttpVersion
.
Minor
==
0
)
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
requestBodyStream
,
long
.
MaxValue
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
long
.
MaxValue
);
}
WebSession
.
Request
.
RequestBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Request
.
ContentEncoding
,
requestBodyStream
.
ToArray
());
}
...
...
@@ -117,18 +124,18 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol
if
(
WebSession
.
Response
.
IsChunked
)
{
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStreamChunked
(
responseBodyStream
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
responseBodyStream
);
}
else
{
if
(
WebSession
.
Response
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
}
else
if
(
WebSession
.
Response
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
responseBodyStream
,
long
.
MaxValue
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
long
.
MaxValue
);
}
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
());
...
...
@@ -285,7 +292,7 @@ namespace Titanium.Web.Proxy.EventArguments
var
decompressionFactory
=
new
DecompressionFactory
();
var
decompressor
=
decompressionFactory
.
Create
(
encodingType
);
return
await
decompressor
.
Decompress
(
responseBodyStream
);
return
await
decompressor
.
Decompress
(
responseBodyStream
,
bufferSize
);
}
...
...
@@ -338,7 +345,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Request
.
CancelRequest
=
true
;
}
/// a generic responder method
public
async
Task
Respond
(
Response
response
)
{
...
...
@@ -349,8 +356,15 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Response
=
response
;
await
ProxyServer
.
HandleHttpSessionResponse
(
this
);
await
httpResponseHandler
(
this
);
}
/// <summary>
/// implement any cleanup here
/// </summary>
public
void
Dispose
()
{
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
749fb44d
...
...
@@ -35,22 +35,22 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="stream"></param>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal
static
async
Task
CopyBytesToStream
(
this
CustomBinaryReader
streamReader
,
Stream
stream
,
long
totalBytesToRead
)
internal
static
async
Task
CopyBytesToStream
(
this
CustomBinaryReader
streamReader
,
int
bufferSize
,
Stream
stream
,
long
totalBytesToRead
)
{
var
totalbytesRead
=
0
;
long
bytesToRead
;
if
(
totalBytesToRead
<
ProxyConstants
.
BUFFER_SIZE
)
if
(
totalBytesToRead
<
bufferSize
)
{
bytesToRead
=
totalBytesToRead
;
}
else
bytesToRead
=
ProxyConstants
.
BUFFER_SIZE
;
bytesToRead
=
bufferSize
;
while
(
totalbytesRead
<
totalBytesToRead
)
{
var
buffer
=
await
streamReader
.
ReadBytesAsync
(
bytesToRead
);
var
buffer
=
await
streamReader
.
ReadBytesAsync
(
b
ufferSize
,
b
ytesToRead
);
if
(
buffer
.
Length
==
0
)
break
;
...
...
@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="clientStreamReader"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal
static
async
Task
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
)
internal
static
async
Task
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
int
bufferSize
,
Stream
stream
)
{
while
(
true
)
{
...
...
@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Extensions
if
(
chunkSize
!=
0
)
{
var
buffer
=
await
clientStreamReader
.
ReadBytesAsync
(
chunkSize
);
var
buffer
=
await
clientStreamReader
.
ReadBytesAsync
(
bufferSize
,
chunkSize
);
await
stream
.
WriteAsync
(
buffer
,
0
,
buffer
.
Length
);
//chunk trail
await
clientStreamReader
.
ReadLineAsync
();
...
...
@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="isChunked"></param>
/// <param name="ContentLength"></param>
/// <returns></returns>
internal
static
async
Task
WriteResponseBody
(
this
CustomBinaryReader
inStreamReader
,
Stream
outStream
,
bool
isChunked
,
long
ContentLength
)
internal
static
async
Task
WriteResponseBody
(
this
CustomBinaryReader
inStreamReader
,
int
bufferSize
,
Stream
outStream
,
bool
isChunked
,
long
ContentLength
)
{
if
(!
isChunked
)
{
...
...
@@ -126,12 +126,12 @@ namespace Titanium.Web.Proxy.Extensions
if
(
ContentLength
==
-
1
)
ContentLength
=
long
.
MaxValue
;
int
bytesToRead
=
ProxyConstants
.
BUFFER_SIZE
;
int
bytesToRead
=
bufferSize
;
if
(
ContentLength
<
ProxyConstants
.
BUFFER_SIZE
)
if
(
ContentLength
<
bufferSize
)
bytesToRead
=
(
int
)
ContentLength
;
var
buffer
=
new
byte
[
ProxyConstants
.
BUFFER_SIZE
];
var
buffer
=
new
byte
[
bufferSize
];
var
bytesRead
=
0
;
var
totalBytesRead
=
0
;
...
...
@@ -146,11 +146,11 @@ namespace Titanium.Web.Proxy.Extensions
bytesRead
=
0
;
var
remainingBytes
=
(
ContentLength
-
totalBytesRead
);
bytesToRead
=
remainingBytes
>
(
long
)
ProxyConstants
.
BUFFER_SIZE
?
ProxyConstants
.
BUFFER_SIZE
:
(
int
)
remainingBytes
;
bytesToRead
=
remainingBytes
>
(
long
)
bufferSize
?
bufferSize
:
(
int
)
remainingBytes
;
}
}
else
await
WriteResponseBodyChunked
(
inStreamReader
,
outStream
);
await
WriteResponseBodyChunked
(
inStreamReader
,
bufferSize
,
outStream
);
}
/// <summary>
...
...
@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="inStreamReader"></param>
/// <param name="outStream"></param>
/// <returns></returns>
internal
static
async
Task
WriteResponseBodyChunked
(
this
CustomBinaryReader
inStreamReader
,
Stream
outStream
)
internal
static
async
Task
WriteResponseBodyChunked
(
this
CustomBinaryReader
inStreamReader
,
int
bufferSize
,
Stream
outStream
)
{
while
(
true
)
{
...
...
@@ -168,7 +168,7 @@ namespace Titanium.Web.Proxy.Extensions
if
(
chunkSize
!=
0
)
{
var
buffer
=
await
inStreamReader
.
ReadBytesAsync
(
chunkSize
);
var
buffer
=
await
inStreamReader
.
ReadBytesAsync
(
bufferSize
,
chunkSize
);
var
chunkHeadBytes
=
Encoding
.
ASCII
.
GetBytes
(
chunkSize
.
ToString
(
"x2"
));
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
749fb44d
...
...
@@ -91,14 +91,14 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
long
totalBytesToRead
)
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
int
bufferSize
,
long
totalBytesToRead
)
{
int
bytesToRead
=
ProxyConstants
.
BUFFER_SIZE
;
int
bytesToRead
=
bufferSize
;
if
(
totalBytesToRead
<
ProxyConstants
.
BUFFER_SIZE
)
if
(
totalBytesToRead
<
bufferSize
)
bytesToRead
=
(
int
)
totalBytesToRead
;
var
buffer
=
new
byte
[
ProxyConstants
.
BUFFER_SIZE
];
var
buffer
=
new
byte
[
bufferSize
];
var
bytesRead
=
0
;
var
totalBytesRead
=
0
;
...
...
@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy.Helpers
bytesRead
=
0
;
var
remainingBytes
=
(
totalBytesToRead
-
totalBytesRead
);
bytesToRead
=
remainingBytes
>
(
long
)
ProxyConstants
.
BUFFER_SIZE
?
ProxyConstants
.
BUFFER_SIZE
:
(
int
)
remainingBytes
;
bytesToRead
=
remainingBytes
>
(
long
)
bufferSize
?
bufferSize
:
(
int
)
remainingBytes
;
}
return
outStream
.
ToArray
();
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
749fb44d
...
...
@@ -6,9 +6,9 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// A helper class to set proxy settings for firefox
/// </summary>
public
class
FireFox
Help
er
public
class
FireFox
ProxySettingsManag
er
{
public
static
void
AddFirefox
()
public
void
AddFirefox
()
{
try
{
...
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
public
static
void
RemoveFirefox
()
public
void
RemoveFirefox
()
{
try
{
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
749fb44d
...
...
@@ -11,7 +11,7 @@ using System.Linq;
namespace
Titanium.Web.Proxy.Helpers
{
internal
static
class
NativeMethods
internal
class
NativeMethods
{
[
DllImport
(
"wininet.dll"
)]
internal
static
extern
bool
InternetSetOption
(
IntPtr
hInternet
,
int
dwOption
,
IntPtr
lpBuffer
,
...
...
@@ -32,13 +32,15 @@ namespace Titanium.Web.Proxy.Helpers
return
"https="
+
HostName
+
":"
+
Port
;
}
}
internal
static
class
SystemProxyHelper
/// <summary>
/// Manage system proxy settings
/// </summary>
internal
class
SystemProxyManager
{
internal
const
int
InternetOptionSettingsChanged
=
39
;
internal
const
int
InternetOptionRefresh
=
37
;
internal
static
void
SetHttpProxy
(
string
hostname
,
int
port
)
internal
void
SetHttpProxy
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
...
...
@@ -66,7 +68,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Remove the http proxy setting from current machine
/// </summary>
internal
static
void
RemoveHttpProxy
()
internal
void
RemoveHttpProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
...
...
@@ -100,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
internal
static
void
SetHttpsProxy
(
string
hostname
,
int
port
)
internal
void
SetHttpsProxy
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
...
...
@@ -130,7 +132,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Removes the https proxy setting to nothing
/// </summary>
internal
static
void
RemoveHttpsProxy
()
internal
void
RemoveHttpsProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
...
...
@@ -163,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Removes all types of proxy settings (both http & https)
/// </summary>
internal
static
void
DisableAllProxy
()
internal
void
DisableAllProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
...
...
@@ -182,7 +184,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="prevServerValue"></param>
/// <returns></returns>
private
static
List
<
HttpSystemProxyValue
>
GetSystemProxyValues
(
string
prevServerValue
)
private
List
<
HttpSystemProxyValue
>
GetSystemProxyValues
(
string
prevServerValue
)
{
var
result
=
new
List
<
HttpSystemProxyValue
>();
...
...
@@ -215,7 +217,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private
static
HttpSystemProxyValue
parseProxyValue
(
string
value
)
private
HttpSystemProxyValue
parseProxyValue
(
string
value
)
{
var
tmp
=
Regex
.
Replace
(
value
,
@"\s+"
,
" "
).
Trim
().
ToLower
();
if
(
tmp
.
StartsWith
(
"http="
))
...
...
@@ -245,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers
/// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary>
/// <param name="reg"></param>
private
static
void
prepareRegistry
(
RegistryKey
reg
)
private
void
prepareRegistry
(
RegistryKey
reg
)
{
if
(
reg
.
GetValue
(
"ProxyEnable"
)
==
null
)
{
...
...
@@ -262,7 +264,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Refresh the settings so that the system know about a change in proxy setting
/// </summary>
private
static
void
Refresh
()
private
void
Refresh
()
{
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionSettingsChanged
,
IntPtr
.
Zero
,
0
);
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionRefresh
,
IntPtr
.
Zero
,
0
);
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
749fb44d
...
...
@@ -4,6 +4,7 @@ using System.IO;
using
System.Linq
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Security.Authentication
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
...
...
@@ -12,7 +13,7 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Helpers
{
internal
class
TcpHelper
{
/// <summary>
...
...
@@ -26,8 +27,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="tunnelPort"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
internal
async
stati
c
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
)
internal
static
asyn
c
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
,
SslProtocols
supportedProtocols
)
{
//prepare the prefix content
StringBuilder
sb
=
null
;
...
...
@@ -63,7 +64,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
sslStream
=
new
SslStream
(
tunnelStream
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostName
,
null
,
ProxyConstants
.
SupportedSsl
Protocols
,
false
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostName
,
null
,
supported
Protocols
,
false
);
tunnelStream
=
sslStream
;
}
catch
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
749fb44d
...
...
@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Connection to server
/// </summary>
internal
TcpConnection
ServerConnection
{
get
;
set
;
}
internal
TcpConnection
Cache
ServerConnection
{
get
;
set
;
}
public
Request
Request
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
...
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
/// Set the tcp connection to server used by this webclient
/// </summary>
/// <param name="Connection"></param>
internal
void
SetConnection
(
TcpConnection
Connection
)
internal
void
SetConnection
(
TcpConnection
Cache
Connection
)
{
Connection
.
LastAccess
=
DateTime
.
Now
;
ServerConnection
=
Connection
;
...
...
@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.Http
/// Prepare & send the http(s) request
/// </summary>
/// <returns></returns>
internal
async
Task
SendRequest
()
internal
async
Task
SendRequest
(
bool
enable100ContinueBehaviour
)
{
Stream
stream
=
ServerConnection
.
Stream
;
...
...
@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
await
stream
.
WriteAsync
(
requestBytes
,
0
,
requestBytes
.
Length
);
await
stream
.
FlushAsync
();
if
(
ProxyServer
.
E
nable100ContinueBehaviour
)
if
(
e
nable100ContinueBehaviour
)
if
(
this
.
Request
.
ExpectContinue
)
{
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
749fb44d
...
...
@@ -18,8 +18,15 @@ namespace Titanium.Web.Proxy.Network
private
const
string
CertCreateFormat
=
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 {5}"
;
/// <summary>
/// Cache dictionary
/// </summary>
private
readonly
IDictionary
<
string
,
CachedCertificate
>
certificateCache
;
private
static
SemaphoreSlim
semaphoreLock
=
new
SemaphoreSlim
(
1
);
/// <summary>
/// A lock to manage concurrency
/// </summary>
private
SemaphoreSlim
semaphoreLock
=
new
SemaphoreSlim
(
1
);
internal
string
Issuer
{
get
;
private
set
;
}
internal
string
RootCertificateName
{
get
;
private
set
;
}
...
...
@@ -241,7 +248,7 @@ namespace Titanium.Web.Proxy.Network
return
certCreatArgs
;
}
private
static
bool
clearCertificates
{
get
;
set
;
}
private
bool
clearCertificates
{
get
;
set
;
}
/// <summary>
/// Stops the certificate cache clear process
...
...
@@ -254,7 +261,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// A method to clear outdated certificates
/// </summary>
internal
async
void
ClearIdleCertificates
()
internal
async
void
ClearIdleCertificates
(
int
certificateCacheTimeOutMinutes
)
{
clearCertificates
=
true
;
while
(
clearCertificates
)
...
...
@@ -263,7 +270,7 @@ namespace Titanium.Web.Proxy.Network
try
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
ProxyServer
.
C
ertificateCacheTimeOutMinutes
);
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
c
ertificateCacheTimeOutMinutes
);
var
outdated
=
certificateCache
.
Where
(
x
=>
x
.
Value
.
LastAccess
<
cutOff
)
...
...
Titanium.Web.Proxy/Network/TcpConnection.cs
→
Titanium.Web.Proxy/Network/TcpConnection
Cache
.cs
View file @
749fb44d
...
...
@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// An object that holds TcpConnection to a particular server & port
/// </summary>
public
class
TcpConnection
public
class
TcpConnection
Cache
{
internal
string
HostName
{
get
;
set
;
}
internal
int
port
{
get
;
set
;
}
...
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal
DateTime
LastAccess
{
get
;
set
;
}
internal
TcpConnection
()
internal
TcpConnection
Cache
()
{
LastAccess
=
DateTime
.
Now
;
}
...
...
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
→
Titanium.Web.Proxy/Network/TcpConnection
Cache
Manager.cs
View file @
749fb44d
...
...
@@ -10,23 +10,25 @@ using Titanium.Web.Proxy.Helpers;
using
System.Threading
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Authentication
;
namespace
Titanium.Web.Proxy.Network
{
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
internal
class
TcpConnectionManager
internal
class
TcpConnection
Cache
Manager
{
/// <summary>
/// Connection cache
/// </summary>
static
Dictionary
<
string
,
List
<
TcpConnection
>>
connectionCache
=
new
Dictionary
<
string
,
List
<
TcpConnection
>>();
Dictionary
<
string
,
List
<
TcpConnectionCache
>>
connectionCache
=
new
Dictionary
<
string
,
List
<
TcpConnectionCache
>>();
/// <summary>
/// A lock to manage concurrency
/// </summary>
static
SemaphoreSlim
connectionAccessLock
=
new
SemaphoreSlim
(
1
);
SemaphoreSlim
connectionAccessLock
=
new
SemaphoreSlim
(
1
);
/// <summary>
/// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version
...
...
@@ -36,10 +38,12 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
static
async
Task
<
TcpConnection
>
GetClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
internal
async
Task
<
TcpConnectionCache
>
GetClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
ExternalProxy
upStreamHttpProxy
,
ExternalProxy
upStreamHttpsProxy
,
int
bufferSize
,
SslProtocols
supportedSslProtocols
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallBack
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
)
{
List
<
TcpConnection
>
cachedConnections
=
null
;
TcpConnection
cached
=
null
;
List
<
TcpConnection
Cache
>
cachedConnections
=
null
;
TcpConnection
Cache
cached
=
null
;
//Get a unique string to identify this connection
var
key
=
GetConnectionKey
(
hostname
,
port
,
isHttps
,
version
);
...
...
@@ -77,12 +81,14 @@ namespace Titanium.Web.Proxy.Network
if
(
cached
==
null
)
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
);
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
if
(
cachedConnections
==
null
||
cachedConnections
.
Count
()
<=
2
)
{
var
task
=
CreateClient
(
hostname
,
port
,
isHttps
,
version
)
.
ContinueWith
(
async
(
x
)
=>
{
if
(
x
.
Status
==
TaskStatus
.
RanToCompletion
)
await
ReleaseClient
(
x
.
Result
);
});
var
task
=
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
)
.
ContinueWith
(
async
(
x
)
=>
{
if
(
x
.
Status
==
TaskStatus
.
RanToCompletion
)
await
ReleaseClient
(
x
.
Result
);
});
}
return
cached
;
...
...
@@ -96,7 +102,7 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
st
atic
st
ring
GetConnectionKey
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
internal
string
GetConnectionKey
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
{
return
string
.
Format
(
"{0}:{1}:{2}:{3}:{4}"
,
hostname
.
ToLower
(),
port
,
isHttps
,
version
.
Major
,
version
.
Minor
);
}
...
...
@@ -109,7 +115,9 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
private
static
async
Task
<
TcpConnection
>
CreateClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
private
async
Task
<
TcpConnectionCache
>
CreateClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
,
ExternalProxy
upStreamHttpProxy
,
ExternalProxy
upStreamHttpsProxy
,
int
bufferSize
,
SslProtocols
supportedSslProtocols
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallBack
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
)
{
TcpClient
client
;
Stream
stream
;
...
...
@@ -119,12 +127,12 @@ namespace Titanium.Web.Proxy.Network
SslStream
sslStream
=
null
;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if
(
ProxyServer
.
U
pStreamHttpsProxy
!=
null
)
if
(
u
pStreamHttpsProxy
!=
null
)
{
client
=
new
TcpClient
(
ProxyServer
.
UpStreamHttpsProxy
.
HostName
,
ProxyServer
.
U
pStreamHttpsProxy
.
Port
);
client
=
new
TcpClient
(
upStreamHttpsProxy
.
HostName
,
u
pStreamHttpsProxy
.
Port
);
stream
=
(
Stream
)
client
.
GetStream
();
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
ProxyConstants
.
BUFFER_SIZE
,
true
))
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
true
))
{
await
writer
.
WriteLineAsync
(
string
.
Format
(
"CONNECT {0}:{1} {2}"
,
hostname
,
port
,
version
));
await
writer
.
WriteLineAsync
(
string
.
Format
(
"Host: {0}:{1}"
,
hostname
,
port
));
...
...
@@ -152,9 +160,9 @@ namespace Titanium.Web.Proxy.Network
try
{
sslStream
=
new
SslStream
(
stream
,
true
,
new
RemoteCertificateValidationCallback
(
ProxyServer
.
ValidateServerCertificate
)
,
new
LocalCertificateSelectionCallback
(
ProxyServer
.
SelectClientCertificate
)
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
ProxyConstants
.
S
upportedSslProtocols
,
false
);
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
s
upportedSslProtocols
,
false
);
stream
=
(
Stream
)
sslStream
;
}
catch
...
...
@@ -166,9 +174,9 @@ namespace Titanium.Web.Proxy.Network
}
else
{
if
(
ProxyServer
.
U
pStreamHttpProxy
!=
null
)
if
(
u
pStreamHttpProxy
!=
null
)
{
client
=
new
TcpClient
(
ProxyServer
.
UpStreamHttpProxy
.
HostName
,
ProxyServer
.
U
pStreamHttpProxy
.
Port
);
client
=
new
TcpClient
(
upStreamHttpProxy
.
HostName
,
u
pStreamHttpProxy
.
Port
);
stream
=
(
Stream
)
client
.
GetStream
();
}
else
...
...
@@ -178,7 +186,7 @@ namespace Titanium.Web.Proxy.Network
}
}
return
new
TcpConnection
()
return
new
TcpConnection
Cache
()
{
HostName
=
hostname
,
port
=
port
,
...
...
@@ -195,7 +203,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
internal
static
async
Task
ReleaseClient
(
TcpConnection
connection
)
internal
async
Task
ReleaseClient
(
TcpConnectionCache
connection
)
{
connection
.
LastAccess
=
DateTime
.
Now
;
...
...
@@ -203,25 +211,25 @@ namespace Titanium.Web.Proxy.Network
await
connectionAccessLock
.
WaitAsync
();
try
{
List
<
TcpConnection
>
cachedConnections
;
List
<
TcpConnection
Cache
>
cachedConnections
;
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
if
(
cachedConnections
!=
null
)
cachedConnections
.
Add
(
connection
);
else
connectionCache
.
Add
(
key
,
new
List
<
TcpConnection
>()
{
connection
});
connectionCache
.
Add
(
key
,
new
List
<
TcpConnection
Cache
>()
{
connection
});
}
finally
{
connectionAccessLock
.
Release
();
}
}
private
static
bool
clearConenctions
{
get
;
set
;
}
private
bool
clearConenctions
{
get
;
set
;
}
/// <summary>
/// Stop clearing idle connections
/// </summary>
internal
static
void
StopClearIdleConnections
()
internal
void
StopClearIdleConnections
()
{
clearConenctions
=
false
;
}
...
...
@@ -229,7 +237,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// A method to clear idle connections
/// </summary>
internal
async
static
void
ClearIdleConnections
(
)
internal
async
void
ClearIdleConnections
(
int
connectionCacheTimeOutMinutes
)
{
clearConenctions
=
true
;
while
(
clearConenctions
)
...
...
@@ -237,7 +245,7 @@ namespace Titanium.Web.Proxy.Network
await
connectionAccessLock
.
WaitAsync
();
try
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
ProxyServer
.
C
onnectionCacheTimeOutMinutes
);
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
c
onnectionCacheTimeOutMinutes
);
connectionCache
.
SelectMany
(
x
=>
x
.
Value
)
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
749fb44d
...
...
@@ -8,125 +8,150 @@ using Titanium.Web.Proxy.Helpers;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
System.Linq
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Net.Security
;
using
System.Security.Authentication
;
namespace
Titanium.Web.Proxy
{
/// <summary>
/// Proxy Server Main class
/// </summary>
public
partial
class
ProxyServer
public
partial
class
ProxyServer
:
IDisposable
{
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
private
CertificateManager
certificateCacheManager
{
get
;
set
;
}
static
ProxyServer
()
{
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
//default values
ConnectionCacheTimeOutMinutes
=
3
;
CertificateCacheTimeOutMinutes
=
60
;
}
/// <summary>
/// A object that manages tcp connection cache to server
/// </summary>
private
TcpConnectionCacheManager
tcpConnectionCacheManager
{
get
;
set
;
}
/// <summary>
/// Manage
s certificates used by this proxy
/// Manage
system proxy settings
/// </summary>
private
static
CertificateManager
CertManager
{
get
;
set
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
set
;
}
private
FireFoxProxySettingsManager
firefoxProxySettingsManager
{
get
;
set
;
}
/// <summary>
/// Does the root certificate used by this proxy is trusted by the machine?
/// </summary>
private
static
bool
certTrusted
{
get
;
set
;
}
private
bool
certTrusted
{
get
;
set
;
}
/// <summary>
/// Is the proxy currently running
/// </summary>
private
static
bool
proxyRunning
{
get
;
set
;
}
private
bool
proxyRunning
{
get
;
set
;
}
/// <summary>
/// Buffer size used throughout this proxy
/// </summary>
public
int
BUFFER_SIZE
{
get
;
set
;
}
=
8192
;
/// <summary>
/// Name of the root certificate issuer
/// </summary>
public
st
atic
st
ring
RootCertificateIssuerName
{
get
;
set
;
}
public
string
RootCertificateIssuerName
{
get
;
set
;
}
/// <summary>
/// Name of the root certificate
/// </summary>
public
st
atic
st
ring
RootCertificateName
{
get
;
set
;
}
public
string
RootCertificateName
{
get
;
set
;
}
/// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 contunue implementations on server/client may cause problems if enabled
/// </summary>
public
static
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
public
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
/// <summary>
/// Minutes TCP connection cache to servers to be kept alive when in idle state
/// </summary>
public
static
int
ConnectionCacheTimeOutMinutes
{
get
;
set
;
}
public
int
ConnectionCacheTimeOutMinutes
{
get
;
set
;
}
/// <summary>
/// Minutes certificates should be kept in cache when not used
/// </summary>
public
static
int
CertificateCacheTimeOutMinutes
{
get
;
set
;
}
public
int
CertificateCacheTimeOutMinutes
{
get
;
set
;
}
/// <summary>
/// Intercept request to server
/// </summary>
public
static
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
/// <summary>
/// Intercept response from server
/// </summary>
public
static
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeResponse
;
public
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeResponse
;
/// <summary>
/// External proxy for Http
/// </summary>
public
static
ExternalProxy
UpStreamHttpProxy
{
get
;
set
;
}
public
ExternalProxy
UpStreamHttpProxy
{
get
;
set
;
}
/// <summary>
/// External proxy for Http
/// </summary>
public
static
ExternalProxy
UpStreamHttpsProxy
{
get
;
set
;
}
public
ExternalProxy
UpStreamHttpsProxy
{
get
;
set
;
}
/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// </summary>
public
static
event
Func
<
object
,
CertificateValidationEventArgs
,
Task
>
ServerCertificateValidationCallback
;
public
event
Func
<
object
,
CertificateValidationEventArgs
,
Task
>
ServerCertificateValidationCallback
;
/// <summary>
/// Callback tooverride client certificate during SSL mutual authentication
/// </summary>
public
static
event
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>
ClientCertificateSelectionCallback
;
public
event
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>
ClientCertificateSelectionCallback
;
/// <summary>
/// A list of IpAddress & port this proxy is listening to
/// </summary>
public
static
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
public
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
/// <summary>
///
Initialize the proxy
///
List of supported Ssl versions
/// </summary>
public
static
void
Initialize
()
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
/// <summary>
/// Constructor
/// </summary>
public
ProxyServer
()
{
TcpConnectionManager
.
ClearIdleConnections
();
CertManager
.
ClearIdleCertificates
();
//default values
ConnectionCacheTimeOutMinutes
=
3
;
CertificateCacheTimeOutMinutes
=
60
;
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
tcpConnectionCacheManager
=
new
TcpConnectionCacheManager
();
systemProxySettingsManager
=
new
SystemProxyManager
();
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
RootCertificateName
=
RootCertificateName
??
"Titanium Root Certificate Authority"
;
RootCertificateIssuerName
=
RootCertificateIssuerName
??
"Titanium"
;
certificateCacheManager
=
new
CertificateManager
(
RootCertificateIssuerName
,
RootCertificateName
);
}
/// <summary>
///
Quit
the proxy
///
Initialize
the proxy
/// </summary>
public
static
void
Quit
()
public
void
Initialize
()
{
TcpConnectionManager
.
StopClearIdleConnections
(
);
CertManager
.
StopClearIdleCertificates
(
);
tcpConnectionCacheManager
.
ClearIdleConnections
(
ConnectionCacheTimeOutMinutes
);
certificateCacheManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
}
/// <summary>
/// Add a proxy end point
/// </summary>
/// <param name="endPoint"></param>
public
static
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
public
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
{
ProxyEndPoints
.
Add
(
endPoint
);
...
...
@@ -139,7 +164,7 @@ namespace Titanium.Web.Proxy
/// Will throw error if the end point does'nt exist
/// </summary>
/// <param name="endPoint"></param>
public
static
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
public
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
...
...
@@ -155,19 +180,19 @@ namespace Titanium.Web.Proxy
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public
static
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
public
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
{
ValidateEndPointAsSystemProxy
(
endPoint
);
//clear any settings previously added
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpProxy
=
false
);
SystemProxyHelp
er
.
SetHttpProxy
(
systemProxySettingsManag
er
.
SetHttpProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
endPoint
.
IsSystemHttpProxy
=
true
;
#if !DEBUG
FireFoxHelp
er
.
AddFirefox
();
firefoxProxySettingsManag
er
.
AddFirefox
();
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {1} and port: {2} as System HTTPS Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
...
...
@@ -176,16 +201,16 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Remove any HTTP proxy setting of current machien
/// </summary>
public
static
void
DisableSystemHttpProxy
()
public
void
DisableSystemHttpProxy
()
{
SystemProxyHelp
er
.
RemoveHttpProxy
();
systemProxySettingsManag
er
.
RemoveHttpProxy
();
}
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public
static
void
SetAsSystemHttpsProxy
(
ExplicitProxyEndPoint
endPoint
)
public
void
SetAsSystemHttpsProxy
(
ExplicitProxyEndPoint
endPoint
)
{
ValidateEndPointAsSystemProxy
(
endPoint
);
...
...
@@ -201,7 +226,7 @@ namespace Titanium.Web.Proxy
//If certificate was trusted by the machine
if
(
certTrusted
)
{
SystemProxyHelp
er
.
SetHttpsProxy
(
systemProxySettingsManag
er
.
SetHttpsProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
}
...
...
@@ -209,7 +234,7 @@ namespace Titanium.Web.Proxy
endPoint
.
IsSystemHttpsProxy
=
true
;
#if !DEBUG
FireFoxHelp
er
.
AddFirefox
();
firefoxProxySettingsManag
er
.
AddFirefox
();
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {1} and port: {2} as System HTTPS Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
...
...
@@ -217,34 +242,28 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Remove any HTTPS proxy setting for current machine
/// </summary>
public
static
void
DisableSystemHttpsProxy
()
public
void
DisableSystemHttpsProxy
()
{
SystemProxyHelp
er
.
RemoveHttpsProxy
();
systemProxySettingsManag
er
.
RemoveHttpsProxy
();
}
/// <summary>
/// Clear all proxy settings for current machine
/// </summary>
public
static
void
DisableAllSystemProxies
()
public
void
DisableAllSystemProxies
()
{
SystemProxyHelp
er
.
DisableAllProxy
();
systemProxySettingsManag
er
.
DisableAllProxy
();
}
/// <summary>
/// Start this proxy server
/// </summary>
public
static
void
Start
()
public
void
Start
()
{
if
(
proxyRunning
)
throw
new
Exception
(
"Proxy is already running."
);
RootCertificateName
=
RootCertificateName
??
"Titanium Root Certificate Authority"
;
RootCertificateIssuerName
=
RootCertificateIssuerName
??
"Titanium"
;
CertManager
=
new
CertificateManager
(
RootCertificateIssuerName
,
RootCertificateName
);
certTrusted
=
CertManager
.
CreateTrustedRootCertificate
().
Result
;
certTrusted
=
certificateCacheManager
.
CreateTrustedRootCertificate
().
Result
;
foreach
(
var
endPoint
in
ProxyEndPoints
)
{
...
...
@@ -259,7 +278,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Stop this proxy server
/// </summary>
public
static
void
Stop
()
public
void
Stop
()
{
if
(!
proxyRunning
)
throw
new
Exception
(
"Proxy is not running."
);
...
...
@@ -268,9 +287,9 @@ namespace Titanium.Web.Proxy
if
(
setAsSystemProxy
)
{
SystemProxyHelp
er
.
DisableAllProxy
();
systemProxySettingsManag
er
.
DisableAllProxy
();
#if !DEBUG
FireFoxHelp
er
.
RemoveFirefox
();
firefoxProxySettingsManag
er
.
RemoveFirefox
();
#endif
}
...
...
@@ -279,9 +298,8 @@ namespace Titanium.Web.Proxy
endPoint
.
listener
.
Stop
();
}
CertManager
.
Dispose
();
Quit
();
tcpConnectionCacheManager
.
StopClearIdleConnections
();
certificateCacheManager
.
StopClearIdleCertificates
();
proxyRunning
=
false
;
}
...
...
@@ -290,7 +308,7 @@ namespace Titanium.Web.Proxy
/// Listen on the given end point on local machine
/// </summary>
/// <param name="endPoint"></param>
private
static
void
Listen
(
ProxyEndPoint
endPoint
)
private
void
Listen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
listener
.
Start
();
...
...
@@ -304,7 +322,7 @@ namespace Titanium.Web.Proxy
/// Quit listening on the given end point
/// </summary>
/// <param name="endPoint"></param>
private
static
void
QuitListen
(
ProxyEndPoint
endPoint
)
private
void
QuitListen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
listener
.
Stop
();
}
...
...
@@ -313,7 +331,7 @@ namespace Titanium.Web.Proxy
/// Verifiy if its safe to set this end point as System proxy
/// </summary>
/// <param name="endPoint"></param>
private
static
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
...
...
@@ -326,7 +344,7 @@ namespace Titanium.Web.Proxy
/// When a connection is received from client act
/// </summary>
/// <param name="asyn"></param>
private
static
void
OnAcceptConnection
(
IAsyncResult
asyn
)
private
void
OnAcceptConnection
(
IAsyncResult
asyn
)
{
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
...
...
@@ -353,8 +371,15 @@ namespace Titanium.Web.Proxy
{
//Other errors are discarded to keep proxy running
}
}
public
void
Dispose
()
{
if
(
proxyRunning
)
Stop
();
certificateCacheManager
.
Dispose
();
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/RequestHandler.cs
View file @
749fb44d
...
...
@@ -13,8 +13,8 @@ using Titanium.Web.Proxy.Models;
using
System.Security.Cryptography.X509Certificates
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
namespace
Titanium.Web.Proxy
{
...
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy
partial
class
ProxyServer
{
//This is called when client is aware of proxy
private
static
async
void
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
client
)
private
async
void
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
client
)
{
Stream
clientStream
=
client
.
GetStream
();
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
);
...
...
@@ -82,14 +82,17 @@ namespace Titanium.Web.Proxy
{
//create the Tcp Connection to server and then release it to connection cache
//Just doing what CONNECT request is asking as to do
var
tunnelClient
=
await
TcpConnectionManager
.
GetClient
(
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
true
,
version
);
await
TcpConnectionManager
.
ReleaseClient
(
tunnelClient
);
var
tunnelClient
=
await
tcpConnectionCacheManager
.
GetClient
(
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
true
,
version
,
UpStreamHttpProxy
,
UpStreamHttpsProxy
,
BUFFER_SIZE
,
SupportedSslProtocols
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
),
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
));
await
tcpConnectionCacheManager
.
ReleaseClient
(
tunnelClient
);
sslStream
=
new
SslStream
(
clientStream
,
true
);
var
certificate
=
await
Cert
Manager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
var
certificate
=
await
certificateCache
Manager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
//Successfully managed to authenticate the client using the fake certificate
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
ProxyConstants
.
SupportedSslProtocols
,
false
);
SupportedSslProtocols
,
false
);
//HTTPS server created - we can now decrypt the client's traffic
clientStream
=
sslStream
;
...
...
@@ -120,7 +123,7 @@ namespace Titanium.Web.Proxy
//Just relay the request/response without decrypting it
await
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
false
,
SupportedSslProtocols
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
...
...
@@ -138,7 +141,7 @@ namespace Titanium.Web.Proxy
//This is called when requests are routed through router to this endpoint
//For ssl requests
private
static
async
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
async
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
Stream
clientStream
=
tcpClient
.
GetStream
();
CustomBinaryReader
clientStreamReader
=
null
;
...
...
@@ -150,7 +153,7 @@ namespace Titanium.Web.Proxy
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
//implement in future once SNI supported by SSL stream, for now use the same certificate
certificate
=
await
Cert
Manager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
certificate
=
await
certificateCache
Manager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
try
{
...
...
@@ -195,10 +198,10 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamWriter"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
private
static
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
bool
isHttps
)
{
TcpConnection
connection
=
null
;
TcpConnection
Cache
connection
=
null
;
//Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client)
...
...
@@ -210,7 +213,7 @@ namespace Titanium.Web.Proxy
break
;
}
var
args
=
new
SessionEventArgs
();
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
,
HandleHttpSessionResponse
);
args
.
ProxyClient
.
TcpClient
=
client
;
try
...
...
@@ -281,13 +284,15 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
await
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
IsHttps
);
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
IsHttps
,
SupportedSslProtocols
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
}
//construct the web request that we are going to issue on behalf of the client.
connection
=
await
TcpConnectionManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
);
connection
=
await
tcpConnectionCacheManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
,
UpStreamHttpProxy
,
UpStreamHttpsProxy
,
BUFFER_SIZE
,
SupportedSslProtocols
,
new
RemoteCertificateValidationCallback
(
ValidateServerCertificate
),
new
LocalCertificateSelectionCallback
(
SelectClientCertificate
));
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
...
...
@@ -303,7 +308,7 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
{
args
.
WebSession
.
SetConnection
(
connection
);
await
args
.
WebSession
.
SendRequest
();
await
args
.
WebSession
.
SendRequest
(
Enable100ContinueBehaviour
);
}
//If 100 continue was the response inform that to the client
...
...
@@ -325,7 +330,7 @@ namespace Titanium.Web.Proxy
if
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
{
args
.
WebSession
.
SetConnection
(
connection
);
await
args
.
WebSession
.
SendRequest
();
await
args
.
WebSession
.
SendRequest
(
Enable100ContinueBehaviour
);
}
//If request was modified by user
...
...
@@ -367,7 +372,7 @@ namespace Titanium.Web.Proxy
}
//send the tcp connection to server back to connection cache for reuse
await
TcpConnection
Manager
.
ReleaseClient
(
connection
);
await
tcpConnectionCache
Manager
.
ReleaseClient
(
connection
);
// read the next request
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
...
...
@@ -389,7 +394,7 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamWriter"></param>
/// <param name="httpVersion"></param>
/// <returns></returns>
private
static
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
private
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
{
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2}"
,
httpVersion
.
Major
,
httpVersion
.
Minor
,
"200 Connection established"
));
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
));
...
...
@@ -402,7 +407,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="requestHeaders"></param>
/// <param name="webRequest"></param>
private
static
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
private
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
{
for
(
var
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++)
{
...
...
@@ -426,7 +431,7 @@ namespace Titanium.Web.Proxy
/// Fix proxy specific headers
/// </summary>
/// <param name="headers"></param>
private
static
void
FixRequestProxyHeaders
(
List
<
HttpHeader
>
headers
)
private
void
FixRequestProxyHeaders
(
List
<
HttpHeader
>
headers
)
{
//If proxy-connection close was returned inform to close the connection
var
proxyHeader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
...
...
@@ -450,7 +455,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private
static
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
private
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
{
// End the operation
var
postStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
...
...
@@ -458,14 +463,14 @@ namespace Titanium.Web.Proxy
//send the request body bytes to server
if
(
args
.
WebSession
.
Request
.
ContentLength
>
0
)
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
BUFFER_SIZE
,
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
}
//Need to revist, find any potential bugs
//send the request body bytes to server in chunks
else
if
(
args
.
WebSession
.
Request
.
IsChunked
)
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
postStream
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
BUFFER_SIZE
,
postStream
);
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
749fb44d
...
...
@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy
partial
class
ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
public
static
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
public
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
...
...
@@ -86,11 +86,11 @@ namespace Titanium.Web.Proxy
//Write body only if response is chunked or content length >0
//Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection
if
(
args
.
WebSession
.
Response
.
IsChunked
||
args
.
WebSession
.
Response
.
ContentLength
>
0
||
!
args
.
WebSession
.
Response
.
ResponseKeepAlive
)
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
//write response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
else
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
&&
args
.
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
}
await
args
.
ProxyClient
.
ClientStream
.
FlushAsync
();
...
...
@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy
/// <param name="encodingType"></param>
/// <param name="responseBodyStream"></param>
/// <returns></returns>
private
static
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
{
var
compressionFactory
=
new
CompressionFactory
();
var
compressor
=
compressionFactory
.
Create
(
encodingType
);
...
...
@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy
/// <param name="description"></param>
/// <param name="responseWriter"></param>
/// <returns></returns>
private
static
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
private
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
StreamWriter
responseWriter
)
{
await
responseWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
code
,
description
));
...
...
@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy
/// <param name="responseWriter"></param>
/// <param name="headers"></param>
/// <returns></returns>
private
static
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
)
private
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
)
{
if
(
headers
!=
null
)
{
...
...
@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy
/// Fix the proxy specific headers before sending response headers to client
/// </summary>
/// <param name="headers"></param>
private
static
void
FixResponseProxyHeaders
(
List
<
HttpHeader
>
headers
)
private
void
FixResponseProxyHeaders
(
List
<
HttpHeader
>
headers
)
{
//If proxy-connection close was returned inform to close the connection
var
proxyHeader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
...
...
@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="args"></param>
private
static
void
Dispose
(
TcpClient
client
,
IDisposable
clientStream
,
IDisposable
clientStreamReader
,
private
void
Dispose
(
TcpClient
client
,
IDisposable
clientStream
,
IDisposable
clientStreamReader
,
IDisposable
clientStreamWriter
,
IDisposable
args
)
{
if
(
args
!=
null
)
...
...
Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
749fb44d
using
System
;
using
System.Security.Authentication
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Shared
...
...
@@ -9,7 +8,7 @@ namespace Titanium.Web.Proxy.Shared
/// </summary>
internal
class
ProxyConstants
{
internal
static
readonly
char
[]
SpaceSplit
=
{
' '
};
internal
static
readonly
char
[]
SpaceSplit
=
{
' '
};
internal
static
readonly
char
[]
ColonSplit
=
{
':'
};
internal
static
readonly
char
[]
SemiColonSplit
=
{
';'
};
...
...
@@ -18,8 +17,5 @@ namespace Titanium.Web.Proxy.Shared
internal
static
readonly
byte
[]
ChunkEnd
=
Encoding
.
ASCII
.
GetBytes
(
0.
ToString
(
"x2"
)
+
Environment
.
NewLine
+
Environment
.
NewLine
);
public
static
SslProtocols
SupportedSslProtocols
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
public
static
readonly
int
BUFFER_SIZE
=
8192
;
}
}
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
749fb44d
...
...
@@ -77,8 +77,8 @@
<Compile
Include=
"Http\Request.cs"
/>
<Compile
Include=
"Http\Response.cs"
/>
<Compile
Include=
"Models\ExternalProxy.cs"
/>
<Compile
Include=
"Network\TcpConnection.cs"
/>
<Compile
Include=
"Network\TcpConnectionManager.cs"
/>
<Compile
Include=
"Network\TcpConnection
Cache
.cs"
/>
<Compile
Include=
"Network\TcpConnection
Cache
Manager.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
<Compile
Include=
"Http\HttpWebClient.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment