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
2eed8cb0
Commit
2eed8cb0
authored
Aug 18, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
space before the commetns
parent
67c1e265
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
174 additions
and
171 deletions
+174
-171
README.md
README.md
+70
-70
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+1
-1
SessionEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+8
-8
ExplicitClientHandler.cs
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+2
-1
TcpExtensions.cs
src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+2
-2
Network.cs
src/Titanium.Web.Proxy/Helpers/Network.cs
+1
-1
RunTime.cs
src/Titanium.Web.Proxy/Helpers/RunTime.cs
+1
-1
RetryPolicy.cs
src/Titanium.Web.Proxy/Network/RetryPolicy.cs
+4
-4
TcpClientConnection.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs
+3
-3
TcpConnectionFactory.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+7
-7
TcpServerConnection.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
+3
-3
Common.cs
src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs
+1
-1
ProxyServer.cs
src/Titanium.Web.Proxy/ProxyServer.cs
+6
-4
RequestHandler.cs
src/Titanium.Web.Proxy/RequestHandler.cs
+9
-9
ResponseHandler.cs
src/Titanium.Web.Proxy/ResponseHandler.cs
+4
-4
CopyStream.cs
src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs
+2
-2
CustomBufferedStream.cs
....Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs
+11
-11
SslExtensions.cs
src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs
+28
-28
SslTools.cs
src/Titanium.Web.Proxy/StreamExtended/SslTools.cs
+10
-10
TestServer.cs
...s/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
+1
-1
No files found.
README.md
View file @
2eed8cb0
...
@@ -30,7 +30,7 @@ For stable releases on [stable branch](https://github.com/justcoding121/Titanium
...
@@ -30,7 +30,7 @@ For stable releases on [stable branch](https://github.com/justcoding121/Titanium
Supports
Supports
*
.Net Standard 2.0 or above
*
.Net Standard 2.0 or above
*
.Net Framework 4.
5
or above
*
.Net Framework 4.
6.1
or above
### Development environment
### Development environment
...
@@ -55,11 +55,11 @@ Setup HTTP proxy:
...
@@ -55,11 +55,11 @@ Setup HTTP proxy:
```
csharp
```
csharp
var
proxyServer
=
new
ProxyServer
();
var
proxyServer
=
new
ProxyServer
();
//locally trust root certificate used by this proxy
//
locally trust root certificate used by this proxy
proxyServer
.
CertificateManager
.
TrustRootCertificate
=
true
;
proxyServer
.
CertificateManager
.
TrustRootCertificate
=
true
;
//optionally set the Certificate Engine
//
optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported
//
Under Mono only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
proxyServer
.
BeforeRequest
+=
OnRequest
;
proxyServer
.
BeforeRequest
+=
OnRequest
;
...
@@ -70,28 +70,28 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
...
@@ -70,28 +70,28 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
{
{
//
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")
};
};
//Fired when a CONNECT request is received
//
Fired when a CONNECT request is received
explicitEndPoint
.
BeforeTunnelConnect
+=
OnBeforeTunnelConnect
;
explicitEndPoint
.
BeforeTunnelConnect
+=
OnBeforeTunnelConnect
;
//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
//So client sends request in a proxy friendly manner
//
So client sends request in a proxy friendly manner
proxyServer
.
AddEndPoint
(
explicitEndPoint
);
proxyServer
.
AddEndPoint
(
explicitEndPoint
);
proxyServer
.
Start
();
proxyServer
.
Start
();
//Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)
//
Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)
//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS
//
A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS
//to send data to this endPoint
//
to send data to this endPoint
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Any
,
8001
,
true
)
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Any
,
8001
,
true
)
{
{
//
Generic Certificate hostname to use
//
Generic Certificate hostname to use
//
when SNI is disabled by client
//
when SNI is disabled by client
GenericCertificateName
=
"google.com"
GenericCertificateName
=
"google.com"
};
};
proxyServer
.
AddEndPoint
(
transparentEndPoint
);
proxyServer
.
AddEndPoint
(
transparentEndPoint
);
...
@@ -103,14 +103,14 @@ foreach (var endPoint in proxyServer.ProxyEndPoints)
...
@@ -103,14 +103,14 @@ foreach (var endPoint in proxyServer.ProxyEndPoints)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
//Only explicit proxies can be set as system proxy!
//
Only explicit proxies can be set as system proxy!
proxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
proxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
proxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
proxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
//wait here (You can use something else as a wait function, I am using this as a demo)
//
wait here (You can use something else as a wait function, I am using this as a demo)
Console
.
Read
();
Console
.
Read
();
//Unsubscribe & Quit
//
Unsubscribe & Quit
explicitEndPoint
.
BeforeTunnelConnect
-=
OnBeforeTunnelConnect
;
explicitEndPoint
.
BeforeTunnelConnect
-=
OnBeforeTunnelConnect
;
proxyServer
.
BeforeRequest
-=
OnRequest
;
proxyServer
.
BeforeRequest
-=
OnRequest
;
proxyServer
.
BeforeResponse
-=
OnResponse
;
proxyServer
.
BeforeResponse
-=
OnResponse
;
...
@@ -118,11 +118,11 @@ proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
...
@@ -118,11 +118,11 @@ proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
Stop
();
proxyServer
.
Stop
();
```
```
Sample request and response event handlers
Sample request and response event handlers
```
csharp
```
csharp
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
{
{
...
@@ -130,9 +130,9 @@ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSess
...
@@ -130,9 +130,9 @@ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSess
if
(
hostname
.
Contains
(
"dropbox.com"
))
if
(
hostname
.
Contains
(
"dropbox.com"
))
{
{
//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 dropbox.com
//
for example dropbox.com
e
.
DecryptSsl
=
false
;
e
.
DecryptSsl
=
false
;
}
}
}
}
...
@@ -141,88 +141,88 @@ public async Task OnRequest(object sender, SessionEventArgs e)
...
@@ -141,88 +141,88 @@ public async Task OnRequest(object sender, SessionEventArgs e)
{
{
Console
.
WriteLine
(
e
.
HttpClient
.
Request
.
Url
);
Console
.
WriteLine
(
e
.
HttpClient
.
Request
.
Url
);
//
//
read request headers
//
read request headers
var
requestHeaders
=
e
.
HttpClient
.
Request
.
RequestHeaders
;
var
requestHeaders
=
e
.
HttpClient
.
Request
.
RequestHeaders
;
var
method
=
e
.
HttpClient
.
Request
.
Method
.
ToUpper
();
var
method
=
e
.
HttpClient
.
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
();
await
e
.
SetRequestBody
(
bodyBytes
);
await
e
.
SetRequestBody
(
bodyBytes
);
//
Get/Set request body as string
//
Get/Set request body as string
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
await
e
.
SetRequestBodyString
(
bodyString
);
await
e
.
SetRequestBodyString
(
bodyString
);
//
store request
//
store request
//
so that you can find it from response handler
//
so that you can find it from response handler
e
.
UserData
=
e
.
HttpClient
.
Request
;
e
.
UserData
=
e
.
HttpClient
.
Request
;
}
}
//To cancel a request with a custom HTML content
//
To cancel a request with a custom HTML content
//Filter URL
//
Filter URL
if
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
if
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
{
e
.
Ok
(
"<!DOCTYPE html>"
+
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
.
HttpClient
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"wikipedia.org"
))
if
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"wikipedia.org"
))
{
{
e
.
Redirect
(
"https://www.paypal.com"
);
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
)
{
{
//read response headers
//
read response headers
var
responseHeaders
=
e
.
HttpClient
.
Response
.
ResponseHeaders
;
var
responseHeaders
=
e
.
HttpClient
.
Response
.
ResponseHeaders
;
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
if
(
e
.
HttpClient
.
Request
.
Method
==
"GET"
||
e
.
HttpClient
.
Request
.
Method
==
"POST"
)
if
(
e
.
HttpClient
.
Request
.
Method
==
"GET"
||
e
.
HttpClient
.
Request
.
Method
==
"POST"
)
{
{
if
(
e
.
HttpClient
.
Response
.
ResponseStatusCode
==
"200"
)
if
(
e
.
HttpClient
.
Response
.
ResponseStatusCode
==
"200"
)
{
{
if
(
e
.
HttpClient
.
Response
.
ContentType
!=
null
&&
e
.
HttpClient
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
if
(
e
.
HttpClient
.
Response
.
ContentType
!=
null
&&
e
.
HttpClient
.
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
);
string
body
=
await
e
.
GetResponseBodyAsString
();
string
body
=
await
e
.
GetResponseBodyAsString
();
await
e
.
SetResponseBodyString
(
body
);
await
e
.
SetResponseBodyString
(
body
);
}
}
}
}
}
}
if
(
e
.
UserData
!=
null
)
if
(
e
.
UserData
!=
null
)
{
{
//
access request from UserData property where we stored it in RequestHandler
//
access request from UserData property where we stored it in RequestHandler
var
request
=
(
Request
)
e
.
UserData
;
var
request
=
(
Request
)
e
.
UserData
;
}
}
}
}
//
/
Allows overriding default certificate validation logic
// Allows overriding default certificate validation logic
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
==
System
.
Net
.
Security
.
SslPolicyErrors
.
None
)
if
(
e
.
SslPolicyErrors
==
System
.
Net
.
Security
.
SslPolicyErrors
.
None
)
e
.
IsValid
=
true
;
e
.
IsValid
=
true
;
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
//
/
Allows overriding default client certificate selection logic during mutual authentication
// Allows overriding default client certificate selection logic during mutual authentication
public
Task
OnCertificateSelection
(
object
sender
,
CertificateSelectionEventArgs
e
)
public
Task
OnCertificateSelection
(
object
sender
,
CertificateSelectionEventArgs
e
)
{
{
//set e.clientCertificate to override
//
set e.clientCertificate to override
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
```
```
...
...
examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
2eed8cb0
...
@@ -193,7 +193,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -193,7 +193,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsolutePath
);
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsolutePath
);
//access user data set in request to do something with it
//
access user data set in request to do something with it
//var userData = e.HttpClient.UserData as CustomUserData;
//var userData = e.HttpClient.UserData as CustomUserData;
//if (ext == ".gif" || ext == ".png" || ext == ".jpg")
//if (ext == ".gif" || ext == ".png" || ext == ".jpg")
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
2eed8cb0
...
@@ -615,36 +615,36 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -615,36 +615,36 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public
void
Respond
(
Response
response
,
bool
closeServerConnection
=
false
)
public
void
Respond
(
Response
response
,
bool
closeServerConnection
=
false
)
{
{
//request already send/ready to be sent.
//
request already send/ready to be sent.
if
(
HttpClient
.
Request
.
Locked
)
if
(
HttpClient
.
Request
.
Locked
)
{
{
//response already received from server and ready to be sent to client.
//
response already received from server and ready to be sent to client.
if
(
HttpClient
.
Response
.
Locked
)
if
(
HttpClient
.
Response
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function after response is sent to the client."
);
throw
new
Exception
(
"You cannot call this function after response is sent to the client."
);
}
}
//cleanup original response.
//
cleanup original response.
if
(
closeServerConnection
)
if
(
closeServerConnection
)
{
{
//no need to cleanup original connection.
//
no need to cleanup original connection.
//it will be closed any way.
//
it will be closed any way.
TerminateServerConnection
();
TerminateServerConnection
();
}
}
response
.
SetOriginalHeaders
(
HttpClient
.
Response
);
response
.
SetOriginalHeaders
(
HttpClient
.
Response
);
//response already received from server but not yet ready to sent to client.
//
response already received from server but not yet ready to sent to client.
HttpClient
.
Response
=
response
;
HttpClient
.
Response
=
response
;
HttpClient
.
Response
.
Locked
=
true
;
HttpClient
.
Response
.
Locked
=
true
;
}
}
//request not yet sent/not yet ready to be sent.
//
request not yet sent/not yet ready to be sent.
else
else
{
{
HttpClient
.
Request
.
Locked
=
true
;
HttpClient
.
Request
.
Locked
=
true
;
HttpClient
.
Request
.
CancelRequest
=
true
;
HttpClient
.
Request
.
CancelRequest
=
true
;
//set new response.
//
set new response.
HttpClient
.
Response
=
response
;
HttpClient
.
Response
=
response
;
HttpClient
.
Response
.
Locked
=
true
;
HttpClient
.
Response
.
Locked
=
true
;
}
}
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
2eed8cb0
...
@@ -152,7 +152,8 @@ namespace Titanium.Web.Proxy
...
@@ -152,7 +152,8 @@ namespace Titanium.Web.Proxy
http2Supported
=
connection
.
NegotiatedApplicationProtocol
==
http2Supported
=
connection
.
NegotiatedApplicationProtocol
==
SslApplicationProtocol
.
Http2
;
SslApplicationProtocol
.
Http2
;
//release connection back to pool instead of closing when connection pool is enabled.
// release connection back to pool instead of closing when connection pool is enabled.
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
await
tcpConnectionFactory
.
Release
(
connection
,
true
);
}
}
catch
(
Exception
)
catch
(
Exception
)
...
...
src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
2eed8cb0
...
@@ -50,11 +50,11 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -50,11 +50,11 @@ namespace Titanium.Web.Proxy.Extensions
socket
.
Blocking
=
false
;
socket
.
Blocking
=
false
;
socket
.
Send
(
tmp
,
0
,
0
);
socket
.
Send
(
tmp
,
0
,
0
);
//Connected.
//
Connected.
}
}
catch
catch
{
{
//Should we let 10035 == WSAEWOULDBLOCK as valid connection?
//
Should we let 10035 == WSAEWOULDBLOCK as valid connection?
return
false
;
return
false
;
}
}
finally
finally
...
...
src/Titanium.Web.Proxy/Helpers/Network.cs
View file @
2eed8cb0
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers
return
true
;
return
true
;
}
}
//if hostname matches local host name
//
if hostname matches local host name
if
(
hostName
.
Equals
(
localhostName
,
StringComparison
.
OrdinalIgnoreCase
))
if
(
hostName
.
Equals
(
localhostName
,
StringComparison
.
OrdinalIgnoreCase
))
{
{
return
true
;
return
true
;
...
...
src/Titanium.Web.Proxy/Helpers/RunTime.cs
View file @
2eed8cb0
...
@@ -42,7 +42,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -42,7 +42,7 @@ namespace Titanium.Web.Proxy.Helpers
public
static
bool
IsMac
=>
isRunningOnMac
;
public
static
bool
IsMac
=>
isRunningOnMac
;
//https://github.com/qmatteoq/DesktopBridgeHelpers/blob/master/DesktopBridge.Helpers/Helpers.cs
//
https://github.com/qmatteoq/DesktopBridgeHelpers/blob/master/DesktopBridge.Helpers/Helpers.cs
private
class
UwpHelper
private
class
UwpHelper
{
{
const
long
APPMODEL_ERROR_NO_PACKAGE
=
15700L
;
const
long
APPMODEL_ERROR_NO_PACKAGE
=
15700L
;
...
...
src/Titanium.Web.Proxy/Network/RetryPolicy.cs
View file @
2eed8cb0
...
@@ -37,10 +37,10 @@ namespace Titanium.Web.Proxy.Network
...
@@ -37,10 +37,10 @@ namespace Titanium.Web.Proxy.Network
{
{
try
try
{
{
//setup connection
//
setup connection
currentConnection
=
currentConnection
as
TcpServerConnection
??
currentConnection
=
currentConnection
as
TcpServerConnection
??
await
generator
();
await
generator
();
//try
//
try
@continue
=
await
action
(
currentConnection
);
@continue
=
await
action
(
currentConnection
);
}
}
...
@@ -65,12 +65,12 @@ namespace Titanium.Web.Proxy.Network
...
@@ -65,12 +65,12 @@ namespace Titanium.Web.Proxy.Network
return
new
RetryResult
(
currentConnection
,
exception
,
@continue
);
return
new
RetryResult
(
currentConnection
,
exception
,
@continue
);
}
}
//before retry clear connection
//
before retry clear connection
private
async
Task
disposeConnection
()
private
async
Task
disposeConnection
()
{
{
if
(
currentConnection
!=
null
)
if
(
currentConnection
!=
null
)
{
{
//close connection on error
//
close connection on error
await
tcpConnectionFactory
.
Release
(
currentConnection
,
true
);
await
tcpConnectionFactory
.
Release
(
currentConnection
,
true
);
currentConnection
=
null
;
currentConnection
=
null
;
}
}
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs
View file @
2eed8cb0
...
@@ -82,9 +82,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -82,9 +82,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
Task
.
Run
(
async
()
=>
Task
.
Run
(
async
()
=>
{
{
//delay calling tcp connection close()
//
delay calling tcp connection close()
//so that client have enough time to call close first.
//
so that client have enough time to call close first.
//This way we can push tcp Time_Wait to client side when possible.
//
This way we can push tcp Time_Wait to client side when possible.
await
Task
.
Delay
(
1000
);
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateClientConnectionCount
(
false
);
proxyServer
.
UpdateClientConnectionCount
(
false
);
tcpClient
.
CloseSocket
();
tcpClient
.
CloseSocket
();
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
2eed8cb0
...
@@ -25,15 +25,15 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -25,15 +25,15 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal
class
TcpConnectionFactory
:
IDisposable
internal
class
TcpConnectionFactory
:
IDisposable
{
{
//Tcp server connection pool cache
//
Tcp server connection pool cache
private
readonly
ConcurrentDictionary
<
string
,
ConcurrentQueue
<
TcpServerConnection
>>
cache
private
readonly
ConcurrentDictionary
<
string
,
ConcurrentQueue
<
TcpServerConnection
>>
cache
=
new
ConcurrentDictionary
<
string
,
ConcurrentQueue
<
TcpServerConnection
>>();
=
new
ConcurrentDictionary
<
string
,
ConcurrentQueue
<
TcpServerConnection
>>();
//Tcp connections waiting to be disposed by cleanup task
//
Tcp connections waiting to be disposed by cleanup task
private
readonly
ConcurrentBag
<
TcpServerConnection
>
disposalBag
=
private
readonly
ConcurrentBag
<
TcpServerConnection
>
disposalBag
=
new
ConcurrentBag
<
TcpServerConnection
>();
new
ConcurrentBag
<
TcpServerConnection
>();
//cache object race operations lock
//
cache object race operations lock
private
readonly
SemaphoreSlim
@lock
=
new
SemaphoreSlim
(
1
);
private
readonly
SemaphoreSlim
@lock
=
new
SemaphoreSlim
(
1
);
private
volatile
bool
runCleanUpTask
=
true
;
private
volatile
bool
runCleanUpTask
=
true
;
...
@@ -55,7 +55,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -55,7 +55,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
// That can create cache miss for same server connection unnecessarily especially when prefetching with Connect.
// That can create cache miss for same server connection unnecessarily especially when prefetching with Connect.
// http version 2 is separated using applicationProtocols below.
// http version 2 is separated using applicationProtocols below.
var
cacheKeyBuilder
=
new
StringBuilder
(
$"
{
remoteHostName
}
-
{
remotePort
}
-"
+
var
cacheKeyBuilder
=
new
StringBuilder
(
$"
{
remoteHostName
}
-
{
remotePort
}
-"
+
//when creating Tcp client isConnect won't matter
//
when creating Tcp client isConnect won't matter
$"
{
isHttps
}
-"
);
$"
{
isHttps
}
-"
);
if
(
applicationProtocols
!=
null
)
if
(
applicationProtocols
!=
null
)
{
{
...
@@ -238,7 +238,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -238,7 +238,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
ProxyServer
proxyServer
,
SessionEventArgsBase
session
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
ProxyServer
proxyServer
,
SessionEventArgsBase
session
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
CancellationToken
cancellationToken
)
CancellationToken
cancellationToken
)
{
{
//deny connection to proxy end points to avoid infinite connection loop.
//
deny connection to proxy end points to avoid infinite connection loop.
if
(
Server
.
ProxyEndPoints
.
Any
(
x
=>
x
.
Port
==
remotePort
)
if
(
Server
.
ProxyEndPoints
.
Any
(
x
=>
x
.
Port
==
remotePort
)
&&
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
))
&&
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
))
{
{
...
@@ -288,7 +288,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -288,7 +288,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
LingerState
=
new
LingerOption
(
true
,
proxyServer
.
TcpTimeWaitSeconds
)
LingerState
=
new
LingerOption
(
true
,
proxyServer
.
TcpTimeWaitSeconds
)
};
};
//linux has a bug with socket reuse in .net core.
//
linux has a bug with socket reuse in .net core.
if
(
proxyServer
.
ReuseSocket
&&
RunTime
.
IsWindows
)
if
(
proxyServer
.
ReuseSocket
&&
RunTime
.
IsWindows
)
{
{
tcpClient
.
Client
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
tcpClient
.
Client
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
...
@@ -550,7 +550,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -550,7 +550,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
}
finally
finally
{
{
//cleanup every 3 seconds by default
//
cleanup every 3 seconds by default
await
Task
.
Delay
(
1000
*
3
);
await
Task
.
Delay
(
1000
*
3
);
}
}
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
View file @
2eed8cb0
...
@@ -90,9 +90,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -90,9 +90,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
{
Task
.
Run
(
async
()
=>
Task
.
Run
(
async
()
=>
{
{
//delay calling tcp connection close()
//
delay calling tcp connection close()
//so that server have enough time to call close first.
//
so that server have enough time to call close first.
//This way we can push tcp Time_Wait to server side when possible.
//
This way we can push tcp Time_Wait to server side when possible.
await
Task
.
Delay
(
1000
);
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateServerConnectionCount
(
false
);
proxyServer
.
UpdateServerConnectionCount
(
false
);
Stream
?.
Dispose
();
Stream
?.
Dispose
();
...
...
src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs
View file @
2eed8cb0
...
@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
...
@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
// int cbBuffer;
// int cbBuffer;
// int BufferType;
// int BufferType;
// pvBuffer;
// pvBuffer;
//What we need to do here is to grab a hold of the pvBuffer allocate by the individual
//
What we need to do here is to grab a hold of the pvBuffer allocate by the individual
// SecBuffer and release it...
// SecBuffer and release it...
int
currentOffset
=
index
*
Marshal
.
SizeOf
(
typeof
(
Buffer
));
int
currentOffset
=
index
*
Marshal
.
SizeOf
(
typeof
(
Buffer
));
var
secBufferpvBuffer
=
Marshal
.
ReadIntPtr
(
pBuffers
,
var
secBufferpvBuffer
=
Marshal
.
ReadIntPtr
(
pBuffers
,
...
...
src/Titanium.Web.Proxy/ProxyServer.cs
View file @
2eed8cb0
...
@@ -122,7 +122,9 @@ namespace Titanium.Web.Proxy
...
@@ -122,7 +122,9 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
private
SystemProxyManager
systemProxySettingsManager
{
get
;
}
//Number of exception retries when connection pool is enabled.
/// <summary>
/// Number of exception retries when connection pool is enabled.
/// </summary>
private
int
retries
=>
EnableConnectionPool
?
MaxCachedConnections
:
0
;
private
int
retries
=>
EnableConnectionPool
?
MaxCachedConnections
:
0
;
/// <summary>
/// <summary>
...
@@ -660,7 +662,7 @@ namespace Titanium.Web.Proxy
...
@@ -660,7 +662,7 @@ namespace Titanium.Web.Proxy
{
{
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
//linux/macOS has a bug with socket reuse in .net core.
//
linux/macOS has a bug with socket reuse in .net core.
if
(
ReuseSocket
&&
RunTime
.
IsWindows
)
if
(
ReuseSocket
&&
RunTime
.
IsWindows
)
{
{
endPoint
.
Listener
.
Server
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
endPoint
.
Listener
.
Server
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
...
@@ -871,13 +873,13 @@ namespace Titanium.Web.Proxy
...
@@ -871,13 +873,13 @@ namespace Titanium.Web.Proxy
/// <returns></returns>
/// <returns></returns>
internal
async
Task
InvokeConnectionCreateEvent
(
TcpClient
client
,
bool
isClientConnection
)
internal
async
Task
InvokeConnectionCreateEvent
(
TcpClient
client
,
bool
isClientConnection
)
{
{
//client connection created
//
client connection created
if
(
isClientConnection
&&
OnClientConnectionCreate
!=
null
)
if
(
isClientConnection
&&
OnClientConnectionCreate
!=
null
)
{
{
await
OnClientConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
await
OnClientConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
}
}
//server connection created
//
server connection created
if
(!
isClientConnection
&&
OnServerConnectionCreate
!=
null
)
if
(!
isClientConnection
&&
OnServerConnectionCreate
!=
null
)
{
{
await
OnServerConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
await
OnServerConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
2eed8cb0
...
@@ -163,7 +163,7 @@ namespace Titanium.Web.Proxy
...
@@ -163,7 +163,7 @@ namespace Titanium.Web.Proxy
await
args
.
GetRequestBody
(
cancellationToken
);
await
args
.
GetRequestBody
(
cancellationToken
);
}
}
//we need this to syphon out data from connection if API user changes them.
//
we need this to syphon out data from connection if API user changes them.
request
.
SetOriginalHeaders
();
request
.
SetOriginalHeaders
();
args
.
TimeLine
[
"Request Received"
]
=
DateTime
.
Now
;
args
.
TimeLine
[
"Request Received"
]
=
DateTime
.
Now
;
...
@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy
...
@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy
continue
;
continue
;
}
}
//If prefetch task is available.
//
If prefetch task is available.
if
(
connection
==
null
&&
prefetchTask
!=
null
)
if
(
connection
==
null
&&
prefetchTask
!=
null
)
{
{
try
try
...
@@ -226,11 +226,11 @@ namespace Titanium.Web.Proxy
...
@@ -226,11 +226,11 @@ namespace Titanium.Web.Proxy
clientConnection
.
NegotiatedApplicationProtocol
,
clientConnection
.
NegotiatedApplicationProtocol
,
cancellationToken
,
cancellationTokenSource
);
cancellationToken
,
cancellationTokenSource
);
//update connection to latest used
//
update connection to latest used
connection
=
result
.
LatestConnection
;
connection
=
result
.
LatestConnection
;
closeServerConnection
=
!
result
.
Continue
;
closeServerConnection
=
!
result
.
Continue
;
//throw if exception happened
//
throw if exception happened
if
(!
result
.
IsSuccess
)
if
(!
result
.
IsSuccess
)
{
{
throw
result
.
Exception
;
throw
result
.
Exception
;
...
@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy
...
@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy
return
;
return
;
}
}
//user requested
//
user requested
if
(
args
.
HttpClient
.
CloseServerConnection
)
if
(
args
.
HttpClient
.
CloseServerConnection
)
{
{
closeServerConnection
=
true
;
closeServerConnection
=
true
;
...
@@ -304,13 +304,13 @@ namespace Titanium.Web.Proxy
...
@@ -304,13 +304,13 @@ namespace Titanium.Web.Proxy
TcpServerConnection
serverConnection
,
SslApplicationProtocol
sslApplicationProtocol
,
TcpServerConnection
serverConnection
,
SslApplicationProtocol
sslApplicationProtocol
,
CancellationToken
cancellationToken
,
CancellationTokenSource
cancellationTokenSource
)
CancellationToken
cancellationToken
,
CancellationTokenSource
cancellationTokenSource
)
{
{
//a connection generator task with captured parameters via closure.
//
a connection generator task with captured parameters via closure.
Func
<
Task
<
TcpServerConnection
>>
generator
=
()
=>
Func
<
Task
<
TcpServerConnection
>>
generator
=
()
=>
tcpConnectionFactory
.
GetServerConnection
(
this
,
args
,
isConnect
:
false
,
tcpConnectionFactory
.
GetServerConnection
(
this
,
args
,
isConnect
:
false
,
applicationProtocol
:
sslApplicationProtocol
,
applicationProtocol
:
sslApplicationProtocol
,
noCache
:
false
,
cancellationToken
:
cancellationToken
);
noCache
:
false
,
cancellationToken
:
cancellationToken
);
//for connection pool, retry fails until cache is exhausted.
//
for connection pool, retry fails until cache is exhausted.
return
await
retryPolicy
<
ServerConnectionException
>().
ExecuteAsync
(
async
(
connection
)
=>
return
await
retryPolicy
<
ServerConnectionException
>().
ExecuteAsync
(
async
(
connection
)
=>
{
{
args
.
TimeLine
[
"Connection Ready"
]
=
DateTime
.
Now
;
args
.
TimeLine
[
"Connection Ready"
]
=
DateTime
.
Now
;
...
@@ -390,12 +390,12 @@ namespace Titanium.Web.Proxy
...
@@ -390,12 +390,12 @@ namespace Titanium.Web.Proxy
{
{
var
supportedAcceptEncoding
=
new
List
<
string
>();
var
supportedAcceptEncoding
=
new
List
<
string
>();
//only allow proxy supported compressions
//
only allow proxy supported compressions
supportedAcceptEncoding
.
AddRange
(
acceptEncoding
.
Split
(
','
)
supportedAcceptEncoding
.
AddRange
(
acceptEncoding
.
Split
(
','
)
.
Select
(
x
=>
x
.
Trim
())
.
Select
(
x
=>
x
.
Trim
())
.
Where
(
x
=>
ProxyConstants
.
ProxySupportedCompressions
.
Contains
(
x
)));
.
Where
(
x
=>
ProxyConstants
.
ProxySupportedCompressions
.
Contains
(
x
)));
//uncompressed is always supported by proxy
//
uncompressed is always supported by proxy
supportedAcceptEncoding
.
Add
(
"identity"
);
supportedAcceptEncoding
.
Add
(
"identity"
);
requestHeaders
.
SetOrAddHeaderValue
(
KnownHeaders
.
AcceptEncoding
,
requestHeaders
.
SetOrAddHeaderValue
(
KnownHeaders
.
AcceptEncoding
,
...
...
src/Titanium.Web.Proxy/ResponseHandler.cs
View file @
2eed8cb0
...
@@ -51,8 +51,8 @@ namespace Titanium.Web.Proxy
...
@@ -51,8 +51,8 @@ namespace Titanium.Web.Proxy
}
}
}
}
//save original values so that if user changes them
//
save original values so that if user changes them
//we can still use original values when syphoning out data from attached tcp connection.
//
we can still use original values when syphoning out data from attached tcp connection.
response
.
SetOriginalHeaders
();
response
.
SetOriginalHeaders
();
// if user requested call back then do it
// if user requested call back then do it
...
@@ -66,10 +66,10 @@ namespace Titanium.Web.Proxy
...
@@ -66,10 +66,10 @@ namespace Titanium.Web.Proxy
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
//user set custom response by ignoring original response from server.
//
user set custom response by ignoring original response from server.
if
(
response
.
Locked
)
if
(
response
.
Locked
)
{
{
//write custom user response with body and return.
//
write custom user response with body and return.
await
clientStreamWriter
.
WriteResponseAsync
(
response
,
cancellationToken
:
cancellationToken
);
await
clientStreamWriter
.
WriteResponseAsync
(
response
,
cancellationToken
:
cancellationToken
);
if
(
args
.
HttpClient
.
Connection
!=
null
if
(
args
.
HttpClient
.
Connection
!=
null
...
...
src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs
View file @
2eed8cb0
...
@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
public
void
Flush
()
public
void
Flush
()
{
{
//send out the current data from from the buffer
//
send out the current data from from the buffer
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
writer
.
Write
(
buffer
,
0
,
bufferLength
);
writer
.
Write
(
buffer
,
0
,
bufferLength
);
...
@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
public
async
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
)
public
async
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
//send out the current data from from the buffer
//
send out the current data from from the buffer
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
await
writer
.
WriteAsync
(
buffer
,
0
,
bufferLength
,
cancellationToken
);
await
writer
.
WriteAsync
(
buffer
,
0
,
bufferLength
,
cancellationToken
);
...
...
src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs
View file @
2eed8cb0
...
@@ -257,13 +257,13 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -257,13 +257,13 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
await
FillBufferAsync
(
cancellationToken
);
await
FillBufferAsync
(
cancellationToken
);
}
}
//When index is greater than the buffer size
//
When index is greater than the buffer size
if
(
streamBuffer
.
Length
<=
index
)
if
(
streamBuffer
.
Length
<=
index
)
{
{
throw
new
Exception
(
"Requested Peek index exceeds the buffer size. Consider increasing the buffer size."
);
throw
new
Exception
(
"Requested Peek index exceeds the buffer size. Consider increasing the buffer size."
);
}
}
//When index is greater than the buffer size
//
When index is greater than the buffer size
if
(
Available
<=
index
)
if
(
Available
<=
index
)
{
{
return
-
1
;
return
-
1
;
...
@@ -287,7 +287,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -287,7 +287,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
await
FillBufferAsync
(
cancellationToken
);
await
FillBufferAsync
(
cancellationToken
);
}
}
//When index is greater than the buffer size
//
When index is greater than the buffer size
if
(
streamBuffer
.
Length
<=
(
index
+
size
))
if
(
streamBuffer
.
Length
<=
(
index
+
size
))
{
{
throw
new
Exception
(
"Requested Peek index and size exceeds the buffer size. Consider increasing the buffer size."
);
throw
new
Exception
(
"Requested Peek index and size exceeds the buffer size. Consider increasing the buffer size."
);
...
@@ -477,8 +477,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -477,8 +477,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
//normally we fill the buffer only when it is empty, but sometimes we need more data
//
normally we fill the buffer only when it is empty, but sometimes we need more data
//move the remaining data to the beginning of the buffer
//
move the remaining data to the beginning of the buffer
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
}
}
...
@@ -521,8 +521,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -521,8 +521,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
//normally we fill the buffer only when it is empty, but sometimes we need more data
//
normally we fill the buffer only when it is empty, but sometimes we need more data
//move the remaining data to the beginning of the buffer
//
move the remaining data to the beginning of the buffer
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
}
}
...
@@ -586,7 +586,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -586,7 +586,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
byte
newChar
=
reader
.
ReadByteFromBuffer
();
byte
newChar
=
reader
.
ReadByteFromBuffer
();
buffer
[
bufferDataLength
]
=
newChar
;
buffer
[
bufferDataLength
]
=
newChar
;
//if new line
//
if new line
if
(
newChar
==
'\n'
)
if
(
newChar
==
'\n'
)
{
{
if
(
lastChar
==
'\r'
)
if
(
lastChar
==
'\r'
)
...
@@ -599,7 +599,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -599,7 +599,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
bufferDataLength
++;
bufferDataLength
++;
//store last char for new line comparison
//
store last char for new line comparison
lastChar
=
newChar
;
lastChar
=
newChar
;
if
(
bufferDataLength
==
buffer
.
Length
)
if
(
bufferDataLength
==
buffer
.
Length
)
...
@@ -663,8 +663,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -663,8 +663,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
vAsyncResult
.
ContinueWith
(
pAsyncResult
=>
vAsyncResult
.
ContinueWith
(
pAsyncResult
=>
{
{
//use TaskExtended to pass State as AsyncObject
//
use TaskExtended to pass State as AsyncObject
//callback will call EndRead (otherwise, it will block)
//
callback will call EndRead (otherwise, it will block)
callback
?.
Invoke
(
new
TaskResult
<
int
>(
pAsyncResult
,
state
));
callback
?.
Invoke
(
new
TaskResult
<
int
>(
pAsyncResult
,
state
));
});
});
...
...
src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs
View file @
2eed8cb0
...
@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.StreamExtended
private
static
string
GetExtensionData
(
int
value
,
byte
[]
data
)
private
static
string
GetExtensionData
(
int
value
,
byte
[]
data
)
{
{
//https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
//
https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
switch
(
value
)
switch
(
value
)
{
{
case
0
:
case
0
:
...
@@ -59,8 +59,8 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -59,8 +59,8 @@ namespace Titanium.Web.Proxy.StreamExtended
private
static
string
GetSupportedGroup
(
byte
[]
data
)
private
static
string
GetSupportedGroup
(
byte
[]
data
)
{
{
//https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1
//
https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1
List
<
string
>
list
=
new
List
<
string
>();
var
list
=
new
List
<
string
>();
if
(
data
.
Length
<
2
)
if
(
data
.
Length
<
2
)
{
{
return
string
.
Empty
;
return
string
.
Empty
;
...
@@ -73,70 +73,70 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -73,70 +73,70 @@ namespace Titanium.Web.Proxy.StreamExtended
switch
(
namedCurve
)
switch
(
namedCurve
)
{
{
case
1
:
case
1
:
list
.
Add
(
"sect163k1 [0x1]"
);
//deprecated
list
.
Add
(
"sect163k1 [0x1]"
);
//
deprecated
break
;
break
;
case
2
:
case
2
:
list
.
Add
(
"sect163r1 [0x2]"
);
//deprecated
list
.
Add
(
"sect163r1 [0x2]"
);
//
deprecated
break
;
break
;
case
3
:
case
3
:
list
.
Add
(
"sect163r2 [0x3]"
);
//deprecated
list
.
Add
(
"sect163r2 [0x3]"
);
//
deprecated
break
;
break
;
case
4
:
case
4
:
list
.
Add
(
"sect193r1 [0x4]"
);
//deprecated
list
.
Add
(
"sect193r1 [0x4]"
);
//
deprecated
break
;
break
;
case
5
:
case
5
:
list
.
Add
(
"sect193r2 [0x5]"
);
//deprecated
list
.
Add
(
"sect193r2 [0x5]"
);
//
deprecated
break
;
break
;
case
6
:
case
6
:
list
.
Add
(
"sect233k1 [0x6]"
);
//deprecated
list
.
Add
(
"sect233k1 [0x6]"
);
//
deprecated
break
;
break
;
case
7
:
case
7
:
list
.
Add
(
"sect233r1 [0x7]"
);
//deprecated
list
.
Add
(
"sect233r1 [0x7]"
);
//
deprecated
break
;
break
;
case
8
:
case
8
:
list
.
Add
(
"sect239k1 [0x8]"
);
//deprecated
list
.
Add
(
"sect239k1 [0x8]"
);
//
deprecated
break
;
break
;
case
9
:
case
9
:
list
.
Add
(
"sect283k1 [0x9]"
);
//deprecated
list
.
Add
(
"sect283k1 [0x9]"
);
//
deprecated
break
;
break
;
case
10
:
case
10
:
list
.
Add
(
"sect283r1 [0xA]"
);
//deprecated
list
.
Add
(
"sect283r1 [0xA]"
);
//
deprecated
break
;
break
;
case
11
:
case
11
:
list
.
Add
(
"sect409k1 [0xB]"
);
//deprecated
list
.
Add
(
"sect409k1 [0xB]"
);
//
deprecated
break
;
break
;
case
12
:
case
12
:
list
.
Add
(
"sect409r1 [0xC]"
);
//deprecated
list
.
Add
(
"sect409r1 [0xC]"
);
//
deprecated
break
;
break
;
case
13
:
case
13
:
list
.
Add
(
"sect571k1 [0xD]"
);
//deprecated
list
.
Add
(
"sect571k1 [0xD]"
);
//
deprecated
break
;
break
;
case
14
:
case
14
:
list
.
Add
(
"sect571r1 [0xE]"
);
//deprecated
list
.
Add
(
"sect571r1 [0xE]"
);
//
deprecated
break
;
break
;
case
15
:
case
15
:
list
.
Add
(
"secp160k1 [0xF]"
);
//deprecated
list
.
Add
(
"secp160k1 [0xF]"
);
//
deprecated
break
;
break
;
case
16
:
case
16
:
list
.
Add
(
"secp160r1 [0x10]"
);
//deprecated
list
.
Add
(
"secp160r1 [0x10]"
);
//
deprecated
break
;
break
;
case
17
:
case
17
:
list
.
Add
(
"secp160r2 [0x11]"
);
//deprecated
list
.
Add
(
"secp160r2 [0x11]"
);
//
deprecated
break
;
break
;
case
18
:
case
18
:
list
.
Add
(
"secp192k1 [0x12]"
);
//deprecated
list
.
Add
(
"secp192k1 [0x12]"
);
//
deprecated
break
;
break
;
case
19
:
case
19
:
list
.
Add
(
"secp192r1 [0x13]"
);
//deprecated
list
.
Add
(
"secp192r1 [0x13]"
);
//
deprecated
break
;
break
;
case
20
:
case
20
:
list
.
Add
(
"secp224k1 [0x14]"
);
//deprecated
list
.
Add
(
"secp224k1 [0x14]"
);
//
deprecated
break
;
break
;
case
21
:
case
21
:
list
.
Add
(
"secp224r1 [0x15]"
);
//deprecated
list
.
Add
(
"secp224r1 [0x15]"
);
//
deprecated
break
;
break
;
case
22
:
case
22
:
list
.
Add
(
"secp256k1 [0x16]"
);
//deprecated
list
.
Add
(
"secp256k1 [0x16]"
);
//
deprecated
break
;
break
;
case
23
:
case
23
:
list
.
Add
(
"secp256r1 [0x17]"
);
list
.
Add
(
"secp256r1 [0x17]"
);
...
@@ -178,10 +178,10 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -178,10 +178,10 @@ namespace Titanium.Web.Proxy.StreamExtended
list
.
Add
(
"ffdhe8192 [0x0104]"
);
list
.
Add
(
"ffdhe8192 [0x0104]"
);
break
;
break
;
case
65281
:
case
65281
:
list
.
Add
(
"arbitrary_explicit_prime_curves [0xFF01]"
);
//deprecated
list
.
Add
(
"arbitrary_explicit_prime_curves [0xFF01]"
);
//
deprecated
break
;
break
;
case
65282
:
case
65282
:
list
.
Add
(
"arbitrary_explicit_char2_curves [0xFF02]"
);
//deprecated
list
.
Add
(
"arbitrary_explicit_char2_curves [0xFF02]"
);
//
deprecated
break
;
break
;
default
:
default
:
list
.
Add
(
$"unknown [0x
{
namedCurve
:
X4
}
]"
);
list
.
Add
(
$"unknown [0x
{
namedCurve
:
X4
}
]"
);
...
@@ -318,7 +318,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -318,7 +318,7 @@ namespace Titanium.Web.Proxy.StreamExtended
private
static
string
GetExtensionName
(
int
value
)
private
static
string
GetExtensionName
(
int
value
)
{
{
//https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
//
https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
switch
(
value
)
switch
(
value
)
{
{
case
0
:
case
0
:
...
...
src/Titanium.Web.Proxy/StreamExtended/SslTools.cs
View file @
2eed8cb0
...
@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <returns></returns>
/// <returns></returns>
public
static
async
Task
<
ClientHelloInfo
>
PeekClientHello
(
CustomBufferedStream
clientStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
public
static
async
Task
<
ClientHelloInfo
>
PeekClientHello
(
CustomBufferedStream
clientStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
//detects the HTTPS ClientHello message as it is described in the following url:
//
detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//
https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
int
recordType
=
await
clientStream
.
PeekByteAsync
(
0
,
cancellationToken
);
int
recordType
=
await
clientStream
.
PeekByteAsync
(
0
,
cancellationToken
);
if
(
recordType
==
-
1
)
if
(
recordType
==
-
1
)
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if
((
recordType
&
0x80
)
==
0x80
)
if
((
recordType
&
0x80
)
==
0x80
)
{
{
//SSL 2
//
SSL 2
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
bufferPool
,
1
);
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
bufferPool
,
1
);
// length value + minimum length
// length value + minimum length
...
@@ -105,14 +105,14 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -105,14 +105,14 @@ namespace Titanium.Web.Proxy.StreamExtended
{
{
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
bufferPool
,
1
);
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
bufferPool
,
1
);
//should contain at least 43 bytes
//
should contain at least 43 bytes
// 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length
// 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
{
{
return
null
;
return
null
;
}
}
//SSL 3.0 or TLS 1.0, 1.1 and 1.2
//
SSL 3.0 or TLS 1.0, 1.1 and 1.2
int
majorVersion
=
peekStream
.
ReadByte
();
int
majorVersion
=
peekStream
.
ReadByte
();
int
minorVersion
=
peekStream
.
ReadByte
();
int
minorVersion
=
peekStream
.
ReadByte
();
...
@@ -220,8 +220,8 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -220,8 +220,8 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <returns></returns>
/// <returns></returns>
public
static
async
Task
<
ServerHelloInfo
>
PeekServerHello
(
CustomBufferedStream
serverStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
public
static
async
Task
<
ServerHelloInfo
>
PeekServerHello
(
CustomBufferedStream
serverStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
//detects the HTTPS ClientHello message as it is described in the following url:
//
detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//
https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
int
recordType
=
await
serverStream
.
PeekByteAsync
(
0
,
cancellationToken
);
int
recordType
=
await
serverStream
.
PeekByteAsync
(
0
,
cancellationToken
);
if
(
recordType
==
-
1
)
if
(
recordType
==
-
1
)
...
@@ -231,7 +231,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -231,7 +231,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if
((
recordType
&
0x80
)
==
0x80
)
if
((
recordType
&
0x80
)
==
0x80
)
{
{
//SSL 2
//
SSL 2
// not tested. SSL2 is deprecated
// not tested. SSL2 is deprecated
var
peekStream
=
new
CustomBufferedPeekStream
(
serverStream
,
bufferPool
,
1
);
var
peekStream
=
new
CustomBufferedPeekStream
(
serverStream
,
bufferPool
,
1
);
...
@@ -284,14 +284,14 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -284,14 +284,14 @@ namespace Titanium.Web.Proxy.StreamExtended
{
{
var
peekStream
=
new
CustomBufferedPeekStream
(
serverStream
,
bufferPool
,
1
);
var
peekStream
=
new
CustomBufferedPeekStream
(
serverStream
,
bufferPool
,
1
);
//should contain at least 43 bytes
//
should contain at least 43 bytes
// 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length
// 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
{
{
return
null
;
return
null
;
}
}
//SSL 3.0 or TLS 1.0, 1.1 and 1.2
//
SSL 3.0 or TLS 1.0, 1.1 and 1.2
int
majorVersion
=
peekStream
.
ReadByte
();
int
majorVersion
=
peekStream
.
ReadByte
();
int
minorVersion
=
peekStream
.
ReadByte
();
int
minorVersion
=
peekStream
.
ReadByte
();
...
...
tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
View file @
2eed8cb0
...
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
...
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.IntegrationTests.Setup
namespace
Titanium.Web.Proxy.IntegrationTests.Setup
{
{
//set up a kestrel test server
//
set up a kestrel test server
public
class
TestServer
:
IDisposable
public
class
TestServer
:
IDisposable
{
{
public
string
ListeningHttpUrl
=>
$"http://localhost:
{
HttpListeningPort
}
"
;
public
string
ListeningHttpUrl
=>
$"http://localhost:
{
HttpListeningPort
}
"
;
...
...
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