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
1b0bfecd
Commit
1b0bfecd
authored
Nov 16, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
better uri handling
parent
7325e32a
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
415 additions
and
174 deletions
+415
-174
CompressionFactory.cs
src/Titanium.Web.Proxy/Compression/CompressionFactory.cs
+4
-4
CompressionUtil.cs
src/Titanium.Web.Proxy/Compression/CompressionUtil.cs
+22
-0
DecompressionFactory.cs
src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs
+4
-4
HttpCompression.cs
src/Titanium.Web.Proxy/Compression/HttpCompression.cs
+12
-0
LimitedStream.cs
src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs
+1
-1
SessionEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+2
-2
SessionEventArgsBase.cs
...Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
+1
-1
ExplicitClientHandler.cs
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+9
-6
StreamExtensions.cs
src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+1
-1
HttpHelper.cs
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
+2
-2
HttpWriter.cs
src/Titanium.Web.Proxy/Helpers/HttpWriter.cs
+1
-1
ProxyInfo.cs
src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs
+11
-3
ConnectRequest.cs
src/Titanium.Web.Proxy/Http/ConnectRequest.cs
+6
-3
HeaderBuilder.cs
src/Titanium.Web.Proxy/Http/HeaderBuilder.cs
+1
-1
HeaderCollection.cs
src/Titanium.Web.Proxy/Http/HeaderCollection.cs
+64
-6
HttpWebClient.cs
src/Titanium.Web.Proxy/Http/HttpWebClient.cs
+3
-3
KnownHeader.cs
src/Titanium.Web.Proxy/Http/KnownHeader.cs
+31
-0
KnownHeaders.cs
src/Titanium.Web.Proxy/Http/KnownHeaders.cs
+27
-27
Request.cs
src/Titanium.Web.Proxy/Http/Request.cs
+81
-6
RequestResponseBase.cs
src/Titanium.Web.Proxy/Http/RequestResponseBase.cs
+3
-3
Response.cs
src/Titanium.Web.Proxy/Http/Response.cs
+1
-1
DynamicTable.cs
src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs
+1
-1
Encoder.cs
src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs
+4
-2
Http2FrameHeader.cs
src/Titanium.Web.Proxy/Http2/Http2FrameHeader.cs
+1
-5
Http2Helper.cs
src/Titanium.Web.Proxy/Http2/Http2Helper.cs
+45
-22
ByteString.cs
src/Titanium.Web.Proxy/Models/ByteString.cs
+5
-0
HttpHeader.cs
src/Titanium.Web.Proxy/Models/HttpHeader.cs
+42
-5
TcpConnectionFactory.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+1
-1
ProxyAuthorizationHandler.cs
src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
+6
-4
ProxyServer.cs
src/Titanium.Web.Proxy/ProxyServer.cs
+4
-4
RequestHandler.cs
src/Titanium.Web.Proxy/RequestHandler.cs
+6
-38
ProxyConstants.cs
src/Titanium.Web.Proxy/Shared/ProxyConstants.cs
+3
-6
TransparentClientHandler.cs
src/Titanium.Web.Proxy/TransparentClientHandler.cs
+1
-2
ExpectContinueTests.cs
...itanium.Web.Proxy.IntegrationTests/ExpectContinueTests.cs
+4
-4
HttpsTests.cs
tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
+1
-1
ReverseProxyTests.cs
.../Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs
+4
-4
No files found.
src/Titanium.Web.Proxy/Compression/CompressionFactory.cs
View file @
1b0bfecd
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
/// </summary>
internal
static
class
CompressionFactory
internal
static
class
CompressionFactory
{
{
internal
static
Stream
Create
(
string
type
,
Stream
stream
,
bool
leaveOpen
=
true
)
internal
static
Stream
Create
(
HttpCompression
type
,
Stream
stream
,
bool
leaveOpen
=
true
)
{
{
switch
(
type
)
switch
(
type
)
{
{
case
KnownHeaders
.
ContentEncoding
Gzip
:
case
HttpCompression
.
Gzip
:
return
new
GZipStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
return
new
GZipStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Deflate
:
case
HttpCompression
.
Deflate
:
return
new
DeflateStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
return
new
DeflateStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Brotli
:
case
HttpCompression
.
Brotli
:
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
default
:
default
:
throw
new
Exception
(
$"Unsupported compression mode:
{
type
}
"
);
throw
new
Exception
(
$"Unsupported compression mode:
{
type
}
"
);
...
...
src/Titanium.Web.Proxy/Compression/CompressionUtil.cs
0 → 100644
View file @
1b0bfecd
using
System
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy.Compression
{
internal
static
class
CompressionUtil
{
public
static
HttpCompression
CompressionNameToEnum
(
string
name
)
{
if
(
KnownHeaders
.
ContentEncodingGzip
.
Equals
(
name
.
AsSpan
()))
return
HttpCompression
.
Gzip
;
if
(
KnownHeaders
.
ContentEncodingDeflate
.
Equals
(
name
.
AsSpan
()))
return
HttpCompression
.
Deflate
;
if
(
KnownHeaders
.
ContentEncodingBrotli
.
Equals
(
name
.
AsSpan
()))
return
HttpCompression
.
Brotli
;
return
HttpCompression
.
Unsupported
;
}
}
}
src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs
View file @
1b0bfecd
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
/// </summary>
internal
class
DecompressionFactory
internal
class
DecompressionFactory
{
{
internal
static
Stream
Create
(
string
type
,
Stream
stream
,
bool
leaveOpen
=
true
)
internal
static
Stream
Create
(
HttpCompression
type
,
Stream
stream
,
bool
leaveOpen
=
true
)
{
{
switch
(
type
)
switch
(
type
)
{
{
case
KnownHeaders
.
ContentEncoding
Gzip
:
case
HttpCompression
.
Gzip
:
return
new
GZipStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
return
new
GZipStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Deflate
:
case
HttpCompression
.
Deflate
:
return
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
return
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Brotli
:
case
HttpCompression
.
Brotli
:
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
default
:
default
:
throw
new
Exception
(
$"Unsupported decompression mode:
{
type
}
"
);
throw
new
Exception
(
$"Unsupported decompression mode:
{
type
}
"
);
...
...
src/Titanium.Web.Proxy/Compression/HttpCompression.cs
0 → 100644
View file @
1b0bfecd
using
System.IO.Compression
;
namespace
Titanium.Web.Proxy.Compression
{
internal
enum
HttpCompression
{
Unsupported
,
Gzip
,
Deflate
,
Brotli
,
}
}
src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs
View file @
1b0bfecd
...
@@ -54,7 +54,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -54,7 +54,7 @@ namespace Titanium.Web.Proxy.EventArguments
readChunkTrail
=
true
;
readChunkTrail
=
true
;
string
?
chunkHead
=
baseStream
.
ReadLineAsync
().
Result
;
string
?
chunkHead
=
baseStream
.
ReadLineAsync
().
Result
!
;
int
idx
=
chunkHead
.
IndexOf
(
";"
,
StringComparison
.
Ordinal
);
int
idx
=
chunkHead
.
IndexOf
(
";"
,
StringComparison
.
Ordinal
);
if
(
idx
>=
0
)
if
(
idx
>=
0
)
{
{
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
1b0bfecd
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Constructor to initialize the proxy
/// Constructor to initialize the proxy
/// </summary>
/// </summary>
internal
SessionEventArgs
(
ProxyServer
server
,
ProxyEndPoint
endPoint
,
ProxyClient
proxyClient
,
ConnectRequest
?
connectRequest
,
CancellationTokenSource
cancellationTokenSource
)
internal
SessionEventArgs
(
ProxyServer
server
,
ProxyEndPoint
endPoint
,
ProxyClient
proxyClient
,
ConnectRequest
?
connectRequest
,
CancellationTokenSource
cancellationTokenSource
)
:
base
(
server
,
endPoint
,
proxyClient
,
connectRequest
,
n
ull
,
cancellationTokenSource
)
:
base
(
server
,
endPoint
,
proxyClient
,
connectRequest
,
n
ew
Request
()
,
cancellationTokenSource
)
{
{
}
}
...
@@ -304,7 +304,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -304,7 +304,7 @@ namespace Titanium.Web.Proxy.EventArguments
if
(
transformation
==
TransformationMode
.
Uncompress
&&
contentEncoding
!=
null
)
if
(
transformation
==
TransformationMode
.
Uncompress
&&
contentEncoding
!=
null
)
{
{
s
=
decompressStream
=
DecompressionFactory
.
Create
(
contentEncoding
,
s
);
s
=
decompressStream
=
DecompressionFactory
.
Create
(
CompressionUtil
.
CompressionNameToEnum
(
contentEncoding
)
,
s
);
}
}
try
try
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
View file @
1b0bfecd
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary>
/// </summary>
private
protected
SessionEventArgsBase
(
ProxyServer
server
,
ProxyEndPoint
endPoint
,
private
protected
SessionEventArgsBase
(
ProxyServer
server
,
ProxyEndPoint
endPoint
,
ProxyClient
proxyClient
,
ConnectRequest
?
connectRequest
,
Request
?
request
,
CancellationTokenSource
cancellationTokenSource
)
ProxyClient
proxyClient
,
ConnectRequest
?
connectRequest
,
Request
request
,
CancellationTokenSource
cancellationTokenSource
)
{
{
BufferPool
=
server
.
BufferPool
;
BufferPool
=
server
.
BufferPool
;
ExceptionFunc
=
server
.
ExceptionFunc
;
ExceptionFunc
=
server
.
ExceptionFunc
;
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
1b0bfecd
...
@@ -62,12 +62,15 @@ namespace Titanium.Web.Proxy
...
@@ -62,12 +62,15 @@ namespace Titanium.Web.Proxy
Request
.
ParseRequestLine
(
httpCmd
!,
out
string
_
,
out
string
httpUrl
,
out
var
version
);
Request
.
ParseRequestLine
(
httpCmd
!,
out
string
_
,
out
string
httpUrl
,
out
var
version
);
var
httpRemoteUri
=
new
Uri
(
"http://"
+
httpUrl
);
connectHostname
=
httpUrl
;
connectHostname
=
httpRemoteUri
.
Host
;
int
idx
=
connectHostname
.
IndexOf
(
":"
);
if
(
idx
>=
0
)
{
connectHostname
=
connectHostname
.
Substring
(
0
,
idx
);
}
var
connectRequest
=
new
ConnectRequest
var
connectRequest
=
new
ConnectRequest
(
connectHostname
)
{
{
RequestUri
=
httpRemoteUri
,
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
httpUrl
),
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
httpUrl
),
HttpVersion
=
version
HttpVersion
=
version
};
};
...
@@ -127,6 +130,7 @@ namespace Titanium.Web.Proxy
...
@@ -127,6 +130,7 @@ namespace Titanium.Web.Proxy
bool
isClientHello
=
clientHelloInfo
!=
null
;
bool
isClientHello
=
clientHelloInfo
!=
null
;
if
(
clientHelloInfo
!=
null
)
if
(
clientHelloInfo
!=
null
)
{
{
connectRequest
.
Scheme
=
ProxyServer
.
UriSchemeHttps
;
connectRequest
.
TunnelType
=
TunnelType
.
Https
;
connectRequest
.
TunnelType
=
TunnelType
.
Https
;
connectRequest
.
ClientHelloInfo
=
clientHelloInfo
;
connectRequest
.
ClientHelloInfo
=
clientHelloInfo
;
}
}
...
@@ -136,7 +140,6 @@ namespace Titanium.Web.Proxy
...
@@ -136,7 +140,6 @@ namespace Titanium.Web.Proxy
if
(
decryptSsl
&&
clientHelloInfo
!=
null
)
if
(
decryptSsl
&&
clientHelloInfo
!=
null
)
{
{
clientConnection
.
SslProtocol
=
clientHelloInfo
.
SslProtocol
;
clientConnection
.
SslProtocol
=
clientHelloInfo
.
SslProtocol
;
connectRequest
.
RequestUri
=
new
Uri
(
"https://"
+
httpUrl
);
bool
http2Supported
=
false
;
bool
http2Supported
=
false
;
...
@@ -355,7 +358,7 @@ namespace Titanium.Web.Proxy
...
@@ -355,7 +358,7 @@ namespace Titanium.Web.Proxy
// Now create the request
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
,
connect
Hostname
,
connect
Args
,
prefetchConnectionTask
);
cancellationTokenSource
,
connectArgs
,
prefetchConnectionTask
);
}
}
catch
(
ProxyException
e
)
catch
(
ProxyException
e
)
{
{
...
...
src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
1b0bfecd
...
@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
private
static
async
Task
<
T
>
withCancellation
<
T
>(
this
Task
<
T
>
task
,
CancellationToken
cancellationToken
)
private
static
async
Task
<
T
>
withCancellation
<
T
>(
this
Task
<
T
>
task
,
CancellationToken
cancellationToken
)
where
T
:
struct
{
{
var
tcs
=
new
TaskCompletionSource
<
bool
>();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
using
(
cancellationToken
.
Register
(
s
=>
((
TaskCompletionSource
<
bool
>)
s
).
TrySetResult
(
true
),
tcs
))
using
(
cancellationToken
.
Register
(
s
=>
((
TaskCompletionSource
<
bool
>)
s
).
TrySetResult
(
true
),
tcs
))
...
...
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
View file @
1b0bfecd
...
@@ -78,7 +78,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -78,7 +78,7 @@ namespace Titanium.Web.Proxy.Helpers
{
{
var
parameter
=
p
.
Span
;
var
parameter
=
p
.
Span
;
int
equalsIndex
=
parameter
.
IndexOf
(
'='
);
int
equalsIndex
=
parameter
.
IndexOf
(
'='
);
if
(
equalsIndex
!=
-
1
&&
parameter
.
Slice
(
0
,
equalsIndex
).
TrimStart
().
EqualsIgnoreCase
(
KnownHeaders
.
ContentTypeCharset
.
AsSpan
()))
if
(
equalsIndex
!=
-
1
&&
KnownHeaders
.
ContentTypeCharset
.
Equals
(
parameter
.
Slice
(
0
,
equalsIndex
).
TrimStart
()))
{
{
var
value
=
parameter
.
Slice
(
equalsIndex
+
1
);
var
value
=
parameter
.
Slice
(
equalsIndex
+
1
);
if
(
value
.
EqualsIgnoreCase
(
"x-user-defined"
.
AsSpan
()))
if
(
value
.
EqualsIgnoreCase
(
"x-user-defined"
.
AsSpan
()))
...
@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy.Helpers
foreach
(
var
parameter
in
new
SemicolonSplitEnumerator
(
contentType
))
foreach
(
var
parameter
in
new
SemicolonSplitEnumerator
(
contentType
))
{
{
int
equalsIndex
=
parameter
.
Span
.
IndexOf
(
'='
);
int
equalsIndex
=
parameter
.
Span
.
IndexOf
(
'='
);
if
(
equalsIndex
!=
-
1
&&
parameter
.
Span
.
Slice
(
0
,
equalsIndex
).
TrimStart
().
EqualsIgnoreCase
(
KnownHeaders
.
ContentTypeBoundary
.
AsSpan
()))
if
(
equalsIndex
!=
-
1
&&
KnownHeaders
.
ContentTypeBoundary
.
Equals
(
parameter
.
Span
.
Slice
(
0
,
equalsIndex
).
TrimStart
()))
{
{
var
value
=
parameter
.
Slice
(
equalsIndex
+
1
);
var
value
=
parameter
.
Slice
(
equalsIndex
+
1
);
if
(
value
.
Length
>
2
&&
value
.
Span
[
0
]
==
'"'
&&
value
.
Span
[
value
.
Length
-
1
]
==
'"'
)
if
(
value
.
Length
>
2
&&
value
.
Span
[
0
]
==
'"'
&&
value
.
Span
[
value
.
Length
-
1
]
==
'"'
)
...
...
src/Titanium.Web.Proxy/Helpers/HttpWriter.cs
View file @
1b0bfecd
...
@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers
{
{
while
(
true
)
while
(
true
)
{
{
string
?
chunkHead
=
await
reader
.
ReadLineAsync
(
cancellationToken
)
;
string
chunkHead
=
(
await
reader
.
ReadLineAsync
(
cancellationToken
))!
;
int
idx
=
chunkHead
.
IndexOf
(
";"
);
int
idx
=
chunkHead
.
IndexOf
(
";"
);
if
(
idx
>=
0
)
if
(
idx
>=
0
)
{
{
...
...
src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs
View file @
1b0bfecd
...
@@ -66,9 +66,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -66,9 +66,9 @@ namespace Titanium.Web.Proxy.Helpers
internal
bool
BypassOnLocal
{
get
;
}
internal
bool
BypassOnLocal
{
get
;
}
internal
Dictionary
<
ProxyProtocolType
,
HttpSystemProxyValue
>
Proxies
{
get
;
}
internal
Dictionary
<
ProxyProtocolType
,
HttpSystemProxyValue
>
?
Proxies
{
get
;
}
internal
string
[]
BypassList
{
get
;
}
internal
string
[]
?
BypassList
{
get
;
}
private
static
string
bypassStringEscape
(
string
rawString
)
private
static
string
bypassStringEscape
(
string
rawString
)
{
{
...
@@ -171,7 +171,15 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -171,7 +171,15 @@ namespace Titanium.Web.Proxy.Helpers
if
(
proxyValues
.
Length
>
0
)
if
(
proxyValues
.
Length
>
0
)
{
{
result
.
AddRange
(
proxyValues
.
Select
(
parseProxyValue
).
Where
(
parsedValue
=>
parsedValue
!=
null
));
foreach
(
string
str
in
proxyValues
)
{
var
proxyValue
=
parseProxyValue
(
str
);
if
(
proxyValue
!=
null
)
{
result
.
Add
(
proxyValue
);
}
}
}
}
else
else
{
{
...
...
src/Titanium.Web.Proxy/Http/ConnectRequest.cs
View file @
1b0bfecd
using
Titanium.Web.Proxy.StreamExtended
;
using
System
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.StreamExtended
;
namespace
Titanium.Web.Proxy.Http
namespace
Titanium.Web.Proxy.Http
{
{
...
@@ -7,13 +9,14 @@ namespace Titanium.Web.Proxy.Http
...
@@ -7,13 +9,14 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
class
ConnectRequest
:
Request
public
class
ConnectRequest
:
Request
{
{
public
ConnectRequest
()
public
ConnectRequest
(
string
hostname
)
{
{
Method
=
"CONNECT"
;
Method
=
"CONNECT"
;
Hostname
=
hostname
;
}
}
public
TunnelType
TunnelType
{
get
;
internal
set
;
}
public
TunnelType
TunnelType
{
get
;
internal
set
;
}
public
ClientHelloInfo
ClientHelloInfo
{
get
;
set
;
}
public
ClientHelloInfo
?
ClientHelloInfo
{
get
;
set
;
}
}
}
}
}
src/Titanium.Web.Proxy/Http/HeaderBuilder.cs
View file @
1b0bfecd
...
@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Http
var
encoding
=
HttpHeader
.
Encoding
;
var
encoding
=
HttpHeader
.
Encoding
;
#if NETSTANDARD2_1
#if NETSTANDARD2_1
var
buf
=
ArrayPool
<
byte
>.
Shared
.
Rent
(
str
.
Length
*
4
);
var
buf
=
ArrayPool
<
byte
>.
Shared
.
Rent
(
encoding
.
GetMaxByteCount
(
str
.
Length
)
);
var
span
=
new
Span
<
byte
>(
buf
);
var
span
=
new
Span
<
byte
>(
buf
);
int
bytes
=
encoding
.
GetBytes
(
str
.
AsSpan
(),
span
);
int
bytes
=
encoding
.
GetBytes
(
str
.
AsSpan
(),
span
);
...
...
src/Titanium.Web.Proxy/Http/HeaderCollection.cs
View file @
1b0bfecd
...
@@ -105,6 +105,21 @@ namespace Titanium.Web.Proxy.Http
...
@@ -105,6 +105,21 @@ namespace Titanium.Web.Proxy.Http
return
null
;
return
null
;
}
}
internal
HttpHeader
?
GetFirstHeader
(
KnownHeader
name
)
{
if
(
headers
.
TryGetValue
(
name
.
String
,
out
var
header
))
{
return
header
;
}
if
(
nonUniqueHeaders
.
TryGetValue
(
name
.
String
,
out
var
h
))
{
return
h
.
FirstOrDefault
();
}
return
null
;
}
/// <summary>
/// <summary>
/// Returns all headers
/// Returns all headers
/// </summary>
/// </summary>
...
@@ -129,6 +144,16 @@ namespace Titanium.Web.Proxy.Http
...
@@ -129,6 +144,16 @@ namespace Titanium.Web.Proxy.Http
AddHeader
(
new
HttpHeader
(
name
,
value
));
AddHeader
(
new
HttpHeader
(
name
,
value
));
}
}
internal
void
AddHeader
(
KnownHeader
name
,
string
value
)
{
AddHeader
(
new
HttpHeader
(
name
,
value
));
}
internal
void
AddHeader
(
KnownHeader
name
,
KnownHeader
value
)
{
AddHeader
(
new
HttpHeader
(
name
,
value
));
}
/// <summary>
/// <summary>
/// Adds the given header object to Request
/// Adds the given header object to Request
/// </summary>
/// </summary>
...
@@ -239,6 +264,27 @@ namespace Titanium.Web.Proxy.Http
...
@@ -239,6 +264,27 @@ namespace Titanium.Web.Proxy.Http
return
result
;
return
result
;
}
}
/// <summary>
/// removes all headers with given name
/// </summary>
/// <param name="headerName"></param>
/// <returns>
/// True if header was removed
/// False if no header exists with given name
/// </returns>
public
bool
RemoveHeader
(
KnownHeader
headerName
)
{
bool
result
=
headers
.
Remove
(
headerName
.
String
);
// do not convert to '||' expression to avoid lazy evaluation
if
(
nonUniqueHeaders
.
Remove
(
headerName
.
String
))
{
result
=
true
;
}
return
result
;
}
/// <summary>
/// <summary>
/// Removes given header object if it exist
/// Removes given header object if it exist
/// </summary>
/// </summary>
...
@@ -273,9 +319,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -273,9 +319,9 @@ namespace Titanium.Web.Proxy.Http
nonUniqueHeaders
.
Clear
();
nonUniqueHeaders
.
Clear
();
}
}
internal
string
?
GetHeaderValueOrNull
(
string
headerName
)
internal
string
?
GetHeaderValueOrNull
(
KnownHeader
headerName
)
{
{
if
(
headers
.
TryGetValue
(
headerName
,
out
var
header
))
if
(
headers
.
TryGetValue
(
headerName
.
String
,
out
var
header
))
{
{
return
header
.
Value
;
return
header
.
Value
;
}
}
...
@@ -283,7 +329,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -283,7 +329,7 @@ namespace Titanium.Web.Proxy.Http
return
null
;
return
null
;
}
}
internal
void
SetOrAddHeaderValue
(
string
headerName
,
string
?
value
)
internal
void
SetOrAddHeaderValue
(
KnownHeader
headerName
,
string
?
value
)
{
{
if
(
value
==
null
)
if
(
value
==
null
)
{
{
...
@@ -291,13 +337,25 @@ namespace Titanium.Web.Proxy.Http
...
@@ -291,13 +337,25 @@ namespace Titanium.Web.Proxy.Http
return
;
return
;
}
}
if
(
headers
.
TryGetValue
(
headerName
,
out
var
header
))
if
(
headers
.
TryGetValue
(
headerName
.
String
,
out
var
header
))
{
header
.
SetValue
(
value
);
}
else
{
headers
.
Add
(
headerName
.
String
,
new
HttpHeader
(
headerName
,
value
));
}
}
internal
void
SetOrAddHeaderValue
(
KnownHeader
headerName
,
KnownHeader
value
)
{
if
(
headers
.
TryGetValue
(
headerName
.
String
,
out
var
header
))
{
{
header
.
ValueData
=
value
.
GetByteString
(
);
header
.
SetValue
(
value
);
}
}
else
else
{
{
headers
.
Add
(
headerName
,
new
HttpHeader
(
headerName
,
value
));
headers
.
Add
(
headerName
.
String
,
new
HttpHeader
(
headerName
,
value
));
}
}
}
}
...
...
src/Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
1b0bfecd
...
@@ -18,10 +18,10 @@ namespace Titanium.Web.Proxy.Http
...
@@ -18,10 +18,10 @@ namespace Titanium.Web.Proxy.Http
{
{
private
TcpServerConnection
?
connection
;
private
TcpServerConnection
?
connection
;
internal
HttpWebClient
(
ConnectRequest
?
connectRequest
,
Request
?
request
,
Lazy
<
int
>
processIdFunc
)
internal
HttpWebClient
(
ConnectRequest
?
connectRequest
,
Request
request
,
Lazy
<
int
>
processIdFunc
)
{
{
ConnectRequest
=
connectRequest
;
ConnectRequest
=
connectRequest
;
Request
=
request
??
new
Request
()
;
Request
=
request
;
Response
=
new
Response
();
Response
=
new
Response
();
ProcessId
=
processIdFunc
;
ProcessId
=
processIdFunc
;
}
}
...
@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Http
// write request headers
// write request headers
foreach
(
var
header
in
Request
.
Headers
)
foreach
(
var
header
in
Request
.
Headers
)
{
{
if
(
isTransparent
||
header
.
Name
!=
KnownHeaders
.
ProxyAuthorization
)
if
(
isTransparent
||
header
.
Name
!=
KnownHeaders
.
ProxyAuthorization
.
String
)
{
{
headerBuilder
.
WriteHeader
(
header
);
headerBuilder
.
WriteHeader
(
header
);
}
}
...
...
src/Titanium.Web.Proxy/Http/KnownHeader.cs
0 → 100644
View file @
1b0bfecd
using
System
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Http
{
public
class
KnownHeader
{
internal
ByteString
String8
;
public
string
String
;
private
KnownHeader
(
string
str
)
{
String8
=
(
ByteString
)
str
;
String
=
str
;
}
public
override
string
ToString
()
{
return
String
;
}
internal
bool
Equals
(
ReadOnlySpan
<
char
>
value
)
{
return
String
.
AsSpan
().
EqualsIgnoreCase
(
value
);
}
public
static
implicit
operator
KnownHeader
(
string
str
)
=>
new
KnownHeader
(
str
);
}
}
src/Titanium.Web.Proxy/Http/KnownHeaders.cs
View file @
1b0bfecd
...
@@ -6,46 +6,46 @@
...
@@ -6,46 +6,46 @@
public
static
class
KnownHeaders
public
static
class
KnownHeaders
{
{
// Both
// Both
public
const
string
Connection
=
"Connection"
;
public
static
KnownHeader
Connection
=
"Connection"
;
public
const
string
ConnectionClose
=
"close"
;
public
static
KnownHeader
ConnectionClose
=
"close"
;
public
const
string
ConnectionKeepAlive
=
"keep-alive"
;
public
static
KnownHeader
ConnectionKeepAlive
=
"keep-alive"
;
public
const
string
ContentLength
=
"Content-Length"
;
public
static
KnownHeader
ContentLength
=
"Content-Length"
;
public
const
string
ContentType
=
"Content-Type"
;
public
static
KnownHeader
ContentType
=
"Content-Type"
;
public
const
string
ContentTypeCharset
=
"charset"
;
public
static
KnownHeader
ContentTypeCharset
=
"charset"
;
public
const
string
ContentTypeBoundary
=
"boundary"
;
public
static
KnownHeader
ContentTypeBoundary
=
"boundary"
;
public
const
string
Upgrade
=
"Upgrade"
;
public
static
KnownHeader
Upgrade
=
"Upgrade"
;
public
const
string
UpgradeWebsocket
=
"websocket"
;
public
static
KnownHeader
UpgradeWebsocket
=
"websocket"
;
// Request headers
// Request headers
public
const
string
AcceptEncoding
=
"Accept-Encoding"
;
public
static
KnownHeader
AcceptEncoding
=
"Accept-Encoding"
;
public
const
string
Authorization
=
"Authorization"
;
public
static
KnownHeader
Authorization
=
"Authorization"
;
public
const
string
Expect
=
"Expect"
;
public
static
KnownHeader
Expect
=
"Expect"
;
public
const
string
Expect100Continue
=
"100-continue"
;
public
static
KnownHeader
Expect100Continue
=
"100-continue"
;
public
const
string
Host
=
"Host"
;
public
static
KnownHeader
Host
=
"Host"
;
public
const
string
ProxyAuthorization
=
"Proxy-Authorization"
;
public
static
KnownHeader
ProxyAuthorization
=
"Proxy-Authorization"
;
public
const
string
ProxyAuthorizationBasic
=
"basic"
;
public
static
KnownHeader
ProxyAuthorizationBasic
=
"basic"
;
public
const
string
ProxyConnection
=
"Proxy-Connection"
;
public
static
KnownHeader
ProxyConnection
=
"Proxy-Connection"
;
public
const
string
ProxyConnectionClose
=
"close"
;
public
static
KnownHeader
ProxyConnectionClose
=
"close"
;
// Response headers
// Response headers
public
const
string
ContentEncoding
=
"Content-Encoding"
;
public
static
KnownHeader
ContentEncoding
=
"Content-Encoding"
;
public
const
string
ContentEncodingDeflate
=
"deflate"
;
public
static
KnownHeader
ContentEncodingDeflate
=
"deflate"
;
public
const
string
ContentEncodingGzip
=
"gzip"
;
public
static
KnownHeader
ContentEncodingGzip
=
"gzip"
;
public
const
string
ContentEncodingBrotli
=
"br"
;
public
static
KnownHeader
ContentEncodingBrotli
=
"br"
;
public
const
string
Location
=
"Location"
;
public
static
KnownHeader
Location
=
"Location"
;
public
const
string
ProxyAuthenticate
=
"Proxy-Authenticate"
;
public
static
KnownHeader
ProxyAuthenticate
=
"Proxy-Authenticate"
;
public
const
string
TransferEncoding
=
"Transfer-Encoding"
;
public
static
KnownHeader
TransferEncoding
=
"Transfer-Encoding"
;
public
const
string
TransferEncodingChunked
=
"chunked"
;
public
static
KnownHeader
TransferEncodingChunked
=
"chunked"
;
}
}
}
}
\ No newline at end of file
src/Titanium.Web.Proxy/Http/Request.cs
View file @
1b0bfecd
...
@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Http
public
bool
IsHttps
=>
RequestUri
.
Scheme
==
ProxyServer
.
UriSchemeHttps
;
public
bool
IsHttps
=>
RequestUri
.
Scheme
==
ProxyServer
.
UriSchemeHttps
;
private
ByteString
originalUrlData
;
private
ByteString
originalUrlData
;
private
ByteString
u
rlData
;
private
protected
ByteString
U
rlData
;
internal
ByteString
OriginalUrlData
internal
ByteString
OriginalUrlData
{
{
...
@@ -33,10 +33,14 @@ namespace Titanium.Web.Proxy.Http
...
@@ -33,10 +33,14 @@ namespace Titanium.Web.Proxy.Http
set
set
{
{
originalUrlData
=
value
;
originalUrlData
=
value
;
u
rlData
=
value
;
U
rlData
=
value
;
}
}
}
}
internal
string
Scheme
{
get
;
set
;
}
=
ProxyServer
.
UriSchemeHttp
;
internal
string
?
Hostname
{
get
;
set
;
}
/// <summary>
/// <summary>
/// The original request Url.
/// The original request Url.
/// </summary>
/// </summary>
...
@@ -45,15 +49,45 @@ namespace Titanium.Web.Proxy.Http
...
@@ -45,15 +49,45 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Request HTTP Uri.
/// Request HTTP Uri.
/// </summary>
/// </summary>
public
Uri
RequestUri
{
get
;
set
;
}
public
Uri
RequestUri
{
get
{
string
url
;
if
(
startsWithUriScheme
(
UrlData
))
{
url
=
UrlData
.
GetString
();
}
else
{
string
?
host
=
Host
??
Hostname
;
string
?
hostAndPath
=
host
;
if
(
UrlData
.
Length
>
0
&&
UrlData
[
0
]
==
'/'
)
{
hostAndPath
+=
UrlData
.
GetString
();
}
url
=
string
.
Concat
(
Scheme
==
ProxyServer
.
UriSchemeHttps
?
"https://"
:
"http://"
,
hostAndPath
);
}
try
{
return
new
Uri
(
url
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
url
}
'"
,
ex
);
}
}
}
/// <summary>
/// <summary>
/// The request url as it is in the HTTP header
/// The request url as it is in the HTTP header
/// </summary>
/// </summary>
public
string
Url
public
string
Url
{
{
get
=>
u
rlData
.
GetString
();
get
=>
U
rlData
.
GetString
();
set
=>
u
rlData
=
value
.
GetByteString
();
set
=>
U
rlData
=
value
.
GetByteString
();
}
}
[
Obsolete
(
"This property is obsolete. Use Url property instead"
)]
[
Obsolete
(
"This property is obsolete. Use Url property instead"
)]
...
@@ -142,7 +176,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -142,7 +176,7 @@ namespace Titanium.Web.Proxy.Http
return
false
;
return
false
;
}
}
return
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
UpgradeWebsocket
);
return
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
UpgradeWebsocket
.
String
);
}
}
}
}
...
@@ -256,5 +290,46 @@ namespace Titanium.Web.Proxy.Http
...
@@ -256,5 +290,46 @@ namespace Titanium.Web.Proxy.Http
return
true
;
return
true
;
}
}
private
bool
startsWithUriScheme
(
ByteString
str
)
{
if
(
str
.
Length
<
3
)
{
return
false
;
}
// regex: "^[a-z]*://"
int
i
;
for
(
i
=
0
;
i
<
str
.
Length
-
3
;
i
++)
{
byte
ch
=
str
[
i
];
if
(
ch
==
':'
)
{
break
;
}
if
(
ch
<
'A'
||
ch
>
'z'
||
(
ch
>
'Z'
&&
ch
<
'a'
))
// ASCII letter
{
return
false
;
}
}
if
(
str
[
i
++]
!=
':'
)
{
return
false
;
}
if
(
str
[
i
++]
!=
'/'
)
{
return
false
;
}
if
(
str
[
i
]
!=
'/'
)
{
return
false
;
}
return
true
;
}
}
}
}
}
src/Titanium.Web.Proxy/Http/RequestResponseBase.cs
View file @
1b0bfecd
...
@@ -142,7 +142,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -142,7 +142,7 @@ namespace Titanium.Web.Proxy.Http
get
get
{
{
string
?
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
string
?
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
.
String
);
}
}
set
set
...
@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.Http
/// <param name="encodingType"></param>
/// <param name="encodingType"></param>
/// <param name="body"></param>
/// <param name="body"></param>
/// <returns></returns>
/// <returns></returns>
internal
byte
[]
GetCompressedBody
(
string
encodingType
,
byte
[]
body
)
internal
byte
[]
GetCompressedBody
(
HttpCompression
encodingType
,
byte
[]
body
)
{
{
using
(
var
ms
=
new
MemoryStream
())
using
(
var
ms
=
new
MemoryStream
())
{
{
...
@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Http
var
body
=
Body
;
var
body
=
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
body
=
GetCompressedBody
(
CompressionUtil
.
CompressionNameToEnum
(
contentEncoding
)
,
body
);
if
(
isChunked
==
false
)
if
(
isChunked
==
false
)
{
{
...
...
src/Titanium.Web.Proxy/Http/Response.cs
View file @
1b0bfecd
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Http
if
(
headerValue
!=
null
)
if
(
headerValue
!=
null
)
{
{
if
(
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
ConnectionClose
))
if
(
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
ConnectionClose
.
String
))
{
{
return
false
;
return
false
;
}
}
...
...
src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs
View file @
1b0bfecd
...
@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
...
@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
public
class
DynamicTable
public
class
DynamicTable
{
{
// a circular queue of header fields
// a circular queue of header fields
HttpHeader
?[]
headerFields
;
HttpHeader
[]
headerFields
=
Array
.
Empty
<
HttpHeader
>()
;
int
head
;
int
head
;
int
tail
;
int
tail
;
...
...
src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs
View file @
1b0bfecd
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
private
const
int
bucketSize
=
17
;
private
const
int
bucketSize
=
17
;
// a linked hash map of header fields
// a linked hash map of header fields
private
readonly
HeaderEntry
?
[]
headerFields
=
new
HeaderEntry
[
bucketSize
];
private
readonly
HeaderEntry
[]
headerFields
=
new
HeaderEntry
[
bucketSize
];
private
readonly
HeaderEntry
head
=
new
HeaderEntry
(-
1
,
ByteString
.
Empty
,
ByteString
.
Empty
,
int
.
MaxValue
,
null
);
private
readonly
HeaderEntry
head
=
new
HeaderEntry
(-
1
,
ByteString
.
Empty
,
ByteString
.
Empty
,
int
.
MaxValue
,
null
);
private
int
size
;
private
int
size
;
...
@@ -337,7 +337,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
...
@@ -337,7 +337,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int
h
=
hash
(
name
);
int
h
=
hash
(
name
);
int
i
=
Encoder
.
index
(
h
);
int
i
=
Encoder
.
index
(
h
);
int
index
=
-
1
;
int
index
=
-
1
;
for
(
var
e
=
headerFields
[
i
];
e
!=
null
;
e
=
e
.
Next
)
for
(
HeaderEntry
?
e
=
headerFields
[
i
];
e
!=
null
;
e
=
e
.
Next
)
{
{
if
(
e
.
Hash
==
h
&&
name
.
Equals
(
e
.
NameData
))
if
(
e
.
Hash
==
h
&&
name
.
Equals
(
e
.
NameData
))
{
{
...
@@ -521,6 +521,8 @@ namespace Titanium.Web.Proxy.Http2.Hpack
...
@@ -521,6 +521,8 @@ namespace Titanium.Web.Proxy.Http2.Hpack
Index
=
index
;
Index
=
index
;
Hash
=
hash
;
Hash
=
hash
;
Next
=
next
;
Next
=
next
;
Before
=
this
;
After
=
this
;
}
}
/// <summary>
/// <summary>
...
...
src/Titanium.Web.Proxy/Http2/Http2FrameHeader.cs
View file @
1b0bfecd
...
@@ -10,12 +10,9 @@
...
@@ -10,12 +10,9 @@
public
int
StreamId
;
public
int
StreamId
;
public
byte
[]
Buffer
;
public
void
CopyToBuffer
(
byte
[]
buf
)
public
byte
[]
CopyToBuffer
()
{
{
int
length
=
Length
;
int
length
=
Length
;
var
buf
=
/*new byte[9];*/
Buffer
;
buf
[
0
]
=
(
byte
)((
length
>>
16
)
&
0xff
);
buf
[
0
]
=
(
byte
)((
length
>>
16
)
&
0xff
);
buf
[
1
]
=
(
byte
)((
length
>>
8
)
&
0xff
);
buf
[
1
]
=
(
byte
)((
length
>>
8
)
&
0xff
);
buf
[
2
]
=
(
byte
)(
length
&
0xff
);
buf
[
2
]
=
(
byte
)(
length
&
0xff
);
...
@@ -26,7 +23,6 @@
...
@@ -26,7 +23,6 @@
//buf[6] = (byte)((streamId >> 16) & 0xff);
//buf[6] = (byte)((streamId >> 16) & 0xff);
//buf[7] = (byte)((streamId >> 8) & 0xff);
//buf[7] = (byte)((streamId >> 8) & 0xff);
//buf[8] = (byte)(streamId & 0xff);
//buf[8] = (byte)(streamId & 0xff);
return
buf
;
}
}
}
}
}
}
src/Titanium.Web.Proxy/Http2/Http2Helper.cs
View file @
1b0bfecd
...
@@ -70,11 +70,10 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -70,11 +70,10 @@ namespace Titanium.Web.Proxy.Http2
Decoder
?
decoder
=
null
;
Decoder
?
decoder
=
null
;
var
frameHeader
=
new
Http2FrameHeader
();
var
frameHeader
=
new
Http2FrameHeader
();
frameHeader
.
Buffer
=
new
byte
[
9
];
var
frameHeader
Buffer
=
new
byte
[
9
];
byte
[]?
buffer
=
null
;
byte
[]?
buffer
=
null
;
while
(
true
)
while
(
true
)
{
{
var
frameHeaderBuffer
=
frameHeader
.
Buffer
;
int
read
=
await
forceRead
(
input
,
frameHeaderBuffer
,
0
,
9
,
cancellationToken
);
int
read
=
await
forceRead
(
input
,
frameHeaderBuffer
,
0
,
9
,
cancellationToken
);
if
(
read
!=
9
)
if
(
read
!=
9
)
{
{
...
@@ -265,8 +264,10 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -265,8 +264,10 @@ namespace Titanium.Web.Proxy.Http2
request
.
HttpVersion
=
HttpVersion
.
Version20
;
request
.
HttpVersion
=
HttpVersion
.
Version20
;
request
.
Method
=
method
.
GetString
();
request
.
Method
=
method
.
GetString
();
request
.
OriginalUrlData
=
path
;
request
.
OriginalUrlData
=
path
;
request
.
Scheme
=
headerListener
.
Scheme
;
request
.
Hostname
=
headerListener
.
Authority
.
GetString
();
request
.
RequestUri
=
headerListener
.
GetUri
();
//
request.RequestUri = headerListener.GetUri();
}
}
else
else
{
{
...
@@ -302,7 +303,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -302,7 +303,7 @@ namespace Titanium.Web.Proxy.Http2
{
{
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
null
;
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
null
;
tcs
.
SetResult
(
true
);
tcs
.
SetResult
(
true
);
await
sendHeader
(
remoteSettings
,
frameHeader
,
rr
,
endStream
,
output
,
args
.
IsPromise
);
await
sendHeader
(
remoteSettings
,
frameHeader
,
frameHeaderBuffer
,
rr
,
endStream
,
output
,
args
.
IsPromise
);
}
}
else
else
{
{
...
@@ -379,7 +380,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -379,7 +380,7 @@ namespace Titanium.Web.Proxy.Http2
using
(
var
ms
=
new
MemoryStream
())
using
(
var
ms
=
new
MemoryStream
())
{
{
using
(
var
zip
=
using
(
var
zip
=
DecompressionFactory
.
Create
(
rr
.
ContentEncoding
,
new
MemoryStream
(
body
)))
DecompressionFactory
.
Create
(
CompressionUtil
.
CompressionNameToEnum
(
rr
.
ContentEncoding
)
,
new
MemoryStream
(
body
)))
{
{
zip
.
CopyTo
(
ms
);
zip
.
CopyTo
(
ms
);
}
}
...
@@ -413,7 +414,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -413,7 +414,7 @@ namespace Titanium.Web.Proxy.Http2
breakpoint
();
breakpoint
();
}
}
await
sendBody
(
remoteSettings
,
rr
,
frameHeader
,
buffer
,
output
);
await
sendBody
(
remoteSettings
,
rr
,
frameHeader
,
frameHeaderBuffer
,
buffer
,
output
);
}
}
if
(!
isClient
&&
endStream
)
if
(!
isClient
&&
endStream
)
...
@@ -425,8 +426,8 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -425,8 +426,8 @@ namespace Titanium.Web.Proxy.Http2
if
(
sendPacket
)
if
(
sendPacket
)
{
{
// do not cancel the write operation
// do not cancel the write operation
var
buf
=
frameHeader
.
CopyToBuffer
(
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
length
/*, cancellationToken*/
);
}
}
...
@@ -450,7 +451,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -450,7 +451,7 @@ namespace Titanium.Web.Proxy.Http2
;
;
}
}
private
static
async
Task
sendHeader
(
Http2Settings
settings
,
Http2FrameHeader
frameHeader
,
RequestResponseBase
rr
,
bool
endStream
,
Stream
output
,
bool
pushPromise
)
private
static
async
Task
sendHeader
(
Http2Settings
settings
,
Http2FrameHeader
frameHeader
,
byte
[]
frameHeaderBuffer
,
RequestResponseBase
rr
,
bool
endStream
,
Stream
output
,
bool
pushPromise
)
{
{
var
encoder
=
new
Encoder
(
settings
.
HeaderTableSize
);
var
encoder
=
new
Encoder
(
settings
.
HeaderTableSize
);
var
ms
=
new
MemoryStream
();
var
ms
=
new
MemoryStream
();
...
@@ -507,15 +508,15 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -507,15 +508,15 @@ namespace Titanium.Web.Proxy.Http2
//headerBuffer[4] = (byte)(flags & ~((int)Http2FrameFlag.Padded));
//headerBuffer[4] = (byte)(flags & ~((int)Http2FrameFlag.Padded));
// send the header
// send the header
var
buf
=
frameHeader
.
CopyToBuffer
(
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
data
,
0
,
data
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
data
,
0
,
data
.
Length
/*, cancellationToken*/
);
}
}
private
static
async
Task
sendBody
(
Http2Settings
settings
,
RequestResponseBase
rr
,
Http2FrameHeader
frameHeader
,
byte
[]
buffer
,
Stream
output
)
private
static
async
Task
sendBody
(
Http2Settings
settings
,
RequestResponseBase
rr
,
Http2FrameHeader
frameHeader
,
byte
[]
frameHeaderBuffer
,
byte
[]
buffer
,
Stream
output
)
{
{
var
body
=
rr
.
CompressBodyAndUpdateContentLength
();
var
body
=
rr
.
CompressBodyAndUpdateContentLength
();
await
sendHeader
(
settings
,
frameHeader
,
rr
,
!(
rr
.
HasBody
&&
rr
.
IsBodyRead
),
output
,
false
);
await
sendHeader
(
settings
,
frameHeader
,
frameHeaderBuffer
,
rr
,
!(
rr
.
HasBody
&&
rr
.
IsBodyRead
),
output
,
false
);
if
(
rr
.
HasBody
&&
rr
.
IsBodyRead
)
if
(
rr
.
HasBody
&&
rr
.
IsBodyRead
)
{
{
...
@@ -530,8 +531,8 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -530,8 +531,8 @@ namespace Titanium.Web.Proxy.Http2
frameHeader
.
Type
=
Http2FrameType
.
Data
;
frameHeader
.
Type
=
Http2FrameType
.
Data
;
frameHeader
.
Flags
=
pos
<
body
.
Length
?
(
Http2FrameFlag
)
0
:
Http2FrameFlag
.
EndStream
;
frameHeader
.
Flags
=
pos
<
body
.
Length
?
(
Http2FrameFlag
)
0
:
Http2FrameFlag
.
EndStream
;
var
buf
=
frameHeader
.
CopyToBuffer
(
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
bodyFrameLength
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
bodyFrameLength
/*, cancellationToken*/
);
}
}
}
}
...
@@ -571,18 +572,40 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -571,18 +572,40 @@ namespace Titanium.Web.Proxy.Http2
class
MyHeaderListener
:
IHeaderListener
class
MyHeaderListener
:
IHeaderListener
{
{
private
static
ByteString
SchemeHttp
=
(
ByteString
)
ProxyServer
.
UriSchemeHttp
;
private
static
ByteString
SchemeHttps
=
(
ByteString
)
ProxyServer
.
UriSchemeHttps
;
private
readonly
Action
<
ByteString
,
ByteString
>
addHeaderFunc
;
private
readonly
Action
<
ByteString
,
ByteString
>
addHeaderFunc
;
public
ByteString
Method
{
get
;
private
set
;
}
public
ByteString
Method
{
get
;
private
set
;
}
public
ByteString
Status
{
get
;
private
set
;
}
public
ByteString
Status
{
get
;
private
set
;
}
p
rivate
ByteString
authority
;
p
ublic
ByteString
Authority
{
get
;
private
set
;
}
private
ByteString
scheme
;
private
ByteString
scheme
;
public
ByteString
Path
{
get
;
private
set
;
}
public
ByteString
Path
{
get
;
private
set
;
}
public
string
Scheme
{
get
{
if
(
scheme
.
Equals
(
SchemeHttp
))
{
return
ProxyServer
.
UriSchemeHttp
;
}
if
(
scheme
.
Equals
(
SchemeHttps
))
{
return
ProxyServer
.
UriSchemeHttps
;
}
return
string
.
Empty
;
}
}
public
MyHeaderListener
(
Action
<
ByteString
,
ByteString
>
addHeaderFunc
)
public
MyHeaderListener
(
Action
<
ByteString
,
ByteString
>
addHeaderFunc
)
{
{
this
.
addHeaderFunc
=
addHeaderFunc
;
this
.
addHeaderFunc
=
addHeaderFunc
;
...
@@ -599,7 +622,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -599,7 +622,7 @@ namespace Titanium.Web.Proxy.Http2
Method
=
value
;
Method
=
value
;
return
;
return
;
case
":authority"
:
case
":authority"
:
a
uthority
=
value
;
A
uthority
=
value
;
return
;
return
;
case
":scheme"
:
case
":scheme"
:
scheme
=
value
;
scheme
=
value
;
...
@@ -618,20 +641,20 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -618,20 +641,20 @@ namespace Titanium.Web.Proxy.Http2
public
Uri
GetUri
()
public
Uri
GetUri
()
{
{
if
(
a
uthority
.
Length
==
0
)
if
(
A
uthority
.
Length
==
0
)
{
{
// todo
// todo
a
uthority
=
HttpHeader
.
Encoding
.
GetBytes
(
"abc.abc"
);
A
uthority
=
HttpHeader
.
Encoding
.
GetBytes
(
"abc.abc"
);
}
}
var
bytes
=
new
byte
[
scheme
.
Length
+
3
+
a
uthority
.
Length
+
Path
.
Length
];
var
bytes
=
new
byte
[
scheme
.
Length
+
3
+
A
uthority
.
Length
+
Path
.
Length
];
scheme
.
Span
.
CopyTo
(
bytes
);
scheme
.
Span
.
CopyTo
(
bytes
);
int
idx
=
scheme
.
Length
;
int
idx
=
scheme
.
Length
;
bytes
[
idx
++]
=
(
byte
)
':'
;
bytes
[
idx
++]
=
(
byte
)
':'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
authority
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
a
uthority
.
Length
));
Authority
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
A
uthority
.
Length
));
idx
+=
a
uthority
.
Length
;
idx
+=
A
uthority
.
Length
;
Path
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
Path
.
Length
));
Path
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
Path
.
Length
));
return
new
Uri
(
HttpHeader
.
Encoding
.
GetString
(
bytes
));
return
new
Uri
(
HttpHeader
.
Encoding
.
GetString
(
bytes
));
...
...
src/Titanium.Web.Proxy/Models/ByteString.cs
View file @
1b0bfecd
...
@@ -38,5 +38,10 @@ namespace Titanium.Web.Proxy.Models
...
@@ -38,5 +38,10 @@ namespace Titanium.Web.Proxy.Models
public
static
implicit
operator
ByteString
(
byte
[]
data
)
=>
new
ByteString
(
data
);
public
static
implicit
operator
ByteString
(
byte
[]
data
)
=>
new
ByteString
(
data
);
public
static
implicit
operator
ByteString
(
ReadOnlyMemory
<
byte
>
data
)
=>
new
ByteString
(
data
);
public
static
implicit
operator
ByteString
(
ReadOnlyMemory
<
byte
>
data
)
=>
new
ByteString
(
data
);
public
byte
this
[
int
i
]
{
get
=>
Span
[
i
];
}
}
}
}
}
src/Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
1b0bfecd
...
@@ -41,6 +41,10 @@ namespace Titanium.Web.Proxy.Models
...
@@ -41,6 +41,10 @@ namespace Titanium.Web.Proxy.Models
internal
static
readonly
HttpHeader
ProxyConnectionKeepAlive
=
new
HttpHeader
(
"Proxy-Connection"
,
"keep-alive"
);
internal
static
readonly
HttpHeader
ProxyConnectionKeepAlive
=
new
HttpHeader
(
"Proxy-Connection"
,
"keep-alive"
);
private
string
?
nameString
;
private
string
?
valueString
;
/// <summary>
/// <summary>
/// Initialize a new instance.
/// Initialize a new instance.
/// </summary>
/// </summary>
...
@@ -53,8 +57,29 @@ namespace Titanium.Web.Proxy.Models
...
@@ -53,8 +57,29 @@ namespace Titanium.Web.Proxy.Models
throw
new
Exception
(
"Name cannot be null or empty"
);
throw
new
Exception
(
"Name cannot be null or empty"
);
}
}
NameData
=
name
.
Trim
().
GetByteString
();
nameString
=
name
.
Trim
();
ValueData
=
value
.
Trim
().
GetByteString
();
NameData
=
nameString
.
GetByteString
();
valueString
=
value
.
Trim
();
ValueData
=
valueString
.
GetByteString
();
}
internal
HttpHeader
(
KnownHeader
name
,
string
value
)
{
nameString
=
name
.
String
;
NameData
=
name
.
String8
;
valueString
=
value
.
Trim
();
ValueData
=
valueString
.
GetByteString
();
}
internal
HttpHeader
(
KnownHeader
name
,
KnownHeader
value
)
{
nameString
=
name
.
String
;
NameData
=
name
.
String8
;
valueString
=
value
.
String
;
ValueData
=
value
.
String8
;
}
}
internal
HttpHeader
(
ByteString
name
,
ByteString
value
)
internal
HttpHeader
(
ByteString
name
,
ByteString
value
)
...
@@ -78,16 +103,16 @@ namespace Titanium.Web.Proxy.Models
...
@@ -78,16 +103,16 @@ namespace Titanium.Web.Proxy.Models
/// <summary>
/// <summary>
/// Header Name.
/// Header Name.
/// </summary>
/// </summary>
public
string
Name
=>
NameData
.
GetString
();
public
string
Name
=>
nameString
??=
NameData
.
GetString
();
internal
ByteString
NameData
{
get
;
}
internal
ByteString
NameData
{
get
;
}
/// <summary>
/// <summary>
/// Header Value.
/// Header Value.
/// </summary>
/// </summary>
public
string
Value
=>
ValueData
.
GetString
();
public
string
Value
=>
valueString
??=
ValueData
.
GetString
();
internal
ByteString
ValueData
{
get
;
set
;
}
internal
ByteString
ValueData
{
get
;
private
set
;
}
public
int
Size
=>
Name
.
Length
+
Value
.
Length
+
HttpHeaderOverhead
;
public
int
Size
=>
Name
.
Length
+
Value
.
Length
+
HttpHeaderOverhead
;
...
@@ -96,6 +121,18 @@ namespace Titanium.Web.Proxy.Models
...
@@ -96,6 +121,18 @@ namespace Titanium.Web.Proxy.Models
return
name
.
Length
+
value
.
Length
+
HttpHeaderOverhead
;
return
name
.
Length
+
value
.
Length
+
HttpHeaderOverhead
;
}
}
internal
void
SetValue
(
string
value
)
{
valueString
=
value
;
ValueData
=
value
.
GetByteString
();
}
internal
void
SetValue
(
KnownHeader
value
)
{
valueString
=
value
.
String
;
ValueData
=
value
.
String8
;
}
/// <summary>
/// <summary>
/// Returns header as a valid header string.
/// Returns header as a valid header string.
/// </summary>
/// </summary>
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
1b0bfecd
...
@@ -372,7 +372,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -372,7 +372,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if
(
useUpstreamProxy
&&
(
isConnect
||
isHttps
))
if
(
useUpstreamProxy
&&
(
isConnect
||
isHttps
))
{
{
var
writer
=
new
HttpRequestWriter
(
stream
,
proxyServer
.
BufferPool
);
var
writer
=
new
HttpRequestWriter
(
stream
,
proxyServer
.
BufferPool
);
var
connectRequest
=
new
ConnectRequest
var
connectRequest
=
new
ConnectRequest
(
remoteHostName
)
{
{
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
$"
{
remoteHostName
}
:
{
remotePort
}
"
),
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
$"
{
remoteHostName
}
:
{
remotePort
}
"
),
HttpVersion
=
httpVersion
HttpVersion
=
httpVersion
...
...
src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
1b0bfecd
...
@@ -52,7 +52,7 @@ namespace Titanium.Web.Proxy
...
@@ -52,7 +52,7 @@ namespace Titanium.Web.Proxy
if
(
ProxyBasicAuthenticateFunc
!=
null
)
if
(
ProxyBasicAuthenticateFunc
!=
null
)
{
{
return
await
authenticateUserBasic
(
session
,
authenticationType
,
credentials
);
return
await
authenticateUserBasic
(
session
,
authenticationType
,
credentials
,
ProxyBasicAuthenticateFunc
);
}
}
if
(
ProxySchemeAuthenticateFunc
!=
null
)
if
(
ProxySchemeAuthenticateFunc
!=
null
)
...
@@ -82,9 +82,11 @@ namespace Titanium.Web.Proxy
...
@@ -82,9 +82,11 @@ namespace Titanium.Web.Proxy
}
}
}
}
private
async
Task
<
bool
>
authenticateUserBasic
(
SessionEventArgsBase
session
,
ReadOnlyMemory
<
char
>
authenticationType
,
ReadOnlyMemory
<
char
>
credentials
)
private
async
Task
<
bool
>
authenticateUserBasic
(
SessionEventArgsBase
session
,
ReadOnlyMemory
<
char
>
authenticationType
,
ReadOnlyMemory
<
char
>
credentials
,
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
bool
>>
proxyBasicAuthenticateFunc
)
{
{
if
(!
authenticationType
.
Span
.
EqualsIgnoreCase
(
KnownHeaders
.
ProxyAuthorizationBasic
.
AsSpan
()
))
if
(!
KnownHeaders
.
ProxyAuthorizationBasic
.
Equals
(
authenticationType
.
Span
))
{
{
// Return not authorized
// Return not authorized
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
...
@@ -102,7 +104,7 @@ namespace Titanium.Web.Proxy
...
@@ -102,7 +104,7 @@ namespace Titanium.Web.Proxy
string
username
=
decoded
.
Substring
(
0
,
colonIndex
);
string
username
=
decoded
.
Substring
(
0
,
colonIndex
);
string
password
=
decoded
.
Substring
(
colonIndex
+
1
);
string
password
=
decoded
.
Substring
(
colonIndex
+
1
);
bool
authenticated
=
await
P
roxyBasicAuthenticateFunc
(
session
,
username
,
password
);
bool
authenticated
=
await
p
roxyBasicAuthenticateFunc
(
session
,
username
,
password
);
if
(!
authenticated
)
if
(!
authenticated
)
{
{
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
...
...
src/Titanium.Web.Proxy/ProxyServer.cs
View file @
1b0bfecd
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// <summary>
/// Backing field for exposed public property.
/// Backing field for exposed public property.
/// </summary>
/// </summary>
private
ExceptionHandler
exceptionFunc
;
private
ExceptionHandler
?
exceptionFunc
;
/// <summary>
/// <summary>
/// Backing field for exposed public property.
/// Backing field for exposed public property.
...
@@ -291,14 +291,14 @@ namespace Titanium.Web.Proxy
...
@@ -291,14 +291,14 @@ namespace Titanium.Web.Proxy
/// Parameters are username and password as provided by client.
/// Parameters are username and password as provided by client.
/// Should return true for successful authentication.
/// Should return true for successful authentication.
/// </summary>
/// </summary>
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
bool
>>
ProxyBasicAuthenticateFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
bool
>>
?
ProxyBasicAuthenticateFunc
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc.
/// A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc.
/// Parameters are current working session, schemeType, and token as provided by a calling client.
/// Parameters are current working session, schemeType, and token as provided by a calling client.
/// Should return success for successful authentication, continuation if the package requests, or failure.
/// Should return success for successful authentication, continuation if the package requests, or failure.
/// </summary>
/// </summary>
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
ProxyAuthenticationContext
>>
ProxySchemeAuthenticateFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
ProxyAuthenticationContext
>>
?
ProxySchemeAuthenticateFunc
{
get
;
set
;
}
/// <summary>
/// <summary>
/// A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required.
/// A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required.
...
@@ -707,7 +707,7 @@ namespace Titanium.Web.Proxy
...
@@ -707,7 +707,7 @@ namespace Titanium.Web.Proxy
/// <returns>The external proxy as task result.</returns>
/// <returns>The external proxy as task result.</returns>
private
Task
<
ExternalProxy
?>
getSystemUpStreamProxy
(
SessionEventArgsBase
sessionEventArgs
)
private
Task
<
ExternalProxy
?>
getSystemUpStreamProxy
(
SessionEventArgsBase
sessionEventArgs
)
{
{
var
proxy
=
systemProxyResolver
.
GetProxy
(
sessionEventArgs
.
HttpClient
.
Request
.
RequestUri
);
var
proxy
=
systemProxyResolver
!
.
GetProxy
(
sessionEventArgs
.
HttpClient
.
Request
.
RequestUri
);
return
Task
.
FromResult
(
proxy
);
return
Task
.
FromResult
(
proxy
);
}
}
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
1b0bfecd
...
@@ -33,15 +33,11 @@ namespace Titanium.Web.Proxy
...
@@ -33,15 +33,11 @@ namespace Titanium.Web.Proxy
/// <param name="clientStream">The client stream.</param>
/// <param name="clientStream">The client stream.</param>
/// <param name="clientStreamWriter">The client stream writer.</param>
/// <param name="clientStreamWriter">The client stream writer.</param>
/// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
/// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
/// <param name="httpsConnectHostname">
/// The https hostname as appeared in CONNECT request if this is a HTTPS request from
/// explicit endpoint.
/// </param>
/// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
/// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
private
async
Task
handleHttpSessionRequest
(
ProxyEndPoint
endPoint
,
TcpClientConnection
clientConnection
,
private
async
Task
handleHttpSessionRequest
(
ProxyEndPoint
endPoint
,
TcpClientConnection
clientConnection
,
CustomBufferedStream
clientStream
,
HttpResponseWriter
clientStreamWriter
,
CustomBufferedStream
clientStream
,
HttpResponseWriter
clientStreamWriter
,
CancellationTokenSource
cancellationTokenSource
,
string
?
httpsConnectHostname
,
TunnelConnectSessionEventArgs
?
connectArgs
,
CancellationTokenSource
cancellationTokenSource
,
TunnelConnectSessionEventArgs
?
connectArgs
=
null
,
Task
<
TcpServerConnection
>?
prefetchConnectionTask
=
null
)
Task
<
TcpServerConnection
>?
prefetchConnectionTask
=
null
)
{
{
var
connectRequest
=
connectArgs
?.
HttpClient
.
ConnectRequest
;
var
connectRequest
=
connectArgs
?.
HttpClient
.
ConnectRequest
;
...
@@ -85,41 +81,13 @@ namespace Titanium.Web.Proxy
...
@@ -85,41 +81,13 @@ namespace Titanium.Web.Proxy
await
HeaderParser
.
ReadHeaders
(
clientStream
,
args
.
HttpClient
.
Request
.
Headers
,
await
HeaderParser
.
ReadHeaders
(
clientStream
,
args
.
HttpClient
.
Request
.
Headers
,
cancellationToken
);
cancellationToken
);
Uri
httpRemoteUri
;
var
request
=
args
.
HttpClient
.
Request
;
if
(
ProxyConstants
.
UriSchemeRegex
.
IsMatch
(
httpUrl
)
)
if
(
connectRequest
!=
null
)
{
{
try
request
.
Scheme
=
connectRequest
.
Scheme
;
{
request
.
Hostname
=
connectRequest
.
Hostname
;
httpRemoteUri
=
new
Uri
(
httpUrl
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
httpUrl
}
'"
,
ex
);
}
}
}
else
{
string
?
host
=
args
.
HttpClient
.
Request
.
Host
??
httpsConnectHostname
;
string
?
hostAndPath
=
host
;
if
(
httpUrl
.
StartsWith
(
"/"
))
{
hostAndPath
+=
httpUrl
;
}
string
url
=
string
.
Concat
(
httpsConnectHostname
==
null
?
"http://"
:
"https://"
,
hostAndPath
);
try
{
httpRemoteUri
=
new
Uri
(
url
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
url
}
'"
,
ex
);
}
}
var
request
=
args
.
HttpClient
.
Request
;
request
.
RequestUri
=
httpRemoteUri
;
request
.
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
httpUrl
);
request
.
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
httpUrl
);
request
.
Method
=
httpMethod
;
request
.
Method
=
httpMethod
;
...
@@ -128,7 +96,7 @@ namespace Titanium.Web.Proxy
...
@@ -128,7 +96,7 @@ namespace Titanium.Web.Proxy
if
(!
args
.
IsTransparent
)
if
(!
args
.
IsTransparent
)
{
{
// proxy authorization check
// proxy authorization check
if
(
httpsConnectHostname
==
null
&&
await
checkAuthorization
(
args
)
==
false
)
if
(
connectRequest
==
null
&&
await
checkAuthorization
(
args
)
==
false
)
{
{
await
onBeforeResponse
(
args
);
await
onBeforeResponse
(
args
);
...
...
src/Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
1b0bfecd
...
@@ -15,15 +15,12 @@ namespace Titanium.Web.Proxy.Shared
...
@@ -15,15 +15,12 @@ namespace Titanium.Web.Proxy.Shared
internal
static
readonly
string
NewLine
=
"\r\n"
;
internal
static
readonly
string
NewLine
=
"\r\n"
;
internal
static
readonly
byte
[]
NewLineBytes
=
{
(
byte
)
'\r'
,
(
byte
)
'\n'
};
internal
static
readonly
byte
[]
NewLineBytes
=
{
(
byte
)
'\r'
,
(
byte
)
'\n'
};
internal
static
readonly
Regex
UriSchemeRegex
=
new
Regex
(
"^[a-z]*://"
,
RegexOptions
.
IgnoreCase
|
RegexOptions
.
Compiled
);
internal
static
readonly
HashSet
<
string
>
ProxySupportedCompressions
=
internal
static
readonly
HashSet
<
string
>
ProxySupportedCompressions
=
new
HashSet
<
string
>(
StringComparer
.
OrdinalIgnoreCase
)
new
HashSet
<
string
>(
StringComparer
.
OrdinalIgnoreCase
)
{
{
KnownHeaders
.
ContentEncodingGzip
,
KnownHeaders
.
ContentEncodingGzip
.
String
,
KnownHeaders
.
ContentEncodingDeflate
,
KnownHeaders
.
ContentEncodingDeflate
.
String
,
KnownHeaders
.
ContentEncodingBrotli
KnownHeaders
.
ContentEncodingBrotli
.
String
};
};
internal
static
readonly
Regex
CNRemoverRegex
=
internal
static
readonly
Regex
CNRemoverRegex
=
...
...
src/Titanium.Web.Proxy/TransparentClientHandler.cs
View file @
1b0bfecd
...
@@ -133,8 +133,7 @@ namespace Titanium.Web.Proxy
...
@@ -133,8 +133,7 @@ namespace Titanium.Web.Proxy
// HTTPS server created - we can now decrypt the client's traffic
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
);
cancellationTokenSource
,
httpsHostName
,
null
,
null
);
}
}
catch
(
ProxyException
e
)
catch
(
ProxyException
e
)
{
{
...
...
tests/Titanium.Web.Proxy.IntegrationTests/ExpectContinueTests.cs
View file @
1b0bfecd
...
@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
return
Task
.
CompletedTask
;
};
};
...
@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
return
Task
.
CompletedTask
;
};
};
...
@@ -80,7 +80,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -80,7 +80,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
return
Task
.
CompletedTask
;
};
};
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
{
{
try
try
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
throw
dbzEx
;
throw
dbzEx
;
}
}
catch
catch
...
...
tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
View file @
1b0bfecd
...
@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetProxy
();
var
proxy
=
testSuite
.
GetProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
await
Task
.
FromResult
(
0
);
};
};
...
...
tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs
View file @
1b0bfecd
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
await
Task
.
FromResult
(
0
);
};
};
...
@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
await
Task
.
FromResult
(
0
);
};
};
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpsUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpsUrl
;
await
Task
.
FromResult
(
0
);
await
Task
.
FromResult
(
0
);
};
};
...
@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
...
@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpsUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpsUrl
;
await
Task
.
FromResult
(
0
);
await
Task
.
FromResult
(
0
);
};
};
...
...
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