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
045ec22f
Commit
045ec22f
authored
Dec 10, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NetworkStream read cancellation hack
parent
51abd031
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
79 additions
and
44 deletions
+79
-44
EmptyProxyEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs
+12
-0
SessionEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+1
-1
ExplicitClientHandler.cs
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+10
-5
StreamExtensions.cs
src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+3
-3
HttpClientStream.cs
src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs
+2
-2
HttpServerStream.cs
src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs
+2
-2
HttpStream.cs
src/Titanium.Web.Proxy/Helpers/HttpStream.cs
+41
-22
TcpConnectionFactory.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+2
-2
RequestHandler.cs
src/Titanium.Web.Proxy/RequestHandler.cs
+1
-1
TransparentClientHandler.cs
src/Titanium.Web.Proxy/TransparentClientHandler.cs
+5
-6
No files found.
src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs
0 → 100644
View file @
045ec22f
using
System
;
using
Titanium.Web.Proxy.Network.Tcp
;
namespace
Titanium.Web.Proxy.EventArguments
{
public
class
EmptyProxyEventArgs
:
ProxyEventArgsBase
{
internal
EmptyProxyEventArgs
(
TcpClientConnection
clientConnection
)
:
base
(
clientConnection
)
{
}
}
}
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
045ec22f
...
...
@@ -190,7 +190,7 @@ namespace Titanium.Web.Proxy.EventArguments
private
async
Task
<
byte
[
]>
readBodyAsync
(
bool
isRequest
,
CancellationToken
cancellationToken
)
{
using
var
bodyStream
=
new
MemoryStream
();
using
var
writer
=
new
HttpStream
(
bodyStream
,
BufferPool
);
using
var
writer
=
new
HttpStream
(
bodyStream
,
BufferPool
,
cancellationToken
);
if
(
isRequest
)
{
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
045ec22f
...
...
@@ -33,14 +33,12 @@ namespace Titanium.Web.Proxy
var
cancellationTokenSource
=
new
CancellationTokenSource
();
var
cancellationToken
=
cancellationTokenSource
.
Token
;
var
clientStream
=
new
HttpClientStream
(
clientConnection
,
clientConnection
.
GetStream
(),
BufferPool
);
var
clientStream
=
new
HttpClientStream
(
clientConnection
,
clientConnection
.
GetStream
(),
BufferPool
,
cancellationToken
);
Task
<
TcpServerConnection
>?
prefetchConnectionTask
=
null
;
bool
closeServerConnection
=
false
;
bool
calledRequestHandler
=
false
;
SslStream
?
sslStream
=
null
;
try
{
TunnelConnectSessionEventArgs
?
connectArgs
=
null
;
...
...
@@ -191,6 +189,7 @@ namespace Titanium.Web.Proxy
}
X509Certificate2
?
certificate
=
null
;
SslStream
?
sslStream
=
null
;
try
{
sslStream
=
new
SslStream
(
clientStream
,
false
);
...
...
@@ -221,7 +220,7 @@ namespace Titanium.Web.Proxy
#endif
// HTTPS server created - we can now decrypt the client's traffic
clientStream
=
new
HttpClientStream
(
clientStream
.
Connection
,
sslStream
,
BufferPool
);
clientStream
=
new
HttpClientStream
(
clientStream
.
Connection
,
sslStream
,
BufferPool
,
cancellationToken
);
sslStream
=
null
;
// clientStream was created, no need to keep SSL stream reference
clientStream
.
DataRead
+=
(
o
,
args
)
=>
connectArgs
.
OnDecryptedDataSent
(
args
.
Buffer
,
args
.
Offset
,
args
.
Count
);
...
...
@@ -229,6 +228,8 @@ namespace Titanium.Web.Proxy
}
catch
(
Exception
e
)
{
sslStream
?.
Dispose
();
var
certName
=
certificate
?.
GetNameInfo
(
X509NameType
.
SimpleName
,
false
);
throw
new
ProxyConnectException
(
$"Couldn't authenticate host '
{
connectHostname
}
' with certificate '
{
certName
}
'."
,
e
,
connectArgs
);
...
...
@@ -401,12 +402,16 @@ namespace Titanium.Web.Proxy
}
finally
{
if
(!
cancellationTokenSource
.
IsCancellationRequested
)
{
cancellationTokenSource
.
Cancel
();
}
if
(!
calledRequestHandler
)
{
await
tcpConnectionFactory
.
Release
(
prefetchConnectionTask
,
closeServerConnection
);
}
sslStream
?.
Dispose
();
clientStream
.
Dispose
();
}
}
...
...
src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
045ec22f
...
...
@@ -42,8 +42,8 @@ namespace Titanium.Web.Proxy.Extensions
{
// cancellation is not working on Socket ReadAsync
// https://github.com/dotnet/corefx/issues/15033
int
num
=
await
input
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
,
CancellationToken
.
None
)
.
w
ithCancellation
(
cancellationToken
);
int
num
=
await
input
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
,
cancellationToken
)
.
W
ithCancellation
(
cancellationToken
);
int
bytesRead
;
if
((
bytesRead
=
num
)
!=
0
&&
!
cancellationToken
.
IsCancellationRequested
)
{
...
...
@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy.Extensions
}
}
private
static
async
Task
<
T
>
w
ithCancellation
<
T
>(
this
Task
<
T
>
task
,
CancellationToken
cancellationToken
)
where
T
:
struct
internal
static
async
Task
<
T
>
W
ithCancellation
<
T
>(
this
Task
<
T
>
task
,
CancellationToken
cancellationToken
)
where
T
:
struct
{
var
tcs
=
new
TaskCompletionSource
<
bool
>();
using
(
cancellationToken
.
Register
(
s
=>
((
TaskCompletionSource
<
bool
>)
s
).
TrySetResult
(
true
),
tcs
))
...
...
src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs
View file @
045ec22f
...
...
@@ -12,8 +12,8 @@ namespace Titanium.Web.Proxy.Helpers
{
public
TcpClientConnection
Connection
{
get
;
}
internal
HttpClientStream
(
TcpClientConnection
connection
,
Stream
stream
,
IBufferPool
bufferPool
)
:
base
(
stream
,
bufferPool
)
internal
HttpClientStream
(
TcpClientConnection
connection
,
Stream
stream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
)
:
base
(
stream
,
bufferPool
,
cancellationToken
)
{
Connection
=
connection
;
}
...
...
src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs
View file @
045ec22f
...
...
@@ -10,8 +10,8 @@ namespace Titanium.Web.Proxy.Helpers
{
internal
sealed
class
HttpServerStream
:
HttpStream
{
internal
HttpServerStream
(
Stream
stream
,
IBufferPool
bufferPool
)
:
base
(
stream
,
bufferPool
)
internal
HttpServerStream
(
Stream
stream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
)
:
base
(
stream
,
bufferPool
,
cancellationToken
)
{
}
...
...
src/Titanium.Web.Proxy/Helpers/HttpStream.cs
View file @
045ec22f
...
...
@@ -9,6 +9,7 @@ using System.Threading;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Shared
;
...
...
@@ -19,7 +20,7 @@ namespace Titanium.Web.Proxy.Helpers
{
internal
class
HttpStream
:
Stream
,
IHttpStreamWriter
,
IHttpStreamReader
,
IPeekStream
{
private
readonly
bool
swallowException
;
private
readonly
bool
isNetworkStream
;
private
readonly
bool
leaveOpen
;
private
readonly
byte
[]
streamBuffer
;
...
...
@@ -37,6 +38,7 @@ namespace Titanium.Web.Proxy.Helpers
private
bool
closedRead
;
private
readonly
IBufferPool
bufferPool
;
private
readonly
CancellationToken
cancellationToken
;
public
event
EventHandler
<
DataEventArgs
>?
DataRead
;
...
...
@@ -71,18 +73,20 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="baseStream">The base stream.</param>
/// <param name="bufferPool">Bufferpool.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="T:CustomBufferedStream" /> object; otherwise, <see langword="false" />.</param>
internal
HttpStream
(
Stream
baseStream
,
IBufferPool
bufferPool
,
bool
leaveOpen
=
false
)
internal
HttpStream
(
Stream
baseStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
,
bool
leaveOpen
=
false
)
{
if
(
baseStream
is
NetworkStream
)
{
swallowException
=
true
;
isNetworkStream
=
true
;
}
this
.
baseStream
=
baseStream
;
this
.
leaveOpen
=
leaveOpen
;
streamBuffer
=
bufferPool
.
GetBuffer
();
this
.
bufferPool
=
bufferPool
;
this
.
cancellationToken
=
cancellationToken
;
}
/// <summary>
...
...
@@ -102,7 +106,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -181,7 +185,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -228,7 +232,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -450,7 +454,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -476,7 +480,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
finally
...
...
@@ -609,7 +613,7 @@ namespace Titanium.Web.Proxy.Helpers
}
catch
{
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
finally
...
...
@@ -655,7 +659,13 @@ namespace Titanium.Web.Proxy.Helpers
bool
result
=
false
;
try
{
int
readBytes
=
await
baseStream
.
ReadAsync
(
streamBuffer
,
bufferLength
,
bytesToRead
,
cancellationToken
);
var
readTask
=
baseStream
.
ReadAsync
(
streamBuffer
,
bufferLength
,
bytesToRead
,
cancellationToken
);
if
(
isNetworkStream
)
{
readTask
=
readTask
.
WithCancellation
(
cancellationToken
);
}
int
readBytes
=
await
readTask
;
result
=
readBytes
>
0
;
if
(
result
)
{
...
...
@@ -663,9 +673,14 @@ namespace Titanium.Web.Proxy.Helpers
bufferLength
+=
readBytes
;
}
}
catch
(
ObjectDisposedException
)
{
if
(!
isNetworkStream
)
throw
;
}
catch
{
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
finally
...
...
@@ -771,14 +786,18 @@ namespace Titanium.Web.Proxy.Helpers
return
base
.
BeginRead
(
buffer
,
offset
,
count
,
callback
,
state
);
}
var
vAsyncResult
=
this
.
ReadAsync
(
buffer
,
offset
,
count
);
var
vAsyncResult
=
this
.
ReadAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
if
(
isNetworkStream
)
{
vAsyncResult
=
vAsyncResult
.
WithCancellation
(
cancellationToken
);
}
vAsyncResult
.
ContinueWith
(
pAsyncResult
=>
{
// use TaskExtended to pass State as AsyncObject
// callback will call EndRead (otherwise, it will block)
callback
?.
Invoke
(
new
TaskResult
<
int
>(
pAsyncResult
,
state
));
});
}
,
cancellationToken
);
return
vAsyncResult
;
}
...
...
@@ -811,12 +830,12 @@ namespace Titanium.Web.Proxy.Helpers
return
base
.
BeginWrite
(
buffer
,
offset
,
count
,
callback
,
state
);
}
var
vAsyncResult
=
this
.
WriteAsync
(
buffer
,
offset
,
count
);
var
vAsyncResult
=
this
.
WriteAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
vAsyncResult
.
ContinueWith
(
pAsyncResult
=>
{
callback
?.
Invoke
(
new
TaskResult
(
pAsyncResult
,
state
));
});
}
,
cancellationToken
);
return
vAsyncResult
;
}
...
...
@@ -868,7 +887,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
finally
...
...
@@ -893,7 +912,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -940,7 +959,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -964,7 +983,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -1011,7 +1030,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
var
http
=
new
HttpStream
(
s
,
bufferPool
,
true
);
var
http
=
new
HttpStream
(
s
,
bufferPool
,
cancellationToken
,
true
);
await
http
.
CopyBodyAsync
(
writer
,
false
,
-
1
,
onCopy
,
cancellationToken
);
}
finally
...
...
@@ -1196,7 +1215,7 @@ namespace Titanium.Web.Proxy.Helpers
catch
{
closedWrite
=
true
;
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
@@ -1217,7 +1236,7 @@ namespace Titanium.Web.Proxy.Helpers
}
catch
{
if
(!
swallowException
)
if
(!
isNetworkStream
)
throw
;
}
}
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
045ec22f
...
...
@@ -445,7 +445,7 @@ retry:
await
proxyServer
.
InvokeServerConnectionCreateEvent
(
tcpClient
);
stream
=
new
HttpServerStream
(
tcpClient
.
GetStream
(),
proxyServer
.
BufferPool
);
stream
=
new
HttpServerStream
(
tcpClient
.
GetStream
(),
proxyServer
.
BufferPool
,
cancellationToken
);
if
(
externalProxy
!=
null
&&
(
isConnect
||
isHttps
))
{
...
...
@@ -487,7 +487,7 @@ retry:
(
sender
,
targetHost
,
localCertificates
,
remoteCertificate
,
acceptableIssuers
)
=>
proxyServer
.
SelectClientCertificate
(
sender
,
sessionArgs
,
targetHost
,
localCertificates
,
remoteCertificate
,
acceptableIssuers
));
stream
=
new
HttpServerStream
(
sslStream
,
proxyServer
.
BufferPool
);
stream
=
new
HttpServerStream
(
sslStream
,
proxyServer
.
BufferPool
,
cancellationToken
);
var
options
=
new
SslClientAuthenticationOptions
{
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
045ec22f
...
...
@@ -272,7 +272,7 @@ namespace Titanium.Web.Proxy
cancellationToken
);
// for connection pool, retry fails until cache is exhausted.
return
await
retryPolicy
<
ServerConnectionException
>().
ExecuteAsync
(
async
(
connection
)
=>
return
await
retryPolicy
<
ServerConnectionException
>().
ExecuteAsync
(
async
connection
=>
{
// set the connection and send request headers
args
.
HttpClient
.
SetConnection
(
connection
);
...
...
src/Titanium.Web.Proxy/TransparentClientHandler.cs
View file @
045ec22f
...
...
@@ -30,9 +30,7 @@ namespace Titanium.Web.Proxy
var
cancellationTokenSource
=
new
CancellationTokenSource
();
var
cancellationToken
=
cancellationTokenSource
.
Token
;
var
clientStream
=
new
HttpClientStream
(
clientConnection
,
clientConnection
.
GetStream
(),
BufferPool
);
SslStream
?
sslStream
=
null
;
var
clientStream
=
new
HttpClientStream
(
clientConnection
,
clientConnection
.
GetStream
(),
BufferPool
,
cancellationToken
);
try
{
...
...
@@ -57,6 +55,7 @@ namespace Titanium.Web.Proxy
// do client authentication using certificate
X509Certificate2
?
certificate
=
null
;
SslStream
?
sslStream
=
null
;
try
{
sslStream
=
new
SslStream
(
clientStream
,
false
);
...
...
@@ -69,17 +68,18 @@ namespace Titanium.Web.Proxy
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
SslProtocols
.
Tls
,
false
);
// HTTPS server created - we can now decrypt the client's traffic
clientStream
=
new
HttpClientStream
(
clientStream
.
Connection
,
sslStream
,
BufferPool
);
clientStream
=
new
HttpClientStream
(
clientStream
.
Connection
,
sslStream
,
BufferPool
,
cancellationToken
);
sslStream
=
null
;
// clientStream was created, no need to keep SSL stream reference
}
catch
(
Exception
e
)
{
sslStream
?.
Dispose
();
var
certName
=
certificate
?.
GetNameInfo
(
X509NameType
.
SimpleName
,
false
);
var
session
=
new
SessionEventArgs
(
this
,
endPoint
,
clientStream
,
null
,
cancellationTokenSource
);
throw
new
ProxyConnectException
(
$"Couldn't authenticate host '
{
httpsHostName
}
' with certificate '
{
certName
}
'."
,
e
,
session
);
}
}
else
{
...
...
@@ -146,7 +146,6 @@ namespace Titanium.Web.Proxy
}
finally
{
sslStream
?.
Dispose
();
clientStream
.
Dispose
();
}
}
...
...
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