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
69aa70c1
Commit
69aa70c1
authored
May 15, 2017
by
Jehonathan Thomas
Committed by
GitHub
May 15, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #230 from justcoding121/develop
Beta
parents
e8e41ca3
fe81398b
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
567 additions
and
375 deletions
+567
-375
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+36
-23
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+2
-2
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+2
-1
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+21
-0
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+7
-17
CustomBufferedStream.cs
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
+2
-0
Network.cs
Titanium.Web.Proxy/Helpers/Network.cs
+1
-2
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+62
-21
HeaderParser.cs
Titanium.Web.Proxy/Http/HeaderParser.cs
+45
-0
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+7
-34
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+2
-2
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+4
-0
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+62
-7
TcpConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
+2
-2
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+25
-33
TcpRow.cs
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
+27
-8
ProxyAuthorizationHandler.cs
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
+26
-63
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+45
-34
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+155
-105
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+33
-21
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 @
69aa70c1
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
...
@@ -17,6 +18,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -17,6 +18,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
public
ProxyTestController
()
public
ProxyTestController
()
{
{
proxyServer
=
new
ProxyServer
();
proxyServer
=
new
ProxyServer
();
//generate root certificate without storing it in file system
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//proxyServer.CertificateManager.CreateTrustedRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate();
proxyServer
.
ExceptionFunc
=
exception
=>
Console
.
WriteLine
(
exception
.
Message
);
proxyServer
.
ExceptionFunc
=
exception
=>
Console
.
WriteLine
(
exception
.
Message
);
proxyServer
.
TrustRootCertificate
=
true
;
proxyServer
.
TrustRootCertificate
=
true
;
...
@@ -40,7 +47,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -40,7 +47,7 @@ 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>() { "google.com",
"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
...
@@ -92,18 +99,22 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -92,18 +99,22 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
Stop
();
proxyServer
.
Stop
();
//remove the generated certificates
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
}
}
//intecept & cancel redirect or update requests
//intecept & cancel redirect or update requests
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLine
(
"Active Client Connections:"
+
((
ProxyServer
)
sender
).
ClientConnectionCount
);
Console
.
WriteLine
(
e
.
WebSession
.
Request
.
Url
);
Console
.
WriteLine
(
e
.
WebSession
.
Request
.
Url
);
//read request headers
//read request headers
var
requestHeaders
=
e
.
WebSession
.
Request
.
RequestHeaders
;
var
requestHeaders
=
e
.
WebSession
.
Request
.
RequestHeaders
;
var
method
=
e
.
WebSession
.
Request
.
Method
.
ToUpper
();
var
method
=
e
.
WebSession
.
Request
.
Method
.
ToUpper
();
if
(
(
method
==
"POST"
||
method
==
"PUT"
||
method
==
"PATCH"
)
)
if
(
method
==
"POST"
||
method
==
"PUT"
||
method
==
"PATCH"
)
{
{
//Get/Set request body bytes
//Get/Set request body bytes
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
...
@@ -116,30 +127,32 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -116,30 +127,32 @@ namespace Titanium.Web.Proxy.Examples.Basic
requestBodyHistory
[
e
.
Id
]
=
bodyString
;
requestBodyHistory
[
e
.
Id
]
=
bodyString
;
}
}
//To cancel a request with a custom HTML content
//
//
To cancel a request with a custom HTML content
//Filter URL
//
//
Filter URL
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
//
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
{
//
{
await
e
.
Ok
(
"<!DOCTYPE html>"
+
//
await e.Ok("<!DOCTYPE html>" +
"<html><body><h1>"
+
//
"<html><body><h1>" +
"Website Blocked"
+
//
"Website Blocked" +
"</h1>"
+
//
"</h1>" +
"<p>Blocked by titanium web proxy.</p>"
+
//
"<p>Blocked by titanium web proxy.</p>" +
"</body>"
+
//
"</body>" +
"</html>"
);
//
"</html>");
}
//
}
//Redirect example
//
//
Redirect example
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"wikipedia.org"
))
//
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
{
//
{
await
e
.
Redirect
(
"https://www.paypal.com"
);
//
await e.Redirect("https://www.paypal.com");
}
//
}
}
}
//Modify response
//Modify response
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
{
if
(
requestBodyHistory
.
ContainsKey
(
e
.
Id
))
Console
.
WriteLine
(
"Active Server Connections:"
+
(
sender
as
ProxyServer
).
ServerConnectionCount
);
if
(
requestBodyHistory
.
ContainsKey
(
e
.
Id
))
{
{
//access request body by looking up the shared dictionary using requestId
//access request body by looking up the shared dictionary using requestId
var
requestBody
=
requestBodyHistory
[
e
.
Id
];
var
requestBody
=
requestBodyHistory
[
e
.
Id
];
...
@@ -149,14 +162,14 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -149,14 +162,14 @@ namespace Titanium.Web.Proxy.Examples.Basic
var
responseHeaders
=
e
.
WebSession
.
Response
.
ResponseHeaders
;
var
responseHeaders
=
e
.
WebSession
.
Response
.
ResponseHeaders
;
// print out process id of current session
// print out process id of current session
Console
.
WriteLine
(
$"PID:
{
e
.
WebSession
.
ProcessId
.
Value
}
"
);
//
Console.WriteLine($"PID: {e.WebSession.ProcessId.Value}");
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
if
(
e
.
WebSession
.
Request
.
Method
==
"GET"
||
e
.
WebSession
.
Request
.
Method
==
"POST"
)
if
(
e
.
WebSession
.
Request
.
Method
==
"GET"
||
e
.
WebSession
.
Request
.
Method
==
"POST"
)
{
{
if
(
e
.
WebSession
.
Response
.
ResponseStatusCode
==
"200"
)
if
(
e
.
WebSession
.
Response
.
ResponseStatusCode
==
"200"
)
{
{
if
(
e
.
WebSession
.
Response
.
ContentType
!=
null
&&
e
.
WebSession
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
if
(
e
.
WebSession
.
Response
.
ContentType
!=
null
&&
e
.
WebSession
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
{
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
await
e
.
SetResponseBody
(
bodyBytes
);
await
e
.
SetResponseBody
(
bodyBytes
);
...
...
Titanium.Web.Proxy/CertificateHandler.cs
View file @
69aa70c1
...
@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy
...
@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
/// <returns></returns>
private
bool
ValidateServerCertificate
(
internal
bool
ValidateServerCertificate
(
object
sender
,
object
sender
,
X509Certificate
certificate
,
X509Certificate
certificate
,
X509Chain
chain
,
X509Chain
chain
,
...
@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy
...
@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param>
/// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param>
/// <param name="acceptableIssuers"></param>
/// <returns></returns>
/// <returns></returns>
private
X509Certificate
SelectClientCertificate
(
internal
X509Certificate
SelectClientCertificate
(
object
sender
,
object
sender
,
string
targetHost
,
string
targetHost
,
X509CertificateCollection
localCertificates
,
X509CertificateCollection
localCertificates
,
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
69aa70c1
...
@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
//GET request don't have a request body to read
//GET request don't have a request body to read
var
method
=
WebSession
.
Request
.
Method
.
ToUpper
();
var
method
=
WebSession
.
Request
.
Method
.
ToUpper
();
if
(
(
method
!=
"POST"
&&
method
!=
"PUT"
&&
method
!=
"PATCH"
)
)
if
(
method
!=
"POST"
&&
method
!=
"PUT"
&&
method
!=
"PATCH"
)
{
{
throw
new
BodyNotFoundException
(
"Request don't have a body. "
+
throw
new
BodyNotFoundException
(
"Request don't have a body. "
+
"Please verify that this request is a Http POST/PUT/PATCH and request "
+
"Please verify that this request is a Http POST/PUT/PATCH and request "
+
...
@@ -411,6 +411,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -411,6 +411,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
response
.
ResponseHeaders
=
headers
;
response
.
ResponseHeaders
=
headers
;
}
}
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
ResponseBody
=
result
;
response
.
ResponseBody
=
result
;
...
...
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
69aa70c1
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Extensions
namespace
Titanium.Web.Proxy.Extensions
{
{
...
@@ -32,5 +33,25 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -32,5 +33,25 @@ namespace Titanium.Web.Proxy.Extensions
client
.
Blocking
=
blockingState
;
client
.
Blocking
=
blockingState
;
}
}
}
}
/// <summary>
/// Gets the local port from a native TCP row object.
/// </summary>
/// <param name="tcpRow">The TCP row.</param>
/// <returns>The local port</returns>
internal
static
int
GetLocalPort
(
this
NativeMethods
.
TcpRow
tcpRow
)
{
return
(
tcpRow
.
localPort1
<<
8
)
+
tcpRow
.
localPort2
+
(
tcpRow
.
localPort3
<<
24
)
+
(
tcpRow
.
localPort4
<<
16
);
}
/// <summary>
/// Gets the remote port from a native TCP row object.
/// </summary>
/// <param name="tcpRow">The TCP row.</param>
/// <returns>The remote port</returns>
internal
static
int
GetRemotePort
(
this
NativeMethods
.
TcpRow
tcpRow
)
{
return
(
tcpRow
.
remotePort1
<<
8
)
+
tcpRow
.
remotePort2
+
(
tcpRow
.
remotePort3
<<
24
)
+
(
tcpRow
.
remotePort4
<<
16
);
}
}
}
}
}
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
69aa70c1
...
@@ -15,27 +15,14 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -15,27 +15,14 @@ namespace Titanium.Web.Proxy.Helpers
{
{
private
readonly
CustomBufferedStream
stream
;
private
readonly
CustomBufferedStream
stream
;
private
readonly
int
bufferSize
;
private
readonly
int
bufferSize
;
private
readonly
byte
[]
staticBuffer
;
private
readonly
Encoding
encoding
;
private
readonly
Encoding
encoding
;
[
ThreadStatic
]
private
static
byte
[]
staticBufferField
;
private
byte
[]
staticBuffer
{
get
{
if
(
staticBufferField
==
null
||
staticBufferField
.
Length
!=
bufferSize
)
{
staticBufferField
=
new
byte
[
bufferSize
];
}
return
staticBufferField
;
}
}
internal
CustomBinaryReader
(
CustomBufferedStream
stream
,
int
bufferSize
)
internal
CustomBinaryReader
(
CustomBufferedStream
stream
,
int
bufferSize
)
{
{
this
.
stream
=
stream
;
this
.
stream
=
stream
;
staticBuffer
=
new
byte
[
bufferSize
];
this
.
bufferSize
=
bufferSize
;
this
.
bufferSize
=
bufferSize
;
//default to UTF-8
//default to UTF-8
...
@@ -122,10 +109,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -122,10 +109,13 @@ namespace Titanium.Web.Proxy.Helpers
{
{
int
bytesToRead
=
bufferSize
;
int
bytesToRead
=
bufferSize
;
var
buffer
=
staticBuffer
;
if
(
totalBytesToRead
<
bufferSize
)
if
(
totalBytesToRead
<
bufferSize
)
{
bytesToRead
=
(
int
)
totalBytesToRead
;
bytesToRead
=
(
int
)
totalBytesToRead
;
buffer
=
new
byte
[
bytesToRead
];
}
var
buffer
=
staticBuffer
;
int
bytesRead
;
int
bytesRead
;
var
totalBytesRead
=
0
;
var
totalBytesRead
=
0
;
...
...
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
View file @
69aa70c1
...
@@ -168,6 +168,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -168,6 +168,7 @@ namespace Titanium.Web.Proxy.Helpers
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
await
destination
.
WriteAsync
(
streamBuffer
,
bufferPos
,
bufferLength
,
cancellationToken
);
await
destination
.
WriteAsync
(
streamBuffer
,
bufferPos
,
bufferLength
,
cancellationToken
);
bufferLength
=
0
;
}
}
await
baseStream
.
CopyToAsync
(
destination
,
bufferSize
,
cancellationToken
);
await
baseStream
.
CopyToAsync
(
destination
,
bufferSize
,
cancellationToken
);
...
@@ -307,6 +308,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -307,6 +308,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>
/// <returns>
/// A task that represents the asynchronous write operation.
/// A task that represents the asynchronous write operation.
/// </returns>
/// </returns>
[
DebuggerStepThrough
]
public
override
Task
WriteAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
)
public
override
Task
WriteAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
)
{
{
return
baseStream
.
WriteAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
return
baseStream
.
WriteAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
...
...
Titanium.Web.Proxy/Helpers/Network.cs
View file @
69aa70c1
...
@@ -8,8 +8,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -8,8 +8,7 @@ namespace Titanium.Web.Proxy.Helpers
{
{
private
static
int
FindProcessIdFromLocalPort
(
int
port
,
IpVersion
ipVersion
)
private
static
int
FindProcessIdFromLocalPort
(
int
port
,
IpVersion
ipVersion
)
{
{
var
tcpRow
=
TcpHelper
.
GetExtendedTcpTable
(
ipVersion
).
FirstOrDefault
(
var
tcpRow
=
TcpHelper
.
GetTcpRowByLocalPort
(
ipVersion
,
port
);
row
=>
row
.
LocalEndPoint
.
Port
==
port
);
return
tcpRow
?.
ProcessId
??
0
;
return
tcpRow
?.
ProcessId
??
0
;
}
}
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
69aa70c1
...
@@ -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
)));
}
}
}
}
}
}
...
@@ -123,30 +123,71 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -123,30 +123,71 @@ namespace Titanium.Web.Proxy.Helpers
return
new
TcpTable
(
tcpRows
);
return
new
TcpTable
(
tcpRows
);
}
}
/// <summary>
/// Gets the TCP row by local port number.
/// </summary>
/// <returns><see cref="TcpRow"/>.</returns>
internal
static
TcpRow
GetTcpRowByLocalPort
(
IpVersion
ipVersion
,
int
localPort
)
{
IntPtr
tcpTable
=
IntPtr
.
Zero
;
int
tcpTableLength
=
0
;
var
ipVersionValue
=
ipVersion
==
IpVersion
.
Ipv4
?
NativeMethods
.
AfInet
:
NativeMethods
.
AfInet6
;
if
(
NativeMethods
.
GetExtendedTcpTable
(
tcpTable
,
ref
tcpTableLength
,
false
,
ipVersionValue
,
(
int
)
NativeMethods
.
TcpTableType
.
OwnerPidAll
,
0
)
!=
0
)
{
try
{
tcpTable
=
Marshal
.
AllocHGlobal
(
tcpTableLength
);
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
));
IntPtr
rowPtr
=
(
IntPtr
)((
long
)
tcpTable
+
Marshal
.
SizeOf
(
table
.
length
));
for
(
int
i
=
0
;
i
<
table
.
length
;
++
i
)
{
var
tcpRow
=
(
NativeMethods
.
TcpRow
)
Marshal
.
PtrToStructure
(
rowPtr
,
typeof
(
NativeMethods
.
TcpRow
));
if
(
tcpRow
.
GetLocalPort
()
==
localPort
)
{
return
new
TcpRow
(
tcpRow
);
}
rowPtr
=
(
IntPtr
)((
long
)
rowPtr
+
Marshal
.
SizeOf
(
typeof
(
NativeMethods
.
TcpRow
)));
}
}
}
finally
{
if
(
tcpTable
!=
IntPtr
.
Zero
)
{
Marshal
.
FreeHGlobal
(
tcpTable
);
}
}
}
return
null
;
}
/// <summary>
/// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
/// Usefull for websocket requests
/// Usefull for websocket requests
/// </summary>
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="server"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="remoteHostName"></param>
/// <param name="remotePort"></param>
/// <param name="httpCmd"></param>
/// <param name="httpCmd"></param>
/// <param name="httpVersion"></param>
/// <param name="httpVersion"></param>
/// <param name="requestHeaders"></param>
/// <param name="requestHeaders"></param>
/// <param name="isHttps"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
/// <param name="supportedProtocols"></param>
/// <param name="remoteCertificateValidationCallback"></param>
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <param name="tcpConnectionFactory"></param>
/// <param name="tcpConnectionFactory"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
SendRaw
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
internal
static
async
Task
SendRaw
(
ProxyServer
server
,
string
remoteHostName
,
int
remotePort
,
string
httpCmd
,
Version
httpVersion
,
Dictionary
<
string
,
HttpHeader
>
requestHeaders
,
string
remoteHostName
,
int
remotePort
,
bool
isHttps
,
SslProtocols
supportedProtocol
s
,
string
httpCmd
,
Version
httpVersion
,
Dictionary
<
string
,
HttpHeader
>
requestHeader
s
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallback
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
,
bool
isHttps
,
Stream
clientStream
,
TcpConnectionFactory
tcpConnectionFactory
,
IPEndPoint
upStreamEndPoint
)
Stream
clientStream
,
TcpConnectionFactory
tcpConnectionFactory
)
{
{
//prepare the prefix content
//prepare the prefix content
StringBuilder
sb
=
null
;
StringBuilder
sb
=
null
;
...
@@ -172,11 +213,10 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -172,11 +213,10 @@ namespace Titanium.Web.Proxy.Helpers
sb
.
Append
(
ProxyConstants
.
NewLine
);
sb
.
Append
(
ProxyConstants
.
NewLine
);
}
}
var
tcpConnection
=
await
tcpConnectionFactory
.
CreateClient
(
bufferSize
,
connectionTimeOutSeconds
,
var
tcpConnection
=
await
tcpConnectionFactory
.
CreateClient
(
server
,
remoteHostName
,
remotePort
,
remoteHostName
,
remotePort
,
httpVersion
,
isHttps
,
httpVersion
,
isHttps
,
supportedProtocols
,
remoteCertificateValidationCallback
,
localCertificateSelectionCallback
,
null
,
null
,
clientStream
);
null
,
null
,
clientStream
,
upStreamEndPoint
);
try
try
{
{
...
@@ -192,6 +232,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -192,6 +232,7 @@ namespace Titanium.Web.Proxy.Helpers
finally
finally
{
{
tcpConnection
.
Dispose
();
tcpConnection
.
Dispose
();
server
.
ServerConnectionCount
--;
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Http/HeaderParser.cs
0 → 100644
View file @
69aa70c1
using
System.Collections.Generic
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Http
{
internal
static
class
HeaderParser
{
internal
static
async
Task
ReadHeaders
(
CustomBinaryReader
reader
,
Dictionary
<
string
,
List
<
HttpHeader
>>
nonUniqueResponseHeaders
,
Dictionary
<
string
,
HttpHeader
>
headers
)
{
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
reader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
newHeader
=
new
HttpHeader
(
header
[
0
],
header
[
1
]);
//if header exist in non-unique header collection add it there
if
(
nonUniqueResponseHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
nonUniqueResponseHeaders
[
newHeader
.
Name
].
Add
(
newHeader
);
}
//if header is alread in unique header collection then move both to non-unique collection
else
if
(
headers
.
ContainsKey
(
newHeader
.
Name
))
{
var
existing
=
headers
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
};
nonUniqueResponseHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
headers
.
Remove
(
newHeader
.
Name
);
}
//add to unique header collection
else
{
headers
.
Add
(
newHeader
.
Name
,
newHeader
);
}
}
}
}
}
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
69aa70c1
...
@@ -170,10 +170,10 @@ namespace Titanium.Web.Proxy.Http
...
@@ -170,10 +170,10 @@ namespace Titanium.Web.Proxy.Http
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
version
=
new
Version
(
1
,
1
)
;
var
version
=
HttpHeader
.
Version11
;
if
(
0
==
string
.
CompareOrdinal
(
httpVersion
,
"http/1.0"
))
if
(
string
.
Equals
(
httpVersion
,
"HTTP/1.0"
,
StringComparison
.
OrdinalIgnoreCase
))
{
{
version
=
new
Version
(
1
,
0
)
;
version
=
HttpHeader
.
Version10
;
}
}
Response
.
HttpVersion
=
version
;
Response
.
HttpVersion
=
version
;
...
@@ -192,7 +192,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -192,7 +192,8 @@ namespace Titanium.Web.Proxy.Http
await
ReceiveResponse
();
await
ReceiveResponse
();
return
;
return
;
}
}
else
if
(
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
if
(
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
&&
Response
.
ResponseStatusDescription
.
Equals
(
"expectation failed"
,
StringComparison
.
CurrentCultureIgnoreCase
))
&&
Response
.
ResponseStatusDescription
.
Equals
(
"expectation failed"
,
StringComparison
.
CurrentCultureIgnoreCase
))
{
{
//read next line after expectation failed response
//read next line after expectation failed response
...
@@ -204,36 +205,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -204,36 +205,8 @@ namespace Titanium.Web.Proxy.Http
return
;
return
;
}
}
//Read the Response headers
//Read the response headers in to unique and non-unique header collections
//Read the response headers in to unique and non-unique header collections
string
tmpLine
;
await
HeaderParser
.
ReadHeaders
(
ServerConnection
.
StreamReader
,
Response
.
NonUniqueResponseHeaders
,
Response
.
ResponseHeaders
);
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
newHeader
=
new
HttpHeader
(
header
[
0
],
header
[
1
]);
//if header exist in non-unique header collection add it there
if
(
Response
.
NonUniqueResponseHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
Response
.
NonUniqueResponseHeaders
[
newHeader
.
Name
].
Add
(
newHeader
);
}
//if header is alread in unique header collection then move both to non-unique collection
else
if
(
Response
.
ResponseHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
var
existing
=
Response
.
ResponseHeaders
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
};
Response
.
NonUniqueResponseHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
Response
.
ResponseHeaders
.
Remove
(
newHeader
.
Name
);
}
//add to unique header collection
else
{
Response
.
ResponseHeaders
.
Add
(
newHeader
.
Name
,
newHeader
);
}
}
}
}
}
}
}
}
Titanium.Web.Proxy/Http/Request.cs
View file @
69aa70c1
...
@@ -242,8 +242,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -242,8 +242,8 @@ namespace Titanium.Web.Proxy.Http
/// </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
;
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
69aa70c1
...
@@ -9,6 +9,10 @@ namespace Titanium.Web.Proxy.Models
...
@@ -9,6 +9,10 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
/// </summary>
public
class
HttpHeader
public
class
HttpHeader
{
{
internal
static
Version
Version10
=
new
Version
(
1
,
0
);
internal
static
Version
Version11
=
new
Version
(
1
,
1
);
/// <summary>
/// <summary>
/// Constructor.
/// Constructor.
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
69aa70c1
...
@@ -29,9 +29,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -29,9 +29,9 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// <summary>
/// A class to manage SSL certificates used by this proxy server
/// A class to manage SSL certificates used by this proxy server
/// </summary>
/// </summary>
internal
class
CertificateManager
:
IDisposable
public
class
CertificateManager
:
IDisposable
{
{
public
CertificateEngine
Engine
internal
CertificateEngine
Engine
{
{
get
{
return
engine
;
}
get
{
return
engine
;
}
set
set
...
@@ -164,10 +164,13 @@ namespace Titanium.Web.Proxy.Network
...
@@ -164,10 +164,13 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// <summary>
/// Attempts to create a RootCertificate
/// Attempts to create a RootCertificate
/// </summary>
/// </summary>
/// <returns>true if succeeded, else false</returns>
/// <param name="persistToFile">if set to <c>true</c> try to load/save the certificate from rootCert.pfx.</param>
internal
bool
CreateTrustedRootCertificate
()
/// <returns>
/// true if succeeded, else false
/// </returns>
public
bool
CreateTrustedRootCertificate
(
bool
persistToFile
=
true
)
{
{
if
(
RootCertificate
==
null
)
if
(
persistToFile
&&
RootCertificate
==
null
)
{
{
RootCertificate
=
LoadRootCertificate
();
RootCertificate
=
LoadRootCertificate
();
}
}
...
@@ -186,7 +189,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -186,7 +189,7 @@ namespace Titanium.Web.Proxy.Network
exceptionFunc
(
e
);
exceptionFunc
(
e
);
}
}
if
(
RootCertificate
!=
null
)
if
(
persistToFile
&&
RootCertificate
!=
null
)
{
{
try
try
{
{
...
@@ -205,7 +208,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -205,7 +208,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// <summary>
/// Trusts the root certificate.
/// Trusts the root certificate.
/// </summary>
/// </summary>
internal
void
TrustRootCertificate
()
public
void
TrustRootCertificate
()
{
{
//current user
//current user
TrustRootCertificate
(
StoreLocation
.
CurrentUser
);
TrustRootCertificate
(
StoreLocation
.
CurrentUser
);
...
@@ -214,6 +217,18 @@ namespace Titanium.Web.Proxy.Network
...
@@ -214,6 +217,18 @@ namespace Titanium.Web.Proxy.Network
TrustRootCertificate
(
StoreLocation
.
LocalMachine
);
TrustRootCertificate
(
StoreLocation
.
LocalMachine
);
}
}
/// <summary>
/// Removes the trusted certificates.
/// </summary>
public
void
RemoveTrustedRootCertificates
()
{
//current user
RemoveTrustedRootCertificates
(
StoreLocation
.
CurrentUser
);
//current system
RemoveTrustedRootCertificates
(
StoreLocation
.
LocalMachine
);
}
/// <summary>
/// <summary>
/// Create an SSL certificate
/// Create an SSL certificate
/// </summary>
/// </summary>
...
@@ -336,6 +351,46 @@ namespace Titanium.Web.Proxy.Network
...
@@ -336,6 +351,46 @@ namespace Titanium.Web.Proxy.Network
}
}
}
}
/// <summary>
/// Remove the Root Certificate trust
/// </summary>
/// <param name="storeLocation"></param>
/// <returns></returns>
internal
void
RemoveTrustedRootCertificates
(
StoreLocation
storeLocation
)
{
if
(
RootCertificate
==
null
)
{
exceptionFunc
(
new
Exception
(
"Could not set root certificate"
+
" as system proxy since it is null or empty."
));
return
;
}
X509Store
x509RootStore
=
new
X509Store
(
StoreName
.
Root
,
storeLocation
);
var
x509PersonalStore
=
new
X509Store
(
StoreName
.
My
,
storeLocation
);
try
{
x509RootStore
.
Open
(
OpenFlags
.
ReadWrite
);
x509PersonalStore
.
Open
(
OpenFlags
.
ReadWrite
);
x509RootStore
.
Remove
(
RootCertificate
);
x509PersonalStore
.
Remove
(
RootCertificate
);
}
catch
(
Exception
e
)
{
exceptionFunc
(
new
Exception
(
"Failed to make system trust root certificate "
+
$" for
{
storeLocation
}
store location. You may need admin rights."
,
e
));
}
finally
{
x509RootStore
.
Close
();
x509PersonalStore
.
Close
();
}
}
public
void
Dispose
()
public
void
Dispose
()
{
{
}
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
View file @
69aa70c1
...
@@ -55,10 +55,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -55,10 +55,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
Stream
?.
Close
();
Stream
?.
Close
();
Stream
?.
Dispose
();
Stream
?.
Dispose
();
StreamReader
?.
Dispose
();
StreamReader
?.
Dispose
();
TcpClient
.
LingerState
=
new
LingerOption
(
true
,
0
);
TcpClient
?.
Close
();
TcpClient
.
Close
();
}
}
}
}
}
}
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
69aa70c1
...
@@ -6,43 +6,35 @@ using System.IO;
...
@@ -6,43 +6,35 @@ using System.IO;
using
System.Net.Security
;
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.Security.Authentication
;
using
System.Linq
;
using
System.Linq
;
using
Titanium.Web.Proxy.Extensions
;
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
{
{
using
System.Net
;
/// <summary>
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
/// </summary>
internal
class
TcpConnectionFactory
internal
class
TcpConnectionFactory
{
{
/// <summary>
/// <summary>
/// Creates a TCP connection to server
/// Creates a TCP connection to server
/// </summary>
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="server"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="remoteHostName"></param>
/// <param name="remotePort"></param>
/// <param name="httpVersion"></param>
/// <param name="httpVersion"></param>
/// <param name="isHttps"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
/// <param name="supportedSslProtocols"></param>
/// <param name="remoteCertificateValidationCallback"></param>
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
/// <returns></returns>
internal
async
Task
<
TcpConnection
>
CreateClient
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
internal
async
Task
<
TcpConnection
>
CreateClient
(
ProxyServer
server
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
SslProtocols
supportedSslProtocols
,
bool
isHttps
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallback
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
Stream
clientStream
,
IPEndPoint
upStreamEndPoint
)
Stream
clientStream
)
{
{
TcpClient
client
;
TcpClient
client
;
CustomBufferedStream
stream
;
CustomBufferedStream
stream
;
...
@@ -59,11 +51,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -59,11 +51,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if
(
useHttpsProxy
)
if
(
useHttpsProxy
)
{
{
client
=
new
TcpClient
(
u
pStreamEndPoint
);
client
=
new
TcpClient
(
server
.
U
pStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
b
ufferSize
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
server
.
B
ufferSize
);
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
b
ufferSize
,
true
)
{
NewLine
=
ProxyConstants
.
NewLine
})
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
server
.
B
ufferSize
,
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
}
"
);
...
@@ -79,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -79,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
writer
.
Close
();
writer
.
Close
();
}
}
using
(
var
reader
=
new
CustomBinaryReader
(
stream
,
b
ufferSize
))
using
(
var
reader
=
new
CustomBinaryReader
(
stream
,
server
.
B
ufferSize
))
{
{
var
result
=
await
reader
.
ReadLineAsync
();
var
result
=
await
reader
.
ReadLineAsync
();
...
@@ -93,19 +85,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -93,19 +85,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
}
else
else
{
{
client
=
new
TcpClient
(
u
pStreamEndPoint
);
client
=
new
TcpClient
(
server
.
U
pStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
b
ufferSize
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
server
.
B
ufferSize
);
}
}
try
try
{
{
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallback
,
sslStream
=
new
SslStream
(
stream
,
true
,
server
.
ValidateServerCertificate
,
localCertificateSelectionCallback
);
server
.
SelectClientCertificate
);
await
sslStream
.
AuthenticateAsClientAsync
(
remoteHostName
,
null
,
supportedSslProtocols
,
false
);
await
sslStream
.
AuthenticateAsClientAsync
(
remoteHostName
,
null
,
s
erver
.
S
upportedSslProtocols
,
false
);
stream
=
new
CustomBufferedStream
(
sslStream
,
b
ufferSize
);
stream
=
new
CustomBufferedStream
(
sslStream
,
server
.
B
ufferSize
);
}
}
catch
catch
{
{
...
@@ -118,24 +110,24 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -118,24 +110,24 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
if
(
useHttpProxy
)
if
(
useHttpProxy
)
{
{
client
=
new
TcpClient
(
u
pStreamEndPoint
);
client
=
new
TcpClient
(
server
.
U
pStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpProxy
.
HostName
,
externalHttpProxy
.
Port
);
await
client
.
ConnectAsync
(
externalHttpProxy
.
HostName
,
externalHttpProxy
.
Port
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
b
ufferSize
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
server
.
B
ufferSize
);
}
}
else
else
{
{
client
=
new
TcpClient
(
u
pStreamEndPoint
);
client
=
new
TcpClient
(
server
.
U
pStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
b
ufferSize
);
stream
=
new
CustomBufferedStream
(
client
.
GetStream
(),
server
.
B
ufferSize
);
}
}
}
}
client
.
ReceiveTimeout
=
c
onnectionTimeOutSeconds
*
1000
;
client
.
ReceiveTimeout
=
server
.
C
onnectionTimeOutSeconds
*
1000
;
client
.
SendTimeout
=
c
onnectionTimeOutSeconds
*
1000
;
client
.
SendTimeout
=
server
.
C
onnectionTimeOutSeconds
*
1000
;
stream
.
ReadTimeout
=
connectionTimeOutSeconds
*
1000
;
client
.
LingerState
=
new
LingerOption
(
true
,
0
);
stream
.
WriteTimeout
=
connectionTimeOutSeconds
*
1000
;
server
.
ServerConnectionCount
++;
return
new
TcpConnection
return
new
TcpConnection
{
{
...
@@ -145,7 +137,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -145,7 +137,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
Port
=
remotePort
,
Port
=
remotePort
,
IsHttps
=
isHttps
,
IsHttps
=
isHttps
,
TcpClient
=
client
,
TcpClient
=
client
,
StreamReader
=
new
CustomBinaryReader
(
stream
,
b
ufferSize
),
StreamReader
=
new
CustomBinaryReader
(
stream
,
server
.
B
ufferSize
),
Stream
=
stream
,
Stream
=
stream
,
Version
=
httpVersion
Version
=
httpVersion
};
};
...
...
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
View file @
69aa70c1
using
System.Net
;
using
System.Net
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Network.Tcp
namespace
Titanium.Web.Proxy.Network.Tcp
...
@@ -17,24 +18,42 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -17,24 +18,42 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
ProcessId
=
tcpRow
.
owningPid
;
ProcessId
=
tcpRow
.
owningPid
;
int
localPort
=
(
tcpRow
.
localPort1
<<
8
)
+
(
tcpRow
.
localPort2
)
+
(
tcpRow
.
localPort3
<<
24
)
+
(
tcpRow
.
localPort4
<<
16
);
LocalPort
=
tcpRow
.
GetLocalPort
();
long
localAddress
=
tcpRow
.
localAddr
;
LocalAddress
=
tcpRow
.
localAddr
;
LocalEndPoint
=
new
IPEndPoint
(
localAddress
,
localPort
);
int
remotePort
=
(
tcpRow
.
remotePort1
<<
8
)
+
(
tcpRow
.
remotePort2
)
+
(
tcpRow
.
remotePort3
<<
24
)
+
(
tcpRow
.
remotePort4
<<
16
);
RemotePort
=
tcpRow
.
GetRemotePort
();
long
remoteAddress
=
tcpRow
.
remoteAddr
;
RemoteAddress
=
tcpRow
.
remoteAddr
;
RemoteEndPoint
=
new
IPEndPoint
(
remoteAddress
,
remotePort
);
}
}
/// <summary>
/// Gets the local end point address.
/// </summary>
internal
long
LocalAddress
{
get
;
}
/// <summary>
/// Gets the local end point port.
/// </summary>
internal
int
LocalPort
{
get
;
}
/// <summary>
/// <summary>
/// Gets the local end point.
/// Gets the local end point.
/// </summary>
/// </summary>
internal
IPEndPoint
LocalEndPoint
{
get
;
}
internal
IPEndPoint
LocalEndPoint
=>
new
IPEndPoint
(
LocalAddress
,
LocalPort
);
/// <summary>
/// Gets the remote end point address.
/// </summary>
internal
long
RemoteAddress
{
get
;
}
/// <summary>
/// Gets the remote end point port.
/// </summary>
internal
int
RemotePort
{
get
;
}
/// <summary>
/// <summary>
/// Gets the remote end point.
/// Gets the remote end point.
/// </summary>
/// </summary>
internal
IPEndPoint
RemoteEndPoint
{
get
;
}
internal
IPEndPoint
RemoteEndPoint
=>
new
IPEndPoint
(
RemoteAddress
,
RemotePort
);
/// <summary>
/// <summary>
/// Gets the process identifier.
/// Gets the process identifier.
...
...
Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
69aa70c1
...
@@ -19,78 +19,36 @@ namespace Titanium.Web.Proxy
...
@@ -19,78 +19,36 @@ namespace Titanium.Web.Proxy
return
true
;
return
true
;
}
}
var
httpHeaders
=
headers
as
HttpHeader
[]
??
headers
.
ToArray
();
var
httpHeaders
=
headers
as
ICollection
<
HttpHeader
>
??
headers
.
ToArray
();
try
try
{
{
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
if
(
httpHeaders
.
All
(
t
=>
t
.
Name
!=
"Proxy-Authorization"
))
{
{
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
await
SendAuthentication407Response
(
clientStreamWriter
,
"Proxy Authentication Required"
);
"Proxy Authentication Required"
,
clientStreamWriter
);
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
return
false
;
}
}
var
header
=
httpHeaders
.
FirstOrDefault
(
t
=>
t
.
Name
==
"Proxy-Authorization"
);
var
header
=
httpHeaders
.
FirstOrDefault
(
t
=>
t
.
Name
==
"Proxy-Authorization"
);
if
(
null
==
header
)
throw
new
NullReferenceException
();
if
(
header
==
null
)
throw
new
NullReferenceException
();
var
headerValue
=
header
.
Value
.
Trim
();
var
headerValue
=
header
.
Value
.
Trim
();
if
(!
headerValue
.
StartsWith
(
"basic"
,
StringComparison
.
CurrentCultureIgnoreCase
))
if
(!
headerValue
.
StartsWith
(
"basic"
,
StringComparison
.
CurrentCultureIgnoreCase
))
{
{
//Return not authorized
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
await
SendAuthentication407Response
(
clientStreamWriter
,
"Proxy Authentication Invalid"
);
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
return
false
;
}
}
headerValue
=
headerValue
.
Substring
(
5
).
Trim
();
headerValue
=
headerValue
.
Substring
(
5
).
Trim
();
var
decoded
=
Encoding
.
UTF8
.
GetString
(
Convert
.
FromBase64String
(
headerValue
));
var
decoded
=
Encoding
.
UTF8
.
GetString
(
Convert
.
FromBase64String
(
headerValue
));
if
(
decoded
.
Contains
(
":"
)
==
false
)
if
(
decoded
.
Contains
(
":"
)
==
false
)
{
{
//Return not authorized
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
await
SendAuthentication407Response
(
clientStreamWriter
,
"Proxy Authentication Invalid"
);
"Proxy Authentication Invalid"
,
clientStreamWriter
);
var
response
=
new
Response
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
{
{
"Proxy-Authenticate"
,
new
HttpHeader
(
"Proxy-Authenticate"
,
"Basic realm=\"TitaniumProxy\""
)
},
{
"Proxy-Connection"
,
new
HttpHeader
(
"Proxy-Connection"
,
"close"
)}
}
};
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
return
false
;
}
}
var
username
=
decoded
.
Substring
(
0
,
decoded
.
IndexOf
(
':'
));
var
username
=
decoded
.
Substring
(
0
,
decoded
.
IndexOf
(
':'
));
var
password
=
decoded
.
Substring
(
decoded
.
IndexOf
(
':'
)
+
1
);
var
password
=
decoded
.
Substring
(
decoded
.
IndexOf
(
':'
)
+
1
);
return
await
AuthenticateUserFunc
(
username
,
password
);
return
await
AuthenticateUserFunc
(
username
,
password
);
...
@@ -98,9 +56,16 @@ namespace Titanium.Web.Proxy
...
@@ -98,9 +56,16 @@ namespace Titanium.Web.Proxy
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
ExceptionFunc
(
new
ProxyAuthorizationException
(
"Error whilst authorizing request"
,
e
,
httpHeaders
));
ExceptionFunc
(
new
ProxyAuthorizationException
(
"Error whilst authorizing request"
,
e
,
httpHeaders
));
//Return not authorized
//Return not authorized
await
WriteResponseStatus
(
new
Version
(
1
,
1
),
"407"
,
await
SendAuthentication407Response
(
clientStreamWriter
,
"Proxy Authentication Invalid"
);
"Proxy Authentication Invalid"
,
clientStreamWriter
);
return
false
;
}
}
private
async
Task
SendAuthentication407Response
(
StreamWriter
clientStreamWriter
,
string
description
)
{
await
WriteResponseStatus
(
HttpHeader
.
Version11
,
"407"
,
description
,
clientStreamWriter
);
var
response
=
new
Response
var
response
=
new
Response
{
{
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>
...
@@ -112,8 +77,6 @@ namespace Titanium.Web.Proxy
...
@@ -112,8 +77,6 @@ namespace Titanium.Web.Proxy
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
WriteResponseHeaders
(
clientStreamWriter
,
response
);
await
clientStreamWriter
.
WriteLineAsync
();
await
clientStreamWriter
.
WriteLineAsync
();
return
false
;
}
}
}
}
}
}
}
Titanium.Web.Proxy/ProxyServer.cs
View file @
69aa70c1
...
@@ -24,11 +24,6 @@ namespace Titanium.Web.Proxy
...
@@ -24,11 +24,6 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
private
bool
proxyRunning
{
get
;
set
;
}
private
bool
proxyRunning
{
get
;
set
;
}
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
private
CertificateManager
certificateManager
{
get
;
set
;
}
/// <summary>
/// <summary>
/// An default exception log func
/// An default exception log func
/// </summary>
/// </summary>
...
@@ -64,13 +59,18 @@ namespace Titanium.Web.Proxy
...
@@ -64,13 +59,18 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
int
BufferSize
{
get
;
set
;
}
=
8192
;
public
int
BufferSize
{
get
;
set
;
}
=
8192
;
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
public
CertificateManager
CertificateManager
{
get
;
}
/// <summary>
/// <summary>
/// The root certificate
/// The root certificate
/// </summary>
/// </summary>
public
X509Certificate2
RootCertificate
public
X509Certificate2
RootCertificate
{
{
get
{
return
c
ertificateManager
.
RootCertificate
;
}
get
{
return
C
ertificateManager
.
RootCertificate
;
}
set
{
c
ertificateManager
.
RootCertificate
=
value
;
}
set
{
C
ertificateManager
.
RootCertificate
=
value
;
}
}
}
/// <summary>
/// <summary>
...
@@ -79,8 +79,8 @@ namespace Titanium.Web.Proxy
...
@@ -79,8 +79,8 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
string
RootCertificateIssuerName
public
string
RootCertificateIssuerName
{
{
get
{
return
c
ertificateManager
.
Issuer
;
}
get
{
return
C
ertificateManager
.
Issuer
;
}
set
{
certificateManager
.
RootCertificateName
=
value
;
}
set
{
CertificateManager
.
Issuer
=
value
;
}
}
}
/// <summary>
/// <summary>
...
@@ -92,8 +92,8 @@ namespace Titanium.Web.Proxy
...
@@ -92,8 +92,8 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
string
RootCertificateName
public
string
RootCertificateName
{
{
get
{
return
c
ertificateManager
.
RootCertificateName
;
}
get
{
return
C
ertificateManager
.
RootCertificateName
;
}
set
{
certificateManager
.
Issuer
=
value
;
}
set
{
CertificateManager
.
RootCertificateName
=
value
;
}
}
}
/// <summary>
/// <summary>
...
@@ -121,8 +121,8 @@ namespace Titanium.Web.Proxy
...
@@ -121,8 +121,8 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
CertificateEngine
CertificateEngine
public
CertificateEngine
CertificateEngine
{
{
get
{
return
c
ertificateManager
.
Engine
;
}
get
{
return
C
ertificateManager
.
Engine
;
}
set
{
c
ertificateManager
.
Engine
=
value
;
}
set
{
C
ertificateManager
.
Engine
=
value
;
}
}
}
/// <summary>
/// <summary>
...
@@ -226,6 +226,17 @@ namespace Titanium.Web.Proxy
...
@@ -226,6 +226,17 @@ namespace Titanium.Web.Proxy
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>
/// Total number of active client connections
/// </summary>
public
int
ClientConnectionCount
{
get
;
private
set
;
}
/// <summary>
/// Total number of active server connections
/// </summary>
public
int
ServerConnectionCount
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Constructor
/// Constructor
/// </summary>
/// </summary>
...
@@ -241,7 +252,7 @@ namespace Titanium.Web.Proxy
...
@@ -241,7 +252,7 @@ namespace Titanium.Web.Proxy
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
{
//default values
//default values
ConnectionTimeOutSeconds
=
12
0
;
ConnectionTimeOutSeconds
=
3
0
;
CertificateCacheTimeOutMinutes
=
60
;
CertificateCacheTimeOutMinutes
=
60
;
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
ProxyEndPoints
=
new
List
<
ProxyEndPoint
>();
...
@@ -251,7 +262,7 @@ namespace Titanium.Web.Proxy
...
@@ -251,7 +262,7 @@ namespace Titanium.Web.Proxy
new
FireFoxProxySettingsManager
();
new
FireFoxProxySettingsManager
();
#endif
#endif
c
ertificateManager
=
new
CertificateManager
(
ExceptionFunc
);
C
ertificateManager
=
new
CertificateManager
(
ExceptionFunc
);
if
(
rootCertificateName
!=
null
)
if
(
rootCertificateName
!=
null
)
{
{
RootCertificateName
=
rootCertificateName
;
RootCertificateName
=
rootCertificateName
;
...
@@ -356,7 +367,7 @@ namespace Titanium.Web.Proxy
...
@@ -356,7 +367,7 @@ namespace Titanium.Web.Proxy
EnsureRootCertificate
();
EnsureRootCertificate
();
//If certificate was trusted by the machine
//If certificate was trusted by the machine
if
(
c
ertificateManager
.
CertValidated
)
if
(
C
ertificateManager
.
CertValidated
)
{
{
systemProxySettingsManager
.
SetHttpsProxy
(
systemProxySettingsManager
.
SetHttpsProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
...
@@ -435,7 +446,7 @@ namespace Titanium.Web.Proxy
...
@@ -435,7 +446,7 @@ namespace Titanium.Web.Proxy
Listen
(
endPoint
);
Listen
(
endPoint
);
}
}
c
ertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
C
ertificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
proxyRunning
=
true
;
proxyRunning
=
true
;
}
}
...
@@ -468,7 +479,7 @@ namespace Titanium.Web.Proxy
...
@@ -468,7 +479,7 @@ namespace Titanium.Web.Proxy
ProxyEndPoints
.
Clear
();
ProxyEndPoints
.
Clear
();
c
ertificateManager
?.
StopClearIdleCertificates
();
C
ertificateManager
?.
StopClearIdleCertificates
();
proxyRunning
=
false
;
proxyRunning
=
false
;
}
}
...
@@ -483,7 +494,7 @@ namespace Titanium.Web.Proxy
...
@@ -483,7 +494,7 @@ namespace Titanium.Web.Proxy
Stop
();
Stop
();
}
}
c
ertificateManager
?.
Dispose
();
C
ertificateManager
?.
Dispose
();
}
}
/// <summary>
/// <summary>
...
@@ -495,7 +506,7 @@ namespace Titanium.Web.Proxy
...
@@ -495,7 +506,7 @@ 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
);
}
}
...
@@ -543,13 +554,13 @@ namespace Titanium.Web.Proxy
...
@@ -543,13 +554,13 @@ namespace Titanium.Web.Proxy
private
void
EnsureRootCertificate
()
private
void
EnsureRootCertificate
()
{
{
if
(!
c
ertificateManager
.
CertValidated
)
if
(!
C
ertificateManager
.
CertValidated
)
{
{
c
ertificateManager
.
CreateTrustedRootCertificate
();
C
ertificateManager
.
CreateTrustedRootCertificate
();
if
(
TrustRootCertificate
)
if
(
TrustRootCertificate
)
{
{
c
ertificateManager
.
TrustRootCertificate
();
C
ertificateManager
.
TrustRootCertificate
();
}
}
}
}
}
}
...
@@ -560,7 +571,7 @@ namespace Titanium.Web.Proxy
...
@@ -560,7 +571,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
;
...
@@ -581,11 +592,18 @@ namespace Titanium.Web.Proxy
...
@@ -581,11 +592,18 @@ namespace Titanium.Web.Proxy
//Other errors are discarded to keep proxy running
//Other errors are discarded to keep proxy running
}
}
if
(
tcpClient
!=
null
)
if
(
tcpClient
!=
null
)
{
{
Task
.
Run
(
async
()
=>
Task
.
Run
(
async
()
=>
{
{
ClientConnectionCount
++;
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
0
);
try
try
{
{
if
(
endPoint
.
GetType
()
==
typeof
(
TransparentProxyEndPoint
))
if
(
endPoint
.
GetType
()
==
typeof
(
TransparentProxyEndPoint
))
...
@@ -599,15 +617,8 @@ namespace Titanium.Web.Proxy
...
@@ -599,15 +617,8 @@ namespace Titanium.Web.Proxy
}
}
finally
finally
{
{
if
(
tcpClient
!=
null
)
ClientConnectionCount
--;
{
tcpClient
?.
Close
();
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
0
);
tcpClient
.
Close
();
}
}
}
});
});
}
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
69aa70c1
...
@@ -33,9 +33,10 @@ namespace Titanium.Web.Proxy
...
@@ -33,9 +33,10 @@ 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
;
try
try
{
{
//read the first line HTTP command
//read the first line HTTP command
...
@@ -56,14 +57,14 @@ namespace Titanium.Web.Proxy
...
@@ -56,14 +57,14 @@ namespace Titanium.Web.Proxy
httpRemoteUri
=
httpVerb
==
"CONNECT"
?
new
Uri
(
"http://"
+
httpCmdSplit
[
1
])
:
new
Uri
(
httpCmdSplit
[
1
]);
httpRemoteUri
=
httpVerb
==
"CONNECT"
?
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
=
HttpHeader
.
Version11
;
if
(
httpCmdSplit
.
Length
==
3
)
if
(
httpCmdSplit
.
Length
==
3
)
{
{
var
httpVersion
=
httpCmdSplit
[
2
].
Trim
();
var
httpVersion
=
httpCmdSplit
[
2
].
Trim
();
if
(
0
==
string
.
CompareOrdinal
(
httpVersion
,
"http/1.0"
))
if
(
string
.
Equals
(
httpVersion
,
"HTTP/1.0"
,
StringComparison
.
OrdinalIgnoreCase
))
{
{
version
=
new
Version
(
1
,
0
)
;
version
=
HttpHeader
.
Version10
;
}
}
}
}
...
@@ -86,8 +87,8 @@ namespace Titanium.Web.Proxy
...
@@ -86,8 +87,8 @@ namespace Titanium.Web.Proxy
if
(
httpVerb
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
if
(
httpVerb
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
{
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
string
tmpLine
;
connectRequestHeaders
=
new
List
<
HttpHeader
>();
connectRequestHeaders
=
new
List
<
HttpHeader
>();
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
...
@@ -110,7 +111,7 @@ namespace Titanium.Web.Proxy
...
@@ -110,7 +111,7 @@ namespace Titanium.Web.Proxy
{
{
sslStream
=
new
SslStream
(
clientStream
,
true
);
sslStream
=
new
SslStream
(
clientStream
,
true
);
var
certificate
=
endPoint
.
GenericCertificate
??
c
ertificateManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
var
certificate
=
endPoint
.
GenericCertificate
??
C
ertificateManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
//Successfully managed to authenticate the client using the fake certificate
//Successfully managed to authenticate the client using the fake certificate
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
...
@@ -119,7 +120,7 @@ namespace Titanium.Web.Proxy
...
@@ -119,7 +120,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
{
{
...
@@ -140,12 +141,11 @@ namespace Titanium.Web.Proxy
...
@@ -140,12 +141,11 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response
//write back successfull CONNECT response
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
await
TcpHelper
.
SendRaw
(
BufferSize
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
await
TcpHelper
.
SendRaw
(
this
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
null
,
version
,
null
,
null
,
version
,
null
,
false
,
SupportedSslProtocols
,
false
,
ValidateServerCertificate
,
clientStream
,
tcpConnectionFactory
);
SelectClientCertificate
,
clientStream
,
tcpConnectionFactory
,
UpStreamEndPoint
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
...
@@ -156,7 +156,9 @@ namespace Titanium.Web.Proxy
...
@@ -156,7 +156,9 @@ namespace Titanium.Web.Proxy
}
}
catch
(
Exception
)
catch
(
Exception
)
{
{
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
}
}
}
}
...
@@ -177,7 +179,7 @@ namespace Titanium.Web.Proxy
...
@@ -177,7 +179,7 @@ namespace Titanium.Web.Proxy
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
//implement in future once SNI supported by SSL stream, for now use the same certificate
//implement in future once SNI supported by SSL stream, for now use the same certificate
var
certificate
=
c
ertificateManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
var
certificate
=
C
ertificateManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
try
try
{
{
...
@@ -187,21 +189,24 @@ namespace Titanium.Web.Proxy
...
@@ -187,21 +189,24 @@ 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
)
{
{
sslStream
.
Dispose
();
sslStream
.
Dispose
();
Dispose
(
sslStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
sslStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
}
}
}
}
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
...
@@ -212,12 +217,17 @@ namespace Titanium.Web.Proxy
...
@@ -212,12 +217,17 @@ namespace Titanium.Web.Proxy
endPoint
.
EnableSsl
?
endPoint
.
GenericCertificateName
:
null
,
endPoint
,
null
);
endPoint
.
EnableSsl
?
endPoint
.
GenericCertificateName
:
null
,
endPoint
,
null
);
}
}
private
async
Task
HandleHttpSessionRequestInternal
(
TcpConnection
connection
,
SessionEventArgs
args
,
ExternalProxy
customUpStreamHttpProxy
,
ExternalProxy
customUpStreamHttpsProxy
,
bool
closeConnection
)
/// <summary>
{
/// Create a Server Connection
try
/// </summary>
{
/// <param name="args"></param>
if
(
connection
==
null
)
/// <returns></returns>
private
async
Task
<
TcpConnection
>
GetServerConnection
(
SessionEventArgs
args
)
{
{
ExternalProxy
customUpStreamHttpProxy
=
null
;
ExternalProxy
customUpStreamHttpsProxy
=
null
;
if
(
args
.
WebSession
.
Request
.
RequestUri
.
Scheme
==
"http"
)
if
(
args
.
WebSession
.
Request
.
RequestUri
.
Scheme
==
"http"
)
{
{
if
(
GetCustomUpStreamHttpProxyFunc
!=
null
)
if
(
GetCustomUpStreamHttpProxyFunc
!=
null
)
...
@@ -236,21 +246,33 @@ namespace Titanium.Web.Proxy
...
@@ -236,21 +246,33 @@ namespace Titanium.Web.Proxy
args
.
CustomUpStreamHttpProxyUsed
=
customUpStreamHttpProxy
;
args
.
CustomUpStreamHttpProxyUsed
=
customUpStreamHttpProxy
;
args
.
CustomUpStreamHttpsProxyUsed
=
customUpStreamHttpsProxy
;
args
.
CustomUpStreamHttpsProxyUsed
=
customUpStreamHttpsProxy
;
connection
=
await
tcpConnectionFactory
.
CreateClient
(
BufferSize
,
ConnectionTimeOutSeconds
,
return
await
tcpConnectionFactory
.
CreateClient
(
this
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
IsHttps
,
SupportedSslProtocols
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
ValidateServerCertificate
,
args
.
WebSession
.
Request
.
HttpVersion
,
SelectClientCertificate
,
args
.
IsHttps
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
,
args
.
ProxyClient
.
ClientStream
,
UpStreamEndPoint
);
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
,
args
.
ProxyClient
.
ClientStream
);
}
}
private
async
Task
<
bool
>
HandleHttpSessionRequestInternal
(
TcpConnection
connection
,
SessionEventArgs
args
,
bool
closeConnection
)
{
try
{
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
//If request was cancelled by user then dispose the client
//If request was cancelled by user then dispose the client
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
{
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
Dispose
(
args
.
ProxyClient
.
ClientStream
,
return
;
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
return
false
;
}
}
//if expect continue is enabled then send the headers first
//if expect continue is enabled then send the headers first
...
@@ -314,28 +336,50 @@ namespace Titanium.Web.Proxy
...
@@ -314,28 +336,50 @@ namespace Titanium.Web.Proxy
//If not expectation failed response was returned by server then parse response
//If not expectation failed response was returned by server then parse response
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
{
await
HandleHttpSessionResponse
(
args
);
var
result
=
await
HandleHttpSessionResponse
(
args
);
//already disposed inside above method
if
(
result
==
false
)
{
return
false
;
}
}
}
//if connection is closing exit
//if connection is closing exit
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
{
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
Dispose
(
args
.
ProxyClient
.
ClientStream
,
return
;
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
return
false
;
}
}
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request (internal)"
,
e
,
args
));
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request (internal)"
,
e
,
args
));
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
return
;
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
return
false
;
}
}
if
(
closeConnection
)
if
(
closeConnection
)
{
{
//dispose
//dispose
connection
?.
Dispose
();
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
return
false
;
}
}
return
true
;
}
}
/// <summary>
/// <summary>
...
@@ -354,7 +398,7 @@ namespace Titanium.Web.Proxy
...
@@ -354,7 +398,7 @@ namespace Titanium.Web.Proxy
/// <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
,
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
,
ExternalProxy
customUpStreamHttpProxy
=
null
,
ExternalProxy
customUpStreamHttpsProxy
=
null
)
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
)
{
{
TcpConnection
connection
=
null
;
TcpConnection
connection
=
null
;
...
@@ -364,20 +408,23 @@ namespace Titanium.Web.Proxy
...
@@ -364,20 +408,23 @@ namespace Titanium.Web.Proxy
{
{
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
{
{
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
connection
);
break
;
break
;
}
}
var
args
=
var
args
=
new
SessionEventArgs
(
BufferSize
,
HandleHttpSessionResponse
)
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
>(()
=>
{
{
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
))
...
@@ -388,6 +435,7 @@ namespace Titanium.Web.Proxy
...
@@ -388,6 +435,7 @@ 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
{
{
//break up the line into three components (method, remote URL & Http Version)
//break up the line into three components (method, remote URL & Http Version)
...
@@ -396,51 +444,22 @@ namespace Titanium.Web.Proxy
...
@@ -396,51 +444,22 @@ namespace Titanium.Web.Proxy
var
httpMethod
=
httpCmdSplit
[
0
];
var
httpMethod
=
httpCmdSplit
[
0
];
//find the request HTTP version
//find the request HTTP version
var
httpVersion
=
new
Version
(
1
,
1
)
;
var
httpVersion
=
HttpHeader
.
Version11
;
if
(
httpCmdSplit
.
Length
==
3
)
if
(
httpCmdSplit
.
Length
==
3
)
{
{
var
httpVersionString
=
httpCmdSplit
[
2
].
T
oLower
().
T
rim
();
var
httpVersionString
=
httpCmdSplit
[
2
].
Trim
();
if
(
0
==
string
.
CompareOrdinal
(
httpVersionString
,
"http/1.0"
))
if
(
string
.
Equals
(
httpVersionString
,
"HTTP/1.0"
,
StringComparison
.
OrdinalIgnoreCase
))
{
{
httpVersion
=
new
Version
(
1
,
0
)
;
httpVersion
=
HttpHeader
.
Version10
;
}
}
}
}
//Read the request headers in to unique and non-unique header collections
//Read the request headers in to unique and non-unique header collections
string
tmpLine
;
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
,
args
.
WebSession
.
Request
.
RequestHeaders
);
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
newHeader
=
new
HttpHeader
(
header
[
0
],
header
[
1
]);
//if header exist in non-unique header collection add it there
if
(
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
[
newHeader
.
Name
].
Add
(
newHeader
);
}
//if header is alread in unique header collection then move both to non-unique collection
else
if
(
args
.
WebSession
.
Request
.
RequestHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
var
existing
=
args
.
WebSession
.
Request
.
RequestHeaders
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>
{
existing
,
newHeader
};
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Remove
(
newHeader
.
Name
);
}
//add to unique header collection
else
{
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
newHeader
.
Name
,
newHeader
);
}
}
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
;
...
@@ -450,9 +469,15 @@ namespace Titanium.Web.Proxy
...
@@ -450,9 +469,15 @@ namespace Titanium.Web.Proxy
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
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
,
connection
);
break
;
break
;
}
}
...
@@ -467,7 +492,7 @@ namespace Titanium.Web.Proxy
...
@@ -467,7 +492,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
])(
this
,
args
);
}
}
await
Task
.
WhenAll
(
handlerTasks
);
await
Task
.
WhenAll
(
handlerTasks
);
...
@@ -476,28 +501,51 @@ namespace Titanium.Web.Proxy
...
@@ -476,28 +501,51 @@ namespace Titanium.Web.Proxy
//if upgrading to websocket then relay the requet without reading the contents
//if upgrading to websocket then relay the requet without reading the contents
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
{
await
TcpHelper
.
SendRaw
(
BufferSize
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
await
TcpHelper
.
SendRaw
(
this
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpCmd
,
httpVersion
,
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
IsHttps
,
httpCmd
,
httpVersion
,
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
IsHttps
,
SupportedSslProtocols
,
ValidateServerCertificate
,
clientStream
,
tcpConnectionFactory
);
SelectClientCertificate
,
clientStream
,
tcpConnectionFactory
,
UpStreamEndPoint
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
connection
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
break
;
break
;
}
}
if
(
connection
==
null
)
{
connection
=
await
GetServerConnection
(
args
);
}
//construct the web request that we are going to issue on behalf of the client.
//construct the web request that we are going to issue on behalf of the client.
await
HandleHttpSessionRequestInternal
(
null
,
args
,
customUpStreamHttpProxy
,
customUpStreamHttpsProxy
,
false
);
var
result
=
await
HandleHttpSessionRequestInternal
(
connection
,
args
,
false
);
if
(
result
==
false
)
{
//already disposed inside above method
break
;
}
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
{
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
connection
);
break
;
break
;
}
}
//if connection is closing exit
//if connection is closing exit
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
{
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
connection
);
break
;
break
;
}
}
...
@@ -507,13 +555,15 @@ namespace Titanium.Web.Proxy
...
@@ -507,13 +555,15 @@ namespace Titanium.Web.Proxy
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
));
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
));
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
clientStream
,
clientStreamReader
,
clientStreamWriter
,
connection
);
break
;
break
;
}
}
}
}
//dispose
connection
?.
Dispose
();
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
69aa70c1
...
@@ -9,6 +9,7 @@ using Titanium.Web.Proxy.Exceptions;
...
@@ -9,6 +9,7 @@ using Titanium.Web.Proxy.Exceptions;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Network.Tcp
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -21,14 +22,14 @@ namespace Titanium.Web.Proxy
...
@@ -21,14 +22,14 @@ namespace Titanium.Web.Proxy
/// Called asynchronously when a request was successfully and we received the response
/// Called asynchronously when a request was successfully and we received the response
/// </summary>
/// </summary>
/// <param name="args"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <returns>true if no errors</returns>
private
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
private
async
Task
<
bool
>
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
try
{
{
//read response & headers from server
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
await
args
.
WebSession
.
ReceiveResponse
();
try
{
if
(!
args
.
WebSession
.
Response
.
ResponseBodyRead
)
if
(!
args
.
WebSession
.
Response
.
ResponseBodyRead
)
{
{
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
...
@@ -44,7 +45,7 @@ namespace Titanium.Web.Proxy
...
@@ -44,7 +45,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
);
...
@@ -52,8 +53,15 @@ namespace Titanium.Web.Proxy
...
@@ -52,8 +53,15 @@ namespace Titanium.Web.Proxy
if
(
args
.
ReRequest
)
if
(
args
.
ReRequest
)
{
{
await
HandleHttpSessionRequestInternal
(
null
,
args
,
null
,
null
,
true
);
if
(
args
.
WebSession
.
ServerConnection
!=
null
)
return
;
{
args
.
WebSession
.
ServerConnection
.
Dispose
();
ServerConnectionCount
--;
}
var
connection
=
await
GetServerConnection
(
args
);
var
result
=
await
HandleHttpSessionRequestInternal
(
null
,
args
,
true
);
return
result
;
}
}
args
.
WebSession
.
Response
.
ResponseLocked
=
true
;
args
.
WebSession
.
Response
.
ResponseLocked
=
true
;
...
@@ -125,14 +133,16 @@ namespace Titanium.Web.Proxy
...
@@ -125,14 +133,16 @@ namespace Titanium.Web.Proxy
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured wilst handling session response"
,
e
,
args
));
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured w
h
ilst handling session response"
,
e
,
args
));
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
return
false
;
}
}
finally
{
args
.
Dispose
();
args
.
Dispose
();
}
return
true
;
}
}
/// <summary>
/// <summary>
...
@@ -224,19 +234,21 @@ namespace Titanium.Web.Proxy
...
@@ -224,19 +234,21 @@ namespace Titanium.Web.Proxy
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="args"></param>
/// <param name="serverConnection"></param>
private
void
Dispose
(
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
private
void
Dispose
(
Stream
clientStream
,
StreamWriter
clientStreamWriter
,
IDisposable
args
)
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
TcpConnection
serverConnection
)
{
{
ServerConnectionCount
--;
clientStream
?.
Close
();
clientStream
?.
Close
();
clientStream
?.
Dispose
();
clientStream
?.
Dispose
();
clientStreamReader
?.
Dispose
();
clientStreamReader
?.
Dispose
();
clientStreamWriter
?.
Close
();
clientStreamWriter
?.
Dispose
();
clientStreamWriter
?.
Dispose
();
args
?.
Dispose
();
serverConnection
?.
Dispose
();
}
}
}
}
}
}
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
69aa70c1
...
@@ -77,6 +77,7 @@
...
@@ -77,6 +77,7 @@
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
<Compile
Include=
"Helpers\RunTime.cs"
/>
<Compile
Include=
"Helpers\RunTime.cs"
/>
<Compile
Include=
"Http\HeaderParser.cs"
/>
<Compile
Include=
"Http\Responses\GenericResponse.cs"
/>
<Compile
Include=
"Http\Responses\GenericResponse.cs"
/>
<Compile
Include=
"Network\CachedCertificate.cs"
/>
<Compile
Include=
"Network\CachedCertificate.cs"
/>
<Compile
Include=
"Network\Certificate\WinCertificateMaker.cs"
/>
<Compile
Include=
"Network\Certificate\WinCertificateMaker.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