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
8022c434
Commit
8022c434
authored
Apr 07, 2017
by
Rob Garrett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resharper cleanup
parent
4ef9a02d
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
622 additions
and
493 deletions
+622
-493
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+14
-12
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+0
-1
CertificateSelectionEventArgs.cs
...Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
+18
-1
CertificateValidationEventArgs.cs
...eb.Proxy/EventArguments/CertificateValidationEventArgs.cs
+13
-6
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+21
-6
BodyNotFoundException.cs
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
+5
-2
ByteArrayExtensions.cs
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
+4
-1
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+3
-10
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+6
-6
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+28
-28
Network.cs
Titanium.Web.Proxy/Helpers/Network.cs
+6
-24
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+1
-4
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+1
-0
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+42
-36
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+10
-22
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+14
-9
GenericResponse.cs
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
+10
-1
OkResponse.cs
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
+3
-0
RedirectResponse.cs
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
+3
-0
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+47
-11
ExternalProxy.cs
Titanium.Web.Proxy/Models/ExternalProxy.cs
+17
-2
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+13
-1
CertificateMaker.cs
Titanium.Web.Proxy/Network/CertificateMaker.cs
+115
-118
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+38
-48
TcpConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
+3
-0
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+2
-4
TcpRow.cs
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
+3
-3
TcpTable.cs
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
+3
-1
ProxyAuthorizationHandler.cs
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
+64
-40
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+61
-14
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+41
-63
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+12
-17
ProxyConstants.cs
Titanium.Web.Proxy/Shared/ProxyConstants.cs
+1
-2
No files found.
Titanium.Web.Proxy/CertificateHandler.cs
View file @
8022c434
using
System
;
using
System.Linq
;
using
System.Net.Security
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading.Tasks
;
...
...
@@ -26,11 +25,13 @@ namespace Titanium.Web.Proxy
//if user callback is registered then do it
if
(
ServerCertificateValidationCallback
!=
null
)
{
var
args
=
new
CertificateValidationEventArgs
();
var
args
=
new
CertificateValidationEventArgs
{
Certificate
=
certificate
,
Chain
=
chain
,
SslPolicyErrors
=
sslPolicyErrors
};
args
.
Certificate
=
certificate
;
args
.
Chain
=
chain
;
args
.
SslPolicyErrors
=
sslPolicyErrors
;
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
...
...
@@ -73,7 +74,6 @@ namespace Titanium.Web.Proxy
string
[]
acceptableIssuers
)
{
X509Certificate
clientCertificate
=
null
;
var
customSslStream
=
sender
as
SslStream
;
if
(
acceptableIssuers
!=
null
&&
acceptableIssuers
.
Length
>
0
&&
...
...
@@ -100,13 +100,15 @@ namespace Titanium.Web.Proxy
//If user call back is registered
if
(
ClientCertificateSelectionCallback
!=
null
)
{
var
args
=
new
CertificateSelectionEventArgs
();
var
args
=
new
CertificateSelectionEventArgs
{
TargetHost
=
targetHost
,
LocalCertificates
=
localCertificates
,
RemoteCertificate
=
remoteCertificate
,
AcceptableIssuers
=
acceptableIssuers
,
ClientCertificate
=
clientCertificate
};
args
.
TargetHost
=
targetHost
;
args
.
LocalCertificates
=
localCertificates
;
args
.
RemoteCertificate
=
remoteCertificate
;
args
.
AcceptableIssuers
=
acceptableIssuers
;
args
.
ClientCertificate
=
clientCertificate
;
Delegate
[]
invocationList
=
ClientCertificateSelectionCallback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
8022c434
using
System.IO
;
using
System.IO.Compression
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Decompression
{
...
...
Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
View file @
8022c434
...
...
@@ -8,12 +8,29 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
class
CertificateSelectionEventArgs
:
EventArgs
{
/// <summary>
/// Sender object.
/// </summary>
public
object
Sender
{
get
;
internal
set
;
}
/// <summary>
/// Target host.
/// </summary>
public
string
TargetHost
{
get
;
internal
set
;
}
/// <summary>
/// Local certificates.
/// </summary>
public
X509CertificateCollection
LocalCertificates
{
get
;
internal
set
;
}
/// <summary>
/// Remote certificate.
/// </summary>
public
X509Certificate
RemoteCertificate
{
get
;
internal
set
;
}
/// <summary>
/// Acceptable issuers.
/// </summary>
public
string
[]
AcceptableIssuers
{
get
;
internal
set
;
}
/// <summary>
/// Client Certificate.
/// </summary>
public
X509Certificate
ClientCertificate
{
get
;
set
;
}
}
...
...
Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs
View file @
8022c434
...
...
@@ -7,17 +7,24 @@ 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
class
CertificateValidationEventArgs
:
EventArgs
{
/// <summary>
/// Certificate
/// </summary>
public
X509Certificate
Certificate
{
get
;
internal
set
;
}
/// <summary>
/// Certificate chain
/// </summary>
public
X509Chain
Chain
{
get
;
internal
set
;
}
/// <summary>
/// SSL policy errors.
/// </summary>
public
SslPolicyErrors
SslPolicyErrors
{
get
;
internal
set
;
}
/// <summary>
/// is a valid certificate?
/// </summary>
public
bool
IsValid
{
get
;
set
;
}
public
void
Dispose
()
{
}
}
}
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
8022c434
...
...
@@ -44,7 +44,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
Guid
Id
=>
WebSession
.
RequestId
;
//Should we send a rerequest
/// <summary>
/// Should we send a rerequest
/// </summary>
public
bool
ReRequest
{
get
;
...
...
@@ -56,7 +58,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
bool
IsHttps
=>
WebSession
.
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
/// <summary>
/// Client End Point.
/// </summary>
public
IPEndPoint
ClientEndPoint
=>
(
IPEndPoint
)
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
/// <summary>
...
...
@@ -65,8 +69,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public
HttpWebClient
WebSession
{
get
;
set
;
}
/// <summary>
/// Are we using a custom upstream HTTP proxy?
/// </summary>
public
ExternalProxy
CustomUpStreamHttpProxyUsed
{
get
;
set
;
}
/// <summary>
/// Are we using a custom upstream HTTPS proxy?
/// </summary>
public
ExternalProxy
CustomUpStreamHttpsProxyUsed
{
get
;
set
;
}
/// <summary>
...
...
@@ -105,7 +115,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
WebSession
.
Request
.
IsChunked
)
{
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
}
else
{
...
...
@@ -113,7 +123,7 @@ namespace Titanium.Web.Proxy.EventArguments
if
(
WebSession
.
Request
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
}
...
...
@@ -431,7 +441,7 @@ namespace Titanium.Web.Proxy.EventArguments
await
GenericResponse
(
html
,
null
,
status
);
}
///
<summary>
///
<summary>
/// Before request is made to server
/// Respond with the specified HTML string to client
/// and the specified status
...
...
@@ -485,12 +495,17 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Request
.
CancelRequest
=
true
;
}
/// <summary>
/// Redirect to URL.
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public
async
Task
Redirect
(
string
url
)
{
var
response
=
new
RedirectResponse
();
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
ResponseHeaders
.
Add
(
"Location"
,
new
Models
.
HttpHeader
(
"Location"
,
url
));
response
.
ResponseHeaders
.
Add
(
"Location"
,
new
HttpHeader
(
"Location"
,
url
));
response
.
ResponseBody
=
Encoding
.
ASCII
.
GetBytes
(
string
.
Empty
);
await
Respond
(
response
);
...
...
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
View file @
8022c434
using
System
;
namespace
Titanium.Web.Proxy.Exceptions
{
/// <summary>
...
...
@@ -7,6 +6,10 @@ namespace Titanium.Web.Proxy.Exceptions
/// </summary>
public
class
BodyNotFoundException
:
ProxyException
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="message"></param>
public
BodyNotFoundException
(
string
message
)
:
base
(
message
)
{
...
...
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
View file @
8022c434
...
...
@@ -2,6 +2,9 @@
namespace
Titanium.Web.Proxy.Extensions
{
/// <summary>
/// Extension methods for Byte Arrays.
/// </summary>
public
static
class
ByteArrayExtensions
{
/// <summary>
...
...
@@ -14,7 +17,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <returns></returns>
public
static
T
[]
SubArray
<
T
>(
this
T
[]
data
,
int
index
,
int
length
)
{
T
[]
result
=
new
T
[
length
];
var
result
=
new
T
[
length
];
Array
.
Copy
(
data
,
index
,
result
,
0
,
length
);
return
result
;
}
...
...
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
8022c434
...
...
@@ -12,11 +12,11 @@ namespace Titanium.Web.Proxy.Extensions
internal
static
bool
IsConnected
(
this
Socket
client
)
{
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
client
.
Blocking
;
var
blockingState
=
client
.
Blocking
;
try
{
byte
[]
tmp
=
new
byte
[
1
];
var
tmp
=
new
byte
[
1
];
client
.
Blocking
=
false
;
client
.
Send
(
tmp
,
0
,
0
);
...
...
@@ -25,14 +25,7 @@ namespace Titanium.Web.Proxy.Extensions
catch
(
SocketException
e
)
{
// 10035 == WSAEWOULDBLOCK
if
(
e
.
NativeErrorCode
.
Equals
(
10035
))
{
return
true
;
}
else
{
return
false
;
}
return
e
.
NativeErrorCode
.
Equals
(
10035
);
}
finally
{
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
8022c434
...
...
@@ -4,7 +4,6 @@ using System.IO;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Helpers
{
...
...
@@ -16,15 +15,15 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
internal
class
CustomBinaryReader
:
IDisposable
{
private
Stream
stream
;
private
Encoding
encoding
;
private
readonly
Stream
stream
;
private
readonly
Encoding
encoding
;
internal
CustomBinaryReader
(
Stream
stream
)
{
this
.
stream
=
stream
;
//default to UTF-8
this
.
encoding
=
Encoding
.
UTF8
;
encoding
=
Encoding
.
UTF8
;
}
internal
Stream
BaseStream
=>
stream
;
...
...
@@ -40,7 +39,7 @@ namespace Titanium.Web.Proxy.Helpers
var
lastChar
=
default
(
char
);
var
buffer
=
new
byte
[
1
];
while
((
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
1
))
>
0
)
while
((
await
stream
.
ReadAsync
(
buffer
,
0
,
1
))
>
0
)
{
//if new line
if
(
lastChar
==
'\r'
&&
buffer
[
0
]
==
'\n'
)
...
...
@@ -82,6 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Read the specified number of raw bytes from the base stream
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
int
bufferSize
,
long
totalBytesToRead
)
...
...
@@ -98,7 +98,7 @@ namespace Titanium.Web.Proxy.Helpers
using
(
var
outStream
=
new
MemoryStream
())
{
while
((
bytesRead
+=
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
while
((
bytesRead
+=
await
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
))
>
0
)
{
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
);
totalBytesRead
+=
bytesRead
;
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
8022c434
...
...
@@ -8,6 +8,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
public
class
FireFoxProxySettingsManager
{
/// <summary>
/// Add Firefox settings.
/// </summary>
public
void
AddFirefox
()
{
try
...
...
@@ -16,28 +19,27 @@ namespace Titanium.Web.Proxy.Helpers
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
if
(!
File
.
Exists
(
myFfPrefFile
))
return
;
// We have a pref file so let''s make sure it has the proxy setting
var
myReader
=
new
StreamReader
(
myFfPrefFile
);
var
myPrefContents
=
myReader
.
ReadToEnd
();
myReader
.
Close
();
if
(
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
{
if
(!
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
return
;
// Add the proxy enable line and write it back to the file
myPrefContents
=
myPrefContents
.
Replace
(
"user_pref(\"network.proxy.type\", 0);"
,
""
);
File
.
Delete
(
myFfPrefFile
);
File
.
WriteAllText
(
myFfPrefFile
,
myPrefContents
);
}
}
}
catch
(
Exception
)
{
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
}
}
/// <summary>
/// Remove firefox settings.
/// </summary>
public
void
RemoveFirefox
()
{
try
...
...
@@ -46,8 +48,7 @@ namespace Titanium.Web.Proxy.Helpers
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
if
(!
File
.
Exists
(
myFfPrefFile
))
return
;
// We have a pref file so let''s make sure it has the proxy setting
var
myReader
=
new
StreamReader
(
myFfPrefFile
);
var
myPrefContents
=
myReader
.
ReadToEnd
();
...
...
@@ -61,7 +62,6 @@ namespace Titanium.Web.Proxy.Helpers
File
.
WriteAllText
(
myFfPrefFile
,
myPrefContents
);
}
}
}
catch
(
Exception
)
{
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
...
...
Titanium.Web.Proxy/Helpers/Network.cs
View file @
8022c434
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Helpers
{
...
...
@@ -33,28 +29,14 @@ namespace Titanium.Web.Proxy.Helpers
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address></param>
/// <param name="address
"
></param>
/// <returns></returns>
internal
static
bool
IsLocalIpAddress
(
IPAddress
address
)
{
try
{
// get local IP addresses
IPAddress
[]
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
var
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
// test if any host IP equals to any local IP or to localhost
// is localhost
if
(
IPAddress
.
IsLoopback
(
address
))
return
true
;
// is local address
foreach
(
IPAddress
localIP
in
localIPs
)
{
if
(
address
.
Equals
(
localIP
))
return
true
;
}
}
catch
{
}
return
false
;
return
IPAddress
.
IsLoopback
(
address
)
||
localIPs
.
Contains
(
address
);
}
}
}
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
8022c434
...
...
@@ -4,11 +4,8 @@ using Microsoft.Win32;
using
System.Text.RegularExpressions
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net.Sockets
;
/// <summary>
/// Helper classes for setting system proxy settings
/// </summary>
// Helper classes for setting system proxy settings
namespace
Titanium.Web.Proxy.Helpers
{
internal
enum
ProxyProtocolType
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
8022c434
...
...
@@ -140,6 +140,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="clientStream"></param>
/// <param name="tcpConnectionFactory"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
internal
static
async
Task
SendRaw
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
string
remoteHostName
,
int
remotePort
,
string
httpCmd
,
Version
httpVersion
,
Dictionary
<
string
,
HttpHeader
>
requestHeaders
,
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
8022c434
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Shared
;
...
...
@@ -15,17 +13,26 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
class
HttpWebClient
{
/// <summary>
/// Connection to server
/// </summary>
internal
TcpConnection
ServerConnection
{
get
;
set
;
}
public
Guid
RequestId
{
get
;
private
set
;
}
/// <summary>
/// Request ID.
/// </summary>
public
Guid
RequestId
{
get
;
}
/// <summary>
/// Headers passed with Connect.
/// </summary>
public
List
<
HttpHeader
>
ConnectHeaders
{
get
;
set
;
}
/// <summary>
/// Web Request.
/// </summary>
public
Request
Request
{
get
;
set
;
}
/// <summary>
/// Web Response.
/// </summary>
public
Response
Response
{
get
;
set
;
}
/// <summary>
...
...
@@ -37,15 +44,14 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Is Https?
/// </summary>
public
bool
IsHttps
=>
this
.
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
public
bool
IsHttps
=>
Request
.
RequestUri
.
Scheme
==
Uri
.
UriSchemeHttps
;
internal
HttpWebClient
()
{
this
.
RequestId
=
Guid
.
NewGuid
();
this
.
Request
=
new
Request
();
this
.
Response
=
new
Response
();
RequestId
=
Guid
.
NewGuid
();
Request
=
new
Request
();
Response
=
new
Response
();
}
/// <summary>
...
...
@@ -65,18 +71,18 @@ namespace Titanium.Web.Proxy.Http
/// <returns></returns>
internal
async
Task
SendRequest
(
bool
enable100ContinueBehaviour
)
{
Stream
stream
=
ServerConnection
.
Stream
;
var
stream
=
ServerConnection
.
Stream
;
StringBuilde
r
requestLines
=
new
StringBuilder
();
va
r
requestLines
=
new
StringBuilder
();
//prepare the request & headers
if
((
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
)
||
(
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
==
true
))
if
((
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
)
||
(
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
))
{
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
this
.
Request
.
Method
,
this
.
Request
.
RequestUri
.
AbsoluteUri
,
$"HTTP/
{
this
.
Request
.
HttpVersion
.
Major
}
.
{
this
.
Request
.
HttpVersion
.
Minor
}
"
));
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
Request
.
Method
,
Request
.
RequestUri
.
AbsoluteUri
,
$"HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
));
}
else
{
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
this
.
Request
.
Method
,
this
.
Request
.
RequestUri
.
PathAndQuery
,
$"HTTP/
{
this
.
Request
.
HttpVersion
.
Major
}
.
{
this
.
Request
.
HttpVersion
.
Minor
}
"
));
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
Request
.
Method
,
Request
.
RequestUri
.
PathAndQuery
,
$"HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
));
}
//Send Authentication to Upstream proxy if needed
...
...
@@ -86,7 +92,7 @@ namespace Titanium.Web.Proxy.Http
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
ServerConnection
.
UpStreamHttpProxy
.
UserName
+
":"
+
ServerConnection
.
UpStreamHttpProxy
.
Password
)));
}
//write request headers
foreach
(
var
headerItem
in
this
.
Request
.
RequestHeaders
)
foreach
(
var
headerItem
in
Request
.
RequestHeaders
)
{
var
header
=
headerItem
.
Value
;
if
(
headerItem
.
Key
!=
"Proxy-Authorization"
)
...
...
@@ -96,7 +102,7 @@ namespace Titanium.Web.Proxy.Http
}
//write non unique request headers
foreach
(
var
headerItem
in
this
.
Request
.
NonUniqueRequestHeaders
)
foreach
(
var
headerItem
in
Request
.
NonUniqueRequestHeaders
)
{
var
headers
=
headerItem
.
Value
;
foreach
(
var
header
in
headers
)
...
...
@@ -110,15 +116,15 @@ namespace Titanium.Web.Proxy.Http
requestLines
.
AppendLine
();
string
request
=
requestLines
.
ToString
();
byte
[]
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
var
request
=
requestLines
.
ToString
();
var
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
await
stream
.
WriteAsync
(
requestBytes
,
0
,
requestBytes
.
Length
);
await
stream
.
FlushAsync
();
if
(
enable100ContinueBehaviour
)
{
if
(
this
.
Request
.
ExpectContinue
)
if
(
Request
.
ExpectContinue
)
{
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
var
responseStatusCode
=
httpResult
[
1
].
Trim
();
...
...
@@ -128,13 +134,13 @@ namespace Titanium.Web.Proxy.Http
if
(
responseStatusCode
.
Equals
(
"100"
)
&&
responseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
{
this
.
Request
.
Is100Continue
=
true
;
Request
.
Is100Continue
=
true
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
}
else
if
(
responseStatusCode
.
Equals
(
"417"
)
&&
responseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
{
this
.
Request
.
ExpectationFailed
=
true
;
Request
.
ExpectationFailed
=
true
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
}
}
...
...
@@ -148,7 +154,7 @@ namespace Titanium.Web.Proxy.Http
internal
async
Task
ReceiveResponse
()
{
//return if this is already read
if
(
this
.
Response
.
ResponseStatusCode
!=
null
)
return
;
if
(
Response
.
ResponseStatusCode
!=
null
)
return
;
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
...
...
@@ -161,33 +167,33 @@ namespace Titanium.Web.Proxy.Http
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
version
=
new
Version
(
1
,
1
);
if
(
httpVersion
==
"http/1.0"
)
if
(
0
==
string
.
CompareOrdinal
(
httpVersion
,
"http/1.0"
)
)
{
version
=
new
Version
(
1
,
0
);
}
this
.
Response
.
HttpVersion
=
version
;
this
.
Response
.
ResponseStatusCode
=
httpResult
[
1
].
Trim
();
this
.
Response
.
ResponseStatusDescription
=
httpResult
[
2
].
Trim
();
Response
.
HttpVersion
=
version
;
Response
.
ResponseStatusCode
=
httpResult
[
1
].
Trim
();
Response
.
ResponseStatusDescription
=
httpResult
[
2
].
Trim
();
//For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
if
(
this
.
Response
.
ResponseStatusCode
.
Equals
(
"100"
)
&&
this
.
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
if
(
Response
.
ResponseStatusCode
.
Equals
(
"100"
)
&&
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
{
//Read the next line after 100-continue
this
.
Response
.
Is100Continue
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
Response
.
Is100Continue
=
true
;
Response
.
ResponseStatusCode
=
null
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
//now receive response
await
ReceiveResponse
();
return
;
}
else
if
(
this
.
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
&&
this
.
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
else
if
(
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
&&
Response
.
ResponseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
{
//read next line after expectation failed response
this
.
Response
.
ExpectationFailed
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
Response
.
ExpectationFailed
=
true
;
Response
.
ResponseStatusCode
=
null
;
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
//now receive response
await
ReceiveResponse
();
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
8022c434
...
...
@@ -34,12 +34,7 @@ namespace Titanium.Web.Proxy.Http
get
{
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"host"
);
if
(
hasHeader
)
{
return
RequestHeaders
[
"host"
].
Value
;
}
return
null
;
return
hasHeader
?
RequestHeaders
[
"host"
].
Value
:
null
;
}
set
{
...
...
@@ -154,11 +149,11 @@ namespace Titanium.Web.Proxy.Http
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"content-type"
];
header
.
Value
=
value
.
ToString
()
;
header
.
Value
=
value
;
}
else
{
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
.
ToString
()
));
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
));
}
}
...
...
@@ -219,15 +214,11 @@ namespace Titanium.Web.Proxy.Http
{
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"expect"
);
if
(
hasHeader
)
{
if
(!
hasHeader
)
return
false
;
var
header
=
RequestHeaders
[
"expect"
];
return
header
.
Value
.
Equals
(
"100-continue"
);
}
return
false
;
}
}
/// <summary>
...
...
@@ -275,13 +266,7 @@ namespace Titanium.Web.Proxy.Http
var
header
=
RequestHeaders
[
"upgrade"
];
if
(
header
.
Value
.
ToLower
()
==
"websocket"
)
{
return
true
;
}
return
false
;
return
header
.
Value
.
ToLower
()
==
"websocket"
;
}
}
...
...
@@ -305,6 +290,9 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
/// <summary>
/// Constructor.
/// </summary>
public
Request
()
{
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
8022c434
...
...
@@ -12,7 +12,13 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
class
Response
{
/// <summary>
/// Response Status Code.
/// </summary>
public
string
ResponseStatusCode
{
get
;
set
;
}
/// <summary>
/// Response Status description.
/// </summary>
public
string
ResponseStatusDescription
{
get
;
set
;
}
internal
Encoding
Encoding
=>
this
.
GetResponseCharacterEncoding
();
...
...
@@ -26,15 +32,11 @@ namespace Titanium.Web.Proxy.Http
{
var
hasHeader
=
ResponseHeaders
.
ContainsKey
(
"content-encoding"
);
if
(
hasHeader
)
{
if
(!
hasHeader
)
return
null
;
var
header
=
ResponseHeaders
[
"content-encoding"
];
return
header
.
Value
.
Trim
();
}
return
null
;
}
}
internal
Version
HttpVersion
{
get
;
set
;
}
...
...
@@ -229,10 +231,13 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
/// <summary>
/// Constructor.
/// </summary>
public
Response
()
{
this
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
this
.
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
...
...
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
View file @
8022c434
...
...
@@ -7,16 +7,25 @@ namespace Titanium.Web.Proxy.Http.Responses
/// </summary>
public
class
GenericResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="status"></param>
public
GenericResponse
(
HttpStatusCode
status
)
{
ResponseStatusCode
=
((
int
)
status
).
ToString
();
ResponseStatusDescription
=
status
.
ToString
();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="statusCode"></param>
/// <param name="statusDescription"></param>
public
GenericResponse
(
string
statusCode
,
string
statusDescription
)
{
ResponseStatusCode
=
statusCode
;
ResponseStatusDescription
=
statusCode
;
ResponseStatusDescription
=
statusDescription
;
}
}
}
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
View file @
8022c434
...
...
@@ -5,6 +5,9 @@
/// </summary>
public
sealed
class
OkResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
public
OkResponse
()
{
ResponseStatusCode
=
"200"
;
...
...
Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs
View file @
8022c434
...
...
@@ -5,6 +5,9 @@
/// </summary>
public
sealed
class
RedirectResponse
:
Response
{
/// <summary>
/// Constructor.
/// </summary>
public
RedirectResponse
()
{
ResponseStatusCode
=
"302"
;
...
...
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
8022c434
...
...
@@ -10,20 +10,38 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
abstract
class
ProxyEndPoint
{
public
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
protected
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
{
this
.
IpAddress
=
IpAddress
;
this
.
Port
=
Port
;
this
.
EnableSsl
=
EnableSsl
;
}
/// <summary>
/// Ip Address.
/// </summary>
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
/// <summary>
/// Port.
/// </summary>
public
int
Port
{
get
;
internal
set
;
}
/// <summary>
/// Enable SSL?
/// </summary>
public
bool
EnableSsl
{
get
;
internal
set
;
}
public
bool
IpV6Enabled
=>
IpAddress
==
IPAddress
.
IPv6Any
||
IpAddress
==
IPAddress
.
IPv6Loopback
||
IpAddress
==
IPAddress
.
IPv6None
;
/// <summary>
/// Is IPv6 enabled?
/// </summary>
public
bool
IpV6Enabled
=>
Equals
(
IpAddress
,
IPAddress
.
IPv6Any
)
||
Equals
(
IpAddress
,
IPAddress
.
IPv6Loopback
)
||
Equals
(
IpAddress
,
IPAddress
.
IPv6None
);
internal
TcpListener
listener
{
get
;
set
;
}
}
...
...
@@ -37,10 +55,22 @@ namespace Titanium.Web.Proxy.Models
internal
bool
IsSystemHttpProxy
{
get
;
set
;
}
internal
bool
IsSystemHttpsProxy
{
get
;
set
;
}
/// <summary>
/// List of host names to exclude using Regular Expressions.
/// </summary>
public
List
<
string
>
ExcludedHttpsHostNameRegex
{
get
;
set
;
}
/// <summary>
/// Generic certificate to use for SSL decryption.
/// </summary>
public
X509Certificate2
GenericCertificate
{
get
;
set
;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
public
ExplicitProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
...
...
@@ -54,13 +84,19 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
//This is valid only when UseServerNameIndication is set to false
public
string
GenericCertificateName
{
get
;
set
;
}
// public bool UseServerNameIndication { get; set; }
/// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public
string
GenericCertificateName
{
get
;
set
;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="IpAddress"></param>
/// <param name="Port"></param>
/// <param name="EnableSsl"></param>
public
TransparentProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
...
...
Titanium.Web.Proxy/Models/ExternalProxy.cs
View file @
8022c434
...
...
@@ -13,10 +13,16 @@ namespace Titanium.Web.Proxy.Models
private
string
userName
;
private
string
password
;
/// <summary>
/// Use default windows credentials?
/// </summary>
public
bool
UseDefaultCredentials
{
get
;
set
;
}
/// <summary>
/// Username.
/// </summary>
public
string
UserName
{
get
{
return
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
UserName
:
userName
;
}
get
=>
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
UserName
:
userName
;
set
{
userName
=
value
;
...
...
@@ -28,9 +34,12 @@ namespace Titanium.Web.Proxy.Models
}
}
/// <summary>
/// Password.
/// </summary>
public
string
Password
{
get
{
return
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
Password
:
password
;
}
get
=>
UseDefaultCredentials
?
DefaultCredentials
.
Value
.
Password
:
password
;
set
{
password
=
value
;
...
...
@@ -42,7 +51,13 @@ namespace Titanium.Web.Proxy.Models
}
}
/// <summary>
/// Host name.
/// </summary>
public
string
HostName
{
get
;
set
;
}
/// <summary>
/// Port.
/// </summary>
public
int
Port
{
get
;
set
;
}
}
}
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
8022c434
...
...
@@ -7,6 +7,12 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
HttpHeader
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <exception cref="Exception"></exception>
public
HttpHeader
(
string
name
,
string
value
)
{
if
(
string
.
IsNullOrEmpty
(
name
))
...
...
@@ -18,7 +24,13 @@ namespace Titanium.Web.Proxy.Models
Value
=
value
.
Trim
();
}
/// <summary>
/// Header Name.
/// </summary>
public
string
Name
{
get
;
set
;
}
/// <summary>
/// Header Value.
/// </summary>
public
string
Value
{
get
;
set
;
}
/// <summary>
...
...
@@ -27,7 +39,7 @@ namespace Titanium.Web.Proxy.Models
/// <returns></returns>
public
override
string
ToString
()
{
return
string
.
Format
(
"{0}: {1}"
,
Name
,
Value
)
;
return
$"
{
Name
}
:
{
Value
}
"
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/CertificateMaker.cs
View file @
8022c434
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
8022c434
...
...
@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal
class
CertificateManager
:
IDisposable
{
private
CertificateMaker
certEngine
=
null
;
private
readonly
CertificateMaker
certEngine
;
private
bool
clearCertificates
{
get
;
set
;
}
/// <summary>
...
...
@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
private
readonly
IDictionary
<
string
,
CachedCertificate
>
certificateCache
;
private
Action
<
Exception
>
exceptionFunc
;
private
readonly
Action
<
Exception
>
exceptionFunc
;
internal
string
Issuer
{
get
;
private
set
;
}
internal
string
RootCertificateName
{
get
;
private
set
;
}
internal
string
Issuer
{
get
;
}
internal
string
RootCertificateName
{
get
;
}
internal
X509Certificate2
rootCertificate
{
get
;
set
;
}
...
...
@@ -42,10 +42,11 @@ namespace Titanium.Web.Proxy.Network
internal
X509Certificate2
GetRootCertificate
()
{
var
fileName
=
Path
.
Combine
(
System
.
IO
.
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
),
"rootCert.pfx"
);
var
path
=
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
);
if
(
null
==
path
)
throw
new
NullReferenceException
();
var
fileName
=
Path
.
Combine
(
path
,
"rootCert.pfx"
);
if
(
File
.
Exists
(
fileName
))
{
if
(!
File
.
Exists
(
fileName
))
return
null
;
try
{
return
new
X509Certificate2
(
fileName
,
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
...
...
@@ -57,8 +58,6 @@ namespace Titanium.Web.Proxy.Network
return
null
;
}
}
return
null
;
}
/// <summary>
/// Attempts to create a RootCertificate
/// </summary>
...
...
@@ -75,7 +74,7 @@ namespace Titanium.Web.Proxy.Network
{
rootCertificate
=
CreateCertificate
(
RootCertificateName
,
true
);
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
...
...
@@ -83,38 +82,36 @@ namespace Titanium.Web.Proxy.Network
{
try
{
var
fileName
=
Path
.
Combine
(
System
.
IO
.
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
),
"rootCert.pfx"
);
var
path
=
Path
.
GetDirectoryName
(
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
);
if
(
null
==
path
)
throw
new
NullReferenceException
();
var
fileName
=
Path
.
Combine
(
path
,
"rootCert.pfx"
);
File
.
WriteAllBytes
(
fileName
,
rootCertificate
.
Export
(
X509ContentType
.
Pkcs12
));
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
}
return
rootCertificate
!=
null
;
}
/// <summary>
/// Create an SSL certificate
/// </summary>
/// <param name="store"></param>
/// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param>
/// <returns></returns>
internal
virtual
X509Certificate2
CreateCertificate
(
string
certificateName
,
bool
isRootCertificate
)
{
try
{
if
(
certificateCache
.
ContainsKey
(
certificateName
))
{
var
cached
=
certificateCache
[
certificateName
];
cached
.
LastAccess
=
DateTime
.
Now
;
return
cached
.
Certificate
;
}
}
catch
{
}
X509Certificate2
certificate
=
null
;
lock
(
string
.
Intern
(
certificateName
))
{
...
...
@@ -124,7 +121,7 @@ namespace Titanium.Web.Proxy.Network
{
certificate
=
certEngine
.
MakeCertificate
(
certificateName
,
isRootCertificate
,
rootCertificate
);
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
exceptionFunc
(
e
);
}
...
...
@@ -165,9 +162,6 @@ namespace Titanium.Web.Proxy.Network
{
clearCertificates
=
true
;
while
(
clearCertificates
)
{
try
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
certificateCacheTimeOutMinutes
);
...
...
@@ -177,10 +171,6 @@ namespace Titanium.Web.Proxy.Network
foreach
(
var
cache
in
outdated
)
certificateCache
.
Remove
(
cache
.
Key
);
}
finally
{
}
//after a minute come back to check for outdated certificates in cache
await
Task
.
Delay
(
1000
*
60
);
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
View file @
8022c434
...
...
@@ -47,6 +47,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
LastAccess
=
DateTime
.
Now
;
}
/// <summary>
/// Dispose.
/// </summary>
public
void
Dispose
()
{
Stream
.
Close
();
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
8022c434
...
...
@@ -19,14 +19,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal
class
TcpConnectionFactory
{
/// <summary>
/// Creates a TCP connection to server
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="httpCmd"></param>
/// <param name="httpVersion"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
...
...
@@ -69,7 +67,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if
(!
string
.
IsNullOrEmpty
(
externalHttpsProxy
.
UserName
)
&&
externalHttpsProxy
.
Password
!=
null
)
{
await
writer
.
WriteLineAsync
(
"Proxy-Connection: keep-alive"
);
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
System
.
Text
.
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
}
await
writer
.
WriteLineAsync
();
await
writer
.
FlushAsync
();
...
...
@@ -81,7 +79,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
var
result
=
await
reader
.
ReadLineAsync
();
if
(!
new
string
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
{
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
View file @
8022c434
...
...
@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Gets the local end point.
/// </summary>
public
IPEndPoint
LocalEndPoint
{
get
;
private
set
;
}
public
IPEndPoint
LocalEndPoint
{
get
;
}
/// <summary>
/// Gets the remote end point.
/// </summary>
public
IPEndPoint
RemoteEndPoint
{
get
;
private
set
;
}
public
IPEndPoint
RemoteEndPoint
{
get
;
}
/// <summary>
/// Gets the process identifier.
/// </summary>
public
int
ProcessId
{
get
;
private
set
;
}
public
int
ProcessId
{
get
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
View file @
8022c434
...
...
@@ -6,7 +6,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Represents collection of TcpRows
/// </summary>
/// <seealso cref="System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}" />
/// <seealso>
/// <cref>System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}</cref>
/// </seealso>
internal
class
TcpTable
:
IEnumerable
<
TcpRow
>
{
private
readonly
IEnumerable
<
TcpRow
>
tcpRows
;
...
...
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
8022c434
...
...
@@ -24,32 +24,46 @@ namespace Titanium.Web.Proxy
try
{
if
(
!
httpHeaders
.
Where
(
t
=>
t
.
Name
==
"Proxy-Authorization"
).
Any
(
))
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
{
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Required"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
}
else
{
var
headerValue
=
httpHeaders
.
Where
(
t
=>
t
.
Name
==
"Proxy-Authorization"
).
FirstOrDefault
()
.
Value
.
Trim
();
var
header
=
httpHeaders
.
FirstOrDefault
(
t
=>
t
.
Name
==
"Proxy-Authorization"
);
if
(
null
==
header
)
throw
new
NullReferenceException
();
var
headerValue
=
header
.
Value
.
Trim
();
if
(!
headerValue
.
ToLower
().
StartsWith
(
"basic"
))
{
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
@@ -63,10 +77,17 @@ namespace Titanium.Web.Proxy
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
@@ -76,17 +97,20 @@ namespace Titanium.Web.Proxy
var
password
=
decoded
.
Substring
(
decoded
.
IndexOf
(
':'
)
+
1
);
return
await
AuthenticateUserFunc
(
username
,
password
).
ConfigureAwait
(
false
);
}
}
catch
(
Exception
e
)
{
ExceptionFunc
(
new
ProxyAuthorizationException
(
"Error whilst authorizing request"
,
e
,
httpHeaders
));
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
();
response
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>();
response
.
ResponseHeaders
.
Add
(
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
));
response
.
ResponseHeaders
.
Add
(
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
));
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
8022c434
...
...
@@ -47,14 +47,16 @@ namespace Titanium.Web.Proxy
/// <summary>
/// A object that creates tcp connection to server
/// </summary>
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
set
;
}
private
TcpConnectionFactory
tcpConnectionFactory
{
get
;
}
/// <summary>
/// Manage system proxy settings
/// </summary>
private
SystemProxyManager
systemProxySettingsManager
{
get
;
set
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
#if !DEBUG
private
FireFoxProxySettingsManager
firefoxProxySettingsManager
{
get
;
set
;
}
#endif
/// <summary>
/// Buffer size used throughout this proxy
...
...
@@ -138,14 +140,8 @@ namespace Titanium.Web.Proxy
/// </summary>
public
Action
<
Exception
>
ExceptionFunc
{
get
{
return
exceptionFunc
??
defaultExceptionFunc
.
Value
;
}
set
{
exceptionFunc
=
value
;
}
get
=>
exceptionFunc
??
defaultExceptionFunc
.
Value
;
set
=>
exceptionFunc
=
value
;
}
/// <summary>
...
...
@@ -172,6 +168,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// return the ExternalProxy object with valid credentials
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
{
get
;
...
...
@@ -203,6 +200,11 @@ namespace Titanium.Web.Proxy
/// </summary>
public
ProxyServer
()
:
this
(
null
,
null
)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="rootCertificateName">Name of root certificate.</param>
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
RootCertificateName
=
rootCertificateName
;
...
...
@@ -214,8 +216,9 @@ namespace Titanium.Web.Proxy
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
tcpConnectionFactory
=
new
TcpConnectionFactory
();
systemProxySettingsManager
=
new
SystemProxyManager
();
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
#if !DEBUG
new
FireFoxProxySettingsManager
();
#endif
RootCertificateName
=
RootCertificateName
??
"Titanium Root Certificate Authority"
;
RootCertificateIssuerName
=
RootCertificateIssuerName
??
"Titanium"
;
}
...
...
@@ -277,7 +280,7 @@ namespace Titanium.Web.Proxy
#if !DEBUG
firefoxProxySettingsManager
.
AddFirefox
();
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {
1} and port: {2} as System HTTP Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
Console
.
WriteLine
(
"Set endpoint at Ip {
0} and port: {1} as System HTTP Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
...
...
@@ -313,7 +316,7 @@ namespace Titanium.Web.Proxy
#if !DEBUG
firefoxProxySettingsManager
.
AddFirefox
();
#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 {
0} and port: {1} as System HTTPS Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
/// <summary>
...
...
@@ -461,6 +464,7 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint"></param>
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
if
(
endPoint
==
null
)
throw
new
ArgumentNullException
(
nameof
(
endPoint
));
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
...
...
@@ -542,6 +546,9 @@ namespace Titanium.Web.Proxy
endPoint
.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
/// <summary>
/// Dispose Proxy.
/// </summary>
public
void
Dispose
()
{
if
(
proxyRunning
)
...
...
@@ -551,5 +558,45 @@ namespace Titanium.Web.Proxy
certificateCacheManager
?.
Dispose
();
}
/// <summary>
/// Invocator for BeforeRequest event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnBeforeRequest
(
object
sender
,
SessionEventArgs
e
)
{
BeforeRequest
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for BeforeResponse event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns></returns>
protected
virtual
void
OnBeforeResponse
(
object
sender
,
SessionEventArgs
e
)
{
BeforeResponse
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ServerCertificateValidationCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnServerCertificateValidationCallback
(
object
sender
,
CertificateValidationEventArgs
e
)
{
ServerCertificateValidationCallback
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ClientCertifcateSelectionCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnClientCertificateSelectionCallback
(
object
sender
,
CertificateSelectionEventArgs
e
)
{
ClientCertificateSelectionCallback
?.
Invoke
(
sender
,
e
);
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/RequestHandler.cs
View file @
8022c434
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/ResponseHandler.cs
View file @
8022c434
...
...
@@ -17,7 +17,11 @@ namespace Titanium.Web.Proxy
/// </summary>
partial
class
ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
/// <summary>
/// Called asynchronously when a request was successfully and we received the response
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
//read response & headers from server
...
...
@@ -156,14 +160,14 @@ namespace Titanium.Web.Proxy
private
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
StreamWriter
responseWriter
)
{
await
responseWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
code
,
description
)
);
await
responseWriter
.
WriteLineAsync
(
$"HTTP/
{
version
.
Major
}
.
{
version
.
Minor
}
{
code
}
{
description
}
"
);
}
/// <summary>
/// Write response headers to client
/// </summary>
/// <param name="responseWriter"></param>
/// <param name="
headers
"></param>
/// <param name="
response
"></param>
/// <returns></returns>
private
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
Response
response
)
{
...
...
@@ -220,7 +224,6 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Handle dispose of a client/server session
/// </summary>
/// <param name="tcpClient"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
...
...
@@ -235,21 +238,13 @@ namespace Titanium.Web.Proxy
clientStream
.
Dispose
();
}
if
(
args
!=
null
)
{
args
.
Dispose
();
}
args
?.
Dispose
();
if
(
clientStreamReader
!=
null
)
{
clientStreamReader
.
Dispose
();
}
clientStreamReader
?.
Dispose
();
if
(
clientStreamWriter
!=
null
)
{
if
(
clientStreamWriter
==
null
)
return
;
clientStreamWriter
.
Close
();
clientStreamWriter
.
Dispose
();
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
8022c434
using
System
;
using
System.Text
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Shared
{
...
...
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