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
4b86cde8
Commit
4b86cde8
authored
May 20, 2016
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
asyncify more
parent
ff0dddf4
Show 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 @
4b86cde8
...
...
@@ -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,7 +86,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Filter URL
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
e
.
Ok
(
"<!DOCTYPE html>"
+
await
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
...
...
@@ -97,15 +97,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
//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 @
4b86cde8
...
...
@@ -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
...
...
@@ -62,7 +62,6 @@ Setup HTTP proxy:
};
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,7 +110,7 @@ Sample request and response event handlers
//Filter URL
if
(
e
.
WebSession
.
Request
.
RequestUri
.
AbsoluteUri
.
Contains
(
"google.com"
))
{
e
.
Ok
(
"<!DOCTYPE html>"
+
await
e
.
Ok
(
"<!DOCTYPE html>"
+
"<html><body><h1>"
+
"Website Blocked"
+
"</h1>"
+
...
...
@@ -121,13 +121,13 @@ Sample request and response event handlers
//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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
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 @
4b86cde8
...
...
@@ -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 @
4b86cde8
...
...
@@ -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 @
4b86cde8
...
...
@@ -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 @
4b86cde8
...
...
@@ -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
(()
=>
{
Task
sendRelay
;
if
(
sb
!=
null
)
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
).
Wait
(
);
sendRelay
=
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
);
else
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
).
Wait
(
);
});
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 @
4b86cde8
...
...
@@ -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 @
4b86cde8
...
...
@@ -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,12 +83,12 @@ 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
));
...
...
@@ -95,12 +97,12 @@ namespace Titanium.Web.Proxy.Network
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 @
4b86cde8
...
...
@@ -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
)
...
...
@@ -236,50 +236,5 @@ 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 @
4b86cde8
...
...
@@ -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
;
...
...
@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy
//Now create the request
await
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
true
:
false
);
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
);
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 @
4b86cde8
...
...
@@ -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
{
...
...
@@ -28,7 +29,15 @@ 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