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
9bac69a9
Commit
9bac69a9
authored
Jun 16, 2016
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add more comments
parent
4bcd22fc
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
200 additions
and
16 deletions
+200
-16
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+58
-1
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+39
-1
TcpConnectionManager.cs
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
+1
-1
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+1
-1
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+61
-9
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+40
-3
No files found.
Titanium.Web.Proxy/Http/Request.cs
View file @
9bac69a9
...
@@ -12,10 +12,24 @@ namespace Titanium.Web.Proxy.Http
...
@@ -12,10 +12,24 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
class
Request
public
class
Request
{
{
/// <summary>
/// Request Method
/// </summary>
public
string
Method
{
get
;
set
;
}
public
string
Method
{
get
;
set
;
}
/// <summary>
/// Request HTTP Uri
/// </summary>
public
Uri
RequestUri
{
get
;
set
;
}
public
Uri
RequestUri
{
get
;
set
;
}
/// <summary>
/// Request Http Version
/// </summary>
public
Version
HttpVersion
{
get
;
set
;
}
public
Version
HttpVersion
{
get
;
set
;
}
/// <summary>
/// Request Http hostanem
/// </summary>
internal
string
Host
internal
string
Host
{
{
get
get
...
@@ -35,6 +49,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -35,6 +49,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request content encoding
/// </summary>
internal
string
ContentEncoding
internal
string
ContentEncoding
{
{
get
get
...
@@ -50,6 +67,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -50,6 +67,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request content-length
/// </summary>
public
long
ContentLength
public
long
ContentLength
{
{
get
get
...
@@ -68,7 +88,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -68,7 +88,6 @@ namespace Titanium.Web.Proxy.Http
}
}
set
set
{
{
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
);
var
header
=
RequestHeaders
.
FirstOrDefault
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
);
if
(
value
>=
0
)
if
(
value
>=
0
)
...
@@ -88,6 +107,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -88,6 +107,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request content-type
/// </summary>
public
string
ContentType
public
string
ContentType
{
{
get
get
...
@@ -109,6 +131,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -109,6 +131,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Is request body send as chunked bytes
/// </summary>
public
bool
IsChunked
public
bool
IsChunked
{
{
get
get
...
@@ -140,6 +165,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -140,6 +165,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Does this request has a 100-continue header?
/// </summary>
public
bool
ExpectContinue
public
bool
ExpectContinue
{
{
get
get
...
@@ -150,19 +178,37 @@ namespace Titanium.Web.Proxy.Http
...
@@ -150,19 +178,37 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request Url
/// </summary>
public
string
Url
{
get
{
return
RequestUri
.
OriginalString
;
}
}
public
string
Url
{
get
{
return
RequestUri
.
OriginalString
;
}
}
/// <summary>
/// Encoding for this request
/// </summary>
internal
Encoding
Encoding
{
get
{
return
this
.
GetEncoding
();
}
}
internal
Encoding
Encoding
{
get
{
return
this
.
GetEncoding
();
}
}
/// <summary>
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request
/// Terminates the underlying Tcp Connection to client after current request
/// </summary>
/// </summary>
internal
bool
CancelRequest
{
get
;
set
;
}
internal
bool
CancelRequest
{
get
;
set
;
}
/// <summary>
/// Request body as byte array
/// </summary>
internal
byte
[]
RequestBody
{
get
;
set
;
}
internal
byte
[]
RequestBody
{
get
;
set
;
}
/// <summary>
/// request body as string
/// </summary>
internal
string
RequestBodyString
{
get
;
set
;
}
internal
string
RequestBodyString
{
get
;
set
;
}
internal
bool
RequestBodyRead
{
get
;
set
;
}
internal
bool
RequestBodyRead
{
get
;
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
/// <summary>
/// Does this request has an upgrade to websocket header?
/// </summary>
internal
bool
UpgradeToWebSocket
internal
bool
UpgradeToWebSocket
{
{
get
get
...
@@ -179,8 +225,19 @@ namespace Titanium.Web.Proxy.Http
...
@@ -179,8 +225,19 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request heade collection
/// </summary>
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
set
;
}
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
set
;
}
/// <summary>
/// Does server responsed positively for 100 continue request
/// </summary>
public
bool
Is100Continue
{
get
;
internal
set
;
}
public
bool
Is100Continue
{
get
;
internal
set
;
}
/// <summary>
/// Server responsed negatively for the request for 100 continue
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
public
Request
()
public
Request
()
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
9bac69a9
...
@@ -18,7 +18,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -18,7 +18,9 @@ namespace Titanium.Web.Proxy.Http
internal
Encoding
Encoding
{
get
{
return
this
.
GetResponseCharacterEncoding
();
}
}
internal
Encoding
Encoding
{
get
{
return
this
.
GetResponseCharacterEncoding
();
}
}
/// <summary>
/// Content encoding for this response
/// </summary>
internal
string
ContentEncoding
internal
string
ContentEncoding
{
{
get
get
...
@@ -35,6 +37,10 @@ namespace Titanium.Web.Proxy.Http
...
@@ -35,6 +37,10 @@ namespace Titanium.Web.Proxy.Http
}
}
internal
Version
HttpVersion
{
get
;
set
;
}
internal
Version
HttpVersion
{
get
;
set
;
}
/// <summary>
/// Keep the connection alive?
/// </summary>
internal
bool
ResponseKeepAlive
internal
bool
ResponseKeepAlive
{
{
get
get
...
@@ -51,6 +57,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -51,6 +57,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Content type of this response
/// </summary>
public
string
ContentType
public
string
ContentType
{
{
get
get
...
@@ -67,6 +76,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -67,6 +76,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Length of response body
/// </summary>
internal
long
ContentLength
internal
long
ContentLength
{
{
get
get
...
@@ -105,6 +117,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -105,6 +117,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Response transfer-encoding is chunked?
/// </summary>
internal
bool
IsChunked
internal
bool
IsChunked
{
{
get
get
...
@@ -143,14 +158,37 @@ namespace Titanium.Web.Proxy.Http
...
@@ -143,14 +158,37 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Collection of all response headers
/// </summary>
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
set
;
}
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
set
;
}
/// <summary>
/// Response network stream
/// </summary>
internal
Stream
ResponseStream
{
get
;
set
;
}
internal
Stream
ResponseStream
{
get
;
set
;
}
/// <summary>
/// response body contenst as byte array
/// </summary>
internal
byte
[]
ResponseBody
{
get
;
set
;
}
internal
byte
[]
ResponseBody
{
get
;
set
;
}
/// <summary>
/// response body as string
/// </summary>
internal
string
ResponseBodyString
{
get
;
set
;
}
internal
string
ResponseBodyString
{
get
;
set
;
}
internal
bool
ResponseBodyRead
{
get
;
set
;
}
internal
bool
ResponseBodyRead
{
get
;
set
;
}
internal
bool
ResponseLocked
{
get
;
set
;
}
internal
bool
ResponseLocked
{
get
;
set
;
}
/// <summary>
/// Is response 100-continue
/// </summary>
public
bool
Is100Continue
{
get
;
internal
set
;
}
public
bool
Is100Continue
{
get
;
internal
set
;
}
/// <summary>
/// expectation failed returned by server?
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
public
Response
()
public
Response
()
...
...
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
View file @
9bac69a9
...
@@ -44,7 +44,6 @@ namespace Titanium.Web.Proxy.Network
...
@@ -44,7 +44,6 @@ namespace Titanium.Web.Proxy.Network
//Get a unique string to identify this connection
//Get a unique string to identify this connection
var
key
=
GetConnectionKey
(
hostname
,
port
,
isHttps
,
version
);
var
key
=
GetConnectionKey
(
hostname
,
port
,
isHttps
,
version
);
while
(
true
)
while
(
true
)
{
{
await
connectionAccessLock
.
WaitAsync
();
await
connectionAccessLock
.
WaitAsync
();
...
@@ -76,6 +75,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -76,6 +75,7 @@ namespace Titanium.Web.Proxy.Network
}
}
if
(
cached
==
null
)
if
(
cached
==
null
)
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
);
cached
=
await
CreateClient
(
hostname
,
port
,
isHttps
,
version
);
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
9bac69a9
...
@@ -351,7 +351,7 @@ namespace Titanium.Web.Proxy
...
@@ -351,7 +351,7 @@ namespace Titanium.Web.Proxy
}
}
catch
catch
{
{
//Other errors are discarded to keep
the
proxy running
//Other errors are discarded to keep proxy running
}
}
}
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
9bac69a9
...
@@ -18,7 +18,9 @@ using System.Threading.Tasks;
...
@@ -18,7 +18,9 @@ using System.Threading.Tasks;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
/// <summary>
/// Handle the requesr
/// </summary>
partial
class
ProxyServer
partial
class
ProxyServer
{
{
//This is called when client is aware of proxy
//This is called when client is aware of proxy
...
@@ -43,6 +45,7 @@ namespace Titanium.Web.Proxy
...
@@ -43,6 +45,7 @@ namespace Titanium.Web.Proxy
//break up the line into three components (method, remote URL & Http Version)
//break up the line into three components (method, remote URL & Http Version)
var
httpCmdSplit
=
httpCmd
.
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
var
httpCmdSplit
=
httpCmd
.
Split
(
ProxyConstants
.
SpaceSplit
,
3
);
//Find the request Verb
var
httpVerb
=
httpCmdSplit
[
0
];
var
httpVerb
=
httpCmdSplit
[
0
];
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
...
@@ -50,6 +53,7 @@ namespace Titanium.Web.Proxy
...
@@ -50,6 +53,7 @@ namespace Titanium.Web.Proxy
else
else
httpRemoteUri
=
new
Uri
(
httpCmdSplit
[
1
]);
httpRemoteUri
=
new
Uri
(
httpCmdSplit
[
1
]);
//parse the HTTP version
Version
version
=
new
Version
(
1
,
1
);
Version
version
=
new
Version
(
1
,
1
);
if
(
httpCmdSplit
.
Length
==
3
)
if
(
httpCmdSplit
.
Length
==
3
)
{
{
...
@@ -76,7 +80,8 @@ namespace Titanium.Web.Proxy
...
@@ -76,7 +80,8 @@ namespace Titanium.Web.Proxy
try
try
{
{
//create the Tcp Connection to server and then release it to connection cache
//Just doing what CONNECT request is asking as to do
var
tunnelClient
=
await
TcpConnectionManager
.
GetClient
(
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
true
,
version
);
var
tunnelClient
=
await
TcpConnectionManager
.
GetClient
(
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
true
,
version
);
await
TcpConnectionManager
.
ReleaseClient
(
tunnelClient
);
await
TcpConnectionManager
.
ReleaseClient
(
tunnelClient
);
...
@@ -88,7 +93,6 @@ namespace Titanium.Web.Proxy
...
@@ -88,7 +93,6 @@ namespace Titanium.Web.Proxy
//HTTPS server created - we can now decrypt the client's traffic
//HTTPS server created - we can now decrypt the client's traffic
clientStream
=
sslStream
;
clientStream
=
sslStream
;
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
@@ -102,14 +106,19 @@ namespace Titanium.Web.Proxy
...
@@ -102,14 +106,19 @@ namespace Titanium.Web.Proxy
return
;
return
;
}
}
//Now read the actual HTTPS request line
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
}
}
//Sorry cannot do a HTTPS request decrypt to port 80 at this time
else
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
else
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
{
{
//Cyphen out CONNECT request headers
await
clientStreamReader
.
ReadAllLinesAsync
();
await
clientStreamReader
.
ReadAllLinesAsync
();
//write back successfull CONNECT response
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
//Just relay the request/response without decrypting it
await
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
await
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
false
);
...
@@ -179,12 +188,23 @@ namespace Titanium.Web.Proxy
...
@@ -179,12 +188,23 @@ namespace Titanium.Web.Proxy
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
await
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
true
);
true
);
}
}
/// <summary>
/// This is the core request handler method for a particular connection from client
/// </summary>
/// <param name="client"></param>
/// <param name="httpCmd"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
private
static
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
private
static
async
Task
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
bool
isHttps
)
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
bool
isHttps
)
{
{
TcpConnection
connection
=
null
;
TcpConnection
connection
=
null
;
//Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client)
while
(
true
)
while
(
true
)
{
{
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
...
@@ -203,6 +223,7 @@ namespace Titanium.Web.Proxy
...
@@ -203,6 +223,7 @@ namespace Titanium.Web.Proxy
var
httpMethod
=
httpCmdSplit
[
0
];
var
httpMethod
=
httpCmdSplit
[
0
];
//find the request HTTP version
Version
version
=
new
Version
(
1
,
1
);
Version
version
=
new
Version
(
1
,
1
);
if
(
httpCmdSplit
.
Length
==
3
)
if
(
httpCmdSplit
.
Length
==
3
)
{
{
...
@@ -216,6 +237,7 @@ namespace Titanium.Web.Proxy
...
@@ -216,6 +237,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
args
.
WebSession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
//Read the request headers
string
tmpLine
;
string
tmpLine
;
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
while
(!
string
.
IsNullOrEmpty
(
tmpLine
=
await
clientStreamReader
.
ReadLineAsync
()))
{
{
...
@@ -225,6 +247,8 @@ namespace Titanium.Web.Proxy
...
@@ -225,6 +247,8 @@ namespace Titanium.Web.Proxy
var
httpRemoteUri
=
new
Uri
(!
isHttps
?
httpCmdSplit
[
1
]
:
(
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
,
httpCmdSplit
[
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
//Its annoying
if
(
httpRemoteUri
.
Host
.
Contains
(
"localhost"
))
if
(
httpRemoteUri
.
Host
.
Contains
(
"localhost"
))
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
...
@@ -242,7 +266,7 @@ namespace Titanium.Web.Proxy
...
@@ -242,7 +266,7 @@ namespace Titanium.Web.Proxy
PrepareRequestHeaders
(
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
WebSession
);
PrepareRequestHeaders
(
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
WebSession
);
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
Request
.
RequestUri
.
Authority
;
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
Request
.
RequestUri
.
Authority
;
//If
requested interception
//If
user requested interception do it
if
(
BeforeRequest
!=
null
)
if
(
BeforeRequest
!=
null
)
{
{
Delegate
[]
invocationList
=
BeforeRequest
.
GetInvocationList
();
Delegate
[]
invocationList
=
BeforeRequest
.
GetInvocationList
();
...
@@ -256,6 +280,7 @@ namespace Titanium.Web.Proxy
...
@@ -256,6 +280,7 @@ namespace Titanium.Web.Proxy
await
Task
.
WhenAll
(
handlerTasks
);
await
Task
.
WhenAll
(
handlerTasks
);
}
}
//if upgrading to websocket then relay the requet without reading the contents
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
{
await
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
await
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
WebSession
.
Request
.
RequestHeaders
,
...
@@ -267,21 +292,24 @@ namespace Titanium.Web.Proxy
...
@@ -267,21 +292,24 @@ namespace Titanium.Web.Proxy
//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
=
await
TcpConnectionManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
);
connection
=
await
TcpConnectionManager
.
GetClient
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
IsHttps
,
version
);
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
//If request was cancelled by user then dispose the client
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
break
;
break
;
}
}
//if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
{
{
args
.
WebSession
.
SetConnection
(
connection
);
args
.
WebSession
.
SetConnection
(
connection
);
await
args
.
WebSession
.
SendRequest
();
await
args
.
WebSession
.
SendRequest
();
}
}
//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
)
{
{
...
@@ -296,6 +324,7 @@ namespace Titanium.Web.Proxy
...
@@ -296,6 +324,7 @@ namespace Titanium.Web.Proxy
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
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
if
(!
args
.
WebSession
.
Request
.
ExpectContinue
)
{
{
args
.
WebSession
.
SetConnection
(
connection
);
args
.
WebSession
.
SetConnection
(
connection
);
...
@@ -327,6 +356,7 @@ namespace Titanium.Web.Proxy
...
@@ -327,6 +356,7 @@ namespace Titanium.Web.Proxy
}
}
}
}
//If not expectation failed response was returned by server then parse response
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
{
await
HandleHttpSessionResponse
(
args
);
await
HandleHttpSessionResponse
(
args
);
...
@@ -339,9 +369,10 @@ namespace Titanium.Web.Proxy
...
@@ -339,9 +369,10 @@ namespace Titanium.Web.Proxy
return
;
return
;
}
}
//send the tcp connection to server back to connection cache for reuse
await
TcpConnectionManager
.
ReleaseClient
(
connection
);
await
TcpConnectionManager
.
ReleaseClient
(
connection
);
// read the next request
// read the next request
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
}
}
...
@@ -355,6 +386,12 @@ namespace Titanium.Web.Proxy
...
@@ -355,6 +386,12 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// Write successfull CONNECT response to client
/// </summary>
/// <param name="clientStreamWriter"></param>
/// <param name="httpVersion"></param>
/// <returns></returns>
private
static
async
Task
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
Version
httpVersion
)
private
static
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"
));
...
@@ -363,6 +400,11 @@ namespace Titanium.Web.Proxy
...
@@ -363,6 +400,11 @@ namespace Titanium.Web.Proxy
await
clientStreamWriter
.
FlushAsync
();
await
clientStreamWriter
.
FlushAsync
();
}
}
/// <summary>
/// prepare the request headers so that we can avoid encodings not parsable by this proxy
/// </summary>
/// <param name="requestHeaders"></param>
/// <param name="webRequest"></param>
private
static
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
private
static
void
PrepareRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebClient
webRequest
)
{
{
for
(
var
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++)
for
(
var
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++)
...
@@ -381,6 +423,11 @@ namespace Titanium.Web.Proxy
...
@@ -381,6 +423,11 @@ namespace Titanium.Web.Proxy
FixRequestProxyHeaders
(
requestHeaders
);
FixRequestProxyHeaders
(
requestHeaders
);
webRequest
.
Request
.
RequestHeaders
=
requestHeaders
;
webRequest
.
Request
.
RequestHeaders
=
requestHeaders
;
}
}
/// <summary>
/// Fix proxy specific headers
/// </summary>
/// <param name="headers"></param>
private
static
void
FixRequestProxyHeaders
(
List
<
HttpHeader
>
headers
)
private
static
void
FixRequestProxyHeaders
(
List
<
HttpHeader
>
headers
)
{
{
//If proxy-connection close was returned inform to close the connection
//If proxy-connection close was returned inform to close the connection
...
@@ -400,7 +447,11 @@ namespace Titanium.Web.Proxy
...
@@ -400,7 +447,11 @@ 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
/// <summary>
/// This is called when the request is PUT/POST to read the body
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private
static
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
private
static
async
Task
SendClientRequestBody
(
SessionEventArgs
args
)
{
{
// End the operation
// End the operation
...
@@ -445,6 +496,7 @@ namespace Titanium.Web.Proxy
...
@@ -445,6 +496,7 @@ namespace Titanium.Web.Proxy
X509Chain
chain
,
X509Chain
chain
,
SslPolicyErrors
sslPolicyErrors
)
SslPolicyErrors
sslPolicyErrors
)
{
{
//if user callback is registered then do it
if
(
ServerCertificateValidationCallback
!=
null
)
if
(
ServerCertificateValidationCallback
!=
null
)
{
{
var
args
=
new
CertificateValidationEventArgs
();
var
args
=
new
CertificateValidationEventArgs
();
...
@@ -511,7 +563,7 @@ namespace Titanium.Web.Proxy
...
@@ -511,7 +563,7 @@ namespace Titanium.Web.Proxy
localCertificates
.
Count
>
0
)
localCertificates
.
Count
>
0
)
clientCertificate
=
localCertificates
[
0
];
clientCertificate
=
localCertificates
[
0
];
//If user call back is registered
if
(
ClientCertificateSelectionCallback
!=
null
)
if
(
ClientCertificateSelectionCallback
!=
null
)
{
{
var
args
=
new
CertificateSelectionEventArgs
();
var
args
=
new
CertificateSelectionEventArgs
();
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
9bac69a9
...
@@ -11,11 +11,15 @@ using Titanium.Web.Proxy.Extensions;
...
@@ -11,11 +11,15 @@ using Titanium.Web.Proxy.Extensions;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
/// <summary>
/// Handle the response from server
/// </summary>
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
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
public
static
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
{
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
await
args
.
WebSession
.
ReceiveResponse
();
try
try
...
@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy
...
@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy
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 client request call back then do it
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
if
(
BeforeResponse
!=
null
&&
!
args
.
WebSession
.
Response
.
ResponseLocked
)
{
{
Delegate
[]
invocationList
=
BeforeResponse
.
GetInvocationList
();
Delegate
[]
invocationList
=
BeforeResponse
.
GetInvocationList
();
...
@@ -39,6 +43,7 @@ namespace Titanium.Web.Proxy
...
@@ -39,6 +43,7 @@ namespace Titanium.Web.Proxy
args
.
WebSession
.
Response
.
ResponseLocked
=
true
;
args
.
WebSession
.
Response
.
ResponseLocked
=
true
;
//Write back to client 100-conitinue response if that's what server returned
if
(
args
.
WebSession
.
Response
.
Is100Continue
)
if
(
args
.
WebSession
.
Response
.
Is100Continue
)
{
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
...
@@ -52,6 +57,7 @@ namespace Titanium.Web.Proxy
...
@@ -52,6 +57,7 @@ namespace Titanium.Web.Proxy
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
}
}
//Write back response status
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
args
.
WebSession
.
Response
.
ResponseStatusCode
,
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
args
.
WebSession
.
Response
.
ResponseStatusCode
,
args
.
WebSession
.
Response
.
ResponseStatusDescription
,
args
.
ProxyClient
.
ClientStreamWriter
);
args
.
WebSession
.
Response
.
ResponseStatusDescription
,
args
.
ProxyClient
.
ClientStreamWriter
);
...
@@ -95,6 +101,12 @@ namespace Titanium.Web.Proxy
...
@@ -95,6 +101,12 @@ namespace Titanium.Web.Proxy
}
}
}
}
/// <summary>
/// get the compressed response body from give response bytes
/// </summary>
/// <param name="encodingType"></param>
/// <param name="responseBodyStream"></param>
/// <returns></returns>
private
static
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
static
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
{
{
var
compressionFactory
=
new
CompressionFactory
();
var
compressionFactory
=
new
CompressionFactory
();
...
@@ -102,13 +114,26 @@ namespace Titanium.Web.Proxy
...
@@ -102,13 +114,26 @@ namespace Titanium.Web.Proxy
return
await
compressor
.
Compress
(
responseBodyStream
);
return
await
compressor
.
Compress
(
responseBodyStream
);
}
}
/// <summary>
/// Write response status
/// </summary>
/// <param name="version"></param>
/// <param name="code"></param>
/// <param name="description"></param>
/// <param name="responseWriter"></param>
/// <returns></returns>
private
static
async
Task
WriteResponseStatus
(
Version
version
,
string
code
,
string
description
,
private
static
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
));
}
}
/// <summary>
/// Write response headers to client
/// </summary>
/// <param name="responseWriter"></param>
/// <param name="headers"></param>
/// <returns></returns>
private
static
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
)
private
static
async
Task
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
)
{
{
if
(
headers
!=
null
)
if
(
headers
!=
null
)
...
@@ -124,6 +149,11 @@ namespace Titanium.Web.Proxy
...
@@ -124,6 +149,11 @@ namespace Titanium.Web.Proxy
await
responseWriter
.
WriteLineAsync
();
await
responseWriter
.
WriteLineAsync
();
await
responseWriter
.
FlushAsync
();
await
responseWriter
.
FlushAsync
();
}
}
/// <summary>
/// Fix the proxy specific headers before sending response headers to client
/// </summary>
/// <param name="headers"></param>
private
static
void
FixResponseProxyHeaders
(
List
<
HttpHeader
>
headers
)
private
static
void
FixResponseProxyHeaders
(
List
<
HttpHeader
>
headers
)
{
{
//If proxy-connection close was returned inform to close the connection
//If proxy-connection close was returned inform to close the connection
...
@@ -143,7 +173,14 @@ namespace Titanium.Web.Proxy
...
@@ -143,7 +173,14 @@ namespace Titanium.Web.Proxy
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
headers
.
RemoveAll
(
x
=>
x
.
Name
.
ToLower
()
==
"proxy-connection"
);
}
}
/// <summary>
/// Handle dispose of a client/server session
/// </summary>
/// <param name="client"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="args"></param>
private
static
void
Dispose
(
TcpClient
client
,
IDisposable
clientStream
,
IDisposable
clientStreamReader
,
private
static
void
Dispose
(
TcpClient
client
,
IDisposable
clientStream
,
IDisposable
clientStreamReader
,
IDisposable
clientStreamWriter
,
IDisposable
args
)
IDisposable
clientStreamWriter
,
IDisposable
args
)
{
{
...
...
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