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
6fb5f0bf
Commit
6fb5f0bf
authored
Jun 16, 2016
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add comments
parent
f59fb6a3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
680 additions
and
345 deletions
+680
-345
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+4
-4
CompressionFactory.cs
Titanium.Web.Proxy/Compression/CompressionFactory.cs
+4
-1
DeflateCompression.cs
Titanium.Web.Proxy/Compression/DeflateCompression.cs
+4
-1
GZipCompression.cs
Titanium.Web.Proxy/Compression/GZipCompression.cs
+4
-1
ICompression.cs
Titanium.Web.Proxy/Compression/ICompression.cs
+3
-0
ZlibCompression.cs
Titanium.Web.Proxy/Compression/ZlibCompression.cs
+4
-1
DecompressionFactory.cs
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
+3
-0
DefaultDecompression.cs
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
+4
-0
DeflateDecompression.cs
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
+4
-1
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+4
-1
IDecompression.cs
Titanium.Web.Proxy/Decompression/IDecompression.cs
+4
-2
ZlibDecompression.cs
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
+4
-1
CertificateSelectionEventArgs.cs
...Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
+3
-0
CertificateValidationEventArgs.cs
...eb.Proxy/EventArguments/CertificateValidationEventArgs.cs
+3
-0
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+0
-1
ByteArrayExtensions.cs
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
+0
-4
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+5
-3
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+16
-3
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+40
-7
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+15
-1
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+22
-2
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+3
-0
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+3
-1
OkResponse.cs
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
+4
-3
RedirectResponse.cs
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
+3
-0
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+11
-0
ExternalProxy.cs
Titanium.Web.Proxy/Models/ExternalProxy.cs
+4
-8
CachedCertificate.cs
Titanium.Web.Proxy/Network/CachedCertificate.cs
+25
-0
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+290
-263
TcpConnection.cs
Titanium.Web.Proxy/Network/TcpConnection.cs
+45
-0
TcpConnectionManager.cs
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
+50
-24
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+86
-8
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+3
-3
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+3
-1
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
6fb5f0bf
...
...
@@ -12,10 +12,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public
void
StartProxy
()
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
ServerCertificateValidationCallback
+=
OnCertificateValidation
;
ProxyServer
.
ClientCertificateSelectionCallback
+=
OnCertificateSelection
;
//
ProxyServer.BeforeRequest += OnRequest;
//
ProxyServer.BeforeResponse += OnResponse;
//
ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
//
ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
...
...
Titanium.Web.Proxy/Compression/CompressionFactory.cs
View file @
6fb5f0bf
namespace
Titanium.Web.Proxy.Compression
{
class
CompressionFactory
/// <summary>
/// A factory to generate the compression methods based on the type of compression
/// </summary>
internal
class
CompressionFactory
{
public
ICompression
Create
(
string
type
)
{
...
...
Titanium.Web.Proxy/Compression/DeflateCompression.cs
View file @
6fb5f0bf
...
...
@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.Compression
{
class
DeflateCompression
:
ICompression
/// <summary>
/// Concrete implementation of deflate compression
/// </summary>
internal
class
DeflateCompression
:
ICompression
{
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
...
...
Titanium.Web.Proxy/Compression/GZipCompression.cs
View file @
6fb5f0bf
...
...
@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.Compression
{
class
GZipCompression
:
ICompression
/// <summary>
/// concreate implementation of gzip compression
/// </summary>
internal
class
GZipCompression
:
ICompression
{
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
...
...
Titanium.Web.Proxy/Compression/ICompression.cs
View file @
6fb5f0bf
...
...
@@ -2,6 +2,9 @@
namespace
Titanium.Web.Proxy.Compression
{
/// <summary>
/// An inteface for http compression
/// </summary>
interface
ICompression
{
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
);
...
...
Titanium.Web.Proxy/Compression/ZlibCompression.cs
View file @
6fb5f0bf
...
...
@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.Compression
{
class
ZlibCompression
:
ICompression
/// <summary>
/// concrete implementation of zlib compression
/// </summary>
internal
class
ZlibCompression
:
ICompression
{
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
...
...
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
View file @
6fb5f0bf
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// A factory to generate the de-compression methods based on the type of compression
/// </summary>
internal
class
DecompressionFactory
{
internal
IDecompression
Create
(
string
type
)
...
...
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
View file @
6fb5f0bf
...
...
@@ -2,6 +2,10 @@
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// When no compression is specified just return the byte array
/// </summary>
internal
class
DefaultDecompression
:
IDecompression
{
public
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
...
...
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
View file @
6fb5f0bf
...
...
@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// concrete implementation of deflate de-compression
/// </summary>
internal
class
DeflateDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
...
...
@@ -18,7 +21,7 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
)
.
ConfigureAwait
(
false
)
)
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
await
output
.
WriteAsync
(
buffer
,
0
,
read
);
}
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
6fb5f0bf
...
...
@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// concrete implementation of gzip de-compression
/// </summary>
internal
class
GZipDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
...
...
@@ -15,7 +18,7 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
)
.
ConfigureAwait
(
false
)
)
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
await
output
.
WriteAsync
(
buffer
,
0
,
read
);
}
...
...
Titanium.Web.Proxy/Decompression/IDecompression.cs
View file @
6fb5f0bf
using
System.IO
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// An interface for decompression
/// </summary>
internal
interface
IDecompression
{
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
);
...
...
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
View file @
6fb5f0bf
...
...
@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// concrete implemetation of zlib de-compression
/// </summary>
internal
class
ZlibDecompression
:
IDecompression
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
...
...
@@ -17,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
)
.
ConfigureAwait
(
false
)
)
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
await
output
.
WriteAsync
(
buffer
,
0
,
read
);
}
...
...
Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
View file @
6fb5f0bf
...
...
@@ -3,6 +3,9 @@ using System.Security.Cryptography.X509Certificates;
namespace
Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// An argument passed on to user for client certificate selection during mutual SSL authentication
/// </summary>
public
class
CertificateSelectionEventArgs
:
EventArgs
,
IDisposable
{
public
object
sender
{
get
;
internal
set
;
}
...
...
Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs
View file @
6fb5f0bf
...
...
@@ -4,6 +4,9 @@ using System.Security.Cryptography.X509Certificates;
namespace
Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// An argument passed on to the user for validating the server certificate during SSL authentication
/// </summary>
public
class
CertificateValidationEventArgs
:
EventArgs
,
IDisposable
{
public
X509Certificate
Certificate
{
get
;
internal
set
;
}
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
6fb5f0bf
...
...
@@ -9,7 +9,6 @@ using Titanium.Web.Proxy.Extensions;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Network
;
using
System.Net
;
using
System.Net.Sockets
;
namespace
Titanium.Web.Proxy.EventArguments
{
...
...
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
View file @
6fb5f0bf
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Extensions
{
...
...
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
6fb5f0bf
using
System
;
using
System.Globalization
;
using
System.Globalization
;
using
System.IO
;
using
System.Text
;
using
System.Threading.Tasks
;
...
...
@@ -8,6 +7,9 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Extensions
{
/// <summary>
/// Extensions used for Stream and CustomBinaryReader objects
/// </summary>
internal
static
class
StreamExtensions
{
/// <summary>
...
...
@@ -134,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions
var
bytesRead
=
0
;
var
totalBytesRead
=
0
;
while
((
bytesRead
+=
await
inStreamReader
.
BaseStream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
)
.
ConfigureAwait
(
false
)
)
>
0
)
while
((
bytesRead
+=
await
inStreamReader
.
BaseStream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
{
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
);
totalBytesRead
+=
bytesRead
;
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
6fb5f0bf
...
...
@@ -18,9 +18,12 @@ namespace Titanium.Web.Proxy.Helpers
{
private
Stream
stream
;
private
Encoding
encoding
;
internal
CustomBinaryReader
(
Stream
stream
)
{
this
.
stream
=
stream
;
//default to UTF-8
this
.
encoding
=
Encoding
.
UTF8
;
}
...
...
@@ -41,16 +44,21 @@ namespace Titanium.Web.Proxy.Helpers
while
((
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
1
))
>
0
)
{
//if new line
if
(
lastChar
==
'\r'
&&
buffer
[
0
]
==
'\n'
)
{
var
result
=
readBuffer
.
ToArray
();
return
encoding
.
GetString
(
result
.
SubArray
(
0
,
result
.
Length
-
1
));
}
//end of stream
if
(
buffer
[
0
]
==
'\0'
)
{
return
encoding
.
GetString
(
readBuffer
.
ToArray
());
}
await
readBuffer
.
WriteAsync
(
buffer
,
0
,
1
);
//store last char for new line comparison
lastChar
=
(
char
)
buffer
[
0
];
}
...
...
@@ -58,7 +66,7 @@ namespace Titanium.Web.Proxy.Helpers
}
catch
(
IOException
)
{
return
encoding
.
GetString
(
readBuffer
.
ToArray
())
;
throw
;
}
}
}
...
...
@@ -71,13 +79,18 @@ namespace Titanium.Web.Proxy.Helpers
{
string
tmpLine
;
var
requestLines
=
new
List
<
string
>();
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
ReadLineAsync
()
.
ConfigureAwait
(
false
)
))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
ReadLineAsync
()))
{
requestLines
.
Add
(
tmpLine
);
}
return
requestLines
;
}
/// <summary>
/// Read the specified number of raw bytes from the base stream
/// </summary>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
long
totalBytesToRead
)
{
int
bytesToRead
=
ProxyConstants
.
BUFFER_SIZE
;
...
...
@@ -92,7 +105,7 @@ namespace Titanium.Web.Proxy.Helpers
using
(
var
outStream
=
new
MemoryStream
())
{
while
((
bytesRead
+=
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
)
.
ConfigureAwait
(
false
)
)
>
0
)
while
((
bytesRead
+=
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
{
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
);
totalBytesRead
+=
bytesRead
;
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
6fb5f0bf
...
...
@@ -5,8 +5,12 @@ using System.Text.RegularExpressions;
using
System.Collections.Generic
;
using
System.Linq
;
/// <summary>
/// Helper classes for setting system proxy settings
/// </summary>
namespace
Titanium.Web.Proxy.Helpers
{
internal
static
class
NativeMethods
{
[
DllImport
(
"wininet.dll"
)]
...
...
@@ -14,7 +18,7 @@ namespace Titanium.Web.Proxy.Helpers
int
dwBufferLength
);
}
internal
class
HttpSystemProxyValue
internal
class
HttpSystemProxyValue
{
internal
string
HostName
{
get
;
set
;
}
internal
int
Port
{
get
;
set
;
}
...
...
@@ -59,14 +63,16 @@ namespace Titanium.Web.Proxy.Helpers
Refresh
();
}
/// <summary>
/// Remove the http proxy setting from current machine
/// </summary>
internal
static
void
RemoveHttpProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
if
(
reg
.
GetValue
(
"ProxyServer"
)
!=
null
)
if
(
reg
.
GetValue
(
"ProxyServer"
)
!=
null
)
{
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
...
...
@@ -89,11 +95,16 @@ namespace Titanium.Web.Proxy.Helpers
Refresh
();
}
/// <summary>
/// Set the HTTPS proxy server for current machine
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
internal
static
void
SetHttpsProxy
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
prepareRegistry
(
reg
);
...
...
@@ -116,6 +127,9 @@ namespace Titanium.Web.Proxy.Helpers
Refresh
();
}
/// <summary>
/// Removes the https proxy setting to nothing
/// </summary>
internal
static
void
RemoveHttpsProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
...
...
@@ -139,13 +153,16 @@ namespace Titanium.Web.Proxy.Helpers
reg
.
SetValue
(
"ProxyEnable"
,
0
);
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
}
}
Refresh
();
}
/// <summary>
/// Removes all types of proxy settings (both http & https)
/// </summary>
internal
static
void
DisableAllProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
...
...
@@ -159,6 +176,12 @@ namespace Titanium.Web.Proxy.Helpers
Refresh
();
}
/// <summary>
/// Get the current system proxy setting values
/// </summary>
/// <param name="prevServerValue"></param>
/// <returns></returns>
private
static
List
<
HttpSystemProxyValue
>
GetSystemProxyValues
(
string
prevServerValue
)
{
var
result
=
new
List
<
HttpSystemProxyValue
>();
...
...
@@ -187,6 +210,11 @@ namespace Titanium.Web.Proxy.Helpers
return
result
;
}
/// <summary>
/// Parses the system proxy setting string
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private
static
HttpSystemProxyValue
parseProxyValue
(
string
value
)
{
var
tmp
=
Regex
.
Replace
(
value
,
@"\s+"
,
" "
).
Trim
().
ToLower
();
...
...
@@ -213,7 +241,10 @@ namespace Titanium.Web.Proxy.Helpers
return
null
;
}
/// <summary>
/// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary>
/// <param name="reg"></param>
private
static
void
prepareRegistry
(
RegistryKey
reg
)
{
if
(
reg
.
GetValue
(
"ProxyEnable"
)
==
null
)
...
...
@@ -227,8 +258,10 @@ namespace Titanium.Web.Proxy.Helpers
}
}
/// <summary>
/// Refresh the settings so that the system know about a change in proxy setting
/// </summary>
private
static
void
Refresh
()
{
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionSettingsChanged
,
IntPtr
.
Zero
,
0
);
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
6fb5f0bf
...
...
@@ -12,11 +12,24 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Helpers
{
internal
class
TcpHelper
{
/// <summary>
/// relays the input clientStream to the server at the specified host name & port with the given httpCmd & headers as prefix
/// Usefull for websocket requests
/// </summary>
/// <param name="clientStream"></param>
/// <param name="httpCmd"></param>
/// <param name="requestHeaders"></param>
/// <param name="hostName"></param>
/// <param name="tunnelPort"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
internal
async
static
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
)
{
//prepare the prefix content
StringBuilder
sb
=
null
;
if
(
httpCmd
!=
null
||
requestHeaders
!=
null
)
{
...
...
@@ -38,7 +51,7 @@ namespace Titanium.Web.Proxy.Helpers
TcpClient
tunnelClient
=
null
;
Stream
tunnelStream
=
null
;
//create the TcpClient to the server
try
{
tunnelClient
=
new
TcpClient
(
hostName
,
tunnelPort
);
...
...
@@ -64,6 +77,7 @@ namespace Titanium.Web.Proxy.Helpers
Task
sendRelay
;
//Now async relay all server=>client & client=>server data
if
(
sb
!=
null
)
sendRelay
=
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
);
else
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
6fb5f0bf
...
...
@@ -9,6 +9,9 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Http
{
/// <summary>
/// Used to communicate with the server over HTTP(S)
/// </summary>
public
class
HttpWebClient
{
/// <summary>
...
...
@@ -19,6 +22,9 @@ namespace Titanium.Web.Proxy.Http
public
Request
Request
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
/// <summary>
/// Is Https?
/// </summary>
public
bool
IsHttps
{
get
...
...
@@ -27,6 +33,10 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Set the tcp connection to server used by this webclient
/// </summary>
/// <param name="Connection"></param>
internal
void
SetConnection
(
TcpConnection
Connection
)
{
Connection
.
LastAccess
=
DateTime
.
Now
;
...
...
@@ -39,19 +49,24 @@ namespace Titanium.Web.Proxy.Http
this
.
Response
=
new
Response
();
}
/// <summary>
/// Prepare & send the http(s) request
/// </summary>
/// <returns></returns>
internal
async
Task
SendRequest
()
{
Stream
stream
=
ServerConnection
.
Stream
;
StringBuilder
requestLines
=
new
StringBuilder
();
//prepare the request & headers
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
new
string
[
3
]
{
this
.
Request
.
Method
,
this
.
Request
.
RequestUri
.
PathAndQuery
,
string
.
Format
(
"HTTP/{0}.{1}"
,
this
.
Request
.
HttpVersion
.
Major
,
this
.
Request
.
HttpVersion
.
Minor
)
}));
//write request headers
foreach
(
HttpHeader
httpHeader
in
this
.
Request
.
RequestHeaders
)
{
requestLines
.
AppendLine
(
httpHeader
.
Name
+
':'
+
httpHeader
.
Value
);
...
...
@@ -87,6 +102,10 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Receive & parse the http response from server
/// </summary>
/// <returns></returns>
internal
async
Task
ReceiveResponse
()
{
//return if this is already read
...
...
@@ -130,6 +149,7 @@ namespace Titanium.Web.Proxy.Http
return
;
}
//read response headers
List
<
string
>
responseLines
=
await
ServerConnection
.
StreamReader
.
ReadAllLinesAsync
();
for
(
int
index
=
0
;
index
<
responseLines
.
Count
;
++
index
)
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
6fb5f0bf
...
...
@@ -7,6 +7,9 @@ using Titanium.Web.Proxy.Extensions;
namespace
Titanium.Web.Proxy.Http
{
/// <summary>
/// A HTTP(S) request object
/// </summary>
public
class
Request
{
public
string
Method
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
6fb5f0bf
...
...
@@ -8,7 +8,9 @@ using System;
namespace
Titanium.Web.Proxy.Http
{
/// <summary>
/// Http(s) response object
/// </summary>
public
class
Response
{
public
string
ResponseStatusCode
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
View file @
6fb5f0bf
using
Titanium.Web.Proxy.Network
;
namespace
Titanium.Web.Proxy.Http.Responses
namespace
Titanium.Web.Proxy.Http.Responses
{
/// <summary>
/// 200 Ok response
/// </summary>
public
class
OkResponse
:
Response
{
public
OkResponse
()
...
...
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
View file @
6fb5f0bf
...
...
@@ -2,6 +2,9 @@
namespace
Titanium.Web.Proxy.Http.Responses
{
/// <summary>
/// Redirect response
/// </summary>
public
class
RedirectResponse
:
Response
{
public
RedirectResponse
()
...
...
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
6fb5f0bf
...
...
@@ -4,6 +4,9 @@ using System.Net.Sockets;
namespace
Titanium.Web.Proxy.Models
{
/// <summary>
/// An abstract endpoint where the proxy listens
/// </summary>
public
abstract
class
ProxyEndPoint
{
public
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
...
...
@@ -20,6 +23,10 @@ namespace Titanium.Web.Proxy.Models
internal
TcpListener
listener
{
get
;
set
;
}
}
/// <summary>
/// A proxy endpoint that the client is aware of
/// So client application know that it is communicating with a proxy server
/// </summary>
public
class
ExplicitProxyEndPoint
:
ProxyEndPoint
{
internal
bool
IsSystemHttpProxy
{
get
;
set
;
}
...
...
@@ -34,6 +41,10 @@ namespace Titanium.Web.Proxy.Models
}
}
/// <summary>
/// A proxy end point client is not aware of
/// Usefull when requests are redirected to this proxy end point through port forwarding
/// </summary>
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
...
...
Titanium.Web.Proxy/Models/ExternalProxy.cs
View file @
6fb5f0bf
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Models
namespace
Titanium.Web.Proxy.Models
{
/// <summary>
/// An upstream proxy this proxy uses if any
/// </summary>
public
class
ExternalProxy
{
public
string
HostName
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/Network/CachedCertificate.cs
0 → 100644
View file @
6fb5f0bf
using
System
;
using
System.Security.Cryptography.X509Certificates
;
namespace
Titanium.Web.Proxy.Network
{
/// <summary>
/// An object that holds the cached certificate
/// </summary>
internal
class
CachedCertificate
{
internal
X509Certificate2
Certificate
{
get
;
set
;
}
/// <summary>
/// last time this certificate was used
/// Usefull in determining its cache lifetime
/// </summary>
internal
DateTime
LastAccess
{
get
;
set
;
}
internal
CachedCertificate
()
{
LastAccess
=
DateTime
.
Now
;
}
}
}
Titanium.Web.Proxy/
Helpers
/CertificateManager.cs
→
Titanium.Web.Proxy/
Network
/CertificateManager.cs
View file @
6fb5f0bf
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/Network/TcpConnection.cs
0 → 100644
View file @
6fb5f0bf
using
System
;
using
System.IO
;
using
System.Net.Sockets
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Network
{
/// <summary>
/// An object that holds TcpConnection to a particular server & port
/// </summary>
public
class
TcpConnection
{
internal
string
HostName
{
get
;
set
;
}
internal
int
port
{
get
;
set
;
}
internal
bool
IsHttps
{
get
;
set
;
}
/// <summary>
/// Http version
/// </summary>
internal
Version
Version
{
get
;
set
;
}
internal
TcpClient
TcpClient
{
get
;
set
;
}
/// <summary>
/// used to read lines from server
/// </summary>
internal
CustomBinaryReader
StreamReader
{
get
;
set
;
}
/// <summary>
/// Server stream
/// </summary>
internal
Stream
Stream
{
get
;
set
;
}
/// <summary>
/// Last time this connection was used
/// </summary>
internal
DateTime
LastAccess
{
get
;
set
;
}
internal
TcpConnection
()
{
LastAccess
=
DateTime
.
Now
;
}
}
}
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
View file @
6fb5f0bf
...
...
@@ -10,44 +10,41 @@ using Titanium.Web.Proxy.Helpers;
using
System.Threading
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
using
System.Security.Cryptography.X509Certificates
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Network
{
public
class
TcpConnection
{
internal
string
HostName
{
get
;
set
;
}
internal
int
port
{
get
;
set
;
}
internal
bool
IsHttps
{
get
;
set
;
}
internal
Version
Version
{
get
;
set
;
}
internal
TcpClient
TcpClient
{
get
;
set
;
}
internal
CustomBinaryReader
StreamReader
{
get
;
set
;
}
internal
Stream
Stream
{
get
;
set
;
}
internal
DateTime
LastAccess
{
get
;
set
;
}
internal
TcpConnection
()
{
LastAccess
=
DateTime
.
Now
;
}
}
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
internal
class
TcpConnectionManager
{
/// <summary>
/// Connection cache
/// </summary>
static
Dictionary
<
string
,
List
<
TcpConnection
>>
connectionCache
=
new
Dictionary
<
string
,
List
<
TcpConnection
>>();
static
SemaphoreSlim
connectionAccessLock
=
new
SemaphoreSlim
(
1
);
/// <summary>
/// A lock to manage concurrency
/// </summary>
static
SemaphoreSlim
connectionAccessLock
=
new
SemaphoreSlim
(
1
);
/// <summary>
/// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
static
async
Task
<
TcpConnection
>
GetClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
{
List
<
TcpConnection
>
cachedConnections
=
null
;
TcpConnection
cached
=
null
;
//Get a unique string to identify this connection
var
key
=
GetConnectionKey
(
hostname
,
port
,
isHttps
,
version
);
while
(
true
)
{
await
connectionAccessLock
.
WaitAsync
();
...
...
@@ -76,6 +73,7 @@ namespace Titanium.Web.Proxy.Network
if
(
cached
==
null
)
break
;
}
if
(
cached
==
null
)
...
...
@@ -90,11 +88,27 @@ namespace Titanium.Web.Proxy.Network
return
cached
;
}
/// <summary>
/// Get a string to identfiy the connection to a particular host, port
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal
static
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
);
}
/// <summary>
/// Create connection to a particular host/port optionally with SSL and a particular HTTP version
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
private
static
async
Task
<
TcpConnection
>
CreateClient
(
string
hostname
,
int
port
,
bool
isHttps
,
Version
version
)
{
TcpClient
client
;
...
...
@@ -104,6 +118,7 @@ namespace Titanium.Web.Proxy.Network
{
SslStream
sslStream
=
null
;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if
(
ProxyServer
.
UpStreamHttpsProxy
!=
null
)
{
client
=
new
TcpClient
(
ProxyServer
.
UpStreamHttpsProxy
.
HostName
,
ProxyServer
.
UpStreamHttpsProxy
.
Port
);
...
...
@@ -175,7 +190,11 @@ namespace Titanium.Web.Proxy.Network
};
}
/// <summary>
/// Returns a Tcp Connection back to cache for reuse by other requests
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
internal
static
async
Task
ReleaseClient
(
TcpConnection
connection
)
{
...
...
@@ -199,11 +218,17 @@ namespace Titanium.Web.Proxy.Network
private
static
bool
clearConenctions
{
get
;
set
;
}
/// <summary>
/// Stop clearing idle connections
/// </summary>
internal
static
void
StopClearIdleConnections
()
{
clearConenctions
=
false
;
}
/// <summary>
/// A method to clear idle connections
/// </summary>
internal
async
static
void
ClearIdleConnections
()
{
clearConenctions
=
true
;
...
...
@@ -224,6 +249,7 @@ namespace Titanium.Web.Proxy.Network
}
finally
{
connectionAccessLock
.
Release
();
}
//every minute run this
await
Task
.
Delay
(
1000
*
60
);
}
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
6fb5f0bf
...
...
@@ -22,17 +22,41 @@ namespace Titanium.Web.Proxy
static
ProxyServer
()
{
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
//default values
ConnectionCacheTimeOutMinutes
=
3
;
CertificateCacheTimeOutMinutes
=
60
;
}
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
private
static
CertificateManager
CertManager
{
get
;
set
;
}
/// <summary>
/// Does the root certificate used by this proxy is trusted by the machine?
/// </summary>
private
static
bool
certTrusted
{
get
;
set
;
}
/// <summary>
/// Is the proxy currently running
/// </summary>
private
static
bool
proxyRunning
{
get
;
set
;
}
/// <summary>
/// Name of the root certificate issuer
/// </summary>
public
static
string
RootCertificateIssuerName
{
get
;
set
;
}
/// <summary>
/// Name of the root certificate
/// </summary>
public
static
string
RootCertificateName
{
get
;
set
;
}
/// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 contunue implementations on server/client may cause problems if enabled
/// </summary>
public
static
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
/// <summary>
...
...
@@ -45,13 +69,11 @@ namespace Titanium.Web.Proxy
/// </summary>
public
static
int
CertificateCacheTimeOutMinutes
{
get
;
set
;
}
/// <summary>
/// Intercept request to server
/// </summary>
public
static
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
/// <summary>
/// Intercept response from server
/// </summary>
...
...
@@ -77,20 +99,33 @@ namespace Titanium.Web.Proxy
/// </summary>
public
static
event
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>
ClientCertificateSelectionCallback
;
/// <summary>
/// A list of IpAddress & port this proxy is listening to
/// </summary>
public
static
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
/// <summary>
/// Initialize the proxy
/// </summary>
public
static
void
Initialize
()
{
TcpConnectionManager
.
ClearIdleConnections
();
CertManager
.
ClearIdleCertificates
();
}
/// <summary>
/// Quit the proxy
/// </summary>
public
static
void
Quit
()
{
TcpConnectionManager
.
StopClearIdleConnections
();
CertManager
.
StopClearIdleCertificates
();
}
/// <summary>
/// Add a proxy end point
/// </summary>
/// <param name="endPoint"></param>
public
static
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
{
ProxyEndPoints
.
Add
(
endPoint
);
...
...
@@ -99,6 +134,11 @@ namespace Titanium.Web.Proxy
Listen
(
endPoint
);
}
/// <summary>
/// Remove a proxy end point
/// Will throw error if the end point does'nt exist
/// </summary>
/// <param name="endPoint"></param>
public
static
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
{
...
...
@@ -111,10 +151,13 @@ namespace Titanium.Web.Proxy
QuitListen
(
endPoint
);
}
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public
static
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
{
V
erify
Proxy
(
endPoint
);
V
alidateEndPointAsSystem
Proxy
(
endPoint
);
//clear any settings previously added
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemHttpProxy
=
false
);
...
...
@@ -130,14 +173,21 @@ namespace Titanium.Web.Proxy
}
/// <summary>
/// Remove any HTTP proxy setting of current machien
/// </summary>
public
static
void
DisableSystemHttpProxy
()
{
SystemProxyHelper
.
RemoveHttpProxy
();
}
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public
static
void
SetAsSystemHttpsProxy
(
ExplicitProxyEndPoint
endPoint
)
{
V
erify
Proxy
(
endPoint
);
V
alidateEndPointAsSystem
Proxy
(
endPoint
);
if
(!
endPoint
.
EnableSsl
)
{
...
...
@@ -164,16 +214,25 @@ namespace Titanium.Web.Proxy
Console
.
WriteLine
(
"Set endpoint at Ip {1} and port: {2} as System HTTPS Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
/// <summary>
/// Remove any HTTPS proxy setting for current machine
/// </summary>
public
static
void
DisableSystemHttpsProxy
()
{
SystemProxyHelper
.
RemoveHttpsProxy
();
}
/// <summary>
/// Clear all proxy settings for current machine
/// </summary>
public
static
void
DisableAllSystemProxies
()
{
SystemProxyHelper
.
DisableAllProxy
();
}
/// <summary>
/// Start this proxy server
/// </summary>
public
static
void
Start
()
{
if
(
proxyRunning
)
...
...
@@ -197,6 +256,9 @@ namespace Titanium.Web.Proxy
proxyRunning
=
true
;
}
/// <summary>
/// Stop this proxy server
/// </summary>
public
static
void
Stop
()
{
if
(!
proxyRunning
)
...
...
@@ -224,6 +286,10 @@ namespace Titanium.Web.Proxy
proxyRunning
=
false
;
}
/// <summary>
/// Listen on the given end point on local machine
/// </summary>
/// <param name="endPoint"></param>
private
static
void
Listen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
...
...
@@ -234,13 +300,20 @@ namespace Titanium.Web.Proxy
endPoint
.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
/// <summary>
/// Quit listening on the given end point
/// </summary>
/// <param name="endPoint"></param>
private
static
void
QuitListen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
listener
.
Stop
();
}
private
static
void
VerifyProxy
(
ExplicitProxyEndPoint
endPoint
)
/// <summary>
/// Verifiy if its safe to set this end point as System proxy
/// </summary>
/// <param name="endPoint"></param>
private
static
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
...
...
@@ -249,12 +322,17 @@ namespace Titanium.Web.Proxy
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
}
/// <summary>
/// When a connection is received from client act
/// </summary>
/// <param name="asyn"></param>
private
static
void
OnAcceptConnection
(
IAsyncResult
asyn
)
{
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
try
{
//based on end point type call appropriate request handlers
var
client
=
endPoint
.
listener
.
EndAcceptTcpClient
(
asyn
);
if
(
endPoint
.
GetType
()
==
typeof
(
TransparentProxyEndPoint
))
HandleClient
(
endPoint
as
TransparentProxyEndPoint
,
client
);
...
...
@@ -273,7 +351,7 @@ namespace Titanium.Web.Proxy
}
catch
{
//Other errors are discarded to keep the proxy running
}
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
6fb5f0bf
...
...
@@ -59,10 +59,10 @@ namespace Titanium.Web.Proxy
{
version
=
new
Version
(
1
,
0
);
}
}
var
excluded
=
endPoint
.
ExcludedHttpsHostNameRegex
!=
null
?
endPoint
.
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
:
false
;
var
excluded
=
endPoint
.
ExcludedHttpsHostNameRegex
!=
null
?
endPoint
.
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
:
false
;
//Client wants to create a secure tcp tunnel (its a HTTPS request)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
...
...
@@ -217,7 +217,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()
.
ConfigureAwait
(
false
)
))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
new
HttpHeader
(
header
[
0
],
header
[
1
]));
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
6fb5f0bf
...
...
@@ -63,11 +63,12 @@
<Compile
Include=
"EventArguments\CertificateSelectionEventArgs.cs"
/>
<Compile
Include=
"EventArguments\CertificateValidationEventArgs.cs"
/>
<Compile
Include=
"Extensions\ByteArrayExtensions.cs"
/>
<Compile
Include=
"Network\CachedCertificate.cs"
/>
<Compile
Include=
"Network\ProxyClient.cs"
/>
<Compile
Include=
"Exceptions\BodyNotFoundException.cs"
/>
<Compile
Include=
"Extensions\HttpWebResponseExtensions.cs"
/>
<Compile
Include=
"Extensions\HttpWebRequestExtensions.cs"
/>
<Compile
Include=
"
Helpers
\CertificateManager.cs"
/>
<Compile
Include=
"
Network
\CertificateManager.cs"
/>
<Compile
Include=
"Helpers\Firefox.cs"
/>
<Compile
Include=
"Helpers\SystemProxy.cs"
/>
<Compile
Include=
"Models\EndPoint.cs"
/>
...
...
@@ -75,6 +76,7 @@
<Compile
Include=
"Http\Request.cs"
/>
<Compile
Include=
"Http\Response.cs"
/>
<Compile
Include=
"Models\ExternalProxy.cs"
/>
<Compile
Include=
"Network\TcpConnection.cs"
/>
<Compile
Include=
"Network\TcpConnectionManager.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
<Compile
Include=
"Http\HttpWebClient.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