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
b43dc6b5
Commit
b43dc6b5
authored
May 20, 2016
by
justcoding121
Committed by
justcoding121
May 20, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
asyncify more
parent
750b63f8
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
340 additions
and
294 deletions
+340
-294
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+24
-26
README.md
README.md
+30
-26
DeflateCompression.cs
Titanium.Web.Proxy/Compression/DeflateCompression.cs
+3
-2
GZipCompression.cs
Titanium.Web.Proxy/Compression/GZipCompression.cs
+3
-2
ICompression.cs
Titanium.Web.Proxy/Compression/ICompression.cs
+4
-2
ZlibCompression.cs
Titanium.Web.Proxy/Compression/ZlibCompression.cs
+3
-2
DefaultDecompression.cs
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
+5
-3
DeflateDecompression.cs
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
+4
-3
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+4
-3
IDecompression.cs
Titanium.Web.Proxy/Decompression/IDecompression.cs
+2
-1
ZlibDecompression.cs
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
+4
-3
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+36
-35
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+10
-10
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+8
-7
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+11
-11
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+14
-13
TcpConnectionManager.cs
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
+18
-16
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+5
-50
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+103
-39
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+49
-40
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
b43dc6b5
...
...
@@ -2,6 +2,7 @@
using
System.Collections.Generic
;
using
System.Net
;
using
System.Text.RegularExpressions
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
...
...
@@ -13,7 +14,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
Remote
CertificateValidationCallback
+=
OnCertificateValidation
;
ProxyServer
.
Server
CertificateValidationCallback
+=
OnCertificateValidation
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
...
...
@@ -61,9 +62,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
ProxyServer
.
Stop
();
}
//Test On Request, intecept requests
//Read browser URL send back to proxy by the injection script in OnResponse event
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
//intecept & cancel, redirect or update requests
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
Console
.
WriteLine
(
e
.
WebSession
.
Request
.
Url
);
...
...
@@ -73,12 +73,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
if
((
e
.
WebSession
.
Request
.
Method
.
ToUpper
()
==
"POST"
||
e
.
WebSession
.
Request
.
Method
.
ToUpper
()
==
"PUT"
))
{
//Get/Set request body bytes
byte
[]
bodyBytes
=
e
.
GetRequestBody
();
e
.
SetRequestBody
(
bodyBytes
);
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
await
e
.
SetRequestBody
(
bodyBytes
);
//Get/Set request body as string
string
bodyString
=
e
.
GetRequestBodyAsString
();
e
.
SetRequestBodyString
(
bodyString
);
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
await
e
.
SetRequestBodyString
(
bodyString
);
}
...
...
@@ -86,26 +86,24 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Filter URL
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
await
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
}
//Redirect example
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"wikipedia.org"
))
{
e
.
Redirect
(
"https://www.paypal.com"
);
await
e
.
Redirect
(
"https://www.paypal.com"
);
}
}
//Test script injection
//Insert script to read the Browser URL and send it back to proxy
public
void
OnResponse
(
object
sender
,
SessionEventArgs
e
)
//Modify response
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
//read response headers
var
responseHeaders
=
e
.
WebSession
.
Response
.
ResponseHeaders
;
...
...
@@ -116,11 +114,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
if
(
e
.
WebSession
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
byte
[]
bodyBytes
=
e
.
GetResponseBody
();
e
.
SetResponseBody
(
bodyBytes
);
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
await
e
.
SetResponseBody
(
bodyBytes
);
string
body
=
e
.
GetResponseBodyAsString
();
e
.
SetResponseBodyString
(
body
);
string
body
=
await
e
.
GetResponseBodyAsString
();
await
e
.
SetResponseBodyString
(
body
);
}
}
}
...
...
@@ -131,13 +129,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public
void
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
public
async
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
{
//set IsValid to true/false based on Certificate Errors
if
(
e
.
SslPolicyErrors
==
System
.
Net
.
Security
.
SslPolicyErrors
.
None
)
e
.
IsValid
=
true
;
else
e
.
Session
.
Ok
(
"Cannot validate server certificate! Not safe to proceed."
);
await
e
.
Session
.
Ok
(
"Cannot validate server certificate! Not safe to proceed."
);
}
}
}
\ No newline at end of file
README.md
View file @
b43dc6b5
...
...
@@ -34,7 +34,7 @@ Setup HTTP proxy:
```
csharp
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
Remote
CertificateValidationCallback
+=
OnCertificateValidation
;
ProxyServer
.
Server
CertificateValidationCallback
+=
OnCertificateValidation
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
...
...
@@ -61,8 +61,7 @@ Setup HTTP proxy:
GenericCertificateName
=
"google.com"
};
ProxyServer
.
AddEndPoint
(
transparentEndPoint
);
//ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
...
...
@@ -87,7 +86,8 @@ Sample request and response event handlers
```
csharp
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
//intecept & cancel, redirect or update requests
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
Console
.
WriteLine
(
e
.
WebSession
.
Request
.
Url
);
...
...
@@ -97,12 +97,12 @@ Sample request and response event handlers
if
((
e
.
WebSession
.
Request
.
Method
.
ToUpper
()
==
"POST"
||
e
.
WebSession
.
Request
.
Method
.
ToUpper
()
==
"PUT"
))
{
//Get/Set request body bytes
byte
[]
bodyBytes
=
e
.
GetRequestBody
();
e
.
SetRequestBody
(
bodyBytes
);
byte
[]
bodyBytes
=
await
e
.
GetRequestBody
();
await
e
.
SetRequestBody
(
bodyBytes
);
//Get/Set request body as string
string
bodyString
=
e
.
GetRequestBodyAsString
();
e
.
SetRequestBodyString
(
bodyString
);
string
bodyString
=
await
e
.
GetRequestBodyAsString
();
await
e
.
SetRequestBodyString
(
bodyString
);
}
...
...
@@ -110,24 +110,24 @@ Sample request and response event handlers
//Filter URL
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
await
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
"<p>Blocked by titanium web proxy.</p>"
+
"</body>"
+
"</html>"
);
}
//Redirect example
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"wikipedia.org"
))
{
e
.
Redirect
(
"https://www.paypal.com"
);
await
e
.
Redirect
(
"https://www.paypal.com"
);
}
}
public
void
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
//Modify response
public
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
//read response headers
var
responseHeaders
=
e
.
WebSession
.
Response
.
ResponseHeaders
;
...
...
@@ -138,24 +138,28 @@ Sample request and response event handlers
{
if
(
e
.
WebSession
.
Response
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
byte
[]
bodyBytes
=
e
.
GetResponseBody
();
e
.
SetResponseBody
(
bodyBytes
);
byte
[]
bodyBytes
=
await
e
.
GetResponseBody
();
await
e
.
SetResponseBody
(
bodyBytes
);
string
body
=
e
.
GetResponseBodyAsString
();
e
.
SetResponseBodyString
(
body
);
string
body
=
await
e
.
GetResponseBodyAsString
();
await
e
.
SetResponseBodyString
(
body
);
}
}
}
}
// Allows overriding default certificate validation logic
public
void
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
/// <summary>
/// Allows overriding default certificate validation logic
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public
async
Task
OnCertificateValidation
(
object
sender
,
CertificateValidationEventArgs
e
)
{
//set IsValid to true/false based on Certificate Errors
if
(
e
.
SslPolicyErrors
==
System
.
Net
.
Security
.
SslPolicyErrors
.
None
)
e
.
IsValid
=
true
;
else
e
.
Session
.
Ok
(
"Cannot validate server certificate! Not safe to proceed."
);
await
e
.
Session
.
Ok
(
"Cannot validate server certificate! Not safe to proceed."
);
}
```
Future roadmap
...
...
Titanium.Web.Proxy/Compression/DeflateCompression.cs
View file @
b43dc6b5
using
System.IO
;
using
System.IO.Compression
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Compression
{
class
DeflateCompression
:
ICompression
{
public
byte
[]
Compress
(
byte
[]
responseBody
)
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
new
DeflateStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
zip
.
Write
(
responseBody
,
0
,
responseBody
.
Length
);
await
zip
.
WriteAsync
(
responseBody
,
0
,
responseBody
.
Length
).
ConfigureAwait
(
false
);
}
return
ms
.
ToArray
();
...
...
Titanium.Web.Proxy/Compression/GZipCompression.cs
View file @
b43dc6b5
using
Ionic.Zlib
;
using
System.IO
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Compression
{
class
GZipCompression
:
ICompression
{
public
byte
[]
Compress
(
byte
[]
responseBody
)
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
new
GZipStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
zip
.
Write
(
responseBody
,
0
,
responseBody
.
Length
);
await
zip
.
WriteAsync
(
responseBody
,
0
,
responseBody
.
Length
).
ConfigureAwait
(
false
);
}
return
ms
.
ToArray
();
...
...
Titanium.Web.Proxy/Compression/ICompression.cs
View file @
b43dc6b5
namespace
Titanium.Web.Proxy.Compression
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Compression
{
interface
ICompression
{
byte
[]
Compress
(
byte
[]
responseBody
);
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
);
}
}
Titanium.Web.Proxy/Compression/ZlibCompression.cs
View file @
b43dc6b5
using
Ionic.Zlib
;
using
System.IO
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Compression
{
class
ZlibCompression
:
ICompression
{
public
byte
[]
Compress
(
byte
[]
responseBody
)
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
{
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
new
ZlibStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
zip
.
Write
(
responseBody
,
0
,
responseBody
.
Length
);
await
zip
.
WriteAsync
(
responseBody
,
0
,
responseBody
.
Length
).
ConfigureAwait
(
false
);
}
return
ms
.
ToArray
();
...
...
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
View file @
b43dc6b5
namespace
Titanium.Web.Proxy.Decompression
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Decompression
{
class
DefaultDecompression
:
IDecompression
{
public
byte
[]
Decompress
(
byte
[]
compressedArray
)
public
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
{
return
compressedArray
;
return
Task
.
FromResult
(
compressedArray
)
;
}
}
}
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
View file @
b43dc6b5
using
Ionic.Zlib
;
using
System.IO
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Decompression
{
class
DeflateDecompression
:
IDecompression
{
public
byte
[]
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
{
var
stream
=
new
MemoryStream
(
compressedArray
);
...
...
@@ -17,9 +18,9 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
).
ConfigureAwait
(
false
))
>
0
)
{
output
.
Write
(
buffer
,
0
,
read
);
await
output
.
WriteAsync
(
buffer
,
0
,
read
).
ConfigureAwait
(
false
);
}
return
output
.
ToArray
();
...
...
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
b43dc6b5
using
System.IO
;
using
System.IO.Compression
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Decompression
{
class
GZipDecompression
:
IDecompression
{
public
byte
[]
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
{
using
(
var
decompressor
=
new
GZipStream
(
new
MemoryStream
(
compressedArray
),
CompressionMode
.
Decompress
))
{
...
...
@@ -14,9 +15,9 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
).
ConfigureAwait
(
false
))
>
0
)
{
output
.
Write
(
buffer
,
0
,
read
);
await
output
.
WriteAsync
(
buffer
,
0
,
read
).
ConfigureAwait
(
false
);
}
return
output
.
ToArray
();
}
...
...
Titanium.Web.Proxy/Decompression/IDecompression.cs
View file @
b43dc6b5
using
System.IO
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Decompression
{
interface
IDecompression
{
byte
[]
Decompress
(
byte
[]
compressedArray
);
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
);
}
}
Titanium.Web.Proxy/Decompression/ZlibDecompression.cs
View file @
b43dc6b5
using
Ionic.Zlib
;
using
System.IO
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Decompression
{
class
ZlibDecompression
:
IDecompression
{
public
byte
[]
Decompress
(
byte
[]
compressedArray
)
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
)
{
var
memoryStream
=
new
MemoryStream
(
compressedArray
);
using
(
var
decompressor
=
new
ZlibStream
(
memoryStream
,
CompressionMode
.
Decompress
))
...
...
@@ -16,9 +17,9 @@ namespace Titanium.Web.Proxy.Decompression
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
).
ConfigureAwait
(
false
))
>
0
)
{
output
.
Write
(
buffer
,
0
,
read
);
await
output
.
WriteAsync
(
buffer
,
0
,
read
).
ConfigureAwait
(
false
);
}
return
output
.
ToArray
();
}
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
b43dc6b5
...
...
@@ -6,6 +6,7 @@ using Titanium.Web.Proxy.Decompression;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http.Responses
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.EventArguments
{
...
...
@@ -54,7 +55,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Read request body content as bytes[] for current session
/// </summary>
private
void
ReadRequestBody
()
private
async
Task
ReadRequestBody
()
{
//GET request don't have a request body to read
if
((
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"POST"
&&
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"PUT"
))
...
...
@@ -74,7 +75,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
WebSession
.
Request
.
IsChunked
)
{
this
.
Client
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
requestBodyStream
);
await
this
.
Client
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
requestBodyStream
).
ConfigureAwait
(
false
);
}
else
{
...
...
@@ -82,11 +83,11 @@ namespace Titanium.Web.Proxy.EventArguments
if
(
WebSession
.
Request
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
this
.
Client
.
ClientStreamReader
.
CopyBytesToStream
(
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
await
this
.
Client
.
ClientStreamReader
.
CopyBytesToStream
(
requestBodyStream
,
WebSession
.
Request
.
ContentLength
).
ConfigureAwait
(
false
);
}
}
WebSession
.
Request
.
RequestBody
=
GetDecompressedResponseBody
(
WebSession
.
Request
.
ContentEncoding
,
requestBodyStream
.
ToArray
()
);
WebSession
.
Request
.
RequestBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Request
.
ContentEncoding
,
requestBodyStream
.
ToArray
()).
ConfigureAwait
(
false
);
}
}
...
...
@@ -98,7 +99,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Read response body as byte[] for current response
/// </summary>
private
void
ReadResponseBody
()
private
async
Task
ReadResponseBody
()
{
//If not already read (not cached yet)
if
(
WebSession
.
Response
.
ResponseBody
==
null
)
...
...
@@ -108,19 +109,19 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol
if
(
WebSession
.
Response
.
IsChunked
)
{
WebSession
.
ProxyClient
.
ServerStreamReader
.
CopyBytesToStreamChunked
(
responseBodyStream
);
await
WebSession
.
ProxyClient
.
ServerStreamReader
.
CopyBytesToStreamChunked
(
responseBodyStream
).
ConfigureAwait
(
false
);
}
else
{
if
(
WebSession
.
Response
.
ContentLength
>
0
)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
WebSession
.
ProxyClient
.
ServerStreamReader
.
CopyBytesToStream
(
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
await
WebSession
.
ProxyClient
.
ServerStreamReader
.
CopyBytesToStream
(
responseBodyStream
,
WebSession
.
Response
.
ContentLength
).
ConfigureAwait
(
false
);
}
}
WebSession
.
Response
.
ResponseBody
=
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
()
);
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
()).
ConfigureAwait
(
false
);
}
//set this to true for caching
...
...
@@ -132,25 +133,25 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as bytes
/// </summary>
/// <returns></returns>
public
byte
[]
GetRequestBody
()
public
async
Task
<
byte
[
]>
GetRequestBody
()
{
if
(
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
ReadRequestBody
(
);
await
ReadRequestBody
().
ConfigureAwait
(
false
);
return
WebSession
.
Request
.
RequestBody
;
}
/// <summary>
/// Gets the request body as string
/// </summary>
/// <returns></returns>
public
string
GetRequestBodyAsString
()
public
async
Task
<
string
>
GetRequestBodyAsString
()
{
if
(
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
ReadRequestBody
(
);
await
ReadRequestBody
().
ConfigureAwait
(
false
);
//Use the encoding specified in request to decode the byte[] data to string
return
WebSession
.
Request
.
RequestBodyString
??
(
WebSession
.
Request
.
RequestBodyString
=
WebSession
.
Request
.
Encoding
.
GetString
(
WebSession
.
Request
.
RequestBody
));
...
...
@@ -160,7 +161,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sets the request body
/// </summary>
/// <param name="body"></param>
public
void
SetRequestBody
(
byte
[]
body
)
public
async
Task
SetRequestBody
(
byte
[]
body
)
{
if
(
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
...
...
@@ -168,7 +169,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body
if
(!
WebSession
.
Request
.
RequestBodyRead
)
{
ReadRequestBody
(
);
await
ReadRequestBody
().
ConfigureAwait
(
false
);
}
WebSession
.
Request
.
RequestBody
=
body
;
...
...
@@ -179,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sets the body with the specified string
/// </summary>
/// <param name="body"></param>
public
void
SetRequestBodyString
(
string
body
)
public
async
Task
SetRequestBodyString
(
string
body
)
{
if
(
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
...
...
@@ -187,7 +188,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body
if
(!
WebSession
.
Request
.
RequestBodyRead
)
{
ReadRequestBody
(
);
await
ReadRequestBody
().
ConfigureAwait
(
false
);
}
WebSession
.
Request
.
RequestBody
=
WebSession
.
Request
.
Encoding
.
GetBytes
(
body
);
...
...
@@ -203,12 +204,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as byte array
/// </summary>
/// <returns></returns>
public
byte
[]
GetResponseBody
()
public
async
Task
<
byte
[
]>
GetResponseBody
()
{
if
(!
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
ReadResponseBody
(
);
await
ReadResponseBody
().
ConfigureAwait
(
false
);
return
WebSession
.
Response
.
ResponseBody
;
}
...
...
@@ -216,12 +217,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as string
/// </summary>
/// <returns></returns>
public
string
GetResponseBodyAsString
()
public
async
Task
<
string
>
GetResponseBodyAsString
()
{
if
(!
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
GetResponseBody
(
);
await
GetResponseBody
().
ConfigureAwait
(
false
);
return
WebSession
.
Response
.
ResponseBodyString
??
(
WebSession
.
Response
.
ResponseBodyString
=
WebSession
.
Response
.
Encoding
.
GetString
(
WebSession
.
Response
.
ResponseBody
));
}
...
...
@@ -230,7 +231,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Set the response body bytes
/// </summary>
/// <param name="body"></param>
public
void
SetResponseBody
(
byte
[]
body
)
public
async
Task
SetResponseBody
(
byte
[]
body
)
{
if
(!
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
...
...
@@ -238,7 +239,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body
if
(
WebSession
.
Response
.
ResponseBody
==
null
)
{
GetResponseBody
(
);
await
GetResponseBody
().
ConfigureAwait
(
false
);
}
WebSession
.
Response
.
ResponseBody
=
body
;
...
...
@@ -253,7 +254,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Replace the response body with the specified string
/// </summary>
/// <param name="body"></param>
public
void
SetResponseBodyString
(
string
body
)
public
async
Task
SetResponseBodyString
(
string
body
)
{
if
(!
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
...
...
@@ -261,19 +262,19 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body
if
(
WebSession
.
Response
.
ResponseBody
==
null
)
{
GetResponseBody
(
);
await
GetResponseBody
().
ConfigureAwait
(
false
);
}
var
bodyBytes
=
WebSession
.
Response
.
Encoding
.
GetBytes
(
body
);
SetResponseBody
(
bodyBytes
);
await
SetResponseBody
(
bodyBytes
).
ConfigureAwait
(
false
);
}
private
byte
[]
GetDecompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
async
Task
<
byte
[
]>
GetDecompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
{
var
decompressionFactory
=
new
DecompressionFactory
();
var
decompressor
=
decompressionFactory
.
Create
(
encodingType
);
return
decompressor
.
Decompress
(
responseBodyStream
);
return
await
decompressor
.
Decompress
(
responseBodyStream
).
ConfigureAwait
(
false
);
}
...
...
@@ -283,7 +284,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// and ignore the request
/// </summary>
/// <param name="html"></param>
public
void
Ok
(
string
html
)
public
async
Task
Ok
(
string
html
)
{
if
(
WebSession
.
Request
.
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
...
...
@@ -293,7 +294,7 @@ namespace Titanium.Web.Proxy.EventArguments
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
Ok
(
result
);
await
Ok
(
result
).
ConfigureAwait
(
false
);
}
/// <summary>
...
...
@@ -302,19 +303,19 @@ namespace Titanium.Web.Proxy.EventArguments
/// and ignore the request
/// </summary>
/// <param name="body"></param>
public
void
Ok
(
byte
[]
result
)
public
async
Task
Ok
(
byte
[]
result
)
{
var
response
=
new
OkResponse
();
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
ResponseBody
=
result
;
Respond
(
respon
se
);
await
Respond
(
response
).
ConfigureAwait
(
fal
se
);
WebSession
.
Request
.
CancelRequest
=
true
;
}
public
void
Redirect
(
string
url
)
public
async
Task
Redirect
(
string
url
)
{
var
response
=
new
RedirectResponse
();
...
...
@@ -322,13 +323,13 @@ namespace Titanium.Web.Proxy.EventArguments
response
.
ResponseHeaders
.
Add
(
new
Models
.
HttpHeader
(
"Location"
,
url
));
response
.
ResponseBody
=
Encoding
.
ASCII
.
GetBytes
(
string
.
Empty
);
Respond
(
respon
se
);
await
Respond
(
response
).
ConfigureAwait
(
fal
se
);
WebSession
.
Request
.
CancelRequest
=
true
;
}
/// a generic responder method
public
void
Respond
(
Response
response
)
public
async
Task
Respond
(
Response
response
)
{
WebSession
.
Request
.
RequestLocked
=
true
;
...
...
@@ -337,7 +338,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Response
=
response
;
ProxyServer
.
HandleHttpSessionResponse
(
this
);
await
ProxyServer
.
HandleHttpSessionResponse
(
this
).
ConfigureAwait
(
false
);
}
}
...
...
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
b43dc6b5
...
...
@@ -15,12 +15,12 @@ namespace Titanium.Web.Proxy.Extensions
if
(!
string
.
IsNullOrEmpty
(
initialData
))
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
await
output
.
WriteAsync
(
bytes
,
0
,
bytes
.
Length
);
}
await
input
.
CopyToAsync
(
output
);
}
internal
static
void
CopyBytesToStream
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
,
long
totalBytesToRead
)
internal
static
async
Task
CopyBytesToStream
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
,
long
totalBytesToRead
)
{
var
totalbytesRead
=
0
;
...
...
@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Extensions
while
(
totalbytesRead
<
(
int
)
totalBytesToRead
)
{
var
buffer
=
clientStreamReader
.
ReadBytes
(
bytesToRead
);
var
buffer
=
await
clientStreamReader
.
ReadBytesAsync
(
bytesToRead
);
totalbytesRead
+=
buffer
.
Length
;
var
remainingBytes
=
(
int
)
totalBytesToRead
-
totalbytesRead
;
...
...
@@ -43,26 +43,26 @@ namespace Titanium.Web.Proxy.Extensions
{
bytesToRead
=
remainingBytes
;
}
stream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
await
stream
.
WriteAsync
(
buffer
,
0
,
buffer
.
Length
);
}
}
internal
static
void
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
)
internal
static
async
Task
CopyBytesToStreamChunked
(
this
CustomBinaryReader
clientStreamReader
,
Stream
stream
)
{
while
(
true
)
{
var
chuchkHead
=
clientStreamReader
.
ReadLine
();
var
chuchkHead
=
await
clientStreamReader
.
ReadLineAsync
();
var
chunkSize
=
int
.
Parse
(
chuchkHead
,
NumberStyles
.
HexNumber
);
if
(
chunkSize
!=
0
)
{
var
buffer
=
clientStreamReader
.
ReadBytes
(
chunkSize
);
stream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
var
buffer
=
await
clientStreamReader
.
ReadBytesAsync
(
chunkSize
);
await
stream
.
WriteAsync
(
buffer
,
0
,
buffer
.
Length
);
//chunk trail
clientStreamReader
.
ReadLine
();
await
clientStreamReader
.
ReadLineAsync
();
}
else
{
clientStreamReader
.
ReadLine
();
await
clientStreamReader
.
ReadLineAsync
();
break
;
}
}
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
b43dc6b5
...
...
@@ -4,6 +4,7 @@ using System.IO;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Shared
;
...
...
@@ -31,7 +32,7 @@ namespace Titanium.Web.Proxy.Helpers
/// Read a line from the byte stream
/// </summary>
/// <returns></returns>
internal
string
ReadLine
()
internal
async
Task
<
string
>
ReadLineAsync
()
{
var
readBuffer
=
new
StringBuilder
();
...
...
@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers
var
lastChar
=
default
(
char
);
var
buffer
=
new
byte
[
1
];
while
(
this
.
stream
.
Read
(
buffer
,
0
,
1
)
>
0
)
while
(
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
1
).
ConfigureAwait
(
false
)
>
0
)
{
if
(
lastChar
==
'\r'
&&
buffer
[
0
]
==
'\n'
)
{
...
...
@@ -66,18 +67,18 @@ namespace Titanium.Web.Proxy.Helpers
/// Read until the last new line
/// </summary>
/// <returns></returns>
internal
List
<
string
>
ReadAllLines
()
internal
async
Task
<
List
<
string
>>
ReadAllLinesAsync
()
{
string
tmpLine
;
var
requestLines
=
new
List
<
string
>();
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
ReadLine
(
)))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
ReadLineAsync
().
ConfigureAwait
(
false
)))
{
requestLines
.
Add
(
tmpLine
);
}
return
requestLines
;
}
internal
byte
[]
ReadBytes
(
long
totalBytesToRead
)
internal
async
Task
<
byte
[
]>
ReadBytesAsync
(
long
totalBytesToRead
)
{
int
bytesToRead
=
Constants
.
BUFFER_SIZE
;
...
...
@@ -91,9 +92,9 @@ namespace Titanium.Web.Proxy.Helpers
using
(
var
outStream
=
new
MemoryStream
())
{
while
((
bytesRead
+=
this
.
stream
.
Read
(
buffer
,
0
,
bytesToRead
))
>
0
)
while
((
bytesRead
+=
await
this
.
stream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
).
ConfigureAwait
(
false
))
>
0
)
{
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
).
ConfigureAwait
(
false
);
totalBytesRead
+=
bytesRead
;
if
(
totalBytesRead
==
totalBytesToRead
)
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
b43dc6b5
...
...
@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Helpers
{
public
class
TcpHelper
{
public
static
void
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
public
async
static
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
)
{
StringBuilder
sb
=
null
;
...
...
@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
sslStream
=
new
SslStream
(
tunnelStream
);
sslStream
.
AuthenticateAsClient
(
hostName
,
null
,
Constants
.
SupportedProtocols
,
false
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostName
,
null
,
Constants
.
SupportedProtocols
,
false
);
tunnelStream
=
sslStream
;
}
catch
...
...
@@ -62,17 +62,17 @@ namespace Titanium.Web.Proxy.Helpers
}
}
var
sendRelay
=
Task
.
Factory
.
StartNew
(()
=>
{
if
(
sb
!=
null
)
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
).
Wait
(
);
else
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
).
Wait
(
);
});
Task
sendRelay
;
if
(
sb
!=
null
)
sendRelay
=
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
);
else
sendRelay
=
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
);
var
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
).
Wait
()
);
var
receiveRelay
=
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
);
Task
.
WaitAll
(
sendRelay
,
receiveRelay
);
await
Task
.
WhenAll
(
sendRelay
,
receiveRelay
).
ConfigureAwait
(
false
);
}
catch
{
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
b43dc6b5
...
...
@@ -2,6 +2,7 @@ using System;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Shared
;
...
...
@@ -35,7 +36,7 @@ namespace Titanium.Web.Proxy.Http
this
.
Response
=
new
Response
();
}
internal
void
SendRequest
()
internal
async
Task
SendRequest
()
{
Stream
stream
=
ProxyClient
.
Stream
;
...
...
@@ -57,13 +58,13 @@ namespace Titanium.Web.Proxy.Http
string
request
=
requestLines
.
ToString
();
byte
[]
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
stream
.
Write
(
requestBytes
,
0
,
requestBytes
.
Length
);
await
stream
.
WriteAsync
(
requestBytes
,
0
,
requestBytes
.
Length
);
stream
.
Flush
();
if
(
ProxyServer
.
Enable100ContinueBehaviour
)
if
(
this
.
Request
.
ExpectContinue
)
{
var
httpResult
=
ProxyClient
.
ServerStreamReader
.
ReadLine
(
).
Split
(
Constants
.
SpaceSplit
,
3
);
var
httpResult
=
(
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
()
).
Split
(
Constants
.
SpaceSplit
,
3
);
var
responseStatusCode
=
httpResult
[
1
].
Trim
();
var
responseStatusDescription
=
httpResult
[
2
].
Trim
();
...
...
@@ -72,27 +73,27 @@ namespace Titanium.Web.Proxy.Http
&&
responseStatusDescription
.
ToLower
().
Equals
(
"continue"
))
{
this
.
Request
.
Is100Continue
=
true
;
ProxyClient
.
ServerStreamReader
.
ReadLine
();
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
();
}
else
if
(
responseStatusCode
.
Equals
(
"417"
)
&&
responseStatusDescription
.
ToLower
().
Equals
(
"expectation failed"
))
{
this
.
Request
.
ExpectationFailed
=
true
;
ProxyClient
.
ServerStreamReader
.
ReadLine
();
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
();
}
}
}
internal
void
ReceiveResponse
()
internal
async
Task
ReceiveResponse
()
{
//return if this is already read
if
(
this
.
Response
.
ResponseStatusCode
!=
null
)
return
;
var
httpResult
=
ProxyClient
.
ServerStreamReader
.
ReadLine
(
).
Split
(
Constants
.
SpaceSplit
,
3
);
var
httpResult
=
(
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
()
).
Split
(
Constants
.
SpaceSplit
,
3
);
if
(
string
.
IsNullOrEmpty
(
httpResult
[
0
]))
{
var
s
=
ProxyClient
.
ServerStreamReader
.
ReadLine
();
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
();
}
this
.
Response
.
HttpVersion
=
httpResult
[
0
].
Trim
();
...
...
@@ -105,8 +106,8 @@ namespace Titanium.Web.Proxy.Http
{
this
.
Response
.
Is100Continue
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
ProxyClient
.
ServerStreamReader
.
ReadLine
();
ReceiveResponse
();
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
();
await
ReceiveResponse
();
return
;
}
else
if
(
this
.
Response
.
ResponseStatusCode
.
Equals
(
"417"
)
...
...
@@ -114,12 +115,12 @@ namespace Titanium.Web.Proxy.Http
{
this
.
Response
.
ExpectationFailed
=
true
;
this
.
Response
.
ResponseStatusCode
=
null
;
ProxyClient
.
ServerStreamReader
.
ReadLine
();
ReceiveResponse
();
await
ProxyClient
.
ServerStreamReader
.
ReadLineAsync
();
await
ReceiveResponse
();
return
;
}
List
<
string
>
responseLines
=
ProxyClient
.
ServerStreamReader
.
ReadAllLines
();
List
<
string
>
responseLines
=
await
ProxyClient
.
ServerStreamReader
.
ReadAllLinesAsync
();
for
(
int
index
=
0
;
index
<
responseLines
.
Count
;
++
index
)
{
...
...
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
View file @
b43dc6b5
...
...
@@ -61,13 +61,15 @@ namespace Titanium.Web.Proxy.Network
}
if
(
cached
==
null
)
cached
=
await
CreateClient
(
sessionArgs
,
hostname
,
port
,
isSecure
,
version
);
cached
=
await
CreateClient
(
sessionArgs
,
hostname
,
port
,
isSecure
,
version
).
ConfigureAwait
(
false
);
//if (ConnectionCache.Where(x => x.HostName == hostname && x.port == port &&
//x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2)
//{
// Task.Factory.StartNew(() => CreateClient(sessionArgs, hostname, port, isSecure, version));
//}
//just create one more preemptively
if
(
ConnectionCache
.
Where
(
x
=>
x
.
HostName
==
hostname
&&
x
.
port
==
port
&&
x
.
IsSecure
==
isSecure
&&
x
.
TcpClient
.
Connected
&&
x
.
Version
.
Equals
(
version
)).
Count
()
<
2
)
{
var
task
=
CreateClient
(
sessionArgs
,
hostname
,
port
,
isSecure
,
version
)
.
ContinueWith
(
x
=>
ReleaseClient
(
x
.
Result
));
}
return
cached
;
}
...
...
@@ -81,26 +83,26 @@ namespace Titanium.Web.Proxy.Network
{
CustomSslStream
sslStream
=
null
;
if
(
ProxyServer
.
UpStreamHttpsProxy
!=
null
)
if
(
ProxyServer
.
UpStreamHttpsProxy
!=
null
)
{
client
=
new
TcpClient
(
ProxyServer
.
UpStreamHttpsProxy
.
HostName
,
ProxyServer
.
UpStreamHttpsProxy
.
Port
);
stream
=
(
Stream
)
client
.
GetStream
();
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
Constants
.
BUFFER_SIZE
,
true
);
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
Constants
.
BUFFER_SIZE
,
true
);
writer
.
WriteLine
(
string
.
Format
(
"CONNECT {0}:{1} {2}"
,
sessionArgs
.
WebSession
.
Request
.
RequestUri
.
Host
,
sessionArgs
.
WebSession
.
Request
.
RequestUri
.
Port
,
sessionArgs
.
WebSession
.
Request
.
HttpVersion
));
writer
.
WriteLine
(
string
.
Format
(
"Host: {0}:{1}"
,
sessionArgs
.
WebSession
.
Request
.
RequestUri
.
Host
,
sessionArgs
.
WebSession
.
Request
.
RequestUri
.
Port
));
writer
.
WriteLine
(
"Connection: Keep-Alive"
);
writer
.
WriteLine
();
writer
.
Flush
();
var
reader
=
new
CustomBinaryReader
(
stream
);
var
result
=
reader
.
ReadLine
(
);
var
result
=
await
reader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
if
(!
result
.
ToLower
().
Contains
(
"200 connection established"
))
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
reader
.
ReadAllLines
(
);
await
reader
.
ReadAllLinesAsync
().
ConfigureAwait
(
false
);
}
else
{
...
...
@@ -110,9 +112,9 @@ namespace Titanium.Web.Proxy.Network
try
{
sslStream
=
new
CustomSslStream
(
stream
,
true
,
ProxyServer
.
ValidateServerCertificate
);
sslStream
=
new
CustomSslStream
(
stream
,
true
,
new
RemoteCertificateValidationCallback
(
ProxyServer
.
ValidateServerCertificate
)
);
sslStream
.
Session
=
sessionArgs
;
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
Constants
.
SupportedProtocols
,
false
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
Constants
.
SupportedProtocols
,
false
)
.
ConfigureAwait
(
false
)
;
stream
=
(
Stream
)
sslStream
;
}
catch
...
...
@@ -155,7 +157,7 @@ namespace Titanium.Web.Proxy.Network
ConnectionCache
.
Add
(
Connection
);
}
internal
static
void
ClearIdleConnections
()
internal
async
static
void
ClearIdleConnections
()
{
while
(
true
)
{
...
...
@@ -171,7 +173,7 @@ namespace Titanium.Web.Proxy.Network
ConnectionCache
.
RemoveAll
(
x
=>
x
.
LastAccess
<
cutOff
);
}
Thread
.
Sleep
(
1000
*
60
*
3
);
await
Task
.
Delay
(
1000
*
60
*
3
).
ConfigureAwait
(
false
);
}
}
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
b43dc6b5
...
...
@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy
public
static
string
RootCertificateName
{
get
;
set
;
}
public
static
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeRequest
;
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
static
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeRequest
;
public
static
event
Func
<
object
,
SessionEventArgs
,
Task
>
BeforeResponse
;
/// <summary>
/// External proxy for Http
...
...
@@ -50,14 +50,14 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// </summary>
public
static
event
EventHandler
<
CertificateValidationEventArgs
>
Remote
CertificateValidationCallback
;
public
static
event
Func
<
object
,
CertificateValidationEventArgs
,
Task
>
Server
CertificateValidationCallback
;
public
static
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
public
static
void
Initialize
()
{
T
ask
.
Factory
.
StartNew
(()
=>
TcpConnectionManager
.
ClearIdleConnections
()
);
T
cpConnectionManager
.
ClearIdleConnections
(
);
}
public
static
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
...
...
@@ -235,51 +235,6 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// Call back to override server certificate validation
/// </summary>
/// <param name="sender"></param>
/// <param name="certificate"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal
static
bool
ValidateServerCertificate
(
object
sender
,
X509Certificate
certificate
,
X509Chain
chain
,
SslPolicyErrors
sslPolicyErrors
)
{
var
param
=
sender
as
CustomSslStream
;
if
(
RemoteCertificateValidationCallback
!=
null
)
{
var
args
=
new
CertificateValidationEventArgs
();
args
.
Session
=
param
.
Session
;
args
.
Certificate
=
certificate
;
args
.
Chain
=
chain
;
args
.
SslPolicyErrors
=
sslPolicyErrors
;
RemoteCertificateValidationCallback
.
Invoke
(
null
,
args
);
if
(!
args
.
IsValid
)
{
param
.
Session
.
WebSession
.
Request
.
CancelRequest
=
true
;
}
return
args
.
IsValid
;
}
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
return
true
;
Console
.
WriteLine
(
"Certificate error: {0}"
,
sslPolicyErrors
);
//By default
//do not allow this client to communicate with unauthenticated servers.
return
false
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/RequestHandler.cs
View file @
b43dc6b5
...
...
@@ -34,7 +34,7 @@ namespace Titanium.Web.Proxy
{
//read the first line HTTP command
var
httpCmd
=
clientStreamReader
.
ReadLine
();
var
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
{
...
...
@@ -63,9 +63,9 @@ namespace Titanium.Web.Proxy
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
clientStreamReader
.
ReadAllLines
(
);
await
clientStreamReader
.
ReadAllLinesAsync
().
ConfigureAwait
(
false
);
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
await
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
).
ConfigureAwait
(
false
);
var
certificate
=
CertManager
.
CreateCertificate
(
httpRemoteUri
.
Host
);
...
...
@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy
//Successfully managed to authenticate the client using the fake certificate
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
Constants
.
SupportedProtocols
,
false
);
Constants
.
SupportedProtocols
,
false
)
.
ConfigureAwait
(
false
)
;
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
...
@@ -95,16 +95,16 @@ namespace Titanium.Web.Proxy
}
httpCmd
=
clientStreamReader
.
ReadLine
(
);
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
}
else
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
{
clientStreamReader
.
ReadAllLines
(
);
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
await
clientStreamReader
.
ReadAllLinesAsync
().
ConfigureAwait
(
false
);
await
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
).
ConfigureAwait
(
false
);
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
await
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
)
.
ConfigureAwait
(
false
)
;
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
...
...
@@ -112,8 +112,8 @@ namespace Titanium.Web.Proxy
//Now create the request
await
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
true
:
false
);
await
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
true
:
false
).
ConfigureAwait
(
false
);
}
catch
{
...
...
@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy
//This is called when requests are routed through router to this endpoint
//For ssl requests
private
static
async
Task
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
static
async
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
Stream
clientStream
=
tcpClient
.
GetStream
();
CustomBinaryReader
clientStreamReader
=
null
;
...
...
@@ -144,8 +144,8 @@ namespace Titanium.Web.Proxy
try
{
//Successfully managed to authenticate the client using the fake certificate
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
,
false
);
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
SslProtocols
.
Tls
,
false
).
ConfigureAwait
(
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
...
@@ -167,11 +167,11 @@ namespace Titanium.Web.Proxy
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
);
}
var
httpCmd
=
clientStreamReader
.
ReadLine
(
);
var
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
//Now create the request
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
tru
e
);
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
true
).
ConfigureAwait
(
fals
e
);
}
private
static
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
...
...
@@ -212,7 +212,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
clientStreamReader
.
ReadLine
(
)))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
)))
{
var
header
=
tmpLine
.
Split
(
new
char
[]
{
':'
},
2
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
new
HttpHeader
(
header
[
0
],
header
[
1
]));
...
...
@@ -231,8 +231,8 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
IsHttps
);
await
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
IsHttps
).
ConfigureAwait
(
false
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
}
...
...
@@ -241,12 +241,23 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
Request
.
RequestUri
.
Host
;
//If requested interception
BeforeRequest
?.
Invoke
(
null
,
args
);
if
(
BeforeRequest
!=
null
)
{
Delegate
[]
invocationList
=
BeforeRequest
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
await
Task
.
WhenAll
(
handlerTasks
).
ConfigureAwait
(
false
);
}
//construct the web request that we are going to issue on behalf of the client.
connection
=
connection
==
null
?
await
TcpConnectionManager
.
GetClient
(
args
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
)
:
lastRequestHostName
!=
args
.
WebSession
.
Request
.
RequestUri
.
Host
?
await
TcpConnectionManager
.
GetClient
(
args
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
)
await
TcpConnectionManager
.
GetClient
(
args
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
)
.
ConfigureAwait
(
false
)
:
lastRequestHostName
!=
args
.
WebSession
.
Request
.
RequestUri
.
Host
?
await
TcpConnectionManager
.
GetClient
(
args
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
)
.
ConfigureAwait
(
false
)
:
connection
;
lastRequestHostName
=
args
.
WebSession
.
Request
.
RequestUri
.
Host
;
...
...
@@ -262,7 +273,7 @@ namespace Titanium.Web.Proxy
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
{
args
.
WebSession
.
SetConnection
(
connection
);
a
rgs
.
WebSession
.
SendRequest
(
);
a
wait
args
.
WebSession
.
SendRequest
().
ConfigureAwait
(
false
);
}
if
(
Enable100ContinueBehaviour
)
...
...
@@ -282,7 +293,7 @@ namespace Titanium.Web.Proxy
if
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
{
args
.
WebSession
.
SetConnection
(
connection
);
a
rgs
.
WebSession
.
SendRequest
(
);
a
wait
args
.
WebSession
.
SendRequest
().
ConfigureAwait
(
false
);
}
//If request was modified by user
...
...
@@ -290,7 +301,7 @@ namespace Titanium.Web.Proxy
{
args
.
WebSession
.
Request
.
ContentLength
=
args
.
WebSession
.
Request
.
RequestBody
.
Length
;
var
newStream
=
args
.
WebSession
.
ProxyClient
.
Stream
;
newStream
.
Write
(
args
.
WebSession
.
Request
.
RequestBody
,
0
,
args
.
WebSession
.
Request
.
RequestBody
.
Length
);
await
newStream
.
WriteAsync
(
args
.
WebSession
.
Request
.
RequestBody
,
0
,
args
.
WebSession
.
Request
.
RequestBody
.
Length
).
ConfigureAwait
(
false
);
}
else
{
...
...
@@ -299,14 +310,14 @@ namespace Titanium.Web.Proxy
//If its a post/put request, then read the client html body and send it to server
if
(
httpMethod
.
ToUpper
()
==
"POST"
||
httpMethod
.
ToUpper
()
==
"PUT"
)
{
SendClientRequestBody
(
args
);
await
SendClientRequestBody
(
args
).
ConfigureAwait
(
false
);
}
}
}
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
HandleHttpSessionResponse
(
args
);
await
HandleHttpSessionResponse
(
args
).
ConfigureAwait
(
false
);
}
//if connection is closing exit
...
...
@@ -318,7 +329,7 @@ namespace Titanium.Web.Proxy
}
// read the next request
httpCmd
=
clientStreamReader
.
ReadLine
(
);
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
}
catch
...
...
@@ -333,12 +344,12 @@ namespace Titanium.Web.Proxy
TcpConnectionManager
.
ReleaseClient
(
connection
);
}
private
static
void
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
string
httpVersion
)
private
static
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
string
httpVersion
)
{
clientStreamWriter
.
WriteLine
(
httpVersion
+
" 200 Connection established"
);
clientStreamWriter
.
WriteLine
(
"Timestamp: {0}"
,
DateTime
.
Now
);
clientStreamWriter
.
WriteLine
(
);
clientStreamWriter
.
Flush
(
);
await
clientStreamWriter
.
WriteLineAsync
(
httpVersion
+
" 200 Connection established"
).
ConfigureAwait
(
false
);
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
)).
ConfigureAwait
(
false
);
await
clientStreamWriter
.
WriteLineAsync
().
ConfigureAwait
(
false
);
await
clientStreamWriter
.
FlushAsync
().
ConfigureAwait
(
false
);
}
private
static
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebSession
webRequest
)
...
...
@@ -378,17 +389,16 @@ namespace Titanium.Web.Proxy
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
}
//This is called when the request is PUT/POST to read the body
private
static
void
SendClientRequestBody
(
SessionEventArgs
args
)
private
static
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
{
// End the operation
var
postStream
=
args
.
WebSession
.
ProxyClient
.
Stream
;
if
(
args
.
WebSession
.
Request
.
ContentLength
>
0
)
{
try
{
a
rgs
.
Client
.
ClientStreamReader
.
CopyBytesToStream
(
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
a
wait
args
.
Client
.
ClientStreamReader
.
CopyBytesToStream
(
postStream
,
args
.
WebSession
.
Request
.
ContentLength
).
ConfigureAwait
(
false
);
}
catch
{
...
...
@@ -400,7 +410,7 @@ namespace Titanium.Web.Proxy
{
try
{
a
rgs
.
Client
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
postStream
);
a
wait
args
.
Client
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
postStream
).
ConfigureAwait
(
false
);
}
catch
{
...
...
@@ -409,6 +419,60 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// Call back to override server certificate validation
/// </summary>
/// <param name="sender"></param>
/// <param name="certificate"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal
static
bool
ValidateServerCertificate
(
object
sender
,
X509Certificate
certificate
,
X509Chain
chain
,
SslPolicyErrors
sslPolicyErrors
)
{
var
param
=
sender
as
CustomSslStream
;
if
(
ServerCertificateValidationCallback
!=
null
)
{
var
args
=
new
CertificateValidationEventArgs
();
args
.
Session
=
param
.
Session
;
args
.
Certificate
=
certificate
;
args
.
Chain
=
chain
;
args
.
SslPolicyErrors
=
sslPolicyErrors
;
Delegate
[]
invocationList
=
ServerCertificateValidationCallback
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
CertificateValidationEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
Task
.
WhenAll
(
handlerTasks
).
Wait
();
if
(!
args
.
IsValid
)
{
param
.
Session
.
WebSession
.
Request
.
CancelRequest
=
true
;
}
return
args
.
IsValid
;
}
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
return
true
;
Console
.
WriteLine
(
"Certificate error: {0}"
,
sslPolicyErrors
);
//By default
//do not allow this client to communicate with unauthenticated servers.
return
false
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/ResponseHandler.cs
View file @
b43dc6b5
...
...
@@ -10,15 +10,16 @@ using Titanium.Web.Proxy.Helpers;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.Shared
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy
{
partial
class
ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
public
static
void
HandleHttpSessionResponse
(
SessionEventArgs
args
)
public
static
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
a
rgs
.
WebSession
.
ReceiveResponse
(
);
a
wait
args
.
WebSession
.
ReceiveResponse
().
ConfigureAwait
(
false
);
try
{
...
...
@@ -27,8 +28,16 @@ namespace Titanium.Web.Proxy
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
{
BeforeResponse
(
null
,
args
);
{
Delegate
[]
invocationList
=
BeforeResponse
.
GetInvocationList
();
Task
[]
handlerTasks
=
new
Task
[
invocationList
.
Length
];
for
(
int
i
=
0
;
i
<
invocationList
.
Length
;
i
++)
{
handlerTasks
[
i
]
=
((
Func
<
object
,
SessionEventArgs
,
Task
>)
invocationList
[
i
])(
null
,
args
);
}
await
Task
.
WhenAll
(
handlerTasks
).
ConfigureAwait
(
false
);
}
args
.
WebSession
.
Response
.
ResponseLocked
=
true
;
...
...
@@ -56,19 +65,19 @@ namespace Titanium.Web.Proxy
if
(
contentEncoding
!=
null
)
{
args
.
WebSession
.
Response
.
ResponseBody
=
GetCompressedResponseBody
(
contentEncoding
,
args
.
WebSession
.
Response
.
ResponseBody
);
args
.
WebSession
.
Response
.
ResponseBody
=
await
GetCompressedResponseBody
(
contentEncoding
,
args
.
WebSession
.
Response
.
ResponseBody
).
ConfigureAwait
(
false
);
}
WriteResponseHeaders
(
args
.
Client
.
ClientStreamWriter
,
args
.
WebSession
.
Response
.
ResponseHeaders
,
args
.
WebSession
.
Response
.
ResponseBody
.
Length
,
isChunked
);
WriteResponseBody
(
args
.
Client
.
ClientStream
,
args
.
WebSession
.
Response
.
ResponseBody
,
isChunked
);
await
WriteResponseHeaders
(
args
.
Client
.
ClientStreamWriter
,
args
.
WebSession
.
Response
.
ResponseHeaders
,
args
.
WebSession
.
Response
.
ResponseBody
.
Length
,
isChunked
)
.
ConfigureAwait
(
false
)
;
await
WriteResponseBody
(
args
.
Client
.
ClientStream
,
args
.
WebSession
.
Response
.
ResponseBody
,
isChunked
).
ConfigureAwait
(
false
);
}
else
{
WriteResponseHeaders
(
args
.
Client
.
ClientStreamWriter
,
args
.
WebSession
.
Response
.
ResponseHeaders
);
if
(
args
.
WebSession
.
Response
.
IsChunked
||
args
.
WebSession
.
Response
.
ContentLength
>
0
)
WriteResponseBody
(
args
.
WebSession
.
ProxyClient
.
ServerStreamReader
,
args
.
Client
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
await
WriteResponseBody
(
args
.
WebSession
.
ProxyClient
.
ServerStreamReader
,
args
.
Client
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
).
ConfigureAwait
(
false
);
}
args
.
Client
.
ClientStream
.
Flush
();
...
...
@@ -84,11 +93,11 @@ namespace Titanium.Web.Proxy
}
}
private
static
byte
[]
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
static
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
{
var
compressionFactory
=
new
CompressionFactory
();
var
compressor
=
compressionFactory
.
Create
(
encodingType
);
return
compressor
.
Compress
(
responseBodyStream
);
return
await
compressor
.
Compress
(
responseBodyStream
).
ConfigureAwait
(
false
);
}
...
...
@@ -132,7 +141,7 @@ namespace Titanium.Web.Proxy
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
}
private
static
void
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
,
int
length
,
private
static
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
,
int
length
,
bool
isChunked
)
{
FixResponseProxyHeaders
(
headers
);
...
...
@@ -152,25 +161,25 @@ namespace Titanium.Web.Proxy
if
(!
isChunked
&&
header
.
Name
.
ToLower
()
==
"content-length"
)
header
.
Value
=
length
.
ToString
();
responseWriter
.
WriteLine
(
header
.
ToString
()
);
await
responseWriter
.
WriteLineAsync
(
header
.
ToString
()).
ConfigureAwait
(
false
);
}
}
responseWriter
.
WriteLine
(
);
responseWriter
.
Flush
(
);
await
responseWriter
.
WriteLineAsync
().
ConfigureAwait
(
false
);
await
responseWriter
.
FlushAsync
().
ConfigureAwait
(
false
);
}
private
static
void
WriteResponseBody
(
Stream
clientStream
,
byte
[]
data
,
bool
isChunked
)
private
static
async
Task
WriteResponseBody
(
Stream
clientStream
,
byte
[]
data
,
bool
isChunked
)
{
if
(!
isChunked
)
{
clientStream
.
Write
(
data
,
0
,
data
.
Length
);
await
clientStream
.
WriteAsync
(
data
,
0
,
data
.
Length
).
ConfigureAwait
(
false
);
}
else
WriteResponseBodyChunked
(
data
,
clientStream
);
await
WriteResponseBodyChunked
(
data
,
clientStream
).
ConfigureAwait
(
false
);
}
private
static
void
WriteResponseBody
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
,
bool
isChunked
,
long
ContentLength
)
private
static
async
Task
WriteResponseBody
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
,
bool
isChunked
,
long
ContentLength
)
{
if
(!
isChunked
)
{
...
...
@@ -184,9 +193,9 @@ namespace Titanium.Web.Proxy
var
bytesRead
=
0
;
var
totalBytesRead
=
0
;
while
((
bytesRead
+=
inStreamReader
.
BaseStream
.
Read
(
buffer
,
0
,
bytesToRead
))
>
0
)
while
((
bytesRead
+=
await
inStreamReader
.
BaseStream
.
ReadAsync
(
buffer
,
0
,
bytesToRead
).
ConfigureAwait
(
false
))
>
0
)
{
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
await
outStream
.
WriteAsync
(
buffer
,
0
,
bytesRead
).
ConfigureAwait
(
false
);
totalBytesRead
+=
bytesRead
;
if
(
totalBytesRead
==
ContentLength
)
...
...
@@ -198,50 +207,50 @@ namespace Titanium.Web.Proxy
}
}
else
WriteResponseBodyChunked
(
inStreamReader
,
outStream
);
await
WriteResponseBodyChunked
(
inStreamReader
,
outStream
).
ConfigureAwait
(
false
);
}
//Send chunked response
private
static
void
WriteResponseBodyChunked
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
)
private
static
async
Task
WriteResponseBodyChunked
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
)
{
while
(
true
)
{
var
chu
chkHead
=
inStreamReader
.
ReadLine
(
);
var
chunkSize
=
int
.
Parse
(
chu
ch
kHead
,
NumberStyles
.
HexNumber
);
var
chu
nkHead
=
await
inStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
var
chunkSize
=
int
.
Parse
(
chu
n
kHead
,
NumberStyles
.
HexNumber
);
if
(
chunkSize
!=
0
)
{
var
buffer
=
inStreamReader
.
ReadBytes
(
chunkSiz
e
);
var
buffer
=
await
inStreamReader
.
ReadBytesAsync
(
chunkSize
).
ConfigureAwait
(
fals
e
);
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
chunkSize
.
ToString
(
"x2"
));
var
chunkHead
Bytes
=
Encoding
.
ASCII
.
GetBytes
(
chunkSize
.
ToString
(
"x2"
));
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
);
await
outStream
.
WriteAsync
(
chunkHeadBytes
,
0
,
chunkHeadBytes
.
Length
).
ConfigureAwait
(
false
);
await
outStream
.
WriteAsync
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
).
ConfigureAwait
(
false
);
outStream
.
Write
(
buffer
,
0
,
chunkSiz
e
);
outStream
.
Write
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
);
await
outStream
.
WriteAsync
(
buffer
,
0
,
chunkSize
).
ConfigureAwait
(
fals
e
);
await
outStream
.
WriteAsync
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
).
ConfigureAwait
(
false
);
inStreamReader
.
ReadLine
(
);
await
inStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
}
else
{
inStreamReader
.
ReadLine
(
);
outStream
.
Write
(
Constants
.
ChunkEnd
,
0
,
Constants
.
ChunkEnd
.
Length
);
await
inStreamReader
.
ReadLineAsync
().
ConfigureAwait
(
false
);
await
outStream
.
WriteAsync
(
Constants
.
ChunkEnd
,
0
,
Constants
.
ChunkEnd
.
Length
).
ConfigureAwait
(
false
);
break
;
}
}
}
private
static
void
WriteResponseBodyChunked
(
byte
[]
data
,
Stream
outStream
)
private
static
async
Task
WriteResponseBodyChunked
(
byte
[]
data
,
Stream
outStream
)
{
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
data
.
Length
.
ToString
(
"x2"
));
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
);
outStream
.
Write
(
data
,
0
,
data
.
Length
);
outStream
.
Write
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
);
await
outStream
.
WriteAsync
(
chunkHead
,
0
,
chunkHead
.
Length
).
ConfigureAwait
(
false
);
await
outStream
.
WriteAsync
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
).
ConfigureAwait
(
false
);
await
outStream
.
WriteAsync
(
data
,
0
,
data
.
Length
).
ConfigureAwait
(
false
);
await
outStream
.
WriteAsync
(
Constants
.
NewLineBytes
,
0
,
Constants
.
NewLineBytes
.
Length
).
ConfigureAwait
(
false
);
outStream
.
Write
(
Constants
.
ChunkEnd
,
0
,
Constants
.
ChunkEnd
.
Length
);
await
outStream
.
WriteAsync
(
Constants
.
ChunkEnd
,
0
,
Constants
.
ChunkEnd
.
Length
).
ConfigureAwait
(
false
);
}
...
...
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