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