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