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
7cb42ed1
Commit
7cb42ed1
authored
Nov 30, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decding websocket frame
parent
f1fd7c7a
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
407 additions
and
67 deletions
+407
-67
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+36
-5
SessionEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+4
-0
ExplicitClientHandler.cs
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+33
-12
HttpHelper.cs
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
+82
-37
HttpStream.cs
src/Titanium.Web.Proxy/Helpers/HttpStream.cs
+1
-13
KnownMethod.cs
src/Titanium.Web.Proxy/Helpers/KnownMethod.cs
+71
-0
TcpConnectionFactory.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+2
-0
WebSocketDecoder.cs
src/Titanium.Web.Proxy/WebSocketDecoder.cs
+140
-0
WebSocketFrame.cs
src/Titanium.Web.Proxy/WebSocketFrame.cs
+26
-0
WebsocketOpCode.cs
src/Titanium.Web.Proxy/WebsocketOpCode.cs
+12
-0
No files found.
examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
7cb42ed1
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Text
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
...
@@ -10,6 +12,7 @@ using Titanium.Web.Proxy.Exceptions;
...
@@ -10,6 +12,7 @@ using Titanium.Web.Proxy.Exceptions;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.StreamExtended.Network
;
namespace
Titanium.Web.Proxy.Examples.Basic
namespace
Titanium.Web.Proxy.Examples.Basic
{
{
...
@@ -22,6 +25,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -22,6 +25,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
public
ProxyTestController
()
public
ProxyTestController
()
{
{
proxyServer
=
new
ProxyServer
();
proxyServer
=
new
ProxyServer
();
proxyServer
.
EnableHttp2
=
true
;
// generate root certificate without storing it in file system
// generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.CreateRootCertificate(false);
...
@@ -32,11 +38,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -32,11 +38,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
{
if
(
exception
is
ProxyHttpException
phex
)
if
(
exception
is
ProxyHttpException
phex
)
{
{
await
writeToConsole
(
exception
.
Message
+
": "
+
phex
.
InnerException
?.
Message
,
true
);
await
writeToConsole
(
exception
.
Message
+
": "
+
phex
.
InnerException
?.
Message
,
ConsoleColor
.
Red
);
}
}
else
else
{
{
await
writeToConsole
(
exception
.
Message
,
true
);
await
writeToConsole
(
exception
.
Message
,
ConsoleColor
.
Red
);
}
}
};
};
proxyServer
.
ForwardToUpstreamGateway
=
true
;
proxyServer
.
ForwardToUpstreamGateway
=
true
;
...
@@ -146,6 +152,26 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -146,6 +152,26 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
}
}
}
private
void
WebSocket_DataReceived
(
object
sender
,
DataEventArgs
e
)
{
var
args
=
(
SessionEventArgs
)
sender
;
foreach
(
var
frame
in
args
.
WebSocketDecoder
.
Decode
(
e
.
Buffer
,
e
.
Offset
,
e
.
Count
))
{
if
(
frame
.
OpCode
==
WebsocketOpCode
.
Binary
)
{
var
data
=
frame
.
Data
.
ToArray
();
string
str
=
string
.
Join
(
","
,
data
.
ToArray
().
Select
(
x
=>
x
.
ToString
(
"X2"
)));
writeToConsole
(
str
,
ConsoleColor
.
Blue
).
Wait
();
}
if
(
frame
.
OpCode
==
WebsocketOpCode
.
Text
)
{
writeToConsole
(
frame
.
GetText
(),
ConsoleColor
.
Blue
).
Wait
();
}
}
}
private
Task
onBeforeTunnelConnectResponse
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
private
Task
onBeforeTunnelConnectResponse
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
{
{
return
Task
.
FromResult
(
false
);
return
Task
.
FromResult
(
false
);
...
@@ -205,6 +231,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -205,6 +231,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
private
async
Task
onResponse
(
object
sender
,
SessionEventArgs
e
)
private
async
Task
onResponse
(
object
sender
,
SessionEventArgs
e
)
{
{
if
(
e
.
HttpClient
.
ConnectRequest
?.
TunnelType
==
TunnelType
.
Websocket
)
{
e
.
DataReceived
+=
WebSocket_DataReceived
;
}
await
writeToConsole
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
await
writeToConsole
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsolutePath
);
string
ext
=
System
.
IO
.
Path
.
GetExtension
(
e
.
HttpClient
.
Request
.
RequestUri
.
AbsolutePath
);
...
@@ -277,14 +308,14 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -277,14 +308,14 @@ namespace Titanium.Web.Proxy.Examples.Basic
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
private
async
Task
writeToConsole
(
string
message
,
bool
useRedColor
=
false
)
private
async
Task
writeToConsole
(
string
message
,
ConsoleColor
?
consoleColor
=
null
)
{
{
await
@lock
.
WaitAsync
();
await
@lock
.
WaitAsync
();
if
(
useRedColor
)
if
(
consoleColor
.
HasValue
)
{
{
ConsoleColor
existing
=
Console
.
ForegroundColor
;
ConsoleColor
existing
=
Console
.
ForegroundColor
;
Console
.
ForegroundColor
=
ConsoleColor
.
Red
;
Console
.
ForegroundColor
=
consoleColor
.
Value
;
Console
.
WriteLine
(
message
);
Console
.
WriteLine
(
message
);
Console
.
ForegroundColor
=
existing
;
Console
.
ForegroundColor
=
existing
;
}
}
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
7cb42ed1
...
@@ -26,6 +26,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -26,6 +26,8 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
private
bool
reRequest
;
private
bool
reRequest
;
private
WebSocketDecoder
webSocketDecoder
;
/// <summary>
/// <summary>
/// Is this session a HTTP/2 promise?
/// Is this session a HTTP/2 promise?
/// </summary>
/// </summary>
...
@@ -58,6 +60,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -58,6 +60,8 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
}
}
public
WebSocketDecoder
WebSocketDecoder
=>
webSocketDecoder
??=
new
WebSocketDecoder
(
BufferPool
);
/// <summary>
/// <summary>
/// Occurs when multipart request part sent.
/// Occurs when multipart request part sent.
/// </summary>
/// </summary>
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
7cb42ed1
...
@@ -47,9 +47,15 @@ namespace Titanium.Web.Proxy
...
@@ -47,9 +47,15 @@ namespace Titanium.Web.Proxy
try
try
{
{
TunnelConnectSessionEventArgs
?
connectArgs
=
null
;
TunnelConnectSessionEventArgs
?
connectArgs
=
null
;
var
method
=
await
HttpHelper
.
GetMethod
(
clientStream
,
BufferPool
,
cancellationToken
);
if
(
clientStream
.
IsClosed
)
{
return
;
}
// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if
(
await
HttpHelper
.
IsConnectMethod
(
clientStream
,
BufferPool
,
cancellationToken
)
==
1
)
if
(
method
==
KnownMethod
.
Connect
)
{
{
// read the first line HTTP command
// read the first line HTTP command
var
requestLine
=
await
clientStream
.
ReadRequestLine
(
cancellationToken
);
var
requestLine
=
await
clientStream
.
ReadRequestLine
(
cancellationToken
);
...
@@ -75,6 +81,7 @@ namespace Titanium.Web.Proxy
...
@@ -75,6 +81,7 @@ namespace Titanium.Web.Proxy
// filter out excluded host names
// filter out excluded host names
bool
decryptSsl
=
endPoint
.
DecryptSsl
&&
connectArgs
.
DecryptSsl
;
bool
decryptSsl
=
endPoint
.
DecryptSsl
&&
connectArgs
.
DecryptSsl
;
bool
sendRawData
=
!
decryptSsl
;
if
(
connectArgs
.
DenyConnect
)
if
(
connectArgs
.
DenyConnect
)
{
{
...
@@ -113,6 +120,10 @@ namespace Titanium.Web.Proxy
...
@@ -113,6 +120,10 @@ namespace Titanium.Web.Proxy
await
clientStream
.
WriteResponseAsync
(
response
,
cancellationToken
);
await
clientStream
.
WriteResponseAsync
(
response
,
cancellationToken
);
var
clientHelloInfo
=
await
SslTools
.
PeekClientHello
(
clientStream
,
BufferPool
,
cancellationToken
);
var
clientHelloInfo
=
await
SslTools
.
PeekClientHello
(
clientStream
,
BufferPool
,
cancellationToken
);
if
(
clientStream
.
IsClosed
)
{
return
;
}
bool
isClientHello
=
clientHelloInfo
!=
null
;
bool
isClientHello
=
clientHelloInfo
!=
null
;
if
(
clientHelloInfo
!=
null
)
if
(
clientHelloInfo
!=
null
)
...
@@ -224,31 +235,41 @@ namespace Titanium.Web.Proxy
...
@@ -224,31 +235,41 @@ namespace Titanium.Web.Proxy
$"Couldn't authenticate host '
{
connectHostname
}
' with certificate '
{
certName
}
'."
,
e
,
connectArgs
);
$"Couldn't authenticate host '
{
connectHostname
}
' with certificate '
{
certName
}
'."
,
e
,
connectArgs
);
}
}
if
(
await
HttpHelper
.
IsConnectMethod
(
clientStream
,
BufferPool
,
cancellationToken
)
==
-
1
)
method
=
await
HttpHelper
.
GetMethod
(
clientStream
,
BufferPool
,
cancellationToken
);
if
(
clientStream
.
IsClosed
)
{
{
decryptSsl
=
false
;
return
;
}
}
if
(
!
decryptSsl
)
if
(
method
==
KnownMethod
.
Invalid
)
{
{
sendRawData
=
true
;
await
tcpConnectionFactory
.
Release
(
prefetchConnectionTask
,
true
);
await
tcpConnectionFactory
.
Release
(
prefetchConnectionTask
,
true
);
prefetchConnectionTask
=
null
;
prefetchConnectionTask
=
null
;
}
}
}
}
else
if
(
clientHelloInfo
==
null
)
{
method
=
await
HttpHelper
.
GetMethod
(
clientStream
,
BufferPool
,
cancellationToken
);
if
(
clientStream
.
IsClosed
)
{
return
;
}
}
if
(
cancellationTokenSource
.
IsCancellationRequested
)
if
(
cancellationTokenSource
.
IsCancellationRequested
)
{
{
throw
new
Exception
(
"Session was terminated by user."
);
throw
new
Exception
(
"Session was terminated by user."
);
}
}
// Hostname is excluded or it is not an HTTPS connect
if
(
method
==
KnownMethod
.
Invalid
)
if
(!
decryptSsl
||
!
isClientHello
)
{
{
if
(!
isClientHello
)
sendRawData
=
true
;
{
}
connectRequest
.
TunnelType
=
TunnelType
.
Websocket
;
}
// Hostname is excluded or it is not an HTTPS connect
if
(
sendRawData
)
{
// create new connection to server.
// create new connection to server.
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// this connection should not be HTTPS.
// this connection should not be HTTPS.
...
@@ -302,7 +323,7 @@ namespace Titanium.Web.Proxy
...
@@ -302,7 +323,7 @@ namespace Titanium.Web.Proxy
}
}
}
}
if
(
connectArgs
!=
null
&&
await
HttpHelper
.
IsPriMethod
(
clientStream
,
BufferPool
,
cancellationToken
)
==
1
)
if
(
connectArgs
!=
null
&&
method
==
KnownMethod
.
Pri
)
{
{
// todo
// todo
string
?
httpCmd
=
await
clientStream
.
ReadLineAsync
(
cancellationToken
);
string
?
httpCmd
=
await
clientStream
.
ReadLineAsync
(
cancellationToken
);
...
...
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
View file @
7cb42ed1
...
@@ -167,32 +167,11 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -167,32 +167,11 @@ namespace Titanium.Web.Proxy.Helpers
}
}
/// <summary>
/// <summary>
///
Determines whether is connect method
.
///
Gets the HTTP method from the stream
.
/// </summary>
/// </summary>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
public
static
async
ValueTask
<
KnownMethod
>
GetMethod
(
IPeekStream
httpReader
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
internal
static
ValueTask
<
int
>
IsConnectMethod
(
IPeekStream
httpReader
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
return
startsWith
(
httpReader
,
bufferPool
,
"CONNECT"
,
cancellationToken
);
const
int
lengthToCheck
=
20
;
}
/// <summary>
/// Determines whether is pri method (HTTP/2).
/// </summary>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal
static
ValueTask
<
int
>
IsPriMethod
(
IPeekStream
httpReader
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
return
startsWith
(
httpReader
,
bufferPool
,
"PRI"
,
cancellationToken
);
}
/// <summary>
/// Determines whether the stream starts with the given string.
/// </summary>
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
private
static
async
ValueTask
<
int
>
startsWith
(
IPeekStream
httpReader
,
IBufferPool
bufferPool
,
string
expectedStart
,
CancellationToken
cancellationToken
=
default
)
{
const
int
lengthToCheck
=
10
;
if
(
bufferPool
.
BufferSize
<
lengthToCheck
)
if
(
bufferPool
.
BufferSize
<
lengthToCheck
)
{
{
throw
new
Exception
(
$"Buffer is too small. Minimum size is
{
lengthToCheck
}
bytes"
);
throw
new
Exception
(
$"Buffer is too small. Minimum size is
{
lengthToCheck
}
bytes"
);
...
@@ -201,13 +180,12 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -201,13 +180,12 @@ namespace Titanium.Web.Proxy.Helpers
byte
[]
buffer
=
bufferPool
.
GetBuffer
(
bufferPool
.
BufferSize
);
byte
[]
buffer
=
bufferPool
.
GetBuffer
(
bufferPool
.
BufferSize
);
try
try
{
{
bool
isExpected
=
true
;
int
i
=
0
;
int
i
=
0
;
while
(
i
<
lengthToCheck
)
while
(
i
<
lengthToCheck
)
{
{
int
peeked
=
await
httpReader
.
PeekBytesAsync
(
buffer
,
i
,
i
,
lengthToCheck
-
i
,
cancellationToken
);
int
peeked
=
await
httpReader
.
PeekBytesAsync
(
buffer
,
i
,
i
,
lengthToCheck
-
i
,
cancellationToken
);
if
(
peeked
<=
0
)
if
(
peeked
<=
0
)
return
-
1
;
return
KnownMethod
.
Invalid
;
peeked
+=
i
;
peeked
+=
i
;
...
@@ -216,27 +194,94 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -216,27 +194,94 @@ namespace Titanium.Web.Proxy.Helpers
int
b
=
buffer
[
i
];
int
b
=
buffer
[
i
];
if
(
b
==
' '
&&
i
>
2
)
if
(
b
==
' '
&&
i
>
2
)
return
isExpected
?
1
:
0
;
return
getKnownMethod
(
buffer
.
AsSpan
(
0
,
i
));
else
{
char
ch
=
(
char
)
b
;
char
ch
=
(
char
)
b
;
if
((
ch
<
'A'
||
ch
>
'z'
||
(
ch
>
'Z'
&&
ch
<
'a'
))
&&
(
ch
!=
'-'
))
// ASCII letter
if
(
ch
<
'A'
||
ch
>
'z'
||
(
ch
>
'Z'
&&
ch
<
'a'
))
// ASCII letter
return
KnownMethod
.
Invalid
;
return
-
1
;
else
if
(
i
>=
expectedStart
.
Length
||
ch
!=
expectedStart
[
i
])
isExpected
=
false
;
}
i
++;
i
++;
}
}
}
}
// only letters
// only letters
, but no space (or shorter than 3 characters)
return
0
;
return
KnownMethod
.
Invalid
;
}
}
finally
finally
{
{
bufferPool
.
ReturnBuffer
(
buffer
);
bufferPool
.
ReturnBuffer
(
buffer
);
}
}
}
}
private
static
KnownMethod
getKnownMethod
(
ReadOnlySpan
<
byte
>
method
)
{
// the following methods are supported:
// Connect
// Delete
// Get
// Head
// Options
// Post
// Put
// Trace
// Pri
// method parameter should have at least 3 bytes
byte
b1
=
method
[
0
];
byte
b2
=
method
[
1
];
byte
b3
=
method
[
2
];
switch
(
method
.
Length
)
{
case
3
:
// Get or Put
if
(
b1
==
'G'
)
return
b2
==
'E'
&&
b3
==
'T'
?
KnownMethod
.
Get
:
KnownMethod
.
Unknown
;
if
(
b1
==
'P'
)
{
if
(
b2
==
'U'
)
return
b3
==
'T'
?
KnownMethod
.
Put
:
KnownMethod
.
Unknown
;
if
(
b2
==
'R'
)
return
b3
==
'I'
?
KnownMethod
.
Pri
:
KnownMethod
.
Unknown
;
}
break
;
case
4
:
// Head or Post
if
(
b1
==
'H'
)
return
b2
==
'E'
&&
b3
==
'A'
&&
method
[
3
]
==
'D'
?
KnownMethod
.
Head
:
KnownMethod
.
Unknown
;
if
(
b1
==
'P'
)
return
b2
==
'O'
&&
b3
==
'S'
&&
method
[
3
]
==
'T'
?
KnownMethod
.
Post
:
KnownMethod
.
Unknown
;
break
;
case
5
:
// Trace
if
(
b1
==
'T'
)
return
b2
==
'R'
&&
b3
==
'A'
&&
method
[
3
]
==
'C'
&&
method
[
4
]
==
'E'
?
KnownMethod
.
Trace
:
KnownMethod
.
Unknown
;
break
;
case
6
:
// Delete
if
(
b1
==
'D'
)
return
b2
==
'E'
&&
b3
==
'L'
&&
method
[
3
]
==
'E'
&&
method
[
4
]
==
'T'
&&
method
[
5
]
==
'E'
?
KnownMethod
.
Delete
:
KnownMethod
.
Unknown
;
break
;
case
7
:
// Connect or Options
if
(
b1
==
'C'
)
return
b2
==
'O'
&&
b3
==
'N'
&&
method
[
3
]
==
'N'
&&
method
[
4
]
==
'E'
&&
method
[
5
]
==
'C'
&&
method
[
6
]
==
'T'
?
KnownMethod
.
Connect
:
KnownMethod
.
Unknown
;
if
(
b1
==
'O'
)
return
b2
==
'P'
&&
b3
==
'T'
&&
method
[
3
]
==
'I'
&&
method
[
4
]
==
'O'
&&
method
[
5
]
==
'N'
&&
method
[
6
]
==
'S'
?
KnownMethod
.
Options
:
KnownMethod
.
Unknown
;
break
;
}
return
KnownMethod
.
Unknown
;
}
}
}
}
}
src/Titanium.Web.Proxy/Helpers/HttpStream.cs
View file @
7cb42ed1
...
@@ -650,7 +650,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -650,7 +650,7 @@ namespace Titanium.Web.Proxy.Helpers
if
(
bufferDataLength
==
buffer
.
Length
)
if
(
bufferDataLength
==
buffer
.
Length
)
{
{
resizeBuffer
(
ref
buffer
,
bufferDataLength
*
2
);
Array
.
Resize
(
ref
buffer
,
bufferDataLength
*
2
);
}
}
}
}
}
}
...
@@ -678,18 +678,6 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -678,18 +678,6 @@ namespace Titanium.Web.Proxy.Helpers
}
}
}
}
/// <summary>
/// Increase size of buffer and copy existing content to new buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="size"></param>
private
static
void
resizeBuffer
(
ref
byte
[]
buffer
,
long
size
)
{
var
newBuffer
=
new
byte
[
size
];
Buffer
.
BlockCopy
(
buffer
,
0
,
newBuffer
,
0
,
buffer
.
Length
);
buffer
=
newBuffer
;
}
/// <summary>
/// <summary>
/// Base Stream.BeginRead will call this.Read and block thread (we don't want this, Network stream handles async)
/// Base Stream.BeginRead will call this.Read and block thread (we don't want this, Network stream handles async)
/// In order to really async Reading Launch this.ReadAsync as Task will fire NetworkStream.ReadAsync
/// In order to really async Reading Launch this.ReadAsync as Task will fire NetworkStream.ReadAsync
...
...
src/Titanium.Web.Proxy/Helpers/KnownMethod.cs
0 → 100644
View file @
7cb42ed1
namespace
Titanium.Web.Proxy.Helpers
{
internal
enum
KnownMethod
{
Unknown
,
Invalid
,
// RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
Connect
,
Delete
,
Get
,
Head
,
Options
,
Post
,
Put
,
Trace
,
// RFC 7540: Hypertext Transfer Protocol Version 2
Pri
,
// RFC 5789: PATCH Method for HTTP
Patch
,
// RFC 3744: Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
Acl
,
// RFC 3253: Versioning Extensions to WebDAV (Web Distributed Authoring and Versioning)
BaselineControl
,
Checkin
,
Checkout
,
Label
,
Merge
,
Mkactivity
,
Mkworkspace
,
Report
,
Unckeckout
,
Update
,
VersionControl
,
// RFC 3648: Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol
Orderpatch
,
// RFC 4437: Web Distributed Authoring and Versioning (WebDAV): Redirect Reference Resources
Mkredirectref
,
Updateredirectref
,
// RFC 4791: Calendaring Extensions to WebDAV (CalDAV)
Mkcalendar
,
// RFC 4918: HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)
Copy
,
Lock
,
Mkcol
,
Move
,
Propfind
,
Proppatch
,
Unlock
,
// RFC 5323: Web Distributed Authoring and Versioning (WebDAV) SEARCH
Search
,
// RFC 5842: Binding Extensions to Web Distributed Authoring and Versioning (WebDAV)
Bind
,
Rebind
,
Unbind
,
// Internet Draft snell-link-method: HTTP Link and Unlink Methods
Link
,
Unlink
,
}
}
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
7cb42ed1
...
@@ -60,6 +60,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -60,6 +60,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
cacheKeyBuilder
.
Append
(
"-"
);
cacheKeyBuilder
.
Append
(
"-"
);
cacheKeyBuilder
.
Append
(
remotePort
);
cacheKeyBuilder
.
Append
(
remotePort
);
cacheKeyBuilder
.
Append
(
"-"
);
cacheKeyBuilder
.
Append
(
"-"
);
// when creating Tcp client isConnect won't matter
// when creating Tcp client isConnect won't matter
cacheKeyBuilder
.
Append
(
isHttps
);
cacheKeyBuilder
.
Append
(
isHttps
);
...
@@ -408,6 +409,7 @@ retry:
...
@@ -408,6 +409,7 @@ retry:
continue
;
continue
;
}
}
break
;
break
;
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
...
...
src/Titanium.Web.Proxy/WebSocketDecoder.cs
0 → 100644
View file @
7cb42ed1
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
Titanium.Web.Proxy.StreamExtended.BufferPool
;
namespace
Titanium.Web.Proxy
{
public
class
WebSocketDecoder
{
private
byte
[]
buffer
;
private
long
bufferLength
;
internal
WebSocketDecoder
(
IBufferPool
bufferPool
)
{
buffer
=
new
byte
[
bufferPool
.
BufferSize
];
}
public
IEnumerable
<
WebSocketFrame
>
Decode
(
byte
[]
data
,
int
offset
,
int
count
)
{
var
buffer
=
data
.
AsMemory
(
offset
,
count
);
bool
copied
=
false
;
if
(
bufferLength
>
0
)
{
// already have remaining data
buffer
=
copyToBuffer
(
buffer
);
copied
=
true
;
}
while
(
true
)
{
var
data1
=
buffer
.
Span
;
if
(!
isDataEnough
(
data1
))
{
break
;
}
var
opCode
=
(
WebsocketOpCode
)(
data1
[
0
]
&
0xf
);
byte
b
=
data1
[
1
];
long
size
=
b
&
0x7f
;
// todo: size > int.Max??
bool
masked
=
(
b
&
0x80
)
!=
0
;
int
idx
=
2
;
if
(
size
>
125
)
{
if
(
size
==
126
)
{
size
=
(
data1
[
2
]
<<
8
)
+
data1
[
3
];
idx
=
4
;
}
else
{
size
=
((
long
)
data1
[
2
]
<<
56
)
+
((
long
)
data1
[
3
]
<<
48
)
+
((
long
)
data1
[
4
]
<<
40
)
+
((
long
)
data1
[
5
]
<<
32
)
+
((
long
)
data1
[
6
]
<<
24
)
+
(
data1
[
7
]
<<
16
)
+
(
data1
[
8
]
<<
8
)
+
data1
[
9
];
idx
=
10
;
}
}
uint
mask
=
0
;
if
(
masked
)
{
//mask = (uint)(((long)data1[idx++] << 24) + (data1[idx++] << 16) + (data1[idx++] << 8) + data1[idx++]);
mask
=
(
uint
)(
data1
[
idx
++]
+
(
data1
[
idx
++]
<<
8
)
+
(
data1
[
idx
++]
<<
16
)
+
((
long
)
data1
[
idx
++]
<<
24
));
}
if
(
masked
)
{
uint
m
=
mask
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
data
[
i
+
idx
]
=
(
byte
)(
data1
[
i
+
idx
]
^
(
byte
)
mask
);
m
>>=
8
;
if
(
m
==
0
)
m
=
mask
;
}
}
var
frameData
=
buffer
.
Slice
(
idx
,
(
int
)
size
);
var
frame
=
new
WebSocketFrame
{
Data
=
frameData
,
OpCode
=
opCode
};
yield
return
frame
;
buffer
=
buffer
.
Slice
((
int
)(
idx
+
size
));
}
if
(!
copied
&&
buffer
.
Length
>
0
)
{
copyToBuffer
(
buffer
);
}
}
private
Memory
<
byte
>
copyToBuffer
(
ReadOnlyMemory
<
byte
>
data
)
{
long
requiredLength
=
bufferLength
+
data
.
Length
;
if
(
requiredLength
>
buffer
.
Length
)
{
Array
.
Resize
(
ref
buffer
,
(
int
)
Math
.
Min
(
requiredLength
,
buffer
.
Length
*
2
));
}
data
.
CopyTo
(
buffer
.
AsMemory
((
int
)
bufferLength
));
bufferLength
+=
data
.
Length
;
return
buffer
.
AsMemory
(
0
,
(
int
)
bufferLength
);
}
private
static
bool
isDataEnough
(
ReadOnlySpan
<
byte
>
data
)
{
int
length
=
data
.
Length
;
if
(
length
<
2
)
return
false
;
byte
size
=
data
[
1
];
if
((
size
&
0x80
)
!=
0
)
// masked
length
-=
4
;
size
&=
0x7f
;
if
(
size
==
126
)
{
if
(
length
<
2
)
{
return
false
;
}
}
else
if
(
size
==
127
)
{
if
(
length
<
10
)
{
return
false
;
}
}
return
length
>=
size
;
}
}
}
src/Titanium.Web.Proxy/WebSocketFrame.cs
0 → 100644
View file @
7cb42ed1
using
System
;
using
System.Text
;
namespace
Titanium.Web.Proxy
{
public
class
WebSocketFrame
{
public
WebsocketOpCode
OpCode
{
get
;
internal
set
;
}
public
ReadOnlyMemory
<
byte
>
Data
{
get
;
internal
set
;
}
public
string
GetText
()
{
return
GetText
(
Encoding
.
UTF8
);
}
public
string
GetText
(
Encoding
encoding
)
{
#if NETSTANDARD2_1
return
encoding
.
GetString
(
Data
.
Span
);
#else
return
encoding
.
GetString
(
Data
.
ToArray
());
#endif
}
}
}
src/Titanium.Web.Proxy/WebsocketOpCode.cs
0 → 100644
View file @
7cb42ed1
namespace
Titanium.Web.Proxy
{
public
enum
WebsocketOpCode
:
byte
{
Continuation
,
Text
,
Binary
,
ConnectionClose
=
8
,
Ping
,
Pong
,
}
}
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