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
fe08a1fb
Commit
fe08a1fb
authored
May 16, 2017
by
Jehonathan Thomas
Committed by
GitHub
May 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #233 from honfika/develop
connection count locking + usings sorted
parents
30125ee1
d44ea2d5
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
168 additions
and
158 deletions
+168
-158
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+6
-6
AssemblyInfo.cs
...ium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs
+0
-1
SslTests.cs
Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs
+5
-5
CertificateManagerTests.cs
...s/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
+3
-4
Titanium.Web.Proxy.sln.DotSettings
Titanium.Web.Proxy.sln.DotSettings
+13
-1
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+5
-23
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+7
-7
FuncExtensions.cs
Titanium.Web.Proxy/Extensions/FuncExtensions.cs
+34
-0
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+3
-3
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+2
-2
CustomBufferedStream.cs
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
+1
-1
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+4
-4
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+2
-5
HeaderParser.cs
Titanium.Web.Proxy/Http/HeaderParser.cs
+3
-3
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+2
-2
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+2
-2
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+3
-3
GenericResponse.cs
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
+1
-1
BCCertificateMaker.cs
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
+1
-1
WinCertificateMaker.cs
...nium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
+4
-5
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+8
-7
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+11
-11
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+12
-10
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+26
-35
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+9
-16
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+1
-0
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -47,18 +47,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -47,18 +47,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Exclude Https addresses you don't want to proxy
//Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning
//Useful for clients that use certificate pinning
//for example google.com and dropbox.com
//for example google.com and dropbox.com
ExcludedHttpsHostNameRegex
=
new
List
<
string
>()
{
"dropbox.com"
}
ExcludedHttpsHostNameRegex
=
new
List
<
string
>
{
"dropbox.com"
}
//Include Https addresses you want to proxy (others will be excluded)
//Include Https addresses you want to proxy (others will be excluded)
//for example github.com
//for example github.com
//
IncludedHttpsHostNameRegex = new List<string>()
{ "github.com" }
//
IncludedHttpsHostNameRegex = new List<string>
{ "github.com" }
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Use self-issued generic certificate on all https requests
//Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain
//Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients
//Useful when certificate trust is not required by proxy clients
//
GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
};
};
//An explicit endpoint is where the client knows about the existence of a proxy
//An explicit endpoint is where the client knows about the existence of a proxy
...
@@ -150,7 +150,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -150,7 +150,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Modify response
//Modify response
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLine
(
"Active Server Connections:"
+
(
sender
as
ProxyServ
er
).
ServerConnectionCount
);
Console
.
WriteLine
(
"Active Server Connections:"
+
(
(
ProxyServer
)
send
er
).
ServerConnectionCount
);
if
(
requestBodyHistory
.
ContainsKey
(
e
.
Id
))
if
(
requestBodyHistory
.
ContainsKey
(
e
.
Id
))
{
{
...
@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
public
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
public
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
{
{
//set IsValid to true/false based on Certificate Errors
//set IsValid to true/false based on Certificate Errors
if
(
e
.
SslPolicyErrors
==
S
ystem
.
Net
.
Security
.
S
slPolicyErrors
.
None
)
if
(
e
.
SslPolicyErrors
==
SslPolicyErrors
.
None
)
{
{
e
.
IsValid
=
true
;
e
.
IsValid
=
true
;
}
}
...
...
Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs
View file @
fe08a1fb
using
System.Reflection
;
using
System.Reflection
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
...
...
Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
System.Diagnostics
;
using
System.Net
;
using
System.Net
;
using
System.Net.Http
;
using
System.Net.Security
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
System.Net.Http
;
using
System.Diagnostics
;
namespace
Titanium.Web.Proxy.IntegrationTests
namespace
Titanium.Web.Proxy.IntegrationTests
{
{
...
@@ -13,7 +14,6 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -13,7 +14,6 @@ namespace Titanium.Web.Proxy.IntegrationTests
public
class
SslTests
public
class
SslTests
{
{
[
TestMethod
]
[
TestMethod
]
public
void
TestSsl
()
public
void
TestSsl
()
{
{
//expand this to stress test to find
//expand this to stress test to find
...
@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
public
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
public
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
{
{
//set IsValid to true/false based on Certificate Errors
//set IsValid to true/false based on Certificate Errors
if
(
e
.
SslPolicyErrors
==
S
ystem
.
Net
.
Security
.
S
slPolicyErrors
.
None
)
if
(
e
.
SslPolicyErrors
==
SslPolicyErrors
.
None
)
{
{
e
.
IsValid
=
true
;
e
.
IsValid
=
true
;
}
}
...
...
Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Threading.Tasks
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network
;
using
System.Threading.Tasks
;
using
System.Collections.Generic
;
namespace
Titanium.Web.Proxy.UnitTests
namespace
Titanium.Web.Proxy.UnitTests
{
{
...
@@ -10,8 +10,7 @@ namespace Titanium.Web.Proxy.UnitTests
...
@@ -10,8 +10,7 @@ namespace Titanium.Web.Proxy.UnitTests
public
class
CertificateManagerTests
public
class
CertificateManagerTests
{
{
private
static
readonly
string
[]
hostNames
private
static
readonly
string
[]
hostNames
=
new
string
[]
{
"facebook.com"
,
"youtube.com"
,
"google.com"
,
=
{
"facebook.com"
,
"youtube.com"
,
"google.com"
,
"bing.com"
,
"yahoo.com"
};
"bing.com"
,
"yahoo.com"
};
private
readonly
Random
random
=
new
Random
();
private
readonly
Random
random
=
new
Random
();
...
...
Titanium.Web.Proxy.sln.DotSettings
View file @
fe08a1fb
<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:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">240</s:Int64>
<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/Abbreviations/=CN/@EntryIndexedValue">CN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DN/@EntryIndexedValue">DN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EKU/@EntryIndexedValue">EKU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KU/@EntryIndexedValue">KU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MTA/@EntryIndexedValue">MTA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OID/@EntryIndexedValue">OID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OIDS/@EntryIndexedValue">OIDS</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>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=dda2ffa1_002D435c_002D4111_002D88eb_002D1a7c93c382f0/@EntryIndexedValue"><Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy></s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=dda2ffa1_002D435c_002D4111_002D88eb_002D1a7c93c382f0/@EntryIndexedValue"><Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy></s:String>
\ No newline at end of file
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
Titanium.Web.Proxy/CertificateHandler.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Extensions
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -32,17 +32,8 @@ namespace Titanium.Web.Proxy
...
@@ -32,17 +32,8 @@ namespace Titanium.Web.Proxy
SslPolicyErrors
=
sslPolicyErrors
SslPolicyErrors
=
sslPolicyErrors
};
};
//why is the sender null?
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
ServerCertificateValidationCallback
.
InvokeParallel
(
this
,
args
);
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateValidationEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
return
args
.
IsValid
;
return
args
.
IsValid
;
}
}
...
@@ -108,17 +99,8 @@ namespace Titanium.Web.Proxy
...
@@ -108,17 +99,8 @@ namespace Titanium.Web.Proxy
ClientCertificate
=
clientCertificate
ClientCertificate
=
clientCertificate
};
};
//why is the sender null?
Delegate
[]
invocationList
=
ClientCertificateSelectionCallback
.
GetInvocationList
();
ClientCertificateSelectionCallback
.
InvokeParallel
(
this
,
args
);
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateSelectionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
return
args
.
ClientCertificate
;
return
args
.
ClientCertificate
;
}
}
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
System.Net
;
using
System.Text
;
using
System.Text
;
using
Titanium.Web.Proxy.Exception
s
;
using
System.Threading.Task
s
;
using
Titanium.Web.Proxy.Decompression
;
using
Titanium.Web.Proxy.Decompression
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http.Responses
;
using
Titanium.Web.Proxy.Http.Responses
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Network
;
using
System.Net
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
namespace
Titanium.Web.Proxy.EventArguments
namespace
Titanium.Web.Proxy.EventArguments
{
{
...
@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -56,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
...
@@ -158,7 +158,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -158,7 +158,7 @@ namespace Titanium.Web.Proxy.EventArguments
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
)
{
{
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
long
.
MaxValue
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
long
.
MaxValue
);
}
}
...
...
Titanium.Web.Proxy/Extensions/FuncExtensions.cs
0 → 100644
View file @
fe08a1fb
using
System
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Extensions
{
internal
static
class
FuncExtensions
{
public
static
void
InvokeParallel
<
T
>(
this
Func
<
object
,
T
,
Task
>
callback
,
object
sender
,
T
args
)
{
Delegate
[]
invocationList
=
callback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
T
,
Task
>)
invocationList
[
i
])(
sender
,
args
);
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
}
public
static
async
Task
InvokeParallelAsync
<
T
>(
this
Func
<
object
,
T
,
Task
>
callback
,
object
sender
,
T
args
)
{
Delegate
[]
invocationList
=
callback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
T
,
Task
>)
invocationList
[
i
])(
sender
,
args
);
}
await
Task
.
WhenAll
(
handlerTasks
);
}
}
}
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
fe08a1fb
...
@@ -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
];
...
@@ -153,8 +153,8 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -153,8 +153,8 @@ namespace Titanium.Web.Proxy.Extensions
break
;
break
;
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
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
fe08a1fb
...
@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy.Helpers
var
buffer
=
staticBuffer
;
var
buffer
=
staticBuffer
;
if
(
totalBytesToRead
<
bufferSize
)
if
(
totalBytesToRead
<
bufferSize
)
{
{
bytesToRead
=
(
int
)
totalBytesToRead
;
bytesToRead
=
(
int
)
totalBytesToRead
;
buffer
=
new
byte
[
bytesToRead
];
buffer
=
new
byte
[
bytesToRead
];
}
}
...
@@ -133,7 +133,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -133,7 +133,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 @
fe08a1fb
...
@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -198,7 +198,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/SystemProxy.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Runtime.InteropServices
;
using
Microsoft.Win32
;
using
System.Text.RegularExpressions
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
System.Runtime.InteropServices
;
using
System.Text.RegularExpressions
;
using
Microsoft.Win32
;
// Helper classes for setting system proxy settings
// Helper classes for setting system proxy settings
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
...
@@ -84,7 +84,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -84,7 +84,7 @@ namespace Titanium.Web.Proxy.Helpers
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
protocolType
==
ProxyProtocolType
.
Https
?
x
.
IsHttps
:
!
x
.
IsHttps
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
protocolType
==
ProxyProtocolType
.
Https
?
x
.
IsHttps
:
!
x
.
IsHttps
);
existingSystemProxyValues
.
Add
(
new
HttpSystemProxyValue
()
existingSystemProxyValues
.
Add
(
new
HttpSystemProxyValue
{
{
HostName
=
hostname
,
HostName
=
hostname
,
IsHttps
=
protocolType
==
ProxyProtocolType
.
Https
,
IsHttps
=
protocolType
==
ProxyProtocolType
.
Https
,
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
fe08a1fb
...
@@ -3,10 +3,9 @@ using System.Collections.Generic;
...
@@ -3,10 +3,9 @@ using System.Collections.Generic;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Net.NetworkInformation
;
using
System.Net.NetworkInformation
;
using
System.Net.Security
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
using
System.Security.Authentication
;
using
System.Text
;
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -15,8 +14,6 @@ using Titanium.Web.Proxy.Shared;
...
@@ -15,8 +14,6 @@ using Titanium.Web.Proxy.Shared;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
using
System.Net
;
internal
enum
IpVersion
internal
enum
IpVersion
{
{
Ipv4
=
1
,
Ipv4
=
1
,
...
@@ -232,7 +229,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -232,7 +229,7 @@ namespace Titanium.Web.Proxy.Helpers
finally
finally
{
{
tcpConnection
.
Dispose
();
tcpConnection
.
Dispose
();
server
.
ServerConnectionCount
--
;
Interlocked
.
Decrement
(
ref
server
.
ServerConnectionCountField
)
;
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Http/HeaderParser.cs
View file @
fe08a1fb
...
@@ -8,8 +8,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -8,8 +8,8 @@ namespace Titanium.Web.Proxy.Http
{
{
internal
static
class
HeaderParser
internal
static
class
HeaderParser
{
{
internal
static
async
Task
ReadHeaders
(
CustomBinaryReader
reader
,
internal
static
async
Task
ReadHeaders
(
CustomBinaryReader
reader
,
Dictionary
<
string
,
List
<
HttpHeader
>>
nonUniqueResponseHeaders
,
Dictionary
<
string
,
List
<
HttpHeader
>>
nonUniqueResponseHeaders
,
Dictionary
<
string
,
HttpHeader
>
headers
)
Dictionary
<
string
,
HttpHeader
>
headers
)
{
{
string
tmpLine
;
string
tmpLine
;
...
@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.Http
{
{
var
existing
=
headers
[
newHeader
.
Name
];
var
existing
=
headers
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
};
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
};
nonUniqueResponseHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
nonUniqueResponseHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
headers
.
Remove
(
newHeader
.
Name
);
headers
.
Remove
(
newHeader
.
Name
);
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
fe08a1fb
...
@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
var
requestLines
=
new
StringBuilder
();
var
requestLines
=
new
StringBuilder
();
//prepare the request & headers
//prepare the request & headers
if
(
(
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
)
||
(
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
)
)
if
(
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
||
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
)
{
{
requestLines
.
AppendLine
(
$"
{
Request
.
Method
}
{
Request
.
RequestUri
.
AbsoluteUri
}
HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
);
requestLines
.
AppendLine
(
$"
{
Request
.
Method
}
{
Request
.
RequestUri
.
AbsoluteUri
}
HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
);
}
}
...
@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.Http
{
{
requestLines
.
AppendLine
(
"Proxy-Connection: keep-alive"
);
requestLines
.
AppendLine
(
"Proxy-Connection: keep-alive"
);
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
$"
{
ServerConnection
.
UpStreamHttpProxy
.
UserName
}
:
{
ServerConnection
.
UpStreamHttpProxy
.
Password
}
"
)));
$"
{
ServerConnection
.
UpStreamHttpProxy
.
UserName
}
:
{
ServerConnection
.
UpStreamHttpProxy
.
Password
}
"
)));
}
}
//write request headers
//write request headers
foreach
(
var
headerItem
in
Request
.
RequestHeaders
)
foreach
(
var
headerItem
in
Request
.
RequestHeaders
)
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Http
namespace
Titanium.Web.Proxy.Http
{
{
...
@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http
/// request body as string
/// request body as string
/// </summary>
/// </summary>
internal
string
RequestBodyString
{
get
;
set
;
}
internal
string
RequestBodyString
{
get
;
set
;
}
internal
bool
RequestBodyRead
{
get
;
set
;
}
internal
bool
RequestBodyRead
{
get
;
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
fe08a1fb
using
System.Collections.Generic
;
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
System.Text
;
using
System.Text
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
System
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Http
namespace
Titanium.Web.Proxy.Http
{
{
...
...
Titanium.Web.Proxy/Http/Responses/GenericResponse.cs
View file @
fe08a1fb
...
@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Http.Responses
...
@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Http.Responses
/// <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
();
}
}
...
...
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
View file @
fe08a1fb
...
@@ -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
)
{
{
...
...
Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
View file @
fe08a1fb
...
@@ -114,7 +114,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -114,7 +114,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
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
)
...
@@ -243,7 +243,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -243,7 +243,7 @@ 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
);
...
@@ -251,7 +251,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -251,7 +251,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
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
)
...
@@ -293,8 +293,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -293,8 +293,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
var
graceTime
=
DateTime
.
Now
.
AddDays
(
GraceDays
);
var
graceTime
=
DateTime
.
Now
.
AddDays
(
GraceDays
);
var
now
=
DateTime
.
Now
;
var
now
=
DateTime
.
Now
;
rCert
=
!
isRoot
?
MakeCertificate
(
false
,
sSubjectCN
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
(
ValidDays
),
signingCert
)
:
rCert
=
MakeCertificate
(
isRoot
,
sSubjectCN
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
(
ValidDays
),
isRoot
?
null
:
signingCert
);
MakeCertificate
(
true
,
sSubjectCN
,
fullSubject
,
keyLength
,
HashAlgo
,
graceTime
,
now
.
AddDays
(
ValidDays
),
null
);
return
rCert
;
return
rCert
;
}
}
}
}
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Reflection
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
System.Linq
;
using
System.Collections.Concurrent
;
using
System.IO
;
using
Titanium.Web.Proxy.Network.Certificate
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Network.Certificate
;
namespace
Titanium.Web.Proxy.Network
namespace
Titanium.Web.Proxy.Network
{
{
...
@@ -51,7 +52,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -51,7 +52,7 @@ 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
();
}
}
}
}
...
@@ -132,12 +133,12 @@ namespace Titanium.Web.Proxy.Network
...
@@ -132,12 +133,12 @@ namespace Titanium.Web.Proxy.Network
private
string
GetRootCertificatePath
()
private
string
GetRootCertificatePath
()
{
{
var
assemblyLocation
=
System
.
Reflection
.
Assembly
.
GetExecutingAssembly
().
Location
;
var
assemblyLocation
=
Assembly
.
GetExecutingAssembly
().
Location
;
// dynamically loaded assemblies returns string.Empty location
// dynamically loaded assemblies returns string.Empty location
if
(
assemblyLocation
==
string
.
Empty
)
if
(
assemblyLocation
==
string
.
Empty
)
{
{
assemblyLocation
=
System
.
Reflection
.
Assembly
.
GetEntryAssembly
().
Location
;
assemblyLocation
=
Assembly
.
GetEntryAssembly
().
Location
;
}
}
var
path
=
Path
.
GetDirectoryName
(
assemblyLocation
);
var
path
=
Path
.
GetDirectoryName
(
assemblyLocation
);
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.IO
;
using
System.Linq
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
System.IO
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Net.Security
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
System.Linq
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Network.Tcp
namespace
Titanium.Web.Proxy.Network.Tcp
...
@@ -17,7 +18,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -17,7 +18,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
/// </summary>
internal
class
TcpConnectionFactory
internal
class
TcpConnectionFactory
{
{
/// <summary>
/// <summary>
/// Creates a TCP connection to server
/// Creates a TCP connection to server
/// </summary>
/// </summary>
...
@@ -30,19 +30,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -30,19 +30,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="externalHttpsProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <returns></returns>
/// <returns></returns>
internal
async
Task
<
TcpConnection
>
CreateClient
(
ProxyServer
server
,
internal
async
Task
<
TcpConnection
>
CreateClient
(
ProxyServer
server
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
bool
isHttps
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
Stream
clientStream
)
Stream
clientStream
)
{
{
TcpClient
client
;
TcpClient
client
;
CustomBufferedStream
stream
;
CustomBufferedStream
stream
;
bool
isLocalhost
=
(
externalHttpsProxy
==
null
&&
externalHttpProxy
==
null
)
?
false
:
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
);
bool
isLocalhost
=
(
externalHttpsProxy
!=
null
||
externalHttpProxy
!=
null
)
&&
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
);
bool
useHttpsProxy
=
externalHttpsProxy
!=
null
&&
externalHttpsProxy
.
HostName
!=
remoteHostName
&&
(
externalHttpsProxy
.
BypassForLocalhost
&&
!
isLocalhost
)
;
bool
useHttpsProxy
=
externalHttpsProxy
!=
null
&&
externalHttpsProxy
.
HostName
!=
remoteHostName
&&
externalHttpsProxy
.
BypassForLocalhost
&&
!
isLocalhost
;
bool
useHttpProxy
=
externalHttpProxy
!=
null
&&
externalHttpProxy
.
HostName
!=
remoteHostName
&&
(
externalHttpProxy
.
BypassForLocalhost
&&
!
isLocalhost
)
;
bool
useHttpProxy
=
externalHttpProxy
!=
null
&&
externalHttpProxy
.
HostName
!=
remoteHostName
&&
externalHttpProxy
.
BypassForLocalhost
&&
!
isLocalhost
;
if
(
isHttps
)
if
(
isHttps
)
{
{
...
@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
client
.
LingerState
=
new
LingerOption
(
true
,
0
);
client
.
LingerState
=
new
LingerOption
(
true
,
0
);
server
.
ServerConnectionCount
++
;
Interlocked
.
Increment
(
ref
server
.
ServerConnectionCountField
)
;
return
new
TcpConnection
return
new
TcpConnection
{
{
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Security.Authentication
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Network
;
using
System.Linq
;
using
System.Security.Authentication
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
System.Security.Cryptography.X509Certificates
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -35,6 +36,8 @@ namespace Titanium.Web.Proxy
...
@@ -35,6 +36,8 @@ namespace Titanium.Web.Proxy
private
Action
<
Exception
>
exceptionFunc
;
private
Action
<
Exception
>
exceptionFunc
;
private
bool
trustRootCertificate
;
private
bool
trustRootCertificate
;
private
int
clientConnectionCountField
;
internal
int
ServerConnectionCountField
;
/// <summary>
/// <summary>
/// A object that creates tcp connection to server
/// A object that creates tcp connection to server
...
@@ -50,8 +53,7 @@ namespace Titanium.Web.Proxy
...
@@ -50,8 +53,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// <summary>
/// Set firefox to use default system proxy
/// Set firefox to use default system proxy
/// </summary>
/// </summary>
private
FireFoxProxySettingsManager
firefoxProxySettingsManager
private
FireFoxProxySettingsManager
firefoxProxySettingsManager
=
new
FireFoxProxySettingsManager
();
=
new
FireFoxProxySettingsManager
();
#endif
#endif
/// <summary>
/// <summary>
...
@@ -224,18 +226,18 @@ namespace Titanium.Web.Proxy
...
@@ -224,18 +226,18 @@ namespace Titanium.Web.Proxy
/// List of supported Ssl versions
/// List of supported Ssl versions
/// </summary>
/// </summary>
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
public
SslProtocols
SupportedSslProtocols
{
get
;
set
;
}
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
/// <summary>
/// <summary>
/// Total number of active client connections
/// Total number of active client connections
/// </summary>
/// </summary>
public
int
ClientConnectionCount
{
get
;
private
set
;
}
public
int
ClientConnectionCount
=>
clientConnectionCountField
;
/// <summary>
/// <summary>
/// Total number of active server connections
/// Total number of active server connections
/// </summary>
/// </summary>
public
int
ServerConnectionCount
{
get
;
internal
set
;
}
public
int
ServerConnectionCount
=>
ServerConnectionCountField
;
/// <summary>
/// <summary>
/// Constructor
/// Constructor
...
@@ -596,7 +598,7 @@ namespace Titanium.Web.Proxy
...
@@ -596,7 +598,7 @@ namespace Titanium.Web.Proxy
{
{
Task
.
Run
(
async
()
=>
Task
.
Run
(
async
()
=>
{
{
ClientConnectionCount
++
;
Interlocked
.
Increment
(
ref
clientConnectionCountField
)
;
//This line is important!
//This line is important!
//contributors please don't remove it without discussion
//contributors please don't remove it without discussion
...
@@ -617,7 +619,7 @@ namespace Titanium.Web.Proxy
...
@@ -617,7 +619,7 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
ClientConnectionCount
--
;
Interlocked
.
Decrement
(
ref
clientConnectionCountField
)
;
tcpClient
?.
Close
();
tcpClient
?.
Close
();
}
}
});
});
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
fe08a1fb
...
@@ -6,15 +6,15 @@ using System.Net;
...
@@ -6,15 +6,15 @@ using System.Net;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Security.Authentication
;
using
System.Security.Authentication
;
using
Titanium.Web.Proxy.Exception
s
;
using
System.Threading.Task
s
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy
...
@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy
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
;
...
@@ -188,7 +188,7 @@ namespace Titanium.Web.Proxy
...
@@ -188,7 +188,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
};
//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
)
...
@@ -205,7 +205,7 @@ namespace Titanium.Web.Proxy
...
@@ -205,7 +205,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
...
@@ -392,8 +392,6 @@ namespace Titanium.Web.Proxy
...
@@ -392,8 +392,6 @@ namespace Titanium.Web.Proxy
/// <param name="httpsHostName"></param>
/// <param name="httpsHostName"></param>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
/// <param name="connectHeaders"></param>
/// <param name="connectHeaders"></param>
/// <param name="customUpStreamHttpProxy"></param>
/// <param name="customUpStreamHttpsProxy"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
,
...
@@ -408,18 +406,18 @@ namespace Titanium.Web.Proxy
...
@@ -408,18 +406,18 @@ namespace Titanium.Web.Proxy
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
{
{
Dispose
(
clientStream
,
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamReader
,
clientStreamWriter
,
clientStreamWriter
,
connection
);
connection
);
break
;
break
;
}
}
var
args
=
new
SessionEventArgs
(
BufferSize
,
HandleHttpSessionResponse
)
var
args
=
new
SessionEventArgs
(
BufferSize
,
HandleHttpSessionResponse
)
{
{
ProxyClient
=
{
TcpClient
=
client
},
ProxyClient
=
{
TcpClient
=
client
},
WebSession
=
{
ConnectHeaders
=
connectHeaders
}
WebSession
=
{
ConnectHeaders
=
connectHeaders
}
};
};
args
.
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
args
.
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
{
{
...
@@ -457,7 +455,8 @@ namespace Titanium.Web.Proxy
...
@@ -457,7 +455,8 @@ namespace Titanium.Web.Proxy
//Read the request headers in to unique and non-unique header collections
//Read the request headers in to unique and non-unique header collections
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
,
args
.
WebSession
.
Request
.
RequestHeaders
);
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
,
args
.
WebSession
.
Request
.
RequestHeaders
);
var
httpRemoteUri
=
new
Uri
(
httpsHostName
==
null
?
httpCmdSplit
[
1
]
var
httpRemoteUri
=
new
Uri
(
httpsHostName
==
null
?
httpCmdSplit
[
1
]
:
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
??
httpsHostName
,
httpCmdSplit
[
1
]));
:
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
??
httpsHostName
,
httpCmdSplit
[
1
]));
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
...
@@ -468,14 +467,14 @@ namespace Titanium.Web.Proxy
...
@@ -468,14 +467,14 @@ namespace Titanium.Web.Proxy
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
if
(
httpsHostName
==
null
&&
if
(
httpsHostName
==
null
&&
await
CheckAuthorization
(
clientStreamWriter
,
await
CheckAuthorization
(
clientStreamWriter
,
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
)
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
)
{
{
Dispose
(
clientStream
,
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamReader
,
clientStreamWriter
,
clientStreamWriter
,
connection
);
connection
);
break
;
break
;
}
}
...
@@ -486,15 +485,7 @@ namespace Titanium.Web.Proxy
...
@@ -486,15 +485,7 @@ namespace Titanium.Web.Proxy
//If user requested interception do it
//If user requested interception do it
if
(
BeforeRequest
!=
null
)
if
(
BeforeRequest
!=
null
)
{
{
var
invocationList
=
BeforeRequest
.
GetInvocationList
();
await
BeforeRequest
.
InvokeParallelAsync
(
this
,
args
);
var
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
var
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
this
,
args
);
}
await
Task
.
WhenAll
(
handlerTasks
);
}
}
//if upgrading to websocket then relay the requet without reading the contents
//if upgrading to websocket then relay the requet without reading the contents
...
@@ -556,9 +547,9 @@ namespace Titanium.Web.Proxy
...
@@ -556,9 +547,9 @@ namespace Titanium.Web.Proxy
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
));
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
));
Dispose
(
clientStream
,
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamReader
,
clientStreamWriter
,
clientStreamWriter
,
connection
);
connection
);
break
;
break
;
}
}
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
fe08a1fb
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
Titanium.Web.Proxy.EventArguments
;
using
System.Threading
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Compression
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network.Tcp
;
using
Titanium.Web.Proxy.Network.Tcp
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
...
@@ -40,23 +41,15 @@ namespace Titanium.Web.Proxy
...
@@ -40,23 +41,15 @@ namespace Titanium.Web.Proxy
//If user requested call back then do it
//If user requested call back then do it
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
{
{
Delegate
[]
invocationList
=
BeforeResponse
.
GetInvocationList
();
await
BeforeResponse
.
InvokeParallelAsync
(
this
,
args
);
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
this
,
args
);
}
await
Task
.
WhenAll
(
handlerTasks
);
}
}
if
(
args
.
ReRequest
)
if
(
args
.
ReRequest
)
{
{
if
(
args
.
WebSession
.
ServerConnection
!=
null
)
if
(
args
.
WebSession
.
ServerConnection
!=
null
)
{
{
args
.
WebSession
.
ServerConnection
.
Dispose
();
args
.
WebSession
.
ServerConnection
.
Dispose
();
ServerConnectionCount
--
;
Interlocked
.
Decrement
(
ref
ServerConnectionCountField
)
;
}
}
var
connection
=
await
GetServerConnection
(
args
);
var
connection
=
await
GetServerConnection
(
args
);
...
@@ -240,7 +233,7 @@ namespace Titanium.Web.Proxy
...
@@ -240,7 +233,7 @@ namespace Titanium.Web.Proxy
StreamWriter
clientStreamWriter
,
StreamWriter
clientStreamWriter
,
TcpConnection
serverConnection
)
TcpConnection
serverConnection
)
{
{
ServerConnectionCount
--
;
Interlocked
.
Decrement
(
ref
ServerConnectionCountField
)
;
clientStream
?.
Close
();
clientStream
?.
Close
();
clientStream
?.
Dispose
();
clientStream
?.
Dispose
();
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
fe08a1fb
...
@@ -73,6 +73,7 @@
...
@@ -73,6 +73,7 @@
<Compile
Include=
"EventArguments\CertificateSelectionEventArgs.cs"
/>
<Compile
Include=
"EventArguments\CertificateSelectionEventArgs.cs"
/>
<Compile
Include=
"EventArguments\CertificateValidationEventArgs.cs"
/>
<Compile
Include=
"EventArguments\CertificateValidationEventArgs.cs"
/>
<Compile
Include=
"Extensions\ByteArrayExtensions.cs"
/>
<Compile
Include=
"Extensions\ByteArrayExtensions.cs"
/>
<Compile
Include=
"Extensions\FuncExtensions.cs"
/>
<Compile
Include=
"Extensions\StringExtensions.cs"
/>
<Compile
Include=
"Extensions\StringExtensions.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment