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
e27a4f92
Commit
e27a4f92
authored
Jul 12, 2016
by
justcoding121
Committed by
GitHub
Jul 12, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #96 from justcoding121/release
Peformance: Use header dictionary instead of List
parents
216b8c90
6453375e
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
491 additions
and
160 deletions
+491
-160
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+2
-0
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+6
-1
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+45
-8
HttpWebRequestExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
+2
-0
HttpWebResponseExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
+2
-0
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+14
-0
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+3
-0
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+5
-0
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+15
-2
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+45
-10
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+104
-38
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+65
-25
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+4
-1
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+20
-1
TcpConnectionCacheManager.cs
Titanium.Web.Proxy/Network/TcpConnectionCacheManager.cs
+28
-4
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+19
-1
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+62
-48
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+50
-21
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
e27a4f92
...
@@ -141,7 +141,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -141,7 +141,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
{
//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
;
}
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
...
...
Titanium.Web.Proxy/CertificateHandler.cs
View file @
e27a4f92
...
@@ -47,7 +47,9 @@ namespace Titanium.Web.Proxy
...
@@ -47,7 +47,9 @@ namespace Titanium.Web.Proxy
}
}
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
{
return
true
;
return
true
;
}
//By default
//By default
//do not allow this client to communicate with unauthenticated servers.
//do not allow this client to communicate with unauthenticated servers.
...
@@ -82,13 +84,17 @@ namespace Titanium.Web.Proxy
...
@@ -82,13 +84,17 @@ namespace Titanium.Web.Proxy
{
{
string
issuer
=
certificate
.
Issuer
;
string
issuer
=
certificate
.
Issuer
;
if
(
Array
.
IndexOf
(
acceptableIssuers
,
issuer
)
!=
-
1
)
if
(
Array
.
IndexOf
(
acceptableIssuers
,
issuer
)
!=
-
1
)
{
clientCertificate
=
certificate
;
clientCertificate
=
certificate
;
}
}
}
}
}
if
(
localCertificates
!=
null
&&
if
(
localCertificates
!=
null
&&
localCertificates
.
Count
>
0
)
localCertificates
.
Count
>
0
)
{
clientCertificate
=
localCertificates
[
0
];
clientCertificate
=
localCertificates
[
0
];
}
//If user call back is registered
//If user call back is registered
if
(
ClientCertificateSelectionCallback
!=
null
)
if
(
ClientCertificateSelectionCallback
!=
null
)
...
@@ -115,7 +121,6 @@ namespace Titanium.Web.Proxy
...
@@ -115,7 +121,6 @@ namespace Titanium.Web.Proxy
}
}
return
clientCertificate
;
return
clientCertificate
;
}
}
}
}
}
}
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
e27a4f92
...
@@ -72,7 +72,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -72,7 +72,8 @@ namespace Titanium.Web.Proxy.EventArguments
if
((
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"POST"
&&
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"PUT"
))
if
((
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"POST"
&&
WebSession
.
Request
.
Method
.
ToUpper
()
!=
"PUT"
))
{
{
throw
new
BodyNotFoundException
(
"Request don't have a body."
+
throw
new
BodyNotFoundException
(
"Request don't have a body."
+
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body."
);
"Please verify that this request is a Http POST/PUT and request "
+
"content length is greater than zero before accessing the body."
);
}
}
//Caching check
//Caching check
...
@@ -80,7 +81,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -80,7 +81,6 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
//If chunked then its easy just read the whole body with the content length mentioned in the request header
//If chunked then its easy just read the whole body with the content length mentioned in the request header
using
(
var
requestBodyStream
=
new
MemoryStream
())
using
(
var
requestBodyStream
=
new
MemoryStream
())
{
{
//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
...
@@ -94,13 +94,17 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -94,13 +94,17 @@ 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
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
await
this
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
WebSession
.
Request
.
ContentLength
);
}
}
else
if
(
WebSession
.
Request
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Request
.
HttpVersion
.
Minor
==
0
)
else
if
(
WebSession
.
Request
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Request
.
HttpVersion
.
Minor
==
0
)
{
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
long
.
MaxValue
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
requestBodyStream
,
long
.
MaxValue
);
}
}
}
WebSession
.
Request
.
RequestBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Request
.
ContentEncoding
,
requestBodyStream
.
ToArray
());
WebSession
.
Request
.
RequestBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Request
.
ContentEncoding
,
requestBodyStream
.
ToArray
());
}
}
//Now set the flag to true
//Now set the flag to true
...
@@ -130,14 +134,18 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -130,14 +134,18 @@ namespace Titanium.Web.Proxy.EventArguments
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
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
WebSession
.
Response
.
ContentLength
);
}
}
else
if
(
WebSession
.
Response
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
else
if
(
WebSession
.
Response
.
HttpVersion
.
Major
==
1
&&
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
{
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
long
.
MaxValue
);
await
WebSession
.
ServerConnection
.
StreamReader
.
CopyBytesToStream
(
bufferSize
,
responseBodyStream
,
long
.
MaxValue
);
}
}
}
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
());
WebSession
.
Response
.
ResponseBody
=
await
GetDecompressedResponseBody
(
WebSession
.
Response
.
ContentEncoding
,
responseBodyStream
.
ToArray
());
}
}
//set this to true for caching
//set this to true for caching
...
@@ -154,7 +162,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -154,7 +162,9 @@ namespace Titanium.Web.Proxy.EventArguments
if
(!
WebSession
.
Request
.
RequestBodyRead
)
if
(!
WebSession
.
Request
.
RequestBodyRead
)
{
{
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."
);
}
await
ReadRequestBody
();
await
ReadRequestBody
();
}
}
...
@@ -169,7 +179,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -169,7 +179,9 @@ namespace Titanium.Web.Proxy.EventArguments
if
(!
WebSession
.
Request
.
RequestBodyRead
)
if
(!
WebSession
.
Request
.
RequestBodyRead
)
{
{
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."
);
}
await
ReadRequestBody
();
await
ReadRequestBody
();
}
}
...
@@ -184,7 +196,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -184,7 +196,9 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
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."
);
}
//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
)
...
@@ -195,9 +209,13 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -195,9 +209,13 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession
.
Request
.
RequestBody
=
body
;
WebSession
.
Request
.
RequestBody
=
body
;
if
(
WebSession
.
Request
.
IsChunked
==
false
)
if
(
WebSession
.
Request
.
IsChunked
==
false
)
{
WebSession
.
Request
.
ContentLength
=
body
.
Length
;
WebSession
.
Request
.
ContentLength
=
body
.
Length
;
}
else
else
{
WebSession
.
Request
.
ContentLength
=
-
1
;
WebSession
.
Request
.
ContentLength
=
-
1
;
}
}
}
/// <summary>
/// <summary>
...
@@ -207,7 +225,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -207,7 +225,9 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
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."
);
}
//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
)
...
@@ -226,7 +246,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -226,7 +246,9 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
<
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."
);
}
await
ReadResponseBody
();
await
ReadResponseBody
();
return
WebSession
.
Response
.
ResponseBody
;
return
WebSession
.
Response
.
ResponseBody
;
...
@@ -239,11 +261,14 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -239,11 +261,14 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
<
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."
);
}
await
GetResponseBody
();
await
GetResponseBody
();
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
));
}
}
/// <summary>
/// <summary>
...
@@ -253,7 +278,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -253,7 +278,9 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
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."
);
}
//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
)
...
@@ -265,9 +292,13 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -265,9 +292,13 @@ namespace Titanium.Web.Proxy.EventArguments
//If there is a content length header update it
//If there is a content length header update it
if
(
WebSession
.
Response
.
IsChunked
==
false
)
if
(
WebSession
.
Response
.
IsChunked
==
false
)
{
WebSession
.
Response
.
ContentLength
=
body
.
Length
;
WebSession
.
Response
.
ContentLength
=
body
.
Length
;
}
else
else
{
WebSession
.
Response
.
ContentLength
=
-
1
;
WebSession
.
Response
.
ContentLength
=
-
1
;
}
}
}
/// <summary>
/// <summary>
...
@@ -277,7 +308,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -277,7 +308,9 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
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."
);
}
//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
)
...
@@ -308,10 +341,14 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -308,10 +341,14 @@ namespace Titanium.Web.Proxy.EventArguments
public
async
Task
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."
);
}
if
(
html
==
null
)
if
(
html
==
null
)
{
html
=
string
.
Empty
;
html
=
string
.
Empty
;
}
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
...
@@ -341,7 +378,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -341,7 +378,7 @@ namespace Titanium.Web.Proxy.EventArguments
var
response
=
new
RedirectResponse
();
var
response
=
new
RedirectResponse
();
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
HttpVersion
=
WebSession
.
Request
.
HttpVersion
;
response
.
ResponseHeaders
.
Add
(
new
Models
.
HttpHeader
(
"Location"
,
url
));
response
.
ResponseHeaders
.
Add
(
"Location"
,
new
Models
.
HttpHeader
(
"Location"
,
url
));
response
.
ResponseBody
=
Encoding
.
ASCII
.
GetBytes
(
string
.
Empty
);
response
.
ResponseBody
=
Encoding
.
ASCII
.
GetBytes
(
string
.
Empty
);
await
Respond
(
response
);
await
Respond
(
response
);
...
...
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
View file @
e27a4f92
...
@@ -20,7 +20,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -20,7 +20,9 @@ namespace Titanium.Web.Proxy.Extensions
{
{
//return default if not specified
//return default if not specified
if
(
request
.
ContentType
==
null
)
if
(
request
.
ContentType
==
null
)
{
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
//extract the encoding by finding the charset
//extract the encoding by finding the charset
var
contentTypes
=
request
.
ContentType
.
Split
(
ProxyConstants
.
SemiColonSplit
);
var
contentTypes
=
request
.
ContentType
.
Split
(
ProxyConstants
.
SemiColonSplit
);
...
...
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
View file @
e27a4f92
...
@@ -17,7 +17,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -17,7 +17,9 @@ namespace Titanium.Web.Proxy.Extensions
{
{
//return default if not specified
//return default if not specified
if
(
response
.
ContentType
==
null
)
if
(
response
.
ContentType
==
null
)
{
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
//extract the encoding by finding the charset
//extract the encoding by finding the charset
var
contentTypes
=
response
.
ContentType
.
Split
(
ProxyConstants
.
SemiColonSplit
);
var
contentTypes
=
response
.
ContentType
.
Split
(
ProxyConstants
.
SemiColonSplit
);
...
...
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
e27a4f92
...
@@ -26,6 +26,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -26,6 +26,7 @@ namespace Titanium.Web.Proxy.Extensions
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
await
output
.
WriteAsync
(
bytes
,
0
,
bytes
.
Length
);
await
output
.
WriteAsync
(
bytes
,
0
,
bytes
.
Length
);
}
}
await
input
.
CopyToAsync
(
output
);
await
input
.
CopyToAsync
(
output
);
}
}
/// <summary>
/// <summary>
...
@@ -45,7 +46,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -45,7 +46,9 @@ namespace Titanium.Web.Proxy.Extensions
bytesToRead
=
totalBytesToRead
;
bytesToRead
=
totalBytesToRead
;
}
}
else
else
{
bytesToRead
=
bufferSize
;
bytesToRead
=
bufferSize
;
}
while
(
totalbytesRead
<
totalBytesToRead
)
while
(
totalbytesRead
<
totalBytesToRead
)
...
@@ -53,7 +56,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -53,7 +56,9 @@ namespace Titanium.Web.Proxy.Extensions
var
buffer
=
await
streamReader
.
ReadBytesAsync
(
bufferSize
,
bytesToRead
);
var
buffer
=
await
streamReader
.
ReadBytesAsync
(
bufferSize
,
bytesToRead
);
if
(
buffer
.
Length
==
0
)
if
(
buffer
.
Length
==
0
)
{
break
;
break
;
}
totalbytesRead
+=
buffer
.
Length
;
totalbytesRead
+=
buffer
.
Length
;
...
@@ -62,6 +67,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -62,6 +67,7 @@ namespace Titanium.Web.Proxy.Extensions
{
{
bytesToRead
=
remainingBytes
;
bytesToRead
=
remainingBytes
;
}
}
await
stream
.
WriteAsync
(
buffer
,
0
,
buffer
.
Length
);
await
stream
.
WriteAsync
(
buffer
,
0
,
buffer
.
Length
);
}
}
}
}
...
@@ -107,7 +113,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -107,7 +113,9 @@ namespace Titanium.Web.Proxy.Extensions
await
clientStream
.
WriteAsync
(
data
,
0
,
data
.
Length
);
await
clientStream
.
WriteAsync
(
data
,
0
,
data
.
Length
);
}
}
else
else
{
await
WriteResponseBodyChunked
(
data
,
clientStream
);
await
WriteResponseBodyChunked
(
data
,
clientStream
);
}
}
}
/// <summary>
/// <summary>
/// Copies the specified content length number of bytes to the output stream from the given inputs stream
/// Copies the specified content length number of bytes to the output stream from the given inputs stream
...
@@ -124,12 +132,16 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -124,12 +132,16 @@ namespace Titanium.Web.Proxy.Extensions
{
{
//http 1.0
//http 1.0
if
(
ContentLength
==
-
1
)
if
(
ContentLength
==
-
1
)
{
ContentLength
=
long
.
MaxValue
;
ContentLength
=
long
.
MaxValue
;
}
int
bytesToRead
=
bufferSize
;
int
bytesToRead
=
bufferSize
;
if
(
ContentLength
<
bufferSize
)
if
(
ContentLength
<
bufferSize
)
{
bytesToRead
=
(
int
)
ContentLength
;
bytesToRead
=
(
int
)
ContentLength
;
}
var
buffer
=
new
byte
[
bufferSize
];
var
buffer
=
new
byte
[
bufferSize
];
...
@@ -150,7 +162,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -150,7 +162,9 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
else
else
{
await
WriteResponseBodyChunked
(
inStreamReader
,
bufferSize
,
outStream
);
await
WriteResponseBodyChunked
(
inStreamReader
,
bufferSize
,
outStream
);
}
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
e27a4f92
...
@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.Extensions
{
{
// This is how you can determine whether a socket is still connected.
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
client
.
Blocking
;
bool
blockingState
=
client
.
Blocking
;
try
try
{
{
byte
[]
tmp
=
new
byte
[
1
];
byte
[]
tmp
=
new
byte
[
1
];
...
@@ -25,7 +26,9 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -25,7 +26,9 @@ namespace Titanium.Web.Proxy.Extensions
{
{
// 10035 == WSAEWOULDBLOCK
// 10035 == WSAEWOULDBLOCK
if
(
e
.
NativeErrorCode
.
Equals
(
10035
))
if
(
e
.
NativeErrorCode
.
Equals
(
10035
))
{
return
true
;
return
true
;
}
else
else
{
{
return
false
;
return
false
;
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
e27a4f92
...
@@ -27,9 +27,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -27,9 +27,13 @@ namespace Titanium.Web.Proxy.Helpers
public
override
string
ToString
()
public
override
string
ToString
()
{
{
if
(!
IsHttps
)
if
(!
IsHttps
)
{
return
"http="
+
HostName
+
":"
+
Port
;
return
"http="
+
HostName
+
":"
+
Port
;
}
else
else
{
return
"https="
+
HostName
+
":"
+
Port
;
return
"https="
+
HostName
+
":"
+
Port
;
}
}
}
}
}
/// <summary>
/// <summary>
...
@@ -44,6 +48,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -44,6 +48,7 @@ namespace Titanium.Web.Proxy.Helpers
{
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
if
(
reg
!=
null
)
{
{
prepareRegistry
(
reg
);
prepareRegistry
(
reg
);
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
e27a4f92
...
@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="tunnelPort"></param>
/// <param name="tunnelPort"></param>
/// <param name="isHttps"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
internal
static
async
Task
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
Dictionary
<
string
,
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
,
SslProtocols
supportedProtocols
)
int
tunnelPort
,
bool
isHttps
,
SslProtocols
supportedProtocols
)
{
{
//prepare the prefix content
//prepare the prefix content
...
@@ -35,17 +35,22 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -35,17 +35,22 @@ namespace Titanium.Web.Proxy.Helpers
if
(
httpCmd
!=
null
||
requestHeaders
!=
null
)
if
(
httpCmd
!=
null
||
requestHeaders
!=
null
)
{
{
sb
=
new
StringBuilder
();
sb
=
new
StringBuilder
();
if
(
httpCmd
!=
null
)
if
(
httpCmd
!=
null
)
{
{
sb
.
Append
(
httpCmd
);
sb
.
Append
(
httpCmd
);
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
Environment
.
NewLine
);
}
}
if
(
requestHeaders
!=
null
)
if
(
requestHeaders
!=
null
)
foreach
(
var
header
in
requestHeaders
.
Select
(
t
=>
t
.
ToString
()))
{
foreach
(
var
header
in
requestHeaders
.
Select
(
t
=>
t
.
Value
.
ToString
()))
{
{
sb
.
Append
(
header
);
sb
.
Append
(
header
);
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
Environment
.
NewLine
);
}
}
}
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
Environment
.
NewLine
);
}
}
...
@@ -70,7 +75,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -70,7 +75,9 @@ namespace Titanium.Web.Proxy.Helpers
catch
catch
{
{
if
(
sslStream
!=
null
)
if
(
sslStream
!=
null
)
{
sslStream
.
Dispose
();
sslStream
.
Dispose
();
}
throw
;
throw
;
}
}
...
@@ -80,9 +87,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -80,9 +87,13 @@ namespace Titanium.Web.Proxy.Helpers
//Now async relay all server=>client & client=>server data
//Now async relay all server=>client & client=>server data
if
(
sb
!=
null
)
if
(
sb
!=
null
)
{
sendRelay
=
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
);
sendRelay
=
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
);
}
else
else
{
sendRelay
=
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
);
sendRelay
=
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
);
}
var
receiveRelay
=
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
);
var
receiveRelay
=
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
);
...
@@ -98,7 +109,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -98,7 +109,9 @@ namespace Titanium.Web.Proxy.Helpers
}
}
if
(
tunnelClient
!=
null
)
if
(
tunnelClient
!=
null
)
{
tunnelClient
.
Close
();
tunnelClient
.
Close
();
}
throw
;
throw
;
}
}
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
e27a4f92
...
@@ -58,7 +58,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -58,7 +58,7 @@ namespace Titanium.Web.Proxy.Http
Stream
stream
=
ServerConnection
.
Stream
;
Stream
stream
=
ServerConnection
.
Stream
;
StringBuilder
requestLines
=
new
StringBuilder
();
StringBuilder
requestLines
=
new
StringBuilder
();
//prepare the request & headers
//prepare the request & headers
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
new
string
[
3
]
requestLines
.
AppendLine
(
string
.
Join
(
" "
,
new
string
[
3
]
{
{
...
@@ -66,10 +66,22 @@ namespace Titanium.Web.Proxy.Http
...
@@ -66,10 +66,22 @@ namespace Titanium.Web.Proxy.Http
this
.
Request
.
RequestUri
.
PathAndQuery
,
this
.
Request
.
RequestUri
.
PathAndQuery
,
string
.
Format
(
"HTTP/{0}.{1}"
,
this
.
Request
.
HttpVersion
.
Major
,
this
.
Request
.
HttpVersion
.
Minor
)
string
.
Format
(
"HTTP/{0}.{1}"
,
this
.
Request
.
HttpVersion
.
Major
,
this
.
Request
.
HttpVersion
.
Minor
)
}));
}));
//write request headers
//write request headers
foreach
(
HttpHeader
httpHeader
in
this
.
Request
.
RequestHeaders
)
foreach
(
var
headerItem
in
this
.
Request
.
RequestHeaders
)
{
{
requestLines
.
AppendLine
(
httpHeader
.
Name
+
':'
+
httpHeader
.
Value
);
var
header
=
headerItem
.
Value
;
requestLines
.
AppendLine
(
header
.
Name
+
':'
+
header
.
Value
);
}
//write non unique request headers
foreach
(
var
headerItem
in
this
.
Request
.
NonUniqueRequestHeaders
)
{
var
headers
=
headerItem
.
Value
;
foreach
(
var
header
in
headers
)
{
requestLines
.
AppendLine
(
header
.
Name
+
':'
+
header
.
Value
);
}
}
}
requestLines
.
AppendLine
();
requestLines
.
AppendLine
();
...
@@ -80,6 +92,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -80,6 +92,7 @@ namespace Titanium.Web.Proxy.Http
await
stream
.
FlushAsync
();
await
stream
.
FlushAsync
();
if
(
enable100ContinueBehaviour
)
if
(
enable100ContinueBehaviour
)
{
if
(
this
.
Request
.
ExpectContinue
)
if
(
this
.
Request
.
ExpectContinue
)
{
{
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
var
httpResult
=
(
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()).
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
...
@@ -100,6 +113,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -100,6 +113,7 @@ namespace Titanium.Web.Proxy.Http
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
await
ServerConnection
.
StreamReader
.
ReadLineAsync
();
}
}
}
}
}
}
}
/// <summary>
/// <summary>
...
@@ -121,7 +135,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -121,7 +135,7 @@ namespace Titanium.Web.Proxy.Http
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
httpVersion
=
httpResult
[
0
].
Trim
().
ToLower
();
var
version
=
new
Version
(
1
,
1
);
var
version
=
new
Version
(
1
,
1
);
if
(
httpVersion
==
"http/1.0"
)
if
(
httpVersion
==
"http/1.0"
)
{
{
version
=
new
Version
(
1
,
0
);
version
=
new
Version
(
1
,
0
);
...
@@ -155,13 +169,34 @@ namespace Titanium.Web.Proxy.Http
...
@@ -155,13 +169,34 @@ namespace Titanium.Web.Proxy.Http
return
;
return
;
}
}
//read response headers
//Read the Response headers
List
<
string
>
responseLines
=
await
ServerConnection
.
StreamReader
.
ReadAllLinesAsync
();
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
ServerConnection
.
StreamReader
.
ReadLineAsync
()))
for
(
int
index
=
0
;
index
<
responseLines
.
Count
;
++
index
)
{
{
string
[]
strArray
=
responseLines
[
index
].
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
this
.
Response
.
ResponseHeaders
.
Add
(
new
HttpHeader
(
strArray
[
0
],
strArray
[
1
]));
var
newHeader
=
new
HttpHeader
(
header
[
0
],
header
[
1
]);
if
(
Response
.
NonUniqueResponseHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
Response
.
NonUniqueResponseHeaders
[
newHeader
.
Name
].
Add
(
newHeader
);
}
else
if
(
Response
.
ResponseHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
var
existing
=
Response
.
ResponseHeaders
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>();
nonUniqueHeaders
.
Add
(
existing
);
nonUniqueHeaders
.
Add
(
newHeader
);
Response
.
NonUniqueResponseHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
Response
.
ResponseHeaders
.
Remove
(
newHeader
.
Name
);
}
else
{
Response
.
ResponseHeaders
.
Add
(
newHeader
.
Name
,
newHeader
);
}
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
e27a4f92
...
@@ -34,18 +34,26 @@ namespace Titanium.Web.Proxy.Http
...
@@ -34,18 +34,26 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
host
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"host"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"host"
);
if
(
host
!=
null
)
if
(
hasHeader
)
return
host
.
Value
;
{
return
RequestHeaders
[
"host"
].
Value
;
}
return
null
;
return
null
;
}
}
set
set
{
{
var
host
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"host"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"host"
);
if
(
host
!=
null
)
if
(
hasHeader
)
host
.
Value
=
value
;
{
RequestHeaders
[
"host"
].
Value
=
value
;
}
else
else
RequestHeaders
.
Add
(
new
HttpHeader
(
"Host"
,
value
));
{
RequestHeaders
.
Add
(
"Host"
,
new
HttpHeader
(
"Host"
,
value
));
}
}
}
}
}
...
@@ -56,11 +64,11 @@ namespace Titanium.Web.Proxy.Http
...
@@ -56,11 +64,11 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"content-encoding"
)
);
var
h
asHeader
=
RequestHeaders
.
ContainsKey
(
"content-encoding"
);
if
(
h
eader
!=
null
)
if
(
h
asHeader
)
{
{
return
header
.
Value
.
Trim
()
;
return
RequestHeaders
[
"content-encoding"
].
Value
;
}
}
return
null
;
return
null
;
...
@@ -74,36 +82,52 @@ namespace Titanium.Web.Proxy.Http
...
@@ -74,36 +82,52 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
);
var
h
asHeader
=
RequestHeaders
.
ContainsKey
(
"content-length"
);
if
(
header
==
null
)
if
(
hasHeader
==
false
)
{
return
-
1
;
return
-
1
;
}
var
header
=
RequestHeaders
[
"content-length"
];
long
contentLen
;
long
contentLen
;
long
.
TryParse
(
header
.
Value
,
out
contentLen
);
long
.
TryParse
(
header
.
Value
,
out
contentLen
);
if
(
contentLen
>=
0
)
if
(
contentLen
>=
0
)
{
return
contentLen
;
return
contentLen
;
}
return
-
1
;
return
-
1
;
}
}
set
set
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"content-length"
);
var
header
=
RequestHeaders
[
"content-length"
];
if
(
value
>=
0
)
if
(
value
>=
0
)
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
{
header
.
Value
=
value
.
ToString
();
header
.
Value
=
value
.
ToString
();
}
else
else
RequestHeaders
.
Add
(
new
HttpHeader
(
"content-length"
,
value
.
ToString
()));
{
RequestHeaders
.
Add
(
"content-length"
,
new
HttpHeader
(
"content-length"
,
value
.
ToString
()));
}
IsChunked
=
false
;
IsChunked
=
false
;
}
}
else
else
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
this
.
RequestHeaders
.
Remove
(
header
);
{
RequestHeaders
.
Remove
(
"content-length"
);
}
}
}
}
}
}
}
...
@@ -114,19 +138,29 @@ namespace Titanium.Web.Proxy.Http
...
@@ -114,19 +138,29 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"content-type"
);
if
(
header
!=
null
)
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"content-type"
];
return
header
.
Value
;
return
header
.
Value
;
}
return
null
;
return
null
;
}
}
set
set
{
{
var
h
eader
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
);
var
h
asHeader
=
RequestHeaders
.
ContainsKey
(
"content-type"
);
if
(
header
!=
null
)
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"content-type"
];
header
.
Value
=
value
.
ToString
();
header
.
Value
=
value
.
ToString
();
}
else
else
RequestHeaders
.
Add
(
new
HttpHeader
(
"content-type"
,
value
.
ToString
()));
{
RequestHeaders
.
Add
(
"content-type"
,
new
HttpHeader
(
"content-type"
,
value
.
ToString
()));
}
}
}
}
}
...
@@ -138,29 +172,41 @@ namespace Titanium.Web.Proxy.Http
...
@@ -138,29 +172,41 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"transfer-encoding"
);
if
(
header
!=
null
)
return
header
.
Value
.
ToLower
().
Contains
(
"chunked"
);
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"transfer-encoding"
];
return
header
.
Value
.
ToLower
().
Contains
(
"chunked"
);
}
return
false
;
return
false
;
}
}
set
set
{
{
var
h
eader
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
);
var
h
asHeader
=
RequestHeaders
.
ContainsKey
(
"transfer-encoding"
);
if
(
value
)
if
(
value
)
{
{
if
(
h
eader
!=
null
)
if
(
h
asHeader
)
{
{
var
header
=
RequestHeaders
[
"transfer-encoding"
];
header
.
Value
=
"chunked"
;
header
.
Value
=
"chunked"
;
}
}
else
else
RequestHeaders
.
Add
(
new
HttpHeader
(
"transfer-encoding"
,
"chunked"
));
{
RequestHeaders
.
Add
(
"transfer-encoding"
,
new
HttpHeader
(
"transfer-encoding"
,
"chunked"
));
}
this
.
ContentLength
=
-
1
;
ContentLength
=
-
1
;
}
}
else
else
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
RequestHeaders
.
Remove
(
header
);
{
RequestHeaders
.
Remove
(
"transfer-encoding"
);
}
}
}
}
}
}
}
...
@@ -172,8 +218,15 @@ namespace Titanium.Web.Proxy.Http
...
@@ -172,8 +218,15 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"expect"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"expect"
);
if
(
header
!=
null
)
return
header
.
Value
.
Equals
(
"100-continue"
);
if
(
hasHeader
)
{
var
header
=
RequestHeaders
[
"expect"
];
return
header
.
Value
.
Equals
(
"100-continue"
);
}
return
false
;
return
false
;
}
}
}
}
...
@@ -213,12 +266,19 @@ namespace Titanium.Web.Proxy.Http
...
@@ -213,12 +266,19 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"upgrade"
);
var
hasHeader
=
RequestHeaders
.
ContainsKey
(
"upgrade"
);
if
(
header
==
null
)
if
(
hasHeader
==
false
)
{
return
false
;
return
false
;
}
var
header
=
RequestHeaders
[
"upgrade"
];
if
(
header
.
Value
.
ToLower
()
==
"websocket"
)
if
(
header
.
Value
.
ToLower
()
==
"websocket"
)
{
return
true
;
return
true
;
}
return
false
;
return
false
;
...
@@ -226,9 +286,14 @@ namespace Titanium.Web.Proxy.Http
...
@@ -226,9 +286,14 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// <summary>
/// Request heade collection
/// Unique Request header collection
/// </summary>
public
Dictionary
<
string
,
HttpHeader
>
RequestHeaders
{
get
;
set
;
}
/// <summary>
/// Non Unique headers
/// </summary>
/// </summary>
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
set
;
}
public
Dictionary
<
string
,
List
<
HttpHeader
>>
NonUnique
RequestHeaders
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Does server responsed positively for 100 continue request
/// Does server responsed positively for 100 continue request
...
@@ -242,7 +307,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -242,7 +307,8 @@ namespace Titanium.Web.Proxy.Http
public
Request
()
public
Request
()
{
{
this
.
RequestHeaders
=
new
List
<
HttpHeader
>();
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueRequestHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
}
}
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
e27a4f92
...
@@ -25,10 +25,12 @@ namespace Titanium.Web.Proxy.Http
...
@@ -25,10 +25,12 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"content-encoding"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"content-encoding"
);
if
(
h
eader
!=
null
)
if
(
h
asHeader
)
{
{
var
header
=
ResponseHeaders
[
"content-encoding"
];
return
header
.
Value
.
Trim
();
return
header
.
Value
.
Trim
();
}
}
...
@@ -45,11 +47,16 @@ namespace Titanium.Web.Proxy.Http
...
@@ -45,11 +47,16 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"connection"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"connection"
);
if
(
h
eader
!=
null
&&
header
.
Value
.
ToLower
().
Contains
(
"close"
)
)
if
(
h
asHeader
)
{
{
return
false
;
var
header
=
ResponseHeaders
[
"connection"
];
if
(
header
.
Value
.
ToLower
().
Contains
(
"close"
))
{
return
false
;
}
}
}
return
true
;
return
true
;
...
@@ -64,10 +71,12 @@ namespace Titanium.Web.Proxy.Http
...
@@ -64,10 +71,12 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"content-type"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"content-type"
);
if
(
h
eader
!=
null
)
if
(
h
asHeader
)
{
{
var
header
=
ResponseHeaders
[
"content-type"
];
return
header
.
Value
;
return
header
.
Value
;
}
}
...
@@ -83,36 +92,49 @@ namespace Titanium.Web.Proxy.Http
...
@@ -83,36 +92,49 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"content-length"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"content-length"
);
if
(
header
==
null
)
if
(
hasHeader
==
false
)
{
return
-
1
;
return
-
1
;
}
var
header
=
ResponseHeaders
[
"content-length"
];
long
contentLen
;
long
contentLen
;
long
.
TryParse
(
header
.
Value
,
out
contentLen
);
long
.
TryParse
(
header
.
Value
,
out
contentLen
);
if
(
contentLen
>=
0
)
if
(
contentLen
>=
0
)
{
return
contentLen
;
return
contentLen
;
}
return
-
1
;
return
-
1
;
}
}
set
set
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"content-length"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"content-length"
);
if
(
value
>=
0
)
if
(
value
>=
0
)
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
{
var
header
=
ResponseHeaders
[
"content-length"
];
header
.
Value
=
value
.
ToString
();
header
.
Value
=
value
.
ToString
();
}
else
else
ResponseHeaders
.
Add
(
new
HttpHeader
(
"content-length"
,
value
.
ToString
()));
{
ResponseHeaders
.
Add
(
"content-length"
,
new
HttpHeader
(
"content-length"
,
value
.
ToString
()));
}
IsChunked
=
false
;
IsChunked
=
false
;
}
}
else
else
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
this
.
ResponseHeaders
.
Remove
(
header
);
{
ResponseHeaders
.
Remove
(
"content-length"
);
}
}
}
}
}
}
}
...
@@ -124,11 +146,16 @@ namespace Titanium.Web.Proxy.Http
...
@@ -124,11 +146,16 @@ namespace Titanium.Web.Proxy.Http
{
{
get
get
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"transfer-encoding"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"transfer-encoding"
);
if
(
h
eader
!=
null
&&
header
.
Value
.
ToLower
().
Contains
(
"chunked"
)
)
if
(
h
asHeader
)
{
{
return
true
;
var
header
=
ResponseHeaders
[
"transfer-encoding"
];
if
(
header
.
Value
.
ToLower
().
Contains
(
"chunked"
))
{
return
true
;
}
}
}
return
false
;
return
false
;
...
@@ -136,23 +163,29 @@ namespace Titanium.Web.Proxy.Http
...
@@ -136,23 +163,29 @@ namespace Titanium.Web.Proxy.Http
}
}
set
set
{
{
var
h
eader
=
this
.
ResponseHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
().
Equals
(
"transfer-encoding"
)
);
var
h
asHeader
=
ResponseHeaders
.
ContainsKey
(
"transfer-encoding"
);
if
(
value
)
if
(
value
)
{
{
if
(
h
eader
!=
null
)
if
(
h
asHeader
)
{
{
var
header
=
ResponseHeaders
[
"transfer-encoding"
];
header
.
Value
=
"chunked"
;
header
.
Value
=
"chunked"
;
}
}
else
else
ResponseHeaders
.
Add
(
new
HttpHeader
(
"transfer-encoding"
,
"chunked"
));
{
ResponseHeaders
.
Add
(
"transfer-encoding"
,
new
HttpHeader
(
"transfer-encoding"
,
"chunked"
));
}
this
.
ContentLength
=
-
1
;
ContentLength
=
-
1
;
}
}
else
else
{
{
if
(
header
!=
null
)
if
(
hasHeader
)
ResponseHeaders
.
Remove
(
header
);
{
ResponseHeaders
.
Remove
(
"transfer-encoding"
);
}
}
}
}
}
...
@@ -161,7 +194,13 @@ namespace Titanium.Web.Proxy.Http
...
@@ -161,7 +194,13 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Collection of all response headers
/// Collection of all response headers
/// </summary>
/// </summary>
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
set
;
}
public
Dictionary
<
string
,
HttpHeader
>
ResponseHeaders
{
get
;
set
;
}
/// <summary>
/// Non Unique headers
/// </summary>
public
Dictionary
<
string
,
List
<
HttpHeader
>>
NonUniqueResponseHeaders
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Response network stream
/// Response network stream
...
@@ -193,7 +232,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -193,7 +232,8 @@ namespace Titanium.Web.Proxy.Http
public
Response
()
public
Response
()
{
{
this
.
ResponseHeaders
=
new
List
<
HttpHeader
>();
this
.
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
this
.
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
}
}
...
...
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
e27a4f92
...
@@ -9,7 +9,10 @@ namespace Titanium.Web.Proxy.Models
...
@@ -9,7 +9,10 @@ namespace Titanium.Web.Proxy.Models
{
{
public
HttpHeader
(
string
name
,
string
value
)
public
HttpHeader
(
string
name
,
string
value
)
{
{
if
(
string
.
IsNullOrEmpty
(
name
))
throw
new
Exception
(
"Name cannot be null"
);
if
(
string
.
IsNullOrEmpty
(
name
))
{
throw
new
Exception
(
"Name cannot be null"
);
}
Name
=
name
.
Trim
();
Name
=
name
.
Trim
();
Value
=
value
.
Trim
();
Value
=
value
.
Trim
();
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
e27a4f92
...
@@ -114,7 +114,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -114,7 +114,9 @@ namespace Titanium.Web.Proxy.Network
certificates
=
FindCertificates
(
store
,
certificateSubject
);
certificates
=
FindCertificates
(
store
,
certificateSubject
);
if
(
certificates
!=
null
)
if
(
certificates
!=
null
)
{
certificate
=
certificates
[
0
];
certificate
=
certificates
[
0
];
}
}
}
if
(
certificate
==
null
)
if
(
certificate
==
null
)
...
@@ -127,16 +129,22 @@ namespace Titanium.Web.Proxy.Network
...
@@ -127,16 +129,22 @@ namespace Titanium.Web.Proxy.Network
//remove it from store
//remove it from store
if
(!
isRootCertificate
)
if
(!
isRootCertificate
)
{
DestroyCertificate
(
certificateName
);
DestroyCertificate
(
certificateName
);
}
if
(
certificates
!=
null
)
if
(
certificates
!=
null
)
{
certificate
=
certificates
[
0
];
certificate
=
certificates
[
0
];
}
}
}
store
.
Close
();
store
.
Close
();
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
{
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
()
{
Certificate
=
certificate
});
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
()
{
Certificate
=
certificate
});
}
return
certificate
;
return
certificate
;
}
}
...
@@ -162,7 +170,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -162,7 +170,9 @@ namespace Titanium.Web.Proxy.Network
string
file
=
Path
.
Combine
(
Path
.
GetDirectoryName
(
Assembly
.
GetExecutingAssembly
().
Location
),
"makecert.exe"
);
string
file
=
Path
.
Combine
(
Path
.
GetDirectoryName
(
Assembly
.
GetExecutingAssembly
().
Location
),
"makecert.exe"
);
if
(!
File
.
Exists
(
file
))
if
(!
File
.
Exists
(
file
))
{
throw
new
Exception
(
"Unable to locate 'makecert.exe'."
);
throw
new
Exception
(
"Unable to locate 'makecert.exe'."
);
}
process
.
StartInfo
.
Verb
=
"runas"
;
process
.
StartInfo
.
Verb
=
"runas"
;
process
.
StartInfo
.
Arguments
=
args
!=
null
?
args
[
0
]
:
string
.
Empty
;
process
.
StartInfo
.
Arguments
=
args
!=
null
?
args
[
0
]
:
string
.
Empty
;
...
@@ -178,6 +188,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -178,6 +188,7 @@ namespace Titanium.Web.Proxy.Network
};
};
bool
started
=
process
.
Start
();
bool
started
=
process
.
Start
();
if
(!
started
)
if
(!
started
)
{
{
//you may allow for the process to be re-used (started = false)
//you may allow for the process to be re-used (started = false)
...
@@ -214,6 +225,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -214,6 +225,7 @@ namespace Titanium.Web.Proxy.Network
string
certificateSubject
=
string
.
Format
(
"CN={0}, O={1}"
,
certificateName
,
Issuer
);
string
certificateSubject
=
string
.
Format
(
"CN={0}, O={1}"
,
certificateName
,
Issuer
);
certificates
=
FindCertificates
(
store
,
certificateSubject
);
certificates
=
FindCertificates
(
store
,
certificateSubject
);
if
(
certificates
!=
null
)
if
(
certificates
!=
null
)
{
{
store
.
RemoveRange
(
certificates
);
store
.
RemoveRange
(
certificates
);
...
@@ -226,6 +238,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -226,6 +238,7 @@ namespace Titanium.Web.Proxy.Network
{
{
certificateCache
.
Remove
(
certificateName
);
certificateCache
.
Remove
(
certificateName
);
}
}
return
certificates
==
null
;
return
certificates
==
null
;
}
}
/// <summary>
/// <summary>
...
@@ -279,7 +292,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -279,7 +292,9 @@ namespace Titanium.Web.Proxy.Network
foreach
(
var
cache
in
outdated
)
foreach
(
var
cache
in
outdated
)
certificateCache
.
Remove
(
cache
.
Key
);
certificateCache
.
Remove
(
cache
.
Key
);
}
}
finally
{
semaphoreLock
.
Release
();
}
finally
{
semaphoreLock
.
Release
();
}
//after a minute come back to check for outdated certificates in cache
//after a minute come back to check for outdated certificates in cache
await
Task
.
Delay
(
1000
*
60
);
await
Task
.
Delay
(
1000
*
60
);
...
@@ -289,10 +304,14 @@ namespace Titanium.Web.Proxy.Network
...
@@ -289,10 +304,14 @@ namespace Titanium.Web.Proxy.Network
public
void
Dispose
()
public
void
Dispose
()
{
{
if
(
MyStore
!=
null
)
if
(
MyStore
!=
null
)
{
MyStore
.
Close
();
MyStore
.
Close
();
}
if
(
RootStore
!=
null
)
if
(
RootStore
!=
null
)
{
RootStore
.
Close
();
RootStore
.
Close
();
}
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/TcpConnectionCacheManager.cs
View file @
e27a4f92
...
@@ -51,6 +51,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -51,6 +51,7 @@ namespace Titanium.Web.Proxy.Network
while
(
true
)
while
(
true
)
{
{
await
connectionAccessLock
.
WaitAsync
();
await
connectionAccessLock
.
WaitAsync
();
try
try
{
{
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
...
@@ -65,7 +66,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -65,7 +66,9 @@ namespace Titanium.Web.Proxy.Network
cached
=
null
;
cached
=
null
;
}
}
}
}
finally
{
connectionAccessLock
.
Release
();
}
finally
{
connectionAccessLock
.
Release
();
}
if
(
cached
!=
null
&&
!
cached
.
TcpClient
.
Client
.
IsConnected
())
if
(
cached
!=
null
&&
!
cached
.
TcpClient
.
Client
.
IsConnected
())
{
{
...
@@ -75,14 +78,18 @@ namespace Titanium.Web.Proxy.Network
...
@@ -75,14 +78,18 @@ namespace Titanium.Web.Proxy.Network
}
}
if
(
cached
==
null
)
if
(
cached
==
null
)
{
break
;
break
;
}
}
}
if
(
cached
==
null
)
if
(
cached
==
null
)
{
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
,
upStreamHttpProxy
,
upStreamHttpsProxy
,
bufferSize
,
supportedSslProtocols
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
}
if
(
cachedConnections
==
null
||
cachedConnections
.
Count
()
<=
2
)
if
(
cachedConnections
==
null
||
cachedConnections
.
Count
()
<=
2
)
{
{
...
@@ -147,7 +154,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -147,7 +154,9 @@ namespace Titanium.Web.Proxy.Network
var
result
=
await
reader
.
ReadLineAsync
();
var
result
=
await
reader
.
ReadLineAsync
();
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"
);
}
await
reader
.
ReadAllLinesAsync
();
await
reader
.
ReadAllLinesAsync
();
}
}
...
@@ -162,13 +171,18 @@ namespace Titanium.Web.Proxy.Network
...
@@ -162,13 +171,18 @@ namespace Titanium.Web.Proxy.Network
{
{
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallBack
,
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallBack
,
localCertificateSelectionCallback
);
localCertificateSelectionCallback
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
supportedSslProtocols
,
false
);
await
sslStream
.
AuthenticateAsClientAsync
(
hostname
,
null
,
supportedSslProtocols
,
false
);
stream
=
(
Stream
)
sslStream
;
stream
=
(
Stream
)
sslStream
;
}
}
catch
catch
{
{
if
(
sslStream
!=
null
)
if
(
sslStream
!=
null
)
{
sslStream
.
Dispose
();
sslStream
.
Dispose
();
}
throw
;
throw
;
}
}
}
}
...
@@ -209,19 +223,25 @@ namespace Titanium.Web.Proxy.Network
...
@@ -209,19 +223,25 @@ namespace Titanium.Web.Proxy.Network
connection
.
LastAccess
=
DateTime
.
Now
;
connection
.
LastAccess
=
DateTime
.
Now
;
var
key
=
GetConnectionKey
(
connection
.
HostName
,
connection
.
port
,
connection
.
IsHttps
,
connection
.
Version
);
var
key
=
GetConnectionKey
(
connection
.
HostName
,
connection
.
port
,
connection
.
IsHttps
,
connection
.
Version
);
await
connectionAccessLock
.
WaitAsync
();
await
connectionAccessLock
.
WaitAsync
();
try
try
{
{
List
<
TcpConnectionCache
>
cachedConnections
;
List
<
TcpConnectionCache
>
cachedConnections
;
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
connectionCache
.
TryGetValue
(
key
,
out
cachedConnections
);
if
(
cachedConnections
!=
null
)
if
(
cachedConnections
!=
null
)
{
cachedConnections
.
Add
(
connection
);
cachedConnections
.
Add
(
connection
);
}
else
else
{
connectionCache
.
Add
(
key
,
new
List
<
TcpConnectionCache
>()
{
connection
});
connectionCache
.
Add
(
key
,
new
List
<
TcpConnectionCache
>()
{
connection
});
}
}
}
finally
{
connectionAccessLock
.
Release
();
}
finally
{
connectionAccessLock
.
Release
();
}
}
}
private
bool
clearConenctions
{
get
;
set
;
}
private
bool
clearConenctions
{
get
;
set
;
}
...
@@ -240,9 +260,11 @@ namespace Titanium.Web.Proxy.Network
...
@@ -240,9 +260,11 @@ namespace Titanium.Web.Proxy.Network
internal
async
void
ClearIdleConnections
(
int
connectionCacheTimeOutMinutes
)
internal
async
void
ClearIdleConnections
(
int
connectionCacheTimeOutMinutes
)
{
{
clearConenctions
=
true
;
clearConenctions
=
true
;
while
(
clearConenctions
)
while
(
clearConenctions
)
{
{
await
connectionAccessLock
.
WaitAsync
();
await
connectionAccessLock
.
WaitAsync
();
try
try
{
{
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
connectionCacheTimeOutMinutes
);
var
cutOff
=
DateTime
.
Now
.
AddMinutes
(-
1
*
connectionCacheTimeOutMinutes
);
...
@@ -255,7 +277,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -255,7 +277,9 @@ namespace Titanium.Web.Proxy.Network
connectionCache
.
ToList
().
ForEach
(
x
=>
x
.
Value
.
RemoveAll
(
y
=>
y
.
LastAccess
<
cutOff
));
connectionCache
.
ToList
().
ForEach
(
x
=>
x
.
Value
.
RemoveAll
(
y
=>
y
.
LastAccess
<
cutOff
));
}
}
finally
{
connectionAccessLock
.
Release
();
}
finally
{
connectionAccessLock
.
Release
();
}
//every minute run this
//every minute run this
await
Task
.
Delay
(
1000
*
60
);
await
Task
.
Delay
(
1000
*
60
);
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
e27a4f92
...
@@ -143,13 +143,17 @@ namespace Titanium.Web.Proxy
...
@@ -143,13 +143,17 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
public
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
public
void
AddEndPoint
(
ProxyEndPoint
endPoint
)
{
{
if
(
ProxyEndPoints
.
Any
(
x
=>
x
.
IpAddress
==
endPoint
.
IpAddress
&&
x
.
Port
==
endPoint
.
Port
))
if
(
ProxyEndPoints
.
Any
(
x
=>
x
.
IpAddress
==
endPoint
.
IpAddress
&&
x
.
Port
==
endPoint
.
Port
))
{
throw
new
Exception
(
"Cannot add another endpoint to same port & ip address"
);
throw
new
Exception
(
"Cannot add another endpoint to same port & ip address"
);
}
ProxyEndPoints
.
Add
(
endPoint
);
ProxyEndPoints
.
Add
(
endPoint
);
if
(
proxyRunning
)
if
(
proxyRunning
)
{
Listen
(
endPoint
);
Listen
(
endPoint
);
}
}
}
/// <summary>
/// <summary>
...
@@ -160,12 +164,16 @@ namespace Titanium.Web.Proxy
...
@@ -160,12 +164,16 @@ namespace Titanium.Web.Proxy
public
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
public
void
RemoveEndPoint
(
ProxyEndPoint
endPoint
)
{
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
throw
new
Exception
(
"Cannot remove endPoints not added to proxy"
);
throw
new
Exception
(
"Cannot remove endPoints not added to proxy"
);
}
ProxyEndPoints
.
Remove
(
endPoint
);
ProxyEndPoints
.
Remove
(
endPoint
);
if
(
proxyRunning
)
if
(
proxyRunning
)
{
QuitListen
(
endPoint
);
QuitListen
(
endPoint
);
}
}
}
/// <summary>
/// <summary>
...
@@ -254,7 +262,9 @@ namespace Titanium.Web.Proxy
...
@@ -254,7 +262,9 @@ namespace Titanium.Web.Proxy
public
void
Start
()
public
void
Start
()
{
{
if
(
proxyRunning
)
if
(
proxyRunning
)
{
throw
new
Exception
(
"Proxy is already running."
);
throw
new
Exception
(
"Proxy is already running."
);
}
certTrusted
=
certificateCacheManager
.
CreateTrustedRootCertificate
().
Result
;
certTrusted
=
certificateCacheManager
.
CreateTrustedRootCertificate
().
Result
;
...
@@ -275,7 +285,9 @@ namespace Titanium.Web.Proxy
...
@@ -275,7 +285,9 @@ namespace Titanium.Web.Proxy
public
void
Stop
()
public
void
Stop
()
{
{
if
(!
proxyRunning
)
if
(!
proxyRunning
)
{
throw
new
Exception
(
"Proxy is not running."
);
throw
new
Exception
(
"Proxy is not running."
);
}
var
setAsSystemProxy
=
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemHttpProxy
||
x
.
IsSystemHttpsProxy
);
var
setAsSystemProxy
=
ProxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemHttpProxy
||
x
.
IsSystemHttpsProxy
);
...
@@ -332,10 +344,14 @@ namespace Titanium.Web.Proxy
...
@@ -332,10 +344,14 @@ namespace Titanium.Web.Proxy
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
private
void
ValidateEndPointAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
{
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
if
(
ProxyEndPoints
.
Contains
(
endPoint
)
==
false
)
{
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
}
if
(!
proxyRunning
)
if
(!
proxyRunning
)
{
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
}
}
}
/// <summary>
/// <summary>
...
@@ -375,7 +391,9 @@ namespace Titanium.Web.Proxy
...
@@ -375,7 +391,9 @@ namespace Titanium.Web.Proxy
public
void
Dispose
()
public
void
Dispose
()
{
{
if
(
proxyRunning
)
if
(
proxyRunning
)
{
Stop
();
Stop
();
}
certificateCacheManager
.
Dispose
();
certificateCacheManager
.
Dispose
();
}
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
e27a4f92
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy
...
@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy
partial
class
ProxyServer
partial
class
ProxyServer
{
{
//This is called when client is aware of proxy
//This is called when client is aware of proxy
private
async
void
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
client
)
private
async
void
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
client
)
{
{
Stream
clientStream
=
client
.
GetStream
();
Stream
clientStream
=
client
.
GetStream
();
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
);
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
);
...
@@ -49,9 +49,13 @@ namespace Titanium.Web.Proxy
...
@@ -49,9 +49,13 @@ namespace Titanium.Web.Proxy
var
httpVerb
=
httpCmdSplit
[
0
];
var
httpVerb
=
httpCmdSplit
[
0
];
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
{
httpRemoteUri
=
new
Uri
(
"http://"
+
httpCmdSplit
[
1
]);
httpRemoteUri
=
new
Uri
(
"http://"
+
httpCmdSplit
[
1
]);
}
else
else
{
httpRemoteUri
=
new
Uri
(
httpCmdSplit
[
1
]);
httpRemoteUri
=
new
Uri
(
httpCmdSplit
[
1
]);
}
//parse the HTTP version
//parse the HTTP version
Version
version
=
new
Version
(
1
,
1
);
Version
version
=
new
Version
(
1
,
1
);
...
@@ -103,7 +107,9 @@ namespace Titanium.Web.Proxy
...
@@ -103,7 +107,9 @@ namespace Titanium.Web.Proxy
catch
catch
{
{
if
(
sslStream
!=
null
)
if
(
sslStream
!=
null
)
{
sslStream
.
Dispose
();
sslStream
.
Dispose
();
}
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
...
@@ -131,7 +137,7 @@ namespace Titanium.Web.Proxy
...
@@ -131,7 +137,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
?
httpRemoteUri
.
Host
:
null
);
}
}
catch
catch
{
{
...
@@ -141,7 +147,7 @@ namespace Titanium.Web.Proxy
...
@@ -141,7 +147,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
async
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
async
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
{
Stream
clientStream
=
tcpClient
.
GetStream
();
Stream
clientStream
=
tcpClient
.
GetStream
();
CustomBinaryReader
clientStreamReader
=
null
;
CustomBinaryReader
clientStreamReader
=
null
;
...
@@ -169,7 +175,9 @@ namespace Titanium.Web.Proxy
...
@@ -169,7 +175,9 @@ namespace Titanium.Web.Proxy
catch
(
Exception
)
catch
(
Exception
)
{
{
if
(
sslStream
!=
null
)
if
(
sslStream
!=
null
)
{
sslStream
.
Dispose
();
sslStream
.
Dispose
();
}
Dispose
(
tcpClient
,
sslStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
tcpClient
,
sslStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
...
@@ -186,7 +194,7 @@ namespace Titanium.Web.Proxy
...
@@ -186,7 +194,7 @@ namespace Titanium.Web.Proxy
//Now create the request
//Now create the request
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
true
);
endPoint
.
EnableSsl
?
endPoint
.
GenericCertificateName
:
null
);
}
}
/// <summary>
/// <summary>
/// This is the core request handler method for a particular connection from client
/// This is the core request handler method for a particular connection from client
...
@@ -196,10 +204,10 @@ namespace Titanium.Web.Proxy
...
@@ -196,10 +204,10 @@ namespace Titanium.Web.Proxy
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="
isHttps
"></param>
/// <param name="
httpsHostName
"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
private
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
bool
isHttps
)
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsHostName
)
{
{
TcpConnectionCache
connection
=
null
;
TcpConnectionCache
connection
=
null
;
...
@@ -235,26 +243,50 @@ namespace Titanium.Web.Proxy
...
@@ -235,26 +243,50 @@ namespace Titanium.Web.Proxy
}
}
}
}
args
.
WebSession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
//Read the request headers
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
new
HttpHeader
(
header
[
0
],
header
[
1
]));
}
var
httpRemoteUri
=
new
Uri
(!
isHttps
?
httpCmdSplit
[
1
]
:
(
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
,
httpCmdSplit
[
1
])));
#if DEBUG
#if DEBUG
//Just ignore local requests while Debugging
//Just ignore local requests while Debugging
//Its annoying
//Its annoying
if
(
http
RemoteUri
.
Host
.
Contains
(
"localhost"
))
if
(
http
Cmd
.
Contains
(
"localhost"
))
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
break
;
break
;
}
}
#endif
#endif
//Read the request headers
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
var
header
=
tmpLine
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
var
newHeader
=
new
HttpHeader
(
header
[
0
],
header
[
1
]);
if
(
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
[
newHeader
.
Name
].
Add
(
newHeader
);
}
else
if
(
args
.
WebSession
.
Request
.
RequestHeaders
.
ContainsKey
(
newHeader
.
Name
))
{
var
existing
=
args
.
WebSession
.
Request
.
RequestHeaders
[
newHeader
.
Name
];
var
nonUniqueHeaders
=
new
List
<
HttpHeader
>();
nonUniqueHeaders
.
Add
(
existing
);
nonUniqueHeaders
.
Add
(
newHeader
);
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
.
Add
(
newHeader
.
Name
,
nonUniqueHeaders
);
args
.
WebSession
.
Request
.
RequestHeaders
.
Remove
(
newHeader
.
Name
);
}
else
{
args
.
WebSession
.
Request
.
RequestHeaders
.
Add
(
newHeader
.
Name
,
newHeader
);
}
}
var
httpRemoteUri
=
new
Uri
(
httpsHostName
==
null
?
httpCmdSplit
[
1
]
:
(
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
==
null
?
httpsHostName
:
args
.
WebSession
.
Request
.
Host
,
httpCmdSplit
[
1
])));
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
args
.
WebSession
.
Request
.
Method
=
httpMethod
;
args
.
WebSession
.
Request
.
Method
=
httpMethod
;
...
@@ -313,6 +345,7 @@ namespace Titanium.Web.Proxy
...
@@ -313,6 +345,7 @@ namespace Titanium.Web.Proxy
//If 100 continue was the response inform that to the client
//If 100 continue was the response inform that to the client
if
(
Enable100ContinueBehaviour
)
if
(
Enable100ContinueBehaviour
)
{
if
(
args
.
WebSession
.
Request
.
Is100Continue
)
if
(
args
.
WebSession
.
Request
.
Is100Continue
)
{
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
...
@@ -325,6 +358,7 @@ namespace Titanium.Web.Proxy
...
@@ -325,6 +358,7 @@ namespace Titanium.Web.Proxy
"Expectation Failed"
,
args
.
ProxyClient
.
ClientStreamWriter
);
"Expectation Failed"
,
args
.
ProxyClient
.
ClientStreamWriter
);
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
}
}
}
//If expect continue is not enabled then set the connectio and send request headers
//If expect continue is not enabled then set the connectio and send request headers
if
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
if
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
...
@@ -394,7 +428,7 @@ namespace Titanium.Web.Proxy
...
@@ -394,7 +428,7 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamWriter"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="httpVersion"></param>
/// <param name="httpVersion"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
private
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
{
{
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2}"
,
httpVersion
.
Major
,
httpVersion
.
Minor
,
"200 Connection established"
));
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2}"
,
httpVersion
.
Major
,
httpVersion
.
Minor
,
"200 Connection established"
));
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
));
await
clientStreamWriter
.
WriteLineAsync
(
string
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
));
...
@@ -407,15 +441,17 @@ namespace Titanium.Web.Proxy
...
@@ -407,15 +441,17 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
/// <param name="requestHeaders"></param>
/// <param name="requestHeaders"></param>
/// <param name="webRequest"></param>
/// <param name="webRequest"></param>
private
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
private
void
PrepareRequestHeaders
(
Dictionary
<
string
,
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
{
{
for
(
var
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++
)
for
each
(
var
headerItem
in
requestHeaders
)
{
{
switch
(
requestHeaders
[
i
].
Name
.
ToLower
())
var
header
=
headerItem
.
Value
;
switch
(
header
.
Name
.
ToLower
())
{
{
//these are the only encoding this proxy can read
//these are the only encoding this proxy can read
case
"accept-encoding"
:
case
"accept-encoding"
:
requestHeaders
[
i
]
.
Value
=
"gzip,deflate,zlib"
;
header
.
Value
=
"gzip,deflate,zlib"
;
break
;
break
;
default
:
default
:
...
@@ -423,39 +459,17 @@ namespace Titanium.Web.Proxy
...
@@ -423,39 +459,17 @@ namespace Titanium.Web.Proxy
}
}
}
}
Fix
Request
ProxyHeaders
(
requestHeaders
);
FixProxyHeaders
(
requestHeaders
);
webRequest
.
Request
.
RequestHeaders
=
requestHeaders
;
webRequest
.
Request
.
RequestHeaders
=
requestHeaders
;
}
}
/// <summary>
/// Fix proxy specific headers
/// </summary>
/// <param name="headers"></param>
private
void
FixRequestProxyHeaders
(
List
<
HttpHeader
>
headers
)
{
//If proxy-connection close was returned inform to close the connection
var
proxyHeader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
var
connectionheader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"connection"
);
if
(
proxyHeader
!=
null
)
if
(
connectionheader
==
null
)
{
headers
.
Add
(
new
HttpHeader
(
"connection"
,
proxyHeader
.
Value
));
}
else
{
connectionheader
.
Value
=
proxyHeader
.
Value
;
}
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
}
/// <summary>
/// <summary>
/// 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
/// </summary>
/// </summary>
/// <param name="args"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
private
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
{
{
// End the operation
// End the operation
var
postStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
var
postStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e27a4f92
...
@@ -8,6 +8,7 @@ using Titanium.Web.Proxy.Models;
...
@@ -8,6 +8,7 @@ using Titanium.Web.Proxy.Models;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.Compression
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -17,7 +18,7 @@ namespace Titanium.Web.Proxy
...
@@ -17,7 +18,7 @@ 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
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
public
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
{
//read response & headers from server
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
await
args
.
WebSession
.
ReceiveResponse
();
...
@@ -25,7 +26,9 @@ namespace Titanium.Web.Proxy
...
@@ -25,7 +26,9 @@ namespace Titanium.Web.Proxy
try
try
{
{
if
(!
args
.
WebSession
.
Response
.
ResponseBodyRead
)
if
(!
args
.
WebSession
.
Response
.
ResponseBodyRead
)
{
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
}
//If user requested call back then do it
//If user requested call back then do it
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
...
@@ -71,26 +74,39 @@ namespace Titanium.Web.Proxy
...
@@ -71,26 +74,39 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Response
.
ResponseBody
=
await
GetCompressedResponseBody
(
contentEncoding
,
args
.
WebSession
.
Response
.
ResponseBody
);
args
.
WebSession
.
Response
.
ResponseBody
=
await
GetCompressedResponseBody
(
contentEncoding
,
args
.
WebSession
.
Response
.
ResponseBody
);
if
(
isChunked
==
false
)
if
(
isChunked
==
false
)
{
args
.
WebSession
.
Response
.
ContentLength
=
args
.
WebSession
.
Response
.
ResponseBody
.
Length
;
args
.
WebSession
.
Response
.
ContentLength
=
args
.
WebSession
.
Response
.
ResponseBody
.
Length
;
}
else
else
{
args
.
WebSession
.
Response
.
ContentLength
=
-
1
;
args
.
WebSession
.
Response
.
ContentLength
=
-
1
;
}
}
}
await
WriteResponseHeaders
(
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
Response
.
ResponseHeaders
);
await
WriteResponseHeaders
(
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
Response
);
await
args
.
ProxyClient
.
ClientStream
.
WriteResponseBody
(
args
.
WebSession
.
Response
.
ResponseBody
,
isChunked
);
await
args
.
ProxyClient
.
ClientStream
.
WriteResponseBody
(
args
.
WebSession
.
Response
.
ResponseBody
,
isChunked
);
}
}
else
else
{
{
await
WriteResponseHeaders
(
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
Response
.
ResponseHeaders
);
await
WriteResponseHeaders
(
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
Response
);
//Write body only if response is chunked or content length >0
//Write body only if response is chunked or content length >0
//Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection
//Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection
if
(
args
.
WebSession
.
Response
.
IsChunked
||
args
.
WebSession
.
Response
.
ContentLength
>
0
||
!
args
.
WebSession
.
Response
.
ResponseKeepAlive
)
if
(
args
.
WebSession
.
Response
.
IsChunked
||
args
.
WebSession
.
Response
.
ContentLength
>
0
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
||
!
args
.
WebSession
.
Response
.
ResponseKeepAlive
)
{
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
}
//write response if connection:keep-alive header exist and when version is http/1.0
//write response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
else
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
&&
args
.
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
else
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
&&
args
.
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
{
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
BUFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
}
}
}
await
args
.
ProxyClient
.
ClientStream
.
FlushAsync
();
await
args
.
ProxyClient
.
ClientStream
.
FlushAsync
();
...
@@ -98,7 +114,8 @@ namespace Titanium.Web.Proxy
...
@@ -98,7 +114,8 @@ namespace Titanium.Web.Proxy
}
}
catch
catch
{
{
Dispose
(
args
.
ProxyClient
.
TcpClient
,
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
Dispose
(
args
.
ProxyClient
.
TcpClient
,
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
);
}
}
finally
finally
{
{
...
@@ -112,7 +129,7 @@ namespace Titanium.Web.Proxy
...
@@ -112,7 +129,7 @@ namespace Titanium.Web.Proxy
/// <param name="encodingType"></param>
/// <param name="encodingType"></param>
/// <param name="responseBodyStream"></param>
/// <param name="responseBodyStream"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
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
);
...
@@ -127,7 +144,7 @@ namespace Titanium.Web.Proxy
...
@@ -127,7 +144,7 @@ namespace Titanium.Web.Proxy
/// <param name="description"></param>
/// <param name="description"></param>
/// <param name="responseWriter"></param>
/// <param name="responseWriter"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
private
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
StreamWriter
responseWriter
)
StreamWriter
responseWriter
)
{
{
await
responseWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
code
,
description
));
await
responseWriter
.
WriteLineAsync
(
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
code
,
description
));
...
@@ -139,43 +156,56 @@ namespace Titanium.Web.Proxy
...
@@ -139,43 +156,56 @@ namespace Titanium.Web.Proxy
/// <param name="responseWriter"></param>
/// <param name="responseWriter"></param>
/// <param name="headers"></param>
/// <param name="headers"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
)
private
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
Response
response
)
{
{
if
(
headers
!=
null
)
FixProxyHeaders
(
response
.
ResponseHeaders
);
foreach
(
var
header
in
response
.
ResponseHeaders
)
{
{
FixResponseProxyHeaders
(
headers
);
await
responseWriter
.
WriteLineAsync
(
header
.
Value
.
ToString
());
}
//write non unique request headers
foreach
(
var
headerItem
in
response
.
NonUniqueResponseHeaders
)
{
var
headers
=
headerItem
.
Value
;
foreach
(
var
header
in
headers
)
foreach
(
var
header
in
headers
)
{
{
await
responseWriter
.
WriteLineAsync
(
header
.
ToString
());
await
responseWriter
.
WriteLineAsync
(
header
.
ToString
());
}
}
}
}
await
responseWriter
.
WriteLineAsync
();
await
responseWriter
.
WriteLineAsync
();
await
responseWriter
.
FlushAsync
();
await
responseWriter
.
FlushAsync
();
}
}
/// <summary>
/// <summary>
/// Fix
the proxy specific headers before sending response headers to client
/// Fix
proxy specific headers
/// </summary>
/// </summary>
/// <param name="headers"></param>
/// <param name="headers"></param>
private
void
FixResponseProxyHeaders
(
List
<
HttpHeader
>
headers
)
private
void
FixProxyHeaders
(
Dictionary
<
string
,
HttpHeader
>
headers
)
{
{
//If proxy-connection close was returned inform to close the connection
//If proxy-connection close was returned inform to close the connection
var
proxyHeader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
var
hasProxyHeader
=
headers
.
ContainsKey
(
"proxy-connection"
);
var
connectionHeader
=
headers
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"connection"
);
var
hasConnectionheader
=
headers
.
ContainsKey
(
"connection"
);
if
(
proxyHeader
!=
null
)
if
(
hasProxyHeader
)
if
(
connectionHeader
==
null
)
{
var
proxyHeader
=
headers
[
"proxy-connection"
];
if
(
hasConnectionheader
==
false
)
{
{
headers
.
Add
(
new
HttpHeader
(
"connection"
,
proxyHeader
.
Value
));
headers
.
Add
(
"connection"
,
new
HttpHeader
(
"connection"
,
proxyHeader
.
Value
));
}
}
else
else
{
{
var
connectionHeader
=
headers
[
"connection"
];
connectionHeader
.
Value
=
proxyHeader
.
Value
;
connectionHeader
.
Value
=
proxyHeader
.
Value
;
}
}
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
headers
.
Remove
(
"proxy-connection"
);
}
}
}
/// <summary>
/// <summary>
...
@@ -212,7 +242,6 @@ namespace Titanium.Web.Proxy
...
@@ -212,7 +242,6 @@ namespace Titanium.Web.Proxy
if
(
clientStreamWriter
!=
null
)
if
(
clientStreamWriter
!=
null
)
clientStreamWriter
.
Dispose
();
clientStreamWriter
.
Dispose
();
}
}
}
}
}
}
\ No newline at end of file
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