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