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
Supports
*
.Net Standard 2.0 or above
*
.Net Framework 4.
5
or above
*
.Net Framework 4.
6.1
or above
### Development environment
...
...
@@ -55,11 +55,11 @@ Setup HTTP proxy:
```
csharp
var
proxyServer
=
new
ProxyServer
();
//locally trust root certificate used by this proxy
//
locally trust root certificate used by this proxy
proxyServer
.
CertificateManager
.
TrustRootCertificate
=
true
;
//optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported
//
optionally set the Certificate Engine
//
Under Mono only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
proxyServer
.
BeforeRequest
+=
OnRequest
;
...
...
@@ -70,28 +70,28 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
{
//
Use self-issued generic certificate on all https requests
//
Optimizes performance by not creating a certificate for each https-enabled domain
//
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")
//
Use self-issued generic certificate on all https requests
//
Optimizes performance by not creating a certificate for each https-enabled domain
//
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")
};
//Fired when a CONNECT request is received
//
Fired when a CONNECT request is received
explicitEndPoint
.
BeforeTunnelConnect
+=
OnBeforeTunnelConnect
;
//An explicit endpoint is where the client knows about the existence of a proxy
//So client sends request in a proxy friendly manner
//
An explicit endpoint is where the client knows about the existence of a proxy
//
So client sends request in a proxy friendly manner
proxyServer
.
AddEndPoint
(
explicitEndPoint
);
proxyServer
.
Start
();
//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
//to send data to this endPoint
//
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
//
to send data to this endPoint
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Any
,
8001
,
true
)
{
//
Generic Certificate hostname to use
//
when SNI is disabled by client
GenericCertificateName
=
"google.com"
//
Generic Certificate hostname to use
//
when SNI is disabled by client
GenericCertificateName
=
"google.com"
};
proxyServer
.
AddEndPoint
(
transparentEndPoint
);
...
...
@@ -103,14 +103,14 @@ foreach (var endPoint in proxyServer.ProxyEndPoints)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
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
.
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
();
//Unsubscribe & Quit
//
Unsubscribe & Quit
explicitEndPoint
.
BeforeTunnelConnect
-=
OnBeforeTunnelConnect
;
proxyServer
.
BeforeRequest
-=
OnRequest
;
proxyServer
.
BeforeResponse
-=
OnResponse
;
...
...
@@ -118,11 +118,11 @@ proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
proxyServer
.
ClientCertificateSelectionCallback
-=
OnCertificateSelection
;
proxyServer
.
Stop
();
```
Sample request and response event handlers
```
csharp
```
csharp
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
{
...
...
@@ -130,9 +130,9 @@ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSess
if
(
hostname
.
Contains
(
"dropbox.com"
))
{
//Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning
//for example dropbox.com
//
Exclude Https addresses you don't want to proxy
//
Useful for clients that use certificate pinning
//
for example dropbox.com
e
.
DecryptSsl
=
false
;
}
}
...
...
@@ -141,88 +141,88 @@ public async Task OnRequest(object sender, SessionEventArgs e)
{
Console
.
WriteLine
(
e
.
HttpClient
.
Request
.
Url
);
//
//
read request headers
//
read request headers
var
requestHeaders
=
e
.
HttpClient
.
Request
.
RequestHeaders
;
var
method
=
e
.
HttpClient
.
Request
.
Method
.
ToUpper
();
if
((
method
==
"POST"
||
method
==
"PUT"
||
method
==
"PATCH"
))
{
//
Get/Set request body bytes
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
await
e
.
SetRequestBody
(
bodyBytes
);
//
Get/Set request body as string
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
await
e
.
SetRequestBodyString
(
bodyString
);
//
store request
//
so that you can find it from response handler
e
.
UserData
=
e
.
HttpClient
.
Request
;
//
Get/Set request body bytes
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
await
e
.
SetRequestBody
(
bodyBytes
);
//
Get/Set request body as string
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
await
e
.
SetRequestBodyString
(
bodyString
);
//
store request
//
so that you can find it from response handler
e
.
UserData
=
e
.
HttpClient
.
Request
;
}
//To cancel a request with a custom HTML content
//Filter URL
//
To cancel a request with a custom HTML content
//
Filter URL
if
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
}
//Redirect example
// Redirect example
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
)
{
//read response headers
//
read response headers
var
responseHeaders
=
e
.
HttpClient
.
Response
.
ResponseHeaders
;
//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
.
Response
.
ResponseStatusCode
==
"200"
)
{
if
(
e
.
HttpClient
.
Response
.
ContentType
!=
null
&&
e
.
HttpClient
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
await
e
.
SetResponseBody
(
bodyBytes
);
string
body
=
await
e
.
GetResponseBodyAsString
();
await
e
.
SetResponseBodyString
(
body
);
}
}
if
(
e
.
HttpClient
.
Response
.
ResponseStatusCode
==
"200"
)
{
if
(
e
.
HttpClient
.
Response
.
ContentType
!=
null
&&
e
.
HttpClient
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
await
e
.
SetResponseBody
(
bodyBytes
);
string
body
=
await
e
.
GetResponseBodyAsString
();
await
e
.
SetResponseBodyString
(
body
);
}
}
}
if
(
e
.
UserData
!=
null
)
if
(
e
.
UserData
!=
null
)
{
//
access request from UserData property where we stored it in RequestHandler
var
request
=
(
Request
)
e
.
UserData
;
//
access request from UserData property where we stored it in RequestHandler
var
request
=
(
Request
)
e
.
UserData
;
}
}
//
/
Allows overriding default certificate validation logic
// Allows overriding default certificate validation logic
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
)
e
.
IsValid
=
true
;
e
.
IsValid
=
true
;
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
)
{
//set e.clientCertificate to override
//
set e.clientCertificate to override
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
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;
//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
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
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
)
{
//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
)
{
throw
new
Exception
(
"You cannot call this function after response is sent to the client."
);
}
//cleanup original response.
//
cleanup original response.
if
(
closeServerConnection
)
{
//no need to cleanup original connection.
//it will be closed any way.
//
no need to cleanup original connection.
//
it will be closed any way.
TerminateServerConnection
();
}
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
.
Locked
=
true
;
}
//request not yet sent/not yet ready to be sent.
//
request not yet sent/not yet ready to be sent.
else
{
HttpClient
.
Request
.
Locked
=
true
;
HttpClient
.
Request
.
CancelRequest
=
true
;
//set new response.
//
set new response.
HttpClient
.
Response
=
response
;
HttpClient
.
Response
.
Locked
=
true
;
}
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
2eed8cb0
...
...
@@ -152,7 +152,8 @@ namespace Titanium.Web.Proxy
http2Supported
=
connection
.
NegotiatedApplicationProtocol
==
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
);
}
catch
(
Exception
)
...
...
src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
2eed8cb0
...
...
@@ -50,11 +50,11 @@ namespace Titanium.Web.Proxy.Extensions
socket
.
Blocking
=
false
;
socket
.
Send
(
tmp
,
0
,
0
);
//Connected.
//
Connected.
}
catch
{
//Should we let 10035 == WSAEWOULDBLOCK as valid connection?
//
Should we let 10035 == WSAEWOULDBLOCK as valid connection?
return
false
;
}
finally
...
...
src/Titanium.Web.Proxy/Helpers/Network.cs
View file @
2eed8cb0
...
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers
return
true
;
}
//if hostname matches local host name
//
if hostname matches local host name
if
(
hostName
.
Equals
(
localhostName
,
StringComparison
.
OrdinalIgnoreCase
))
{
return
true
;
...
...
src/Titanium.Web.Proxy/Helpers/RunTime.cs
View file @
2eed8cb0
...
...
@@ -42,7 +42,7 @@ namespace Titanium.Web.Proxy.Helpers
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
{
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
{
try
{
//setup connection
//
setup connection
currentConnection
=
currentConnection
as
TcpServerConnection
??
await
generator
();
//try
//
try
@continue
=
await
action
(
currentConnection
);
}
...
...
@@ -65,12 +65,12 @@ namespace Titanium.Web.Proxy.Network
return
new
RetryResult
(
currentConnection
,
exception
,
@continue
);
}
//before retry clear connection
//
before retry clear connection
private
async
Task
disposeConnection
()
{
if
(
currentConnection
!=
null
)
{
//close connection on error
//
close connection on error
await
tcpConnectionFactory
.
Release
(
currentConnection
,
true
);
currentConnection
=
null
;
}
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs
View file @
2eed8cb0
...
...
@@ -82,9 +82,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
Task
.
Run
(
async
()
=>
{
//delay calling tcp connection close()
//so that client have enough time to call close first.
//This way we can push tcp Time_Wait to client side when possible.
//
delay calling tcp connection close()
//
so that client have enough time to call close first.
//
This way we can push tcp Time_Wait to client side when possible.
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateClientConnectionCount
(
false
);
tcpClient
.
CloseSocket
();
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
2eed8cb0
...
...
@@ -25,15 +25,15 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal
class
TcpConnectionFactory
:
IDisposable
{
//Tcp server connection pool cache
//
Tcp server connection pool cache
private
readonly
ConcurrentDictionary
<
string
,
ConcurrentQueue
<
TcpServerConnection
>>
cache
=
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
=
new
ConcurrentBag
<
TcpServerConnection
>();
//cache object race operations lock
//
cache object race operations lock
private
readonly
SemaphoreSlim
@lock
=
new
SemaphoreSlim
(
1
);
private
volatile
bool
runCleanUpTask
=
true
;
...
...
@@ -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.
// http version 2 is separated using applicationProtocols below.
var
cacheKeyBuilder
=
new
StringBuilder
(
$"
{
remoteHostName
}
-
{
remotePort
}
-"
+
//when creating Tcp client isConnect won't matter
//
when creating Tcp client isConnect won't matter
$"
{
isHttps
}
-"
);
if
(
applicationProtocols
!=
null
)
{
...
...
@@ -238,7 +238,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
ProxyServer
proxyServer
,
SessionEventArgsBase
session
,
IPEndPoint
upStreamEndPoint
,
ExternalProxy
externalProxy
,
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
)
&&
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
))
{
...
...
@@ -288,7 +288,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
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
)
{
tcpClient
.
Client
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
...
...
@@ -550,7 +550,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
finally
{
//cleanup every 3 seconds by default
//
cleanup every 3 seconds by default
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
{
Task
.
Run
(
async
()
=>
{
//delay calling tcp connection close()
//so that server have enough time to call close first.
//This way we can push tcp Time_Wait to server side when possible.
//
delay calling tcp connection close()
//
so that server have enough time to call close first.
//
This way we can push tcp Time_Wait to server side when possible.
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateServerConnectionCount
(
false
);
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
// int cbBuffer;
// int BufferType;
// 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...
int
currentOffset
=
index
*
Marshal
.
SizeOf
(
typeof
(
Buffer
));
var
secBufferpvBuffer
=
Marshal
.
ReadIntPtr
(
pBuffers
,
...
...
src/Titanium.Web.Proxy/ProxyServer.cs
View file @
2eed8cb0
...
...
@@ -122,7 +122,9 @@ namespace Titanium.Web.Proxy
/// </summary>
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
;
/// <summary>
...
...
@@ -660,7 +662,7 @@ namespace Titanium.Web.Proxy
{
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
)
{
endPoint
.
Listener
.
Server
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
...
...
@@ -871,13 +873,13 @@ namespace Titanium.Web.Proxy
/// <returns></returns>
internal
async
Task
InvokeConnectionCreateEvent
(
TcpClient
client
,
bool
isClientConnection
)
{
//client connection created
//
client connection created
if
(
isClientConnection
&&
OnClientConnectionCreate
!=
null
)
{
await
OnClientConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
}
//server connection created
//
server connection created
if
(!
isClientConnection
&&
OnServerConnectionCreate
!=
null
)
{
await
OnServerConnectionCreate
.
InvokeAsync
(
this
,
client
,
ExceptionFunc
);
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
2eed8cb0
...
...
@@ -163,7 +163,7 @@ namespace Titanium.Web.Proxy
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
();
args
.
TimeLine
[
"Request Received"
]
=
DateTime
.
Now
;
...
...
@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy
continue
;
}
//If prefetch task is available.
//
If prefetch task is available.
if
(
connection
==
null
&&
prefetchTask
!=
null
)
{
try
...
...
@@ -226,11 +226,11 @@ namespace Titanium.Web.Proxy
clientConnection
.
NegotiatedApplicationProtocol
,
cancellationToken
,
cancellationTokenSource
);
//update connection to latest used
//
update connection to latest used
connection
=
result
.
LatestConnection
;
closeServerConnection
=
!
result
.
Continue
;
//throw if exception happened
//
throw if exception happened
if
(!
result
.
IsSuccess
)
{
throw
result
.
Exception
;
...
...
@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy
return
;
}
//user requested
//
user requested
if
(
args
.
HttpClient
.
CloseServerConnection
)
{
closeServerConnection
=
true
;
...
...
@@ -304,13 +304,13 @@ namespace Titanium.Web.Proxy
TcpServerConnection
serverConnection
,
SslApplicationProtocol
sslApplicationProtocol
,
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
=
()
=>
tcpConnectionFactory
.
GetServerConnection
(
this
,
args
,
isConnect
:
false
,
applicationProtocol
:
sslApplicationProtocol
,
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
)
=>
{
args
.
TimeLine
[
"Connection Ready"
]
=
DateTime
.
Now
;
...
...
@@ -390,12 +390,12 @@ namespace Titanium.Web.Proxy
{
var
supportedAcceptEncoding
=
new
List
<
string
>();
//only allow proxy supported compressions
//
only allow proxy supported compressions
supportedAcceptEncoding
.
AddRange
(
acceptEncoding
.
Split
(
','
)
.
Select
(
x
=>
x
.
Trim
())
.
Where
(
x
=>
ProxyConstants
.
ProxySupportedCompressions
.
Contains
(
x
)));
//uncompressed is always supported by proxy
//
uncompressed is always supported by proxy
supportedAcceptEncoding
.
Add
(
"identity"
);
requestHeaders
.
SetOrAddHeaderValue
(
KnownHeaders
.
AcceptEncoding
,
...
...
src/Titanium.Web.Proxy/ResponseHandler.cs
View file @
2eed8cb0
...
...
@@ -51,8 +51,8 @@ namespace Titanium.Web.Proxy
}
}
//save original values so that if user changes them
//we can still use original values when syphoning out data from attached tcp connection.
//
save original values so that if user changes them
//
we can still use original values when syphoning out data from attached tcp connection.
response
.
SetOriginalHeaders
();
// if user requested call back then do it
...
...
@@ -66,10 +66,10 @@ namespace Titanium.Web.Proxy
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
)
{
//write custom user response with body and return.
//
write custom user response with body and return.
await
clientStreamWriter
.
WriteResponseAsync
(
response
,
cancellationToken
:
cancellationToken
);
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
public
void
Flush
()
{
//send out the current data from from the buffer
//
send out the current data from from the buffer
if
(
bufferLength
>
0
)
{
writer
.
Write
(
buffer
,
0
,
bufferLength
);
...
...
@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
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
)
{
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
await
FillBufferAsync
(
cancellationToken
);
}
//When index is greater than the buffer size
//
When index is greater than the buffer size
if
(
streamBuffer
.
Length
<=
index
)
{
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
)
{
return
-
1
;
...
...
@@ -287,7 +287,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
await
FillBufferAsync
(
cancellationToken
);
}
//When index is greater than the buffer size
//
When index is greater than the buffer size
if
(
streamBuffer
.
Length
<=
(
index
+
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
if
(
bufferLength
>
0
)
{
//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
//
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
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
}
...
...
@@ -521,8 +521,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
if
(
bufferLength
>
0
)
{
//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
//
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
Buffer
.
BlockCopy
(
streamBuffer
,
bufferPos
,
streamBuffer
,
0
,
bufferLength
);
}
...
...
@@ -586,7 +586,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
byte
newChar
=
reader
.
ReadByteFromBuffer
();
buffer
[
bufferDataLength
]
=
newChar
;
//if new line
//
if new line
if
(
newChar
==
'\n'
)
{
if
(
lastChar
==
'\r'
)
...
...
@@ -599,7 +599,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
bufferDataLength
++;
//store last char for new line comparison
//
store last char for new line comparison
lastChar
=
newChar
;
if
(
bufferDataLength
==
buffer
.
Length
)
...
...
@@ -663,8 +663,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
vAsyncResult
.
ContinueWith
(
pAsyncResult
=>
{
//use TaskExtended to pass State as AsyncObject
//callback will call EndRead (otherwise, it will block)
//
use TaskExtended to pass State as AsyncObject
//
callback will call EndRead (otherwise, it will block)
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
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
)
{
case
0
:
...
...
@@ -59,8 +59,8 @@ namespace Titanium.Web.Proxy.StreamExtended
private
static
string
GetSupportedGroup
(
byte
[]
data
)
{
//https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1
List
<
string
>
list
=
new
List
<
string
>();
//
https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1
var
list
=
new
List
<
string
>();
if
(
data
.
Length
<
2
)
{
return
string
.
Empty
;
...
...
@@ -73,70 +73,70 @@ namespace Titanium.Web.Proxy.StreamExtended
switch
(
namedCurve
)
{
case
1
:
list
.
Add
(
"sect163k1 [0x1]"
);
//deprecated
list
.
Add
(
"sect163k1 [0x1]"
);
//
deprecated
break
;
case
2
:
list
.
Add
(
"sect163r1 [0x2]"
);
//deprecated
list
.
Add
(
"sect163r1 [0x2]"
);
//
deprecated
break
;
case
3
:
list
.
Add
(
"sect163r2 [0x3]"
);
//deprecated
list
.
Add
(
"sect163r2 [0x3]"
);
//
deprecated
break
;
case
4
:
list
.
Add
(
"sect193r1 [0x4]"
);
//deprecated
list
.
Add
(
"sect193r1 [0x4]"
);
//
deprecated
break
;
case
5
:
list
.
Add
(
"sect193r2 [0x5]"
);
//deprecated
list
.
Add
(
"sect193r2 [0x5]"
);
//
deprecated
break
;
case
6
:
list
.
Add
(
"sect233k1 [0x6]"
);
//deprecated
list
.
Add
(
"sect233k1 [0x6]"
);
//
deprecated
break
;
case
7
:
list
.
Add
(
"sect233r1 [0x7]"
);
//deprecated
list
.
Add
(
"sect233r1 [0x7]"
);
//
deprecated
break
;
case
8
:
list
.
Add
(
"sect239k1 [0x8]"
);
//deprecated
list
.
Add
(
"sect239k1 [0x8]"
);
//
deprecated
break
;
case
9
:
list
.
Add
(
"sect283k1 [0x9]"
);
//deprecated
list
.
Add
(
"sect283k1 [0x9]"
);
//
deprecated
break
;
case
10
:
list
.
Add
(
"sect283r1 [0xA]"
);
//deprecated
list
.
Add
(
"sect283r1 [0xA]"
);
//
deprecated
break
;
case
11
:
list
.
Add
(
"sect409k1 [0xB]"
);
//deprecated
list
.
Add
(
"sect409k1 [0xB]"
);
//
deprecated
break
;
case
12
:
list
.
Add
(
"sect409r1 [0xC]"
);
//deprecated
list
.
Add
(
"sect409r1 [0xC]"
);
//
deprecated
break
;
case
13
:
list
.
Add
(
"sect571k1 [0xD]"
);
//deprecated
list
.
Add
(
"sect571k1 [0xD]"
);
//
deprecated
break
;
case
14
:
list
.
Add
(
"sect571r1 [0xE]"
);
//deprecated
list
.
Add
(
"sect571r1 [0xE]"
);
//
deprecated
break
;
case
15
:
list
.
Add
(
"secp160k1 [0xF]"
);
//deprecated
list
.
Add
(
"secp160k1 [0xF]"
);
//
deprecated
break
;
case
16
:
list
.
Add
(
"secp160r1 [0x10]"
);
//deprecated
list
.
Add
(
"secp160r1 [0x10]"
);
//
deprecated
break
;
case
17
:
list
.
Add
(
"secp160r2 [0x11]"
);
//deprecated
list
.
Add
(
"secp160r2 [0x11]"
);
//
deprecated
break
;
case
18
:
list
.
Add
(
"secp192k1 [0x12]"
);
//deprecated
list
.
Add
(
"secp192k1 [0x12]"
);
//
deprecated
break
;
case
19
:
list
.
Add
(
"secp192r1 [0x13]"
);
//deprecated
list
.
Add
(
"secp192r1 [0x13]"
);
//
deprecated
break
;
case
20
:
list
.
Add
(
"secp224k1 [0x14]"
);
//deprecated
list
.
Add
(
"secp224k1 [0x14]"
);
//
deprecated
break
;
case
21
:
list
.
Add
(
"secp224r1 [0x15]"
);
//deprecated
list
.
Add
(
"secp224r1 [0x15]"
);
//
deprecated
break
;
case
22
:
list
.
Add
(
"secp256k1 [0x16]"
);
//deprecated
list
.
Add
(
"secp256k1 [0x16]"
);
//
deprecated
break
;
case
23
:
list
.
Add
(
"secp256r1 [0x17]"
);
...
...
@@ -178,10 +178,10 @@ namespace Titanium.Web.Proxy.StreamExtended
list
.
Add
(
"ffdhe8192 [0x0104]"
);
break
;
case
65281
:
list
.
Add
(
"arbitrary_explicit_prime_curves [0xFF01]"
);
//deprecated
list
.
Add
(
"arbitrary_explicit_prime_curves [0xFF01]"
);
//
deprecated
break
;
case
65282
:
list
.
Add
(
"arbitrary_explicit_char2_curves [0xFF02]"
);
//deprecated
list
.
Add
(
"arbitrary_explicit_char2_curves [0xFF02]"
);
//
deprecated
break
;
default
:
list
.
Add
(
$"unknown [0x
{
namedCurve
:
X4
}
]"
);
...
...
@@ -318,7 +318,7 @@ namespace Titanium.Web.Proxy.StreamExtended
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
)
{
case
0
:
...
...
src/Titanium.Web.Proxy/StreamExtended/SslTools.cs
View file @
2eed8cb0
...
...
@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <returns></returns>
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:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//
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
int
recordType
=
await
clientStream
.
PeekByteAsync
(
0
,
cancellationToken
);
if
(
recordType
==
-
1
)
...
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if
((
recordType
&
0x80
)
==
0x80
)
{
//SSL 2
//
SSL 2
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
bufferPool
,
1
);
// length value + minimum length
...
...
@@ -105,14 +105,14 @@ namespace Titanium.Web.Proxy.StreamExtended
{
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
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
{
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
minorVersion
=
peekStream
.
ReadByte
();
...
...
@@ -220,8 +220,8 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <returns></returns>
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:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//
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
int
recordType
=
await
serverStream
.
PeekByteAsync
(
0
,
cancellationToken
);
if
(
recordType
==
-
1
)
...
...
@@ -231,7 +231,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if
((
recordType
&
0x80
)
==
0x80
)
{
//SSL 2
//
SSL 2
// not tested. SSL2 is deprecated
var
peekStream
=
new
CustomBufferedPeekStream
(
serverStream
,
bufferPool
,
1
);
...
...
@@ -284,14 +284,14 @@ namespace Titanium.Web.Proxy.StreamExtended
{
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
if
(!
await
peekStream
.
EnsureBufferLength
(
43
,
cancellationToken
))
{
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
minorVersion
=
peekStream
.
ReadByte
();
...
...
tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
View file @
2eed8cb0
...
...
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy.IntegrationTests.Setup
{
//set up a kestrel test server
//
set up a kestrel test server
public
class
TestServer
:
IDisposable
{
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