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
e24f3cc7
Unverified
Commit
e24f3cc7
authored
Nov 16, 2019
by
honfika
Committed by
GitHub
Nov 16, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #656 from justcoding121/master
better uri handling
parents
183f9601
1b0bfecd
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 @
e24f3cc7
...
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
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
)
{
case
KnownHeaders
.
ContentEncoding
Gzip
:
case
HttpCompression
.
Gzip
:
return
new
GZipStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Deflate
:
case
HttpCompression
.
Deflate
:
return
new
DeflateStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Brotli
:
case
HttpCompression
.
Brotli
:
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Compress
,
leaveOpen
);
default
:
throw
new
Exception
(
$"Unsupported compression mode:
{
type
}
"
);
...
...
src/Titanium.Web.Proxy/Compression/CompressionUtil.cs
0 → 100644
View file @
e24f3cc7
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 @
e24f3cc7
...
...
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
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
)
{
case
KnownHeaders
.
ContentEncoding
Gzip
:
case
HttpCompression
.
Gzip
:
return
new
GZipStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Deflate
:
case
HttpCompression
.
Deflate
:
return
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
case
KnownHeaders
.
ContentEncoding
Brotli
:
case
HttpCompression
.
Brotli
:
return
new
BrotliSharpLib
.
BrotliStream
(
stream
,
CompressionMode
.
Decompress
,
leaveOpen
);
default
:
throw
new
Exception
(
$"Unsupported decompression mode:
{
type
}
"
);
...
...
src/Titanium.Web.Proxy/Compression/HttpCompression.cs
0 → 100644
View file @
e24f3cc7
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 @
e24f3cc7
...
...
@@ -54,7 +54,7 @@ namespace Titanium.Web.Proxy.EventArguments
readChunkTrail
=
true
;
string
?
chunkHead
=
baseStream
.
ReadLineAsync
().
Result
;
string
?
chunkHead
=
baseStream
.
ReadLineAsync
().
Result
!
;
int
idx
=
chunkHead
.
IndexOf
(
";"
,
StringComparison
.
Ordinal
);
if
(
idx
>=
0
)
{
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
e24f3cc7
...
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Constructor to initialize the proxy
/// </summary>
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
if
(
transformation
==
TransformationMode
.
Uncompress
&&
contentEncoding
!=
null
)
{
s
=
decompressStream
=
DecompressionFactory
.
Create
(
contentEncoding
,
s
);
s
=
decompressStream
=
DecompressionFactory
.
Create
(
CompressionUtil
.
CompressionNameToEnum
(
contentEncoding
)
,
s
);
}
try
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
View file @
e24f3cc7
...
...
@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary>
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
;
ExceptionFunc
=
server
.
ExceptionFunc
;
...
...
src/Titanium.Web.Proxy/ExplicitClientHandler.cs
View file @
e24f3cc7
...
...
@@ -62,12 +62,15 @@ namespace Titanium.Web.Proxy
Request
.
ParseRequestLine
(
httpCmd
!,
out
string
_
,
out
string
httpUrl
,
out
var
version
);
var
httpRemoteUri
=
new
Uri
(
"http://"
+
httpUrl
);
connectHostname
=
httpRemoteUri
.
Host
;
connectHostname
=
httpUrl
;
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
),
HttpVersion
=
version
};
...
...
@@ -127,6 +130,7 @@ namespace Titanium.Web.Proxy
bool
isClientHello
=
clientHelloInfo
!=
null
;
if
(
clientHelloInfo
!=
null
)
{
connectRequest
.
Scheme
=
ProxyServer
.
UriSchemeHttps
;
connectRequest
.
TunnelType
=
TunnelType
.
Https
;
connectRequest
.
ClientHelloInfo
=
clientHelloInfo
;
}
...
...
@@ -136,7 +140,6 @@ namespace Titanium.Web.Proxy
if
(
decryptSsl
&&
clientHelloInfo
!=
null
)
{
clientConnection
.
SslProtocol
=
clientHelloInfo
.
SslProtocol
;
connectRequest
.
RequestUri
=
new
Uri
(
"https://"
+
httpUrl
);
bool
http2Supported
=
false
;
...
...
@@ -355,7 +358,7 @@ namespace Titanium.Web.Proxy
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
,
connect
Hostname
,
connect
Args
,
prefetchConnectionTask
);
cancellationTokenSource
,
connectArgs
,
prefetchConnectionTask
);
}
catch
(
ProxyException
e
)
{
...
...
src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
e24f3cc7
...
...
@@ -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
>();
using
(
cancellationToken
.
Register
(
s
=>
((
TaskCompletionSource
<
bool
>)
s
).
TrySetResult
(
true
),
tcs
))
...
...
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
View file @
e24f3cc7
...
...
@@ -78,7 +78,7 @@ namespace Titanium.Web.Proxy.Helpers
{
var
parameter
=
p
.
Span
;
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
);
if
(
value
.
EqualsIgnoreCase
(
"x-user-defined"
.
AsSpan
()))
...
...
@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy.Helpers
foreach
(
var
parameter
in
new
SemicolonSplitEnumerator
(
contentType
))
{
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
);
if
(
value
.
Length
>
2
&&
value
.
Span
[
0
]
==
'"'
&&
value
.
Span
[
value
.
Length
-
1
]
==
'"'
)
...
...
src/Titanium.Web.Proxy/Helpers/HttpWriter.cs
View file @
e24f3cc7
...
...
@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers
{
while
(
true
)
{
string
?
chunkHead
=
await
reader
.
ReadLineAsync
(
cancellationToken
)
;
string
chunkHead
=
(
await
reader
.
ReadLineAsync
(
cancellationToken
))!
;
int
idx
=
chunkHead
.
IndexOf
(
";"
);
if
(
idx
>=
0
)
{
...
...
src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs
View file @
e24f3cc7
...
...
@@ -66,9 +66,9 @@ namespace Titanium.Web.Proxy.Helpers
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
)
{
...
...
@@ -171,7 +171,15 @@ namespace Titanium.Web.Proxy.Helpers
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
{
...
...
src/Titanium.Web.Proxy/Http/ConnectRequest.cs
View file @
e24f3cc7
using
Titanium.Web.Proxy.StreamExtended
;
using
System
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.StreamExtended
;
namespace
Titanium.Web.Proxy.Http
{
...
...
@@ -7,13 +9,14 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public
class
ConnectRequest
:
Request
{
public
ConnectRequest
()
public
ConnectRequest
(
string
hostname
)
{
Method
=
"CONNECT"
;
Hostname
=
hostname
;
}
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 @
e24f3cc7
...
...
@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Http
var
encoding
=
HttpHeader
.
Encoding
;
#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
);
int
bytes
=
encoding
.
GetBytes
(
str
.
AsSpan
(),
span
);
...
...
src/Titanium.Web.Proxy/Http/HeaderCollection.cs
View file @
e24f3cc7
...
...
@@ -105,6 +105,21 @@ namespace Titanium.Web.Proxy.Http
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>
/// Returns all headers
/// </summary>
...
...
@@ -129,6 +144,16 @@ namespace Titanium.Web.Proxy.Http
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>
/// Adds the given header object to Request
/// </summary>
...
...
@@ -239,6 +264,27 @@ namespace Titanium.Web.Proxy.Http
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>
/// Removes given header object if it exist
/// </summary>
...
...
@@ -273,9 +319,9 @@ namespace Titanium.Web.Proxy.Http
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
;
}
...
...
@@ -283,7 +329,7 @@ namespace Titanium.Web.Proxy.Http
return
null
;
}
internal
void
SetOrAddHeaderValue
(
string
headerName
,
string
?
value
)
internal
void
SetOrAddHeaderValue
(
KnownHeader
headerName
,
string
?
value
)
{
if
(
value
==
null
)
{
...
...
@@ -291,13 +337,25 @@ namespace Titanium.Web.Proxy.Http
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
{
headers
.
Add
(
headerName
,
new
HttpHeader
(
headerName
,
value
));
headers
.
Add
(
headerName
.
String
,
new
HttpHeader
(
headerName
,
value
));
}
}
...
...
src/Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
e24f3cc7
...
...
@@ -18,10 +18,10 @@ namespace Titanium.Web.Proxy.Http
{
private
TcpServerConnection
?
connection
;
internal
HttpWebClient
(
ConnectRequest
?
connectRequest
,
Request
?
request
,
Lazy
<
int
>
processIdFunc
)
internal
HttpWebClient
(
ConnectRequest
?
connectRequest
,
Request
request
,
Lazy
<
int
>
processIdFunc
)
{
ConnectRequest
=
connectRequest
;
Request
=
request
??
new
Request
()
;
Request
=
request
;
Response
=
new
Response
();
ProcessId
=
processIdFunc
;
}
...
...
@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Http
// write request headers
foreach
(
var
header
in
Request
.
Headers
)
{
if
(
isTransparent
||
header
.
Name
!=
KnownHeaders
.
ProxyAuthorization
)
if
(
isTransparent
||
header
.
Name
!=
KnownHeaders
.
ProxyAuthorization
.
String
)
{
headerBuilder
.
WriteHeader
(
header
);
}
...
...
src/Titanium.Web.Proxy/Http/KnownHeader.cs
0 → 100644
View file @
e24f3cc7
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 @
e24f3cc7
...
...
@@ -6,46 +6,46 @@
public
static
class
KnownHeaders
{
// Both
public
const
string
Connection
=
"Connection"
;
public
const
string
ConnectionClose
=
"close"
;
public
const
string
ConnectionKeepAlive
=
"keep-alive"
;
public
static
KnownHeader
Connection
=
"Connection"
;
public
static
KnownHeader
ConnectionClose
=
"close"
;
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
const
string
ContentTypeCharset
=
"charset"
;
public
const
string
ContentTypeBoundary
=
"boundary"
;
public
static
KnownHeader
ContentType
=
"Content-Type"
;
public
static
KnownHeader
ContentTypeCharset
=
"charset"
;
public
static
KnownHeader
ContentTypeBoundary
=
"boundary"
;
public
const
string
Upgrade
=
"Upgrade"
;
public
const
string
UpgradeWebsocket
=
"websocket"
;
public
static
KnownHeader
Upgrade
=
"Upgrade"
;
public
static
KnownHeader
UpgradeWebsocket
=
"websocket"
;
// 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
const
string
Expect100Continue
=
"100-continue"
;
public
static
KnownHeader
Expect
=
"Expect"
;
public
static
KnownHeader
Expect100Continue
=
"100-continue"
;
public
const
string
Host
=
"Host"
;
public
static
KnownHeader
Host
=
"Host"
;
public
const
string
ProxyAuthorization
=
"Proxy-Authorization"
;
public
const
string
ProxyAuthorizationBasic
=
"basic"
;
public
static
KnownHeader
ProxyAuthorization
=
"Proxy-Authorization"
;
public
static
KnownHeader
ProxyAuthorizationBasic
=
"basic"
;
public
const
string
ProxyConnection
=
"Proxy-Connection"
;
public
const
string
ProxyConnectionClose
=
"close"
;
public
static
KnownHeader
ProxyConnection
=
"Proxy-Connection"
;
public
static
KnownHeader
ProxyConnectionClose
=
"close"
;
// Response headers
public
const
string
ContentEncoding
=
"Content-Encoding"
;
public
const
string
ContentEncodingDeflate
=
"deflate"
;
public
const
string
ContentEncodingGzip
=
"gzip"
;
public
const
string
ContentEncodingBrotli
=
"br"
;
public
static
KnownHeader
ContentEncoding
=
"Content-Encoding"
;
public
static
KnownHeader
ContentEncodingDeflate
=
"deflate"
;
public
static
KnownHeader
ContentEncodingGzip
=
"gzip"
;
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
const
string
TransferEncodingChunked
=
"chunked"
;
public
static
KnownHeader
TransferEncoding
=
"Transfer-Encoding"
;
public
static
KnownHeader
TransferEncodingChunked
=
"chunked"
;
}
}
}
\ No newline at end of file
src/Titanium.Web.Proxy/Http/Request.cs
View file @
e24f3cc7
...
...
@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Http
public
bool
IsHttps
=>
RequestUri
.
Scheme
==
ProxyServer
.
UriSchemeHttps
;
private
ByteString
originalUrlData
;
private
ByteString
u
rlData
;
private
protected
ByteString
U
rlData
;
internal
ByteString
OriginalUrlData
{
...
...
@@ -33,10 +33,14 @@ namespace Titanium.Web.Proxy.Http
set
{
originalUrlData
=
value
;
u
rlData
=
value
;
U
rlData
=
value
;
}
}
internal
string
Scheme
{
get
;
set
;
}
=
ProxyServer
.
UriSchemeHttp
;
internal
string
?
Hostname
{
get
;
set
;
}
/// <summary>
/// The original request Url.
/// </summary>
...
...
@@ -45,15 +49,45 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Request HTTP Uri.
/// </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>
/// The request url as it is in the HTTP header
/// </summary>
public
string
Url
{
get
=>
u
rlData
.
GetString
();
set
=>
u
rlData
=
value
.
GetByteString
();
get
=>
U
rlData
.
GetString
();
set
=>
U
rlData
=
value
.
GetByteString
();
}
[
Obsolete
(
"This property is obsolete. Use Url property instead"
)]
...
...
@@ -142,7 +176,7 @@ namespace Titanium.Web.Proxy.Http
return
false
;
}
return
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
UpgradeWebsocket
);
return
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
UpgradeWebsocket
.
String
);
}
}
...
...
@@ -256,5 +290,46 @@ namespace Titanium.Web.Proxy.Http
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 @
e24f3cc7
...
...
@@ -142,7 +142,7 @@ namespace Titanium.Web.Proxy.Http
get
{
string
?
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
.
String
);
}
set
...
...
@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.Http
/// <param name="encodingType"></param>
/// <param name="body"></param>
/// <returns></returns>
internal
byte
[]
GetCompressedBody
(
string
encodingType
,
byte
[]
body
)
internal
byte
[]
GetCompressedBody
(
HttpCompression
encodingType
,
byte
[]
body
)
{
using
(
var
ms
=
new
MemoryStream
())
{
...
...
@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Http
var
body
=
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
body
=
GetCompressedBody
(
CompressionUtil
.
CompressionNameToEnum
(
contentEncoding
)
,
body
);
if
(
isChunked
==
false
)
{
...
...
src/Titanium.Web.Proxy/Http/Response.cs
View file @
e24f3cc7
...
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Http
if
(
headerValue
!=
null
)
{
if
(
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
ConnectionClose
))
if
(
headerValue
.
EqualsIgnoreCase
(
KnownHeaders
.
ConnectionClose
.
String
))
{
return
false
;
}
...
...
src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs
View file @
e24f3cc7
...
...
@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
public
class
DynamicTable
{
// a circular queue of header fields
HttpHeader
?[]
headerFields
;
HttpHeader
[]
headerFields
=
Array
.
Empty
<
HttpHeader
>()
;
int
head
;
int
tail
;
...
...
src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs
View file @
e24f3cc7
...
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
private
const
int
bucketSize
=
17
;
// 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
int
size
;
...
...
@@ -337,7 +337,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int
h
=
hash
(
name
);
int
i
=
Encoder
.
index
(
h
);
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
))
{
...
...
@@ -521,6 +521,8 @@ namespace Titanium.Web.Proxy.Http2.Hpack
Index
=
index
;
Hash
=
hash
;
Next
=
next
;
Before
=
this
;
After
=
this
;
}
/// <summary>
...
...
src/Titanium.Web.Proxy/Http2/Http2FrameHeader.cs
View file @
e24f3cc7
...
...
@@ -10,12 +10,9 @@
public
int
StreamId
;
public
byte
[]
Buffer
;
public
byte
[]
CopyToBuffer
()
public
void
CopyToBuffer
(
byte
[]
buf
)
{
int
length
=
Length
;
var
buf
=
/*new byte[9];*/
Buffer
;
buf
[
0
]
=
(
byte
)((
length
>>
16
)
&
0xff
);
buf
[
1
]
=
(
byte
)((
length
>>
8
)
&
0xff
);
buf
[
2
]
=
(
byte
)(
length
&
0xff
);
...
...
@@ -26,7 +23,6 @@
//buf[6] = (byte)((streamId >> 16) & 0xff);
//buf[7] = (byte)((streamId >> 8) & 0xff);
//buf[8] = (byte)(streamId & 0xff);
return
buf
;
}
}
}
src/Titanium.Web.Proxy/Http2/Http2Helper.cs
View file @
e24f3cc7
...
...
@@ -70,11 +70,10 @@ namespace Titanium.Web.Proxy.Http2
Decoder
?
decoder
=
null
;
var
frameHeader
=
new
Http2FrameHeader
();
frameHeader
.
Buffer
=
new
byte
[
9
];
var
frameHeader
Buffer
=
new
byte
[
9
];
byte
[]?
buffer
=
null
;
while
(
true
)
{
var
frameHeaderBuffer
=
frameHeader
.
Buffer
;
int
read
=
await
forceRead
(
input
,
frameHeaderBuffer
,
0
,
9
,
cancellationToken
);
if
(
read
!=
9
)
{
...
...
@@ -265,8 +264,10 @@ namespace Titanium.Web.Proxy.Http2
request
.
HttpVersion
=
HttpVersion
.
Version20
;
request
.
Method
=
method
.
GetString
();
request
.
OriginalUrlData
=
path
;
request
.
Scheme
=
headerListener
.
Scheme
;
request
.
Hostname
=
headerListener
.
Authority
.
GetString
();
request
.
RequestUri
=
headerListener
.
GetUri
();
//
request.RequestUri = headerListener.GetUri();
}
else
{
...
...
@@ -302,7 +303,7 @@ namespace Titanium.Web.Proxy.Http2
{
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
null
;
tcs
.
SetResult
(
true
);
await
sendHeader
(
remoteSettings
,
frameHeader
,
rr
,
endStream
,
output
,
args
.
IsPromise
);
await
sendHeader
(
remoteSettings
,
frameHeader
,
frameHeaderBuffer
,
rr
,
endStream
,
output
,
args
.
IsPromise
);
}
else
{
...
...
@@ -379,7 +380,7 @@ namespace Titanium.Web.Proxy.Http2
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
DecompressionFactory
.
Create
(
rr
.
ContentEncoding
,
new
MemoryStream
(
body
)))
DecompressionFactory
.
Create
(
CompressionUtil
.
CompressionNameToEnum
(
rr
.
ContentEncoding
)
,
new
MemoryStream
(
body
)))
{
zip
.
CopyTo
(
ms
);
}
...
...
@@ -413,7 +414,7 @@ namespace Titanium.Web.Proxy.Http2
breakpoint
();
}
await
sendBody
(
remoteSettings
,
rr
,
frameHeader
,
buffer
,
output
);
await
sendBody
(
remoteSettings
,
rr
,
frameHeader
,
frameHeaderBuffer
,
buffer
,
output
);
}
if
(!
isClient
&&
endStream
)
...
...
@@ -425,8 +426,8 @@ namespace Titanium.Web.Proxy.Http2
if
(
sendPacket
)
{
// do not cancel the write operation
var
buf
=
frameHeader
.
CopyToBuffer
(
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
length
/*, cancellationToken*/
);
}
...
...
@@ -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
ms
=
new
MemoryStream
();
...
...
@@ -507,15 +508,15 @@ namespace Titanium.Web.Proxy.Http2
//headerBuffer[4] = (byte)(flags & ~((int)Http2FrameFlag.Padded));
// send the header
var
buf
=
frameHeader
.
CopyToBuffer
(
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
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
();
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
)
{
...
...
@@ -530,8 +531,8 @@ namespace Titanium.Web.Proxy.Http2
frameHeader
.
Type
=
Http2FrameType
.
Data
;
frameHeader
.
Flags
=
pos
<
body
.
Length
?
(
Http2FrameFlag
)
0
:
Http2FrameFlag
.
EndStream
;
var
buf
=
frameHeader
.
CopyToBuffer
(
);
await
output
.
WriteAsync
(
buf
,
0
,
buf
.
Length
/*, cancellationToken*/
);
frameHeader
.
CopyToBuffer
(
frameHeaderBuffer
);
await
output
.
WriteAsync
(
frameHeaderBuffer
,
0
,
frameHeaderBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
bodyFrameLength
/*, cancellationToken*/
);
}
}
...
...
@@ -571,18 +572,40 @@ namespace Titanium.Web.Proxy.Http2
class
MyHeaderListener
:
IHeaderListener
{
private
static
ByteString
SchemeHttp
=
(
ByteString
)
ProxyServer
.
UriSchemeHttp
;
private
static
ByteString
SchemeHttps
=
(
ByteString
)
ProxyServer
.
UriSchemeHttps
;
private
readonly
Action
<
ByteString
,
ByteString
>
addHeaderFunc
;
public
ByteString
Method
{
get
;
private
set
;
}
public
ByteString
Status
{
get
;
private
set
;
}
p
rivate
ByteString
authority
;
p
ublic
ByteString
Authority
{
get
;
private
set
;
}
private
ByteString
scheme
;
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
)
{
this
.
addHeaderFunc
=
addHeaderFunc
;
...
...
@@ -599,7 +622,7 @@ namespace Titanium.Web.Proxy.Http2
Method
=
value
;
return
;
case
":authority"
:
a
uthority
=
value
;
A
uthority
=
value
;
return
;
case
":scheme"
:
scheme
=
value
;
...
...
@@ -618,20 +641,20 @@ namespace Titanium.Web.Proxy.Http2
public
Uri
GetUri
()
{
if
(
a
uthority
.
Length
==
0
)
if
(
A
uthority
.
Length
==
0
)
{
// 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
);
int
idx
=
scheme
.
Length
;
bytes
[
idx
++]
=
(
byte
)
':'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
bytes
[
idx
++]
=
(
byte
)
'/'
;
authority
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
a
uthority
.
Length
));
idx
+=
a
uthority
.
Length
;
Authority
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
A
uthority
.
Length
));
idx
+=
A
uthority
.
Length
;
Path
.
Span
.
CopyTo
(
bytes
.
AsSpan
(
idx
,
Path
.
Length
));
return
new
Uri
(
HttpHeader
.
Encoding
.
GetString
(
bytes
));
...
...
src/Titanium.Web.Proxy/Models/ByteString.cs
View file @
e24f3cc7
...
...
@@ -38,5 +38,10 @@ namespace Titanium.Web.Proxy.Models
public
static
implicit
operator
ByteString
(
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 @
e24f3cc7
...
...
@@ -41,6 +41,10 @@ namespace Titanium.Web.Proxy.Models
internal
static
readonly
HttpHeader
ProxyConnectionKeepAlive
=
new
HttpHeader
(
"Proxy-Connection"
,
"keep-alive"
);
private
string
?
nameString
;
private
string
?
valueString
;
/// <summary>
/// Initialize a new instance.
/// </summary>
...
...
@@ -53,8 +57,29 @@ namespace Titanium.Web.Proxy.Models
throw
new
Exception
(
"Name cannot be null or empty"
);
}
NameData
=
name
.
Trim
().
GetByteString
();
ValueData
=
value
.
Trim
().
GetByteString
();
nameString
=
name
.
Trim
();
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
)
...
...
@@ -78,16 +103,16 @@ namespace Titanium.Web.Proxy.Models
/// <summary>
/// Header Name.
/// </summary>
public
string
Name
=>
NameData
.
GetString
();
public
string
Name
=>
nameString
??=
NameData
.
GetString
();
internal
ByteString
NameData
{
get
;
}
/// <summary>
/// Header Value.
/// </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
;
...
...
@@ -96,6 +121,18 @@ namespace Titanium.Web.Proxy.Models
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>
/// Returns header as a valid header string.
/// </summary>
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
e24f3cc7
...
...
@@ -372,7 +372,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if
(
useUpstreamProxy
&&
(
isConnect
||
isHttps
))
{
var
writer
=
new
HttpRequestWriter
(
stream
,
proxyServer
.
BufferPool
);
var
connectRequest
=
new
ConnectRequest
var
connectRequest
=
new
ConnectRequest
(
remoteHostName
)
{
OriginalUrlData
=
HttpHeader
.
Encoding
.
GetBytes
(
$"
{
remoteHostName
}
:
{
remotePort
}
"
),
HttpVersion
=
httpVersion
...
...
src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs
View file @
e24f3cc7
...
...
@@ -52,7 +52,7 @@ namespace Titanium.Web.Proxy
if
(
ProxyBasicAuthenticateFunc
!=
null
)
{
return
await
authenticateUserBasic
(
session
,
authenticationType
,
credentials
);
return
await
authenticateUserBasic
(
session
,
authenticationType
,
credentials
,
ProxyBasicAuthenticateFunc
);
}
if
(
ProxySchemeAuthenticateFunc
!=
null
)
...
...
@@ -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
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
...
...
@@ -102,7 +104,7 @@ namespace Titanium.Web.Proxy
string
username
=
decoded
.
Substring
(
0
,
colonIndex
);
string
password
=
decoded
.
Substring
(
colonIndex
+
1
);
bool
authenticated
=
await
P
roxyBasicAuthenticateFunc
(
session
,
username
,
password
);
bool
authenticated
=
await
p
roxyBasicAuthenticateFunc
(
session
,
username
,
password
);
if
(!
authenticated
)
{
session
.
HttpClient
.
Response
=
createAuthentication407Response
(
"Proxy Authentication Invalid"
);
...
...
src/Titanium.Web.Proxy/ProxyServer.cs
View file @
e24f3cc7
...
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Backing field for exposed public property.
/// </summary>
private
ExceptionHandler
exceptionFunc
;
private
ExceptionHandler
?
exceptionFunc
;
/// <summary>
/// Backing field for exposed public property.
...
...
@@ -291,14 +291,14 @@ namespace Titanium.Web.Proxy
/// Parameters are username and password as provided by client.
/// Should return true for successful authentication.
/// </summary>
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
bool
>>
ProxyBasicAuthenticateFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
bool
>>
?
ProxyBasicAuthenticateFunc
{
get
;
set
;
}
/// <summary>
/// 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.
/// Should return success for successful authentication, continuation if the package requests, or failure.
/// </summary>
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
ProxyAuthenticationContext
>>
ProxySchemeAuthenticateFunc
{
get
;
set
;
}
public
Func
<
SessionEventArgsBase
,
string
,
string
,
Task
<
ProxyAuthenticationContext
>>
?
ProxySchemeAuthenticateFunc
{
get
;
set
;
}
/// <summary>
/// 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
/// <returns>The external proxy as task result.</returns>
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
);
}
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
e24f3cc7
...
...
@@ -33,15 +33,11 @@ namespace Titanium.Web.Proxy
/// <param name="clientStream">The client stream.</param>
/// <param name="clientStreamWriter">The client stream writer.</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="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
private
async
Task
handleHttpSessionRequest
(
ProxyEndPoint
endPoint
,
TcpClientConnection
clientConnection
,
CustomBufferedStream
clientStream
,
HttpResponseWriter
clientStreamWriter
,
CancellationTokenSource
cancellationTokenSource
,
string
?
httpsConnectHostname
,
TunnelConnectSessionEventArgs
?
connectArgs
,
CancellationTokenSource
cancellationTokenSource
,
TunnelConnectSessionEventArgs
?
connectArgs
=
null
,
Task
<
TcpServerConnection
>?
prefetchConnectionTask
=
null
)
{
var
connectRequest
=
connectArgs
?.
HttpClient
.
ConnectRequest
;
...
...
@@ -85,41 +81,13 @@ namespace Titanium.Web.Proxy
await
HeaderParser
.
ReadHeaders
(
clientStream
,
args
.
HttpClient
.
Request
.
Headers
,
cancellationToken
);
Uri
httpRemoteUri
;
if
(
ProxyConstants
.
UriSchemeRegex
.
IsMatch
(
httpUrl
)
)
var
request
=
args
.
HttpClient
.
Request
;
if
(
connectRequest
!=
null
)
{
try
{
httpRemoteUri
=
new
Uri
(
httpUrl
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
httpUrl
}
'"
,
ex
);
}
request
.
Scheme
=
connectRequest
.
Scheme
;
request
.
Hostname
=
connectRequest
.
Hostname
;
}
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
.
Method
=
httpMethod
;
...
...
@@ -128,7 +96,7 @@ namespace Titanium.Web.Proxy
if
(!
args
.
IsTransparent
)
{
// proxy authorization check
if
(
httpsConnectHostname
==
null
&&
await
checkAuthorization
(
args
)
==
false
)
if
(
connectRequest
==
null
&&
await
checkAuthorization
(
args
)
==
false
)
{
await
onBeforeResponse
(
args
);
...
...
src/Titanium.Web.Proxy/Shared/ProxyConstants.cs
View file @
e24f3cc7
...
...
@@ -15,15 +15,12 @@ namespace Titanium.Web.Proxy.Shared
internal
static
readonly
string
NewLine
=
"\r\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
=
new
HashSet
<
string
>(
StringComparer
.
OrdinalIgnoreCase
)
{
KnownHeaders
.
ContentEncodingGzip
,
KnownHeaders
.
ContentEncodingDeflate
,
KnownHeaders
.
ContentEncodingBrotli
KnownHeaders
.
ContentEncodingGzip
.
String
,
KnownHeaders
.
ContentEncodingDeflate
.
String
,
KnownHeaders
.
ContentEncodingBrotli
.
String
};
internal
static
readonly
Regex
CNRemoverRegex
=
...
...
src/Titanium.Web.Proxy/TransparentClientHandler.cs
View file @
e24f3cc7
...
...
@@ -133,8 +133,7 @@ namespace Titanium.Web.Proxy
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
,
httpsHostName
,
null
,
null
);
await
handleHttpSessionRequest
(
endPoint
,
clientConnection
,
clientStream
,
clientStreamWriter
,
cancellationTokenSource
);
}
catch
(
ProxyException
e
)
{
...
...
tests/Titanium.Web.Proxy.IntegrationTests/ExpectContinueTests.cs
View file @
e24f3cc7
...
...
@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
};
...
...
@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
};
...
...
@@ -80,7 +80,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
return
Task
.
CompletedTask
;
};
...
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
{
try
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningTcpUrl
;
throw
dbzEx
;
}
catch
...
...
tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
View file @
e24f3cc7
...
...
@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
};
...
...
tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs
View file @
e24f3cc7
...
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
};
...
...
@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpUrl
;
await
Task
.
FromResult
(
0
);
};
...
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpsUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpsUrl
;
await
Task
.
FromResult
(
0
);
};
...
...
@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
BeforeRequest
+=
async
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningHttpsUrl
)
;
e
.
HttpClient
.
Request
.
Url
=
server
.
ListeningHttpsUrl
;
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