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
e8e41ca3
Commit
e8e41ca3
authored
May 15, 2017
by
Jehonathan Thomas
Committed by
GitHub
May 15, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #223 from justcoding121/develop
Merge with develop
parents
54cfea8f
b6d18a61
Show whitespace changes
Inline
Side-by-side
Showing
50 changed files
with
287 additions
and
340 deletions
+287
-340
PULL_REQUEST_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
+1
-1
Titanium.Web.Proxy.sln.DotSettings
Titanium.Web.Proxy.sln.DotSettings
+1
-0
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+6
-7
DeflateCompression.cs
Titanium.Web.Proxy/Compression/DeflateCompression.cs
+1
-1
GZipCompression.cs
Titanium.Web.Proxy/Compression/GZipCompression.cs
+1
-1
DecompressionFactory.cs
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
+1
-1
DefaultDecompression.cs
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
+0
-1
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+1
-1
IDecompression.cs
Titanium.Web.Proxy/Decompression/IDecompression.cs
+1
-1
CertificateSelectionEventArgs.cs
...Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
+5
-1
CertificateValidationEventArgs.cs
...eb.Proxy/EventArguments/CertificateValidationEventArgs.cs
+2
-0
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+30
-41
BodyNotFoundException.cs
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
+2
-3
ProxyAuthorizationException.cs
Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs
+1
-1
ProxyException.cs
Titanium.Web.Proxy/Exceptions/ProxyException.cs
+1
-1
ProxyHttpException.cs
Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs
+1
-1
ByteArrayExtensions.cs
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
+0
-1
HttpWebRequestExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
+1
-1
HttpWebResponseExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
+1
-1
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+40
-41
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+0
-1
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+3
-4
CustomBufferedStream.cs
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
+4
-4
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+1
-1
Network.cs
Titanium.Web.Proxy/Helpers/Network.cs
+1
-2
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+4
-5
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+13
-13
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+9
-6
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+2
-7
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+3
-9
GenericResponse.cs
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
+27
-27
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+3
-4
ExternalProxy.cs
Titanium.Web.Proxy/Models/ExternalProxy.cs
+5
-3
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+1
-1
CachedCertificate.cs
Titanium.Web.Proxy/Network/CachedCertificate.cs
+0
-1
BCCertificateMaker.cs
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
+5
-6
ICertificateMaker.cs
Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs
+1
-1
WinCertificateMaker.cs
...nium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
+22
-25
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+11
-10
ProxyClient.cs
Titanium.Web.Proxy/Network/ProxyClient.cs
+0
-1
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+5
-5
TcpRow.cs
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
+5
-5
TcpTable.cs
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
+1
-1
AssemblyInfo.cs
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
+5
-5
ProxyAuthorizationHandler.cs
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
+2
-5
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+18
-34
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+23
-33
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+7
-9
ProxyConstants.cs
Titanium.Web.Proxy/Shared/ProxyConstants.cs
+4
-4
app.config
Titanium.Web.Proxy/app.config
+5
-2
No files found.
PULL_REQUEST_TEMPLATE.md
View file @
e8e41ca3
Doneness:
Doneness:
-
[
]
Build is okay - I made sure that this change is building successfully.
-
[
]
Build is okay - I made sure that this change is building successfully.
-
[
]
No Bugs - I made sure that this change is working properly as expected. It does
'n
t have any bugs that you are aware of.
-
[
]
No Bugs - I made sure that this change is working properly as expected. It does
n'
t have any bugs that you are aware of.
-
[
]
Branching - If this is not a hotfix, I am making this request against develop branch
-
[
]
Branching - If this is not a hotfix, I am making this request against develop branch
Titanium.Web.Proxy.sln.DotSettings
View file @
e8e41ca3
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
...
...
Titanium.Web.Proxy/CertificateHandler.cs
View file @
e8e41ca3
...
@@ -33,13 +33,12 @@ namespace Titanium.Web.Proxy
...
@@ -33,13 +33,12 @@ namespace Titanium.Web.Proxy
};
};
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
{
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateValidationEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateValidationEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
Task
.
WhenAll
(
handlerTasks
).
Wait
();
...
@@ -115,7 +114,7 @@ namespace Titanium.Web.Proxy
...
@@ -115,7 +114,7 @@ namespace Titanium.Web.Proxy
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
{
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
Task
.
WhenAll
(
handlerTasks
).
Wait
();
...
...
Titanium.Web.Proxy/Compression/DeflateCompression.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Compression/GZipCompression.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
View file @
e8e41ca3
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
{
{
internal
IDecompression
Create
(
string
type
)
internal
IDecompression
Create
(
string
type
)
{
{
switch
(
type
)
switch
(
type
)
{
{
case
"gzip"
:
case
"gzip"
:
return
new
GZipDecompression
();
return
new
GZipDecompression
();
...
...
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
View file @
e8e41ca3
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
namespace
Titanium.Web.Proxy.Decompression
namespace
Titanium.Web.Proxy.Decompression
{
{
/// <summary>
/// <summary>
/// When no compression is specified just return the byte array
/// When no compression is specified just return the byte array
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Decompression/IDecompression.cs
View file @
e8e41ca3
Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs
View file @
e8e41ca3
...
@@ -12,26 +12,30 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -12,26 +12,30 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sender object.
/// Sender object.
/// </summary>
/// </summary>
public
object
Sender
{
get
;
internal
set
;
}
public
object
Sender
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Target host.
/// Target host.
/// </summary>
/// </summary>
public
string
TargetHost
{
get
;
internal
set
;
}
public
string
TargetHost
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Local certificates.
/// Local certificates.
/// </summary>
/// </summary>
public
X509CertificateCollection
LocalCertificates
{
get
;
internal
set
;
}
public
X509CertificateCollection
LocalCertificates
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Remote certificate.
/// Remote certificate.
/// </summary>
/// </summary>
public
X509Certificate
RemoteCertificate
{
get
;
internal
set
;
}
public
X509Certificate
RemoteCertificate
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Acceptable issuers.
/// Acceptable issuers.
/// </summary>
/// </summary>
public
string
[]
AcceptableIssuers
{
get
;
internal
set
;
}
public
string
[]
AcceptableIssuers
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Client Certificate.
/// Client Certificate.
/// </summary>
/// </summary>
public
X509Certificate
ClientCertificate
{
get
;
set
;
}
public
X509Certificate
ClientCertificate
{
get
;
set
;
}
}
}
}
}
Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs
View file @
e8e41ca3
...
@@ -13,10 +13,12 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -13,10 +13,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// Certificate
/// Certificate
/// </summary>
/// </summary>
public
X509Certificate
Certificate
{
get
;
internal
set
;
}
public
X509Certificate
Certificate
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Certificate chain
/// Certificate chain
/// </summary>
/// </summary>
public
X509Chain
Chain
{
get
;
internal
set
;
}
public
X509Chain
Chain
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// SSL policy errors.
/// SSL policy errors.
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
e8e41ca3
...
@@ -22,7 +22,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -22,7 +22,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
public
class
SessionEventArgs
:
EventArgs
,
IDisposable
public
class
SessionEventArgs
:
EventArgs
,
IDisposable
{
{
/// <summary>
/// <summary>
/// Size of Buffers used by this object
/// Size of Buffers used by this object
/// </summary>
/// </summary>
...
@@ -47,11 +46,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -47,11 +46,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// <summary>
/// Should we send a rerequest
/// Should we send a rerequest
/// </summary>
/// </summary>
public
bool
ReRequest
public
bool
ReRequest
{
get
;
set
;
}
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Does this session uses SSL
/// Does this session uses SSL
...
@@ -61,7 +56,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -61,7 +56,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// <summary>
/// Client End Point.
/// Client End Point.
/// </summary>
/// </summary>
public
IPEndPoint
ClientEndPoint
=>
(
IPEndPoint
)
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
public
IPEndPoint
ClientEndPoint
=>
(
IPEndPoint
)
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
/// <summary>
/// <summary>
/// A web session corresponding to a single request/response sequence
/// A web session corresponding to a single request/response sequence
...
@@ -108,14 +103,13 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -108,14 +103,13 @@ namespace Titanium.Web.Proxy.EventArguments
//Caching check
//Caching check
if
(
WebSession
.
Request
.
RequestBody
==
null
)
if
(
WebSession
.
Request
.
RequestBody
==
null
)
{
{
//If chunked then its easy just read the whole body with the content length mentioned in the request header
//If chunked then its easy just read the whole body with the content length mentioned in the request header
using
(
var
requestBodyStream
=
new
MemoryStream
())
using
(
var
requestBodyStream
=
new
MemoryStream
())
{
{
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
WebSession
.
Request
.
IsChunked
)
if
(
WebSession
.
Request
.
IsChunked
)
{
{
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
requestBodyStream
);
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
requestBodyStream
);
}
}
else
else
{
{
...
@@ -125,7 +119,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -125,7 +119,6 @@ namespace Titanium.Web.Proxy.EventArguments
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
await
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
WebSession
.
Request
.
ContentLength
);
}
}
else
if
(
WebSession
.
Request
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Request
.
HttpVersion
.
Minor
==
0
)
else
if
(
WebSession
.
Request
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Request
.
HttpVersion
.
Minor
==
0
)
{
{
...
@@ -140,7 +133,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -140,7 +133,6 @@ namespace Titanium.Web.Proxy.EventArguments
//So that next time we can deliver body from cache
//So that next time we can deliver body from cache
WebSession
.
Request
.
RequestBodyRead
=
true
;
WebSession
.
Request
.
RequestBodyRead
=
true
;
}
}
}
}
/// <summary>
/// <summary>
...
@@ -156,7 +148,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -156,7 +148,7 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol
//If chuncked the read chunk by chunk until we hit chunk end symbol
if
(
WebSession
.
Response
.
IsChunked
)
if
(
WebSession
.
Response
.
IsChunked
)
{
{
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStreamChunked
(
bufferSize
,
responseBodyStream
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStreamChunked
(
responseBodyStream
);
}
}
else
else
{
{
...
@@ -165,7 +157,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -165,7 +157,6 @@ namespace Titanium.Web.Proxy.EventArguments
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
WebSession
.
Response
.
ContentLength
);
}
}
else
if
((
WebSession
.
Response
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
||
WebSession
.
Response
.
ContentLength
==
-
1
)
else
if
((
WebSession
.
Response
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
||
WebSession
.
Response
.
ContentLength
==
-
1
)
{
{
...
@@ -175,7 +166,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -175,7 +166,6 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
());
responseBodyStream
.
ToArray
());
}
}
//set this to true for caching
//set this to true for caching
WebSession
.
Response
.
ResponseBodyRead
=
true
;
WebSession
.
Response
.
ResponseBodyRead
=
true
;
...
@@ -199,6 +189,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -199,6 +189,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
return
WebSession
.
Request
.
RequestBody
;
return
WebSession
.
Request
.
RequestBody
;
}
}
/// <summary>
/// <summary>
/// Gets the request body as string
/// Gets the request body as string
/// </summary>
/// </summary>
...
@@ -265,7 +256,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -265,7 +256,6 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
await
SetRequestBody
(
WebSession
.
Request
.
Encoding
.
GetBytes
(
body
));
await
SetRequestBody
(
WebSession
.
Request
.
Encoding
.
GetBytes
(
body
));
}
}
/// <summary>
/// <summary>
...
@@ -415,7 +405,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -415,7 +405,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="headers"></param>
/// <param name="headers"></param>
public
async
Task
Ok
(
byte
[]
result
,
Dictionary
<
string
,
HttpHeader
>
headers
)
public
async
Task
Ok
(
byte
[]
result
,
Dictionary
<
string
,
HttpHeader
>
headers
)
{
{
var
response
=
new
OkResponse
();
var
response
=
new
OkResponse
();
if
(
headers
!=
null
&&
headers
.
Count
>
0
)
if
(
headers
!=
null
&&
headers
.
Count
>
0
)
{
{
...
@@ -436,9 +426,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -436,9 +426,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
/// <param name="html"></param>
/// <param name="html"></param>
/// <param name="status"></param>
/// <param name="status"></param>
public
async
Task
GenericResponse
(
string
html
,
HttpStatusCode
status
)
public
async
Task
GenericResponse
(
string
html
,
HttpStatusCode
status
)
{
{
await
GenericResponse
(
html
,
null
,
status
);
await
GenericResponse
(
html
,
null
,
status
);
}
}
/// <summary>
/// <summary>
...
@@ -450,21 +440,21 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -450,21 +440,21 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="html"></param>
/// <param name="html"></param>
/// <param name="headers"></param>
/// <param name="headers"></param>
/// <param name="status"></param>
/// <param name="status"></param>
public
async
Task
GenericResponse
(
string
html
,
Dictionary
<
string
,
HttpHeader
>
headers
,
HttpStatusCode
status
)
public
async
Task
GenericResponse
(
string
html
,
Dictionary
<
string
,
HttpHeader
>
headers
,
HttpStatusCode
status
)
{
{
if
(
WebSession
.
Request
.
RequestLocked
)
if
(
WebSession
.
Request
.
RequestLocked
)
{
{
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
}
}
if
(
html
==
null
)
if
(
html
==
null
)
{
{
html
=
string
.
Empty
;
html
=
string
.
Empty
;
}
}
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
await
GenericResponse
(
result
,
headers
,
status
);
await
GenericResponse
(
result
,
headers
,
status
);
}
}
/// <summary>
/// <summary>
...
@@ -531,7 +521,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -531,7 +521,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
}
}
}
}
}
}
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
View file @
e8e41ca3
namespace
Titanium.Web.Proxy.Exceptions
namespace
Titanium.Web.Proxy.Exceptions
{
{
/// <summary>
/// <summary>
/// An expception thrown when body is unexpectedly empty
/// An expception thrown when body is unexpectedly empty
...
...
Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Exceptions/ProxyException.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
View file @
e8e41ca3
...
@@ -21,6 +21,5 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -21,6 +21,5 @@ namespace Titanium.Web.Proxy.Extensions
Array
.
Copy
(
data
,
index
,
result
,
0
,
length
);
Array
.
Copy
(
data
,
index
,
result
,
0
,
length
);
return
result
;
return
result
;
}
}
}
}
}
}
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
e8e41ca3
...
@@ -69,10 +69,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -69,10 +69,9 @@ namespace Titanium.Web.Proxy.Extensions
/// Copies the stream chunked
/// Copies the stream chunked
/// </summary>
/// </summary>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamReader"></param>
/// <param name="bufferSize"></param>
/// <param name="stream"></param>
/// <param name="stream"></param>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
int
bufferSize
,
Stream
stream
)
internal
static
async
Task
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
)
{
{
while
(
true
)
while
(
true
)
{
{
...
@@ -93,6 +92,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -93,6 +92,7 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
}
}
/// <summary>
/// <summary>
/// Writes the byte array body to the given stream; optionally chunked
/// Writes the byte array body to the given stream; optionally chunked
/// </summary>
/// </summary>
...
@@ -136,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -136,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions
if
(
contentLength
<
bufferSize
)
if
(
contentLength
<
bufferSize
)
{
{
bytesToRead
=
(
int
)
contentLength
;
bytesToRead
=
(
int
)
contentLength
;
}
}
var
buffer
=
new
byte
[
bufferSize
];
var
buffer
=
new
byte
[
bufferSize
];
...
@@ -154,12 +154,12 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -154,12 +154,12 @@ namespace Titanium.Web.Proxy.Extensions
bytesRead
=
0
;
bytesRead
=
0
;
var
remainingBytes
=
(
contentLength
-
totalBytesRead
);
var
remainingBytes
=
(
contentLength
-
totalBytesRead
);
bytesToRead
=
remainingBytes
>
(
long
)
bufferSize
?
bufferSize
:
(
int
)
remainingBytes
;
bytesToRead
=
remainingBytes
>
(
long
)
bufferSize
?
bufferSize
:
(
int
)
remainingBytes
;
}
}
}
}
else
else
{
{
await
WriteResponseBodyChunked
(
inStreamReader
,
bufferSize
,
outStream
);
await
WriteResponseBodyChunked
(
inStreamReader
,
outStream
);
}
}
}
}
...
@@ -167,10 +167,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -167,10 +167,9 @@ namespace Titanium.Web.Proxy.Extensions
/// Copies the streams chunked
/// Copies the streams chunked
/// </summary>
/// </summary>
/// <param name="inStreamReader"></param>
/// <param name="inStreamReader"></param>
/// <param name="bufferSize"></param>
/// <param name="outStream"></param>
/// <param name="outStream"></param>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
WriteResponseBodyChunked
(
this
CustomBinaryReader
inStreamReader
,
int
bufferSize
,
Stream
outStream
)
internal
static
async
Task
WriteResponseBodyChunked
(
this
CustomBinaryReader
inStreamReader
,
Stream
outStream
)
{
{
while
(
true
)
while
(
true
)
{
{
...
@@ -199,6 +198,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -199,6 +198,7 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
}
}
/// <summary>
/// <summary>
/// Copies the given input bytes to output stream chunked
/// Copies the given input bytes to output stream chunked
/// </summary>
/// </summary>
...
@@ -216,6 +216,5 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -216,6 +216,5 @@ namespace Titanium.Web.Proxy.Extensions
await
outStream
.
WriteAsync
(
ProxyConstants
.
ChunkEnd
,
0
,
ProxyConstants
.
ChunkEnd
.
Length
);
await
outStream
.
WriteAsync
(
ProxyConstants
.
ChunkEnd
,
0
,
ProxyConstants
.
ChunkEnd
.
Length
);
}
}
}
}
}
}
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
e8e41ca3
...
@@ -33,5 +33,4 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -33,5 +33,4 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
}
}
}
}
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
e8e41ca3
...
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
...
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
/// <summary>
/// <summary>
/// A custom binary reader that would allo us to read string line by line
/// A custom binary reader that would allo us to read string line by line
/// using the specified encoding
/// using the specified encoding
...
@@ -124,7 +123,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -124,7 +123,7 @@ namespace Titanium.Web.Proxy.Helpers
int
bytesToRead
=
bufferSize
;
int
bytesToRead
=
bufferSize
;
if
(
totalBytesToRead
<
bufferSize
)
if
(
totalBytesToRead
<
bufferSize
)
bytesToRead
=
(
int
)
totalBytesToRead
;
bytesToRead
=
(
int
)
totalBytesToRead
;
var
buffer
=
staticBuffer
;
var
buffer
=
staticBuffer
;
int
bytesRead
;
int
bytesRead
;
...
@@ -138,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -138,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers
break
;
break
;
var
remainingBytes
=
totalBytesToRead
-
totalBytesRead
;
var
remainingBytes
=
totalBytesToRead
-
totalBytesRead
;
bytesToRead
=
Math
.
Min
(
bufferSize
,
(
int
)
remainingBytes
);
bytesToRead
=
Math
.
Min
(
bufferSize
,
(
int
)
remainingBytes
);
if
(
totalBytesRead
+
bytesToRead
>
buffer
.
Length
)
if
(
totalBytesRead
+
bytesToRead
>
buffer
.
Length
)
{
{
...
...
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
View file @
e8e41ca3
...
@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Helpers
{
{
if
(
asyncResult
is
ReadAsyncResult
)
if
(
asyncResult
is
ReadAsyncResult
)
{
{
return
((
ReadAsyncResult
)
asyncResult
).
ReadBytes
;
return
((
ReadAsyncResult
)
asyncResult
).
ReadBytes
;
}
}
return
baseStream
.
EndRead
(
asyncResult
);
return
baseStream
.
EndRead
(
asyncResult
);
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Helpers/Network.cs
View file @
e8e41ca3
...
@@ -69,7 +69,6 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -69,7 +69,6 @@ namespace Titanium.Web.Proxy.Helpers
}
}
catch
(
SocketException
)
catch
(
SocketException
)
{
{
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
e8e41ca3
...
@@ -190,8 +190,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -190,8 +190,8 @@ namespace Titanium.Web.Proxy.Helpers
}
}
return
null
;
return
null
;
}
}
/// <summary>
/// <summary>
/// Prepares the proxy server registry (create empty values if they don't exist)
/// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary>
/// </summary>
...
@@ -207,7 +207,6 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -207,7 +207,6 @@ namespace Titanium.Web.Proxy.Helpers
{
{
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
}
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
e8e41ca3
...
@@ -93,21 +93,21 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -93,21 +93,21 @@ namespace Titanium.Web.Proxy.Helpers
var
ipVersionValue
=
ipVersion
==
IpVersion
.
Ipv4
?
NativeMethods
.
AfInet
:
NativeMethods
.
AfInet6
;
var
ipVersionValue
=
ipVersion
==
IpVersion
.
Ipv4
?
NativeMethods
.
AfInet
:
NativeMethods
.
AfInet6
;
if
(
NativeMethods
.
GetExtendedTcpTable
(
tcpTable
,
ref
tcpTableLength
,
false
,
ipVersionValue
,
(
int
)
NativeMethods
.
TcpTableType
.
OwnerPidAll
,
0
)
!=
0
)
if
(
NativeMethods
.
GetExtendedTcpTable
(
tcpTable
,
ref
tcpTableLength
,
false
,
ipVersionValue
,
(
int
)
NativeMethods
.
TcpTableType
.
OwnerPidAll
,
0
)
!=
0
)
{
{
try
try
{
{
tcpTable
=
Marshal
.
AllocHGlobal
(
tcpTableLength
);
tcpTable
=
Marshal
.
AllocHGlobal
(
tcpTableLength
);
if
(
NativeMethods
.
GetExtendedTcpTable
(
tcpTable
,
ref
tcpTableLength
,
true
,
ipVersionValue
,
(
int
)
NativeMethods
.
TcpTableType
.
OwnerPidAll
,
0
)
==
0
)
if
(
NativeMethods
.
GetExtendedTcpTable
(
tcpTable
,
ref
tcpTableLength
,
true
,
ipVersionValue
,
(
int
)
NativeMethods
.
TcpTableType
.
OwnerPidAll
,
0
)
==
0
)
{
{
NativeMethods
.
TcpTable
table
=
(
NativeMethods
.
TcpTable
)
Marshal
.
PtrToStructure
(
tcpTable
,
typeof
(
NativeMethods
.
TcpTable
));
NativeMethods
.
TcpTable
table
=
(
NativeMethods
.
TcpTable
)
Marshal
.
PtrToStructure
(
tcpTable
,
typeof
(
NativeMethods
.
TcpTable
));
IntPtr
rowPtr
=
(
IntPtr
)
((
long
)
tcpTable
+
Marshal
.
SizeOf
(
table
.
length
));
IntPtr
rowPtr
=
(
IntPtr
)
((
long
)
tcpTable
+
Marshal
.
SizeOf
(
table
.
length
));
for
(
int
i
=
0
;
i
<
table
.
length
;
++
i
)
for
(
int
i
=
0
;
i
<
table
.
length
;
++
i
)
{
{
tcpRows
.
Add
(
new
TcpRow
((
NativeMethods
.
TcpRow
)
Marshal
.
PtrToStructure
(
rowPtr
,
typeof
(
NativeMethods
.
TcpRow
))));
tcpRows
.
Add
(
new
TcpRow
((
NativeMethods
.
TcpRow
)
Marshal
.
PtrToStructure
(
rowPtr
,
typeof
(
NativeMethods
.
TcpRow
))));
rowPtr
=
(
IntPtr
)
((
long
)
rowPtr
+
Marshal
.
SizeOf
(
typeof
(
NativeMethods
.
TcpRow
)));
rowPtr
=
(
IntPtr
)
((
long
)
rowPtr
+
Marshal
.
SizeOf
(
typeof
(
NativeMethods
.
TcpRow
)));
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
e8e41ca3
...
@@ -22,14 +22,17 @@ namespace Titanium.Web.Proxy.Http
...
@@ -22,14 +22,17 @@ namespace Titanium.Web.Proxy.Http
/// Request ID.
/// Request ID.
/// </summary>
/// </summary>
public
Guid
RequestId
{
get
;
}
public
Guid
RequestId
{
get
;
}
/// <summary>
/// <summary>
/// Headers passed with Connect.
/// Headers passed with Connect.
/// </summary>
/// </summary>
public
List
<
HttpHeader
>
ConnectHeaders
{
get
;
set
;
}
public
List
<
HttpHeader
>
ConnectHeaders
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Web Request.
/// Web Request.
/// </summary>
/// </summary>
public
Request
Request
{
get
;
set
;
}
public
Request
Request
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Web Response.
/// Web Response.
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
e8e41ca3
...
@@ -47,7 +47,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -47,7 +47,6 @@ namespace Titanium.Web.Proxy.Http
{
{
RequestHeaders
.
Add
(
"Host"
,
new
HttpHeader
(
"Host"
,
value
));
RequestHeaders
.
Add
(
"Host"
,
new
HttpHeader
(
"Host"
,
value
));
}
}
}
}
}
}
...
@@ -119,9 +118,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -119,9 +118,7 @@ namespace Titanium.Web.Proxy.Http
{
{
RequestHeaders
.
Remove
(
"content-length"
);
RequestHeaders
.
Remove
(
"content-length"
);
}
}
}
}
}
}
}
}
...
@@ -156,7 +153,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -156,7 +153,6 @@ namespace Titanium.Web.Proxy.Http
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
));
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
));
}
}
}
}
}
}
/// <summary>
/// <summary>
...
@@ -298,6 +294,5 @@ namespace Titanium.Web.Proxy.Http
...
@@ -298,6 +294,5 @@ namespace Titanium.Web.Proxy.Http
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueRequestHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueRequestHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
}
}
}
}
Titanium.Web.Proxy/Http/Response.cs
View file @
e8e41ca3
...
@@ -16,6 +16,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -16,6 +16,7 @@ namespace Titanium.Web.Proxy.Http
/// Response Status Code.
/// Response Status Code.
/// </summary>
/// </summary>
public
string
ResponseStatusCode
{
get
;
set
;
}
public
string
ResponseStatusCode
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Response Status description.
/// Response Status description.
/// </summary>
/// </summary>
...
@@ -61,7 +62,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -61,7 +62,6 @@ namespace Titanium.Web.Proxy.Http
}
}
return
true
;
return
true
;
}
}
}
}
...
@@ -82,7 +82,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -82,7 +82,6 @@ namespace Titanium.Web.Proxy.Http
}
}
return
null
;
return
null
;
}
}
}
}
...
@@ -110,7 +109,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -110,7 +109,6 @@ namespace Titanium.Web.Proxy.Http
}
}
return
-
1
;
return
-
1
;
}
}
set
set
{
{
...
@@ -160,7 +158,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -160,7 +158,6 @@ namespace Titanium.Web.Proxy.Http
}
}
return
false
;
return
false
;
}
}
set
set
{
{
...
@@ -186,9 +183,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -186,9 +183,7 @@ namespace Titanium.Web.Proxy.Http
{
{
ResponseHeaders
.
Remove
(
"transfer-encoding"
);
ResponseHeaders
.
Remove
(
"transfer-encoding"
);
}
}
}
}
}
}
}
}
...
@@ -240,5 +235,4 @@ namespace Titanium.Web.Proxy.Http
...
@@ -240,5 +235,4 @@ namespace Titanium.Web.Proxy.Http
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
}
}
}
}
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
View file @
e8e41ca3
using
System.Net
;
using
System.Net
;
namespace
Titanium.Web.Proxy.Http.Responses
namespace
Titanium.Web.Proxy.Http.Responses
{
{
/// <summary>
/// <summary>
/// Anything other than a 200 or 302 response
/// Anything other than a 200 or 302 response
/// </summary>
/// </summary>
public
class
GenericResponse
:
Response
public
class
GenericResponse
:
Response
{
{
/// <summary>
/// <summary>
/// Constructor.
/// Constructor.
/// </summary>
/// </summary>
/// <param name="status"></param>
/// <param name="status"></param>
public
GenericResponse
(
HttpStatusCode
status
)
public
GenericResponse
(
HttpStatusCode
status
)
{
{
ResponseStatusCode
=
((
int
)
status
).
ToString
();
ResponseStatusCode
=
((
int
)
status
).
ToString
();
ResponseStatusDescription
=
status
.
ToString
();
ResponseStatusDescription
=
status
.
ToString
();
}
}
/// <summary>
/// <summary>
/// Constructor.
/// Constructor.
/// </summary>
/// </summary>
/// <param name="statusCode"></param>
/// <param name="statusCode"></param>
/// <param name="statusDescription"></param>
/// <param name="statusDescription"></param>
public
GenericResponse
(
string
statusCode
,
string
statusDescription
)
public
GenericResponse
(
string
statusCode
,
string
statusDescription
)
{
{
ResponseStatusCode
=
statusCode
;
ResponseStatusCode
=
statusCode
;
ResponseStatusDescription
=
statusDescription
;
ResponseStatusDescription
=
statusDescription
;
}
}
}
}
}
}
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
e8e41ca3
...
@@ -30,10 +30,12 @@ namespace Titanium.Web.Proxy.Models
...
@@ -30,10 +30,12 @@ namespace Titanium.Web.Proxy.Models
/// Ip Address.
/// Ip Address.
/// </summary>
/// </summary>
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Port.
/// Port.
/// </summary>
/// </summary>
public
int
Port
{
get
;
internal
set
;
}
public
int
Port
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Enable SSL?
/// Enable SSL?
/// </summary>
/// </summary>
...
@@ -75,7 +77,7 @@ namespace Titanium.Web.Proxy.Models
...
@@ -75,7 +77,7 @@ namespace Titanium.Web.Proxy.Models
throw
new
ArgumentException
(
"Cannot set excluded when included is set"
);
throw
new
ArgumentException
(
"Cannot set excluded when included is set"
);
}
}
ExcludedHttpsHostNameRegexList
=
value
?.
Select
(
x
=>
new
Regex
(
x
,
RegexOptions
.
Compiled
)).
ToList
();
ExcludedHttpsHostNameRegexList
=
value
?.
Select
(
x
=>
new
Regex
(
x
,
RegexOptions
.
Compiled
)).
ToList
();
}
}
}
}
...
@@ -110,7 +112,6 @@ namespace Titanium.Web.Proxy.Models
...
@@ -110,7 +112,6 @@ namespace Titanium.Web.Proxy.Models
public
ExplicitProxyEndPoint
(
IPAddress
ipAddress
,
int
port
,
bool
enableSsl
)
public
ExplicitProxyEndPoint
(
IPAddress
ipAddress
,
int
port
,
bool
enableSsl
)
:
base
(
ipAddress
,
port
,
enableSsl
)
:
base
(
ipAddress
,
port
,
enableSsl
)
{
{
}
}
}
}
...
@@ -120,7 +121,6 @@ namespace Titanium.Web.Proxy.Models
...
@@ -120,7 +121,6 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
/// </summary>
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
{
/// <summary>
/// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// 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
/// This is valid only when UseServerNameIndication is set to false
...
@@ -139,5 +139,4 @@ namespace Titanium.Web.Proxy.Models
...
@@ -139,5 +139,4 @@ namespace Titanium.Web.Proxy.Models
GenericCertificateName
=
"localhost"
;
GenericCertificateName
=
"localhost"
;
}
}
}
}
}
}
Titanium.Web.Proxy/Models/ExternalProxy.cs
View file @
e8e41ca3
...
@@ -26,7 +26,8 @@ namespace Titanium.Web.Proxy.Models
...
@@ -26,7 +26,8 @@ namespace Titanium.Web.Proxy.Models
/// <summary>
/// <summary>
/// Username.
/// Username.
/// </summary>
/// </summary>
public
string
UserName
{
public
string
UserName
{
get
{
return
UseDefaultCredentials
?
defaultCredentials
.
Value
.
UserName
:
userName
;
}
get
{
return
UseDefaultCredentials
?
defaultCredentials
.
Value
.
UserName
:
userName
;
}
set
set
{
{
...
@@ -60,6 +61,7 @@ namespace Titanium.Web.Proxy.Models
...
@@ -60,6 +61,7 @@ namespace Titanium.Web.Proxy.Models
/// Host name.
/// Host name.
/// </summary>
/// </summary>
public
string
HostName
{
get
;
set
;
}
public
string
HostName
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Port.
/// Port.
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Network/CachedCertificate.cs
View file @
e8e41ca3
...
@@ -20,6 +20,5 @@ namespace Titanium.Web.Proxy.Network
...
@@ -20,6 +20,5 @@ namespace Titanium.Web.Proxy.Network
{
{
LastAccess
=
DateTime
.
Now
;
LastAccess
=
DateTime
.
Now
;
}
}
}
}
}
}
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
View file @
e8e41ca3
...
@@ -110,7 +110,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -110,7 +110,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
// Corresponding private key
// Corresponding private key
var
privateKeyInfo
=
PrivateKeyInfoFactory
.
CreatePrivateKeyInfo
(
subjectKeyPair
.
Private
);
var
privateKeyInfo
=
PrivateKeyInfoFactory
.
CreatePrivateKeyInfo
(
subjectKeyPair
.
Private
);
var
seq
=
(
Asn1Sequence
)
Asn1Object
.
FromByteArray
(
privateKeyInfo
.
ParsePrivateKey
().
GetDerEncoded
());
var
seq
=
(
Asn1Sequence
)
Asn1Object
.
FromByteArray
(
privateKeyInfo
.
ParsePrivateKey
().
GetDerEncoded
());
if
(
seq
.
Count
!=
9
)
if
(
seq
.
Count
!=
9
)
{
{
...
@@ -190,5 +190,4 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -190,5 +190,4 @@ namespace Titanium.Web.Proxy.Network.Certificate
return
MakeCertificateInternal
(
isRoot
,
subject
,
$"CN=
{
subject
}
"
,
DateTime
.
UtcNow
.
AddDays
(-
certificateGraceDays
),
DateTime
.
UtcNow
.
AddDays
(
certificateValidDays
),
isRoot
?
null
:
signingCert
);
return
MakeCertificateInternal
(
isRoot
,
subject
,
$"CN=
{
subject
}
"
,
DateTime
.
UtcNow
.
AddDays
(-
certificateGraceDays
),
DateTime
.
UtcNow
.
AddDays
(
certificateValidDays
),
isRoot
?
null
:
signingCert
);
}
}
}
}
}
}
Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
View file @
e8e41ca3
...
@@ -5,7 +5,6 @@ using System.Threading;
...
@@ -5,7 +5,6 @@ using System.Threading;
namespace
Titanium.Web.Proxy.Network.Certificate
namespace
Titanium.Web.Proxy.Network.Certificate
{
{
/// <summary>
/// <summary>
/// Certificate Maker - uses MakeCert
/// Certificate Maker - uses MakeCert
/// Calls COM objects using reflection
/// Calls COM objects using reflection
...
@@ -90,7 +89,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -90,7 +89,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
}
}
var
x500CertDN
=
Activator
.
CreateInstance
(
typeX500DN
);
var
x500CertDN
=
Activator
.
CreateInstance
(
typeX500DN
);
var
typeValue
=
new
object
[]
{
fullSubject
,
0
};
var
typeValue
=
new
object
[]
{
fullSubject
,
0
};
typeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500CertDN
,
typeValue
);
typeX500DN
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
x500CertDN
,
typeValue
);
var
x500RootCertDN
=
Activator
.
CreateInstance
(
typeX500DN
);
var
x500RootCertDN
=
Activator
.
CreateInstance
(
typeX500DN
);
...
@@ -111,16 +110,16 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -111,16 +110,16 @@ namespace Titanium.Web.Proxy.Network.Certificate
if
(
sharedPrivateKey
==
null
)
if
(
sharedPrivateKey
==
null
)
{
{
sharedPrivateKey
=
Activator
.
CreateInstance
(
typeX509PrivateKey
);
sharedPrivateKey
=
Activator
.
CreateInstance
(
typeX509PrivateKey
);
typeValue
=
new
object
[]
{
sProviderName
};
typeValue
=
new
object
[]
{
sProviderName
};
typeX509PrivateKey
.
InvokeMember
(
"ProviderName"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeX509PrivateKey
.
InvokeMember
(
"ProviderName"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeValue
[
0
]
=
2
;
typeValue
[
0
]
=
2
;
typeX509PrivateKey
.
InvokeMember
(
"ExportPolicy"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeX509PrivateKey
.
InvokeMember
(
"ExportPolicy"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeValue
=
new
object
[]
{
(
isRoot
?
2
:
1
)
};
typeValue
=
new
object
[]
{
(
isRoot
?
2
:
1
)
};
typeX509PrivateKey
.
InvokeMember
(
"KeySpec"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeX509PrivateKey
.
InvokeMember
(
"KeySpec"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
if
(!
isRoot
)
if
(!
isRoot
)
{
{
typeValue
=
new
object
[]
{
176
};
typeValue
=
new
object
[]
{
176
};
typeX509PrivateKey
.
InvokeMember
(
"KeyUsage"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
typeX509PrivateKey
.
InvokeMember
(
"KeyUsage"
,
BindingFlags
.
PutDispProperty
,
null
,
sharedPrivateKey
,
typeValue
);
}
}
...
@@ -150,9 +149,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -150,9 +149,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
var
requestCert
=
Activator
.
CreateInstance
(
typeRequestCert
);
var
requestCert
=
Activator
.
CreateInstance
(
typeRequestCert
);
typeValue
=
new
[]
{
1
,
sharedPrivateKey
,
string
.
Empty
};
typeValue
=
new
[]
{
1
,
sharedPrivateKey
,
string
.
Empty
};
typeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
requestCert
,
typeValue
);
typeValue
=
new
[]
{
x500CertDN
};
typeValue
=
new
[]
{
x500CertDN
};
typeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeValue
[
0
]
=
x500RootCertDN
;
typeValue
[
0
]
=
x500RootCertDN
;
typeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
...
@@ -187,14 +186,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -187,14 +186,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
var
extNames
=
Activator
.
CreateInstance
(
typeExtNames
);
var
extNames
=
Activator
.
CreateInstance
(
typeExtNames
);
var
altDnsNames
=
Activator
.
CreateInstance
(
typeCAlternativeName
);
var
altDnsNames
=
Activator
.
CreateInstance
(
typeCAlternativeName
);
typeValue
=
new
object
[]
{
3
,
subject
};
typeValue
=
new
object
[]
{
3
,
subject
};
typeCAlternativeName
.
InvokeMember
(
"InitializeFromString"
,
BindingFlags
.
InvokeMethod
,
null
,
altDnsNames
,
typeValue
);
typeCAlternativeName
.
InvokeMember
(
"InitializeFromString"
,
BindingFlags
.
InvokeMethod
,
null
,
altDnsNames
,
typeValue
);
typeValue
=
new
[]
{
altDnsNames
};
typeValue
=
new
[]
{
altDnsNames
};
typeAltNamesCollection
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
altNameCollection
,
typeValue
);
typeAltNamesCollection
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
altNameCollection
,
typeValue
);
typeValue
=
new
[]
{
altNameCollection
};
typeValue
=
new
[]
{
altNameCollection
};
typeExtNames
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
extNames
,
typeValue
);
typeExtNames
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
extNames
,
typeValue
);
typeValue
[
0
]
=
extNames
;
typeValue
[
0
]
=
extNames
;
...
@@ -205,27 +204,27 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -205,27 +204,27 @@ namespace Titanium.Web.Proxy.Network.Certificate
{
{
var
signerCertificate
=
Activator
.
CreateInstance
(
typeSignerCertificate
);
var
signerCertificate
=
Activator
.
CreateInstance
(
typeSignerCertificate
);
typeValue
=
new
object
[]
{
0
,
0
,
12
,
signingCertificate
.
Thumbprint
};
typeValue
=
new
object
[]
{
0
,
0
,
12
,
signingCertificate
.
Thumbprint
};
typeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
signerCertificate
,
typeValue
);
typeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
signerCertificate
,
typeValue
);
typeValue
=
new
[]
{
signerCertificate
};
typeValue
=
new
[]
{
signerCertificate
};
typeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
}
}
else
else
{
{
var
basicConstraints
=
Activator
.
CreateInstance
(
typeBasicConstraints
);
var
basicConstraints
=
Activator
.
CreateInstance
(
typeBasicConstraints
);
typeValue
=
new
object
[]
{
"true"
,
"0"
};
typeValue
=
new
object
[]
{
"true"
,
"0"
};
typeBasicConstraints
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
basicConstraints
,
typeValue
);
typeBasicConstraints
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
basicConstraints
,
typeValue
);
typeValue
=
new
[]
{
basicConstraints
};
typeValue
=
new
[]
{
basicConstraints
};
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
certificate
,
typeValue
);
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
certificate
,
typeValue
);
}
}
oid
=
Activator
.
CreateInstance
(
typeOID
);
oid
=
Activator
.
CreateInstance
(
typeOID
);
typeValue
=
new
object
[]
{
1
,
0
,
0
,
hashAlg
};
typeValue
=
new
object
[]
{
1
,
0
,
0
,
hashAlg
};
typeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
oid
,
typeValue
);
typeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
oid
,
typeValue
);
typeValue
=
new
[]
{
oid
};
typeValue
=
new
[]
{
oid
};
typeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
requestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
requestCert
,
null
);
typeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
requestCert
,
null
);
...
@@ -238,7 +237,6 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -238,7 +237,6 @@ namespace Titanium.Web.Proxy.Network.Certificate
{
{
typeValue
[
0
]
=
fullSubject
;
typeValue
[
0
]
=
fullSubject
;
typeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
x509Enrollment
,
typeValue
);
typeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
x509Enrollment
,
typeValue
);
}
}
var
members
=
typeX509Enrollment
.
GetMembers
();
var
members
=
typeX509Enrollment
.
GetMembers
();
...
@@ -246,14 +244,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -246,14 +244,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue
[
0
]
=
0
;
typeValue
[
0
]
=
0
;
var
createCertRequest
=
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
var
createCertRequest
=
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
typeValue
=
new
[]
{
2
,
createCertRequest
,
0
,
string
.
Empty
};
typeValue
=
new
[]
{
2
,
createCertRequest
,
0
,
string
.
Empty
};
typeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
typeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
typeValue
=
new
object
[]
{
null
,
0
,
1
};
typeValue
=
new
object
[]
{
null
,
0
,
1
};
try
try
{
{
var
empty
=
(
string
)
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
var
empty
=
(
string
)
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
x509Enrollment
,
typeValue
);
return
new
X509Certificate2
(
Convert
.
FromBase64String
(
empty
),
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
return
new
X509Certificate2
(
Convert
.
FromBase64String
(
empty
),
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
}
}
catch
(
Exception
)
catch
(
Exception
)
...
@@ -300,5 +298,4 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -300,5 +298,4 @@ namespace Titanium.Web.Proxy.Network.Certificate
return
rCert
;
return
rCert
;
}
}
}
}
}
}
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
e8e41ca3
...
@@ -50,8 +50,8 @@ namespace Titanium.Web.Proxy.Network
...
@@ -50,8 +50,8 @@ namespace Titanium.Web.Proxy.Network
if
(
certEngine
==
null
)
if
(
certEngine
==
null
)
{
{
certEngine
=
engine
==
CertificateEngine
.
BouncyCastle
?
certEngine
=
engine
==
CertificateEngine
.
BouncyCastle
(
ICertificateMaker
)
new
BCCertificateMaker
()
?
(
ICertificateMaker
)
new
BCCertificateMaker
()
:
new
WinCertificateMaker
();
:
new
WinCertificateMaker
();
}
}
}
}
...
@@ -160,6 +160,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -160,6 +160,7 @@ namespace Titanium.Web.Proxy.Network
return
null
;
return
null
;
}
}
}
}
/// <summary>
/// <summary>
/// Attempts to create a RootCertificate
/// Attempts to create a RootCertificate
/// </summary>
/// </summary>
...
@@ -248,7 +249,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -248,7 +249,7 @@ namespace Titanium.Web.Proxy.Network
}
}
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
{
{
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
{
Certificate
=
certificate
});
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
{
Certificate
=
certificate
});
}
}
}
}
else
else
...
...
Titanium.Web.Proxy/Network/ProxyClient.cs
View file @
e8e41ca3
...
@@ -28,6 +28,5 @@ namespace Titanium.Web.Proxy.Network
...
@@ -28,6 +28,5 @@ namespace Titanium.Web.Proxy.Network
/// used to write line by line to client
/// used to write line by line to client
/// </summary>
/// </summary>
internal
StreamWriter
ClientStreamWriter
{
get
;
set
;
}
internal
StreamWriter
ClientStreamWriter
{
get
;
set
;
}
}
}
}
}
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
e8e41ca3
...
@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
bufferSize
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
bufferSize
);
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
true
)
{
NewLine
=
ProxyConstants
.
NewLine
})
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
true
)
{
NewLine
=
ProxyConstants
.
NewLine
})
{
{
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
...
@@ -83,7 +83,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -83,7 +83,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
var
result
=
await
reader
.
ReadLineAsync
();
var
result
=
await
reader
.
ReadLineAsync
();
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ContainsIgnoreCase
(
s
)))
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ContainsIgnoreCase
(
s
)))
{
{
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
}
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
View file @
e8e41ca3
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
View file @
e8e41ca3
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
e8e41ca3
...
@@ -12,7 +12,6 @@ namespace Titanium.Web.Proxy
...
@@ -12,7 +12,6 @@ namespace Titanium.Web.Proxy
{
{
public
partial
class
ProxyServer
public
partial
class
ProxyServer
{
{
private
async
Task
<
bool
>
CheckAuthorization
(
StreamWriter
clientStreamWriter
,
IEnumerable
<
HttpHeader
>
headers
)
private
async
Task
<
bool
>
CheckAuthorization
(
StreamWriter
clientStreamWriter
,
IEnumerable
<
HttpHeader
>
headers
)
{
{
if
(
AuthenticateUserFunc
==
null
)
if
(
AuthenticateUserFunc
==
null
)
...
@@ -26,7 +25,6 @@ namespace Titanium.Web.Proxy
...
@@ -26,7 +25,6 @@ namespace Titanium.Web.Proxy
{
{
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
{
{
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
"Proxy Authentication Required"
,
clientStreamWriter
);
"Proxy Authentication Required"
,
clientStreamWriter
);
var
response
=
new
Response
var
response
=
new
Response
...
@@ -116,7 +114,6 @@ namespace Titanium.Web.Proxy
...
@@ -116,7 +114,6 @@ namespace Titanium.Web.Proxy
await
clientStreamWriter
.
WriteLineAsync
();
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
return
false
;
}
}
}
}
}
}
}
}
Titanium.Web.Proxy/ProxyServer.cs
View file @
e8e41ca3
...
@@ -201,31 +201,19 @@ namespace Titanium.Web.Proxy
...
@@ -201,31 +201,19 @@ namespace Titanium.Web.Proxy
/// Parameters are username, password provided by client
/// Parameters are username, password provided by client
/// return true for successful authentication
/// return true for successful authentication
/// </summary>
/// </summary>
public
Func
<
string
,
string
,
Task
<
bool
>>
AuthenticateUserFunc
public
Func
<
string
,
string
,
Task
<
bool
>>
AuthenticateUserFunc
{
get
;
set
;
}
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP requests
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP requests
/// return the ExternalProxy object with valid credentials
/// return the ExternalProxy object with valid credentials
/// </summary>
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpProxyFunc
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpProxyFunc
{
get
;
set
;
}
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// return the ExternalProxy object with valid credentials
/// return the ExternalProxy object with valid credentials
/// </summary>
/// </summary>
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
public
Func
<
SessionEventArgs
,
Task
<
ExternalProxy
>>
GetCustomUpStreamHttpsProxyFunc
{
get
;
set
;
}
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A list of IpAddress & port this proxy is listening to
/// A list of IpAddress & port this proxy is listening to
...
@@ -321,7 +309,7 @@ namespace Titanium.Web.Proxy
...
@@ -321,7 +309,7 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
public
void
SetAsSystemHttpProxy
(
ExplicitProxyEndPoint
endPoint
)
{
{
if
(
RunTime
.
IsRunningOnMono
())
if
(
RunTime
.
IsRunningOnMono
())
{
{
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
throw
new
Exception
(
"Mono Runtime do not support system proxy settings."
);
}
}
...
@@ -339,7 +327,6 @@ namespace Titanium.Web.Proxy
...
@@ -339,7 +327,6 @@ namespace Titanium.Web.Proxy
firefoxProxySettingsManager
.
AddFirefox
();
firefoxProxySettingsManager
.
AddFirefox
();
#endif
#endif
Console
.
WriteLine
(
"Set endpoint at Ip {0} and port: {1} as System HTTP Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
Console
.
WriteLine
(
"Set endpoint at Ip {0} and port: {1} as System HTTP Proxy"
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
}
...
@@ -373,8 +360,7 @@ namespace Titanium.Web.Proxy
...
@@ -373,8 +360,7 @@ namespace Titanium.Web.Proxy
{
{
systemProxySettingsManager
.
SetHttpsProxy
(
systemProxySettingsManager
.
SetHttpsProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
endPoint
.
Port
);
}
}
...
@@ -509,13 +495,11 @@ namespace Titanium.Web.Proxy
...
@@ -509,13 +495,11 @@ namespace Titanium.Web.Proxy
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
Listener
.
Start
();
endPoint
.
Listener
.
Start
();
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
endPoint
.
Port
=
((
IPEndPoint
)
endPoint
.
Listener
.
LocalEndpoint
).
Port
;
// accept clients asynchronously
// accept clients asynchronously
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
}
/// <summary>
/// <summary>
/// Verifiy if its safe to set this end point as System proxy
/// Verifiy if its safe to set this end point as System proxy
/// </summary>
/// </summary>
...
@@ -576,7 +560,7 @@ namespace Titanium.Web.Proxy
...
@@ -576,7 +560,7 @@ namespace Titanium.Web.Proxy
/// <param name="asyn"></param>
/// <param name="asyn"></param>
private
void
OnAcceptConnection
(
IAsyncResult
asyn
)
private
void
OnAcceptConnection
(
IAsyncResult
asyn
)
{
{
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
TcpClient
tcpClient
=
null
;
TcpClient
tcpClient
=
null
;
...
@@ -612,7 +596,6 @@ namespace Titanium.Web.Proxy
...
@@ -612,7 +596,6 @@ namespace Titanium.Web.Proxy
{
{
await
HandleClient
(
endPoint
as
ExplicitProxyEndPoint
,
tcpClient
);
await
HandleClient
(
endPoint
as
ExplicitProxyEndPoint
,
tcpClient
);
}
}
}
}
finally
finally
{
{
...
@@ -664,6 +647,7 @@ namespace Titanium.Web.Proxy
...
@@ -664,6 +647,7 @@ namespace Titanium.Web.Proxy
{
{
BeforeResponse
?.
Invoke
(
sender
,
e
);
BeforeResponse
?.
Invoke
(
sender
,
e
);
}
}
/// <summary>
/// <summary>
/// Invocator for ServerCertificateValidationCallback event.
/// Invocator for ServerCertificateValidationCallback event.
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
e8e41ca3
...
@@ -23,19 +23,17 @@ namespace Titanium.Web.Proxy
...
@@ -23,19 +23,17 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
partial
class
ProxyServer
partial
class
ProxyServer
{
{
//This is called when client is aware of proxy
//This is called when client is aware of proxy
//So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
//So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
private
async
Task
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
async
Task
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
{
CustomBufferedStream
clientStream
=
new
CustomBufferedStream
(
tcpClient
.
GetStream
(),
BufferSize
);
CustomBufferedStream
clientStream
=
new
CustomBufferedStream
(
tcpClient
.
GetStream
(),
BufferSize
);
clientStream
.
ReadTimeout
=
ConnectionTimeOutSeconds
*
1000
;
clientStream
.
ReadTimeout
=
ConnectionTimeOutSeconds
*
1000
;
clientStream
.
WriteTimeout
=
ConnectionTimeOutSeconds
*
1000
;
clientStream
.
WriteTimeout
=
ConnectionTimeOutSeconds
*
1000
;
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
var
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
var
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
Uri
httpRemoteUri
;
Uri
httpRemoteUri
;
try
try
...
@@ -55,8 +53,7 @@ namespace Titanium.Web.Proxy
...
@@ -55,8 +53,7 @@ namespace Titanium.Web.Proxy
//Find the request Verb
//Find the request Verb
var
httpVerb
=
httpCmdSplit
[
0
].
ToUpper
();
var
httpVerb
=
httpCmdSplit
[
0
].
ToUpper
();
httpRemoteUri
=
httpVerb
==
"CONNECT"
?
httpRemoteUri
=
httpVerb
==
"CONNECT"
?
new
Uri
(
"http://"
+
httpCmdSplit
[
1
])
:
new
Uri
(
httpCmdSplit
[
1
]);
new
Uri
(
"http://"
+
httpCmdSplit
[
1
])
:
new
Uri
(
httpCmdSplit
[
1
]);
//parse the HTTP version
//parse the HTTP version
var
version
=
new
Version
(
1
,
1
);
var
version
=
new
Version
(
1
,
1
);
...
@@ -122,7 +119,7 @@ namespace Titanium.Web.Proxy
...
@@ -122,7 +119,7 @@ namespace Titanium.Web.Proxy
clientStream
=
new
CustomBufferedStream
(
sslStream
,
BufferSize
);
clientStream
=
new
CustomBufferedStream
(
sslStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
}
}
catch
catch
{
{
...
@@ -134,7 +131,6 @@ namespace Titanium.Web.Proxy
...
@@ -134,7 +131,6 @@ namespace Titanium.Web.Proxy
//Now read the actual HTTPS request line
//Now read the actual HTTPS request line
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
}
}
//Sorry cannot do a HTTPS request decrypt to port 80 at this time
//Sorry cannot do a HTTPS request decrypt to port 80 at this time
else
if
(
httpVerb
==
"CONNECT"
)
else
if
(
httpVerb
==
"CONNECT"
)
...
@@ -191,9 +187,8 @@ namespace Titanium.Web.Proxy
...
@@ -191,9 +187,8 @@ namespace Titanium.Web.Proxy
clientStream
=
new
CustomBufferedStream
(
sslStream
,
BufferSize
);
clientStream
=
new
CustomBufferedStream
(
sslStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
//HTTPS server created - we can now decrypt the client's traffic
//HTTPS server created - we can now decrypt the client's traffic
}
}
catch
(
Exception
)
catch
(
Exception
)
{
{
...
@@ -206,7 +201,7 @@ namespace Titanium.Web.Proxy
...
@@ -206,7 +201,7 @@ namespace Titanium.Web.Proxy
else
else
{
{
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
BufferSize
);
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
clientStreamWriter
=
new
StreamWriter
(
clientStream
)
{
NewLine
=
ProxyConstants
.
NewLine
};
}
}
//now read the request line
//now read the request line
...
@@ -382,7 +377,7 @@ namespace Titanium.Web.Proxy
...
@@ -382,7 +377,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
args
.
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
{
{
var
remoteEndPoint
=
(
IPEndPoint
)
args
.
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
var
remoteEndPoint
=
(
IPEndPoint
)
args
.
ProxyClient
.
TcpClient
.
Client
.
RemoteEndPoint
;
//If client is localhost get the process id
//If client is localhost get the process id
if
(
NetworkHelper
.
IsLocalIpAddress
(
remoteEndPoint
.
Address
))
if
(
NetworkHelper
.
IsLocalIpAddress
(
remoteEndPoint
.
Address
))
...
@@ -392,7 +387,6 @@ namespace Titanium.Web.Proxy
...
@@ -392,7 +387,6 @@ namespace Titanium.Web.Proxy
//can't access process Id of remote request from remote machine
//can't access process Id of remote request from remote machine
return
-
1
;
return
-
1
;
});
});
try
try
{
{
...
@@ -458,7 +452,6 @@ namespace Titanium.Web.Proxy
...
@@ -458,7 +452,6 @@ namespace Titanium.Web.Proxy
if
(
httpsHostName
==
null
&&
(
await
CheckAuthorization
(
clientStreamWriter
,
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
))
if
(
httpsHostName
==
null
&&
(
await
CheckAuthorization
(
clientStreamWriter
,
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
))
{
{
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
break
;
break
;
}
}
...
@@ -474,7 +467,7 @@ namespace Titanium.Web.Proxy
...
@@ -474,7 +467,7 @@ namespace Titanium.Web.Proxy
for
(
var
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
for
(
var
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
}
await
Task
.
WhenAll
(
handlerTasks
);
await
Task
.
WhenAll
(
handlerTasks
);
...
@@ -510,7 +503,6 @@ namespace Titanium.Web.Proxy
...
@@ -510,7 +503,6 @@ namespace Titanium.Web.Proxy
// read the next request
// read the next request
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
...
@@ -518,7 +510,6 @@ namespace Titanium.Web.Proxy
...
@@ -518,7 +510,6 @@ namespace Titanium.Web.Proxy
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
break
;
break
;
}
}
}
}
//dispose
//dispose
...
@@ -578,13 +569,12 @@ namespace Titanium.Web.Proxy
...
@@ -578,13 +569,12 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Request
.
ContentLength
>
0
)
if
(
args
.
WebSession
.
Request
.
ContentLength
>
0
)
{
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
BufferSize
,
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
BufferSize
,
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
}
}
//Need to revist, find any potential bugs
//Need to revist, find any potential bugs
//send the request body bytes to server in chunks
//send the request body bytes to server in chunks
else
if
(
args
.
WebSession
.
Request
.
IsChunked
)
else
if
(
args
.
WebSession
.
Request
.
IsChunked
)
{
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
BufferSize
,
postStream
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
postStream
);
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e8e41ca3
...
@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy
...
@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
this
,
args
);
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
this
,
args
);
}
}
await
Task
.
WhenAll
(
handlerTasks
);
await
Task
.
WhenAll
(
handlerTasks
);
...
@@ -122,7 +122,6 @@ namespace Titanium.Web.Proxy
...
@@ -122,7 +122,6 @@ namespace Titanium.Web.Proxy
}
}
await
args
.
ProxyClient
.
ClientStream
.
FlushAsync
();
await
args
.
ProxyClient
.
ClientStream
.
FlushAsync
();
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
...
@@ -217,7 +216,6 @@ namespace Titanium.Web.Proxy
...
@@ -217,7 +216,6 @@ namespace Titanium.Web.Proxy
headers
.
Remove
(
"proxy-connection"
);
headers
.
Remove
(
"proxy-connection"
);
}
}
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
e8e41ca3
...
@@ -7,9 +7,9 @@ namespace Titanium.Web.Proxy.Shared
...
@@ -7,9 +7,9 @@ namespace Titanium.Web.Proxy.Shared
/// </summary>
/// </summary>
internal
class
ProxyConstants
internal
class
ProxyConstants
{
{
internal
static
readonly
char
[]
SpaceSplit
=
{
' '
};
internal
static
readonly
char
[]
SpaceSplit
=
{
' '
};
internal
static
readonly
char
[]
ColonSplit
=
{
':'
};
internal
static
readonly
char
[]
ColonSplit
=
{
':'
};
internal
static
readonly
char
[]
SemiColonSplit
=
{
';'
};
internal
static
readonly
char
[]
SemiColonSplit
=
{
';'
};
internal
static
readonly
byte
[]
NewLineBytes
=
Encoding
.
ASCII
.
GetBytes
(
NewLine
);
internal
static
readonly
byte
[]
NewLineBytes
=
Encoding
.
ASCII
.
GetBytes
(
NewLine
);
...
...
Titanium.Web.Proxy/app.config
View file @
e8e41ca3
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
configuration
>
<
runtime
>
<
runtime
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
...
@@ -12,4 +12,7 @@
...
@@ -12,4 +12,7 @@
</
dependentAssembly
>
</
dependentAssembly
>
</
assemblyBinding
>
</
assemblyBinding
>
</
runtime
>
</
runtime
>
<
startup
><
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.5"
/></
startup
></
configuration
>
<
startup
>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.5"
/>
</
startup
>
</
configuration
>
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