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
/// </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 @
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
/// </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 @
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
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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
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 @@
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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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 @
1b0bfecd
...
...
@@ -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