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
6a66e7b1
Commit
6a66e7b1
authored
May 18, 2017
by
Jehonathan Thomas
Committed by
GitHub
May 18, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #240 from justcoding121/develop
Beta
parents
9afb81c6
37b14243
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
312 additions
and
218 deletions
+312
-218
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+5
-1
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+3
-7
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+16
-1
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+16
-1
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+93
-8
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+0
-41
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+179
-159
No files found.
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
6a66e7b1
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// <summary>
/// Holds a reference to proxy response handler method
/// Holds a reference to proxy response handler method
/// </summary>
/// </summary>
private
readonly
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
;
private
Func
<
SessionEventArgs
,
Task
>
httpResponseHandler
;
/// <summary>
/// <summary>
/// Holds a reference to client
/// Holds a reference to client
...
@@ -522,6 +522,10 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -522,6 +522,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
httpResponseHandler
=
null
;
CustomUpStreamHttpProxyUsed
=
null
;
CustomUpStreamHttpsProxyUsed
=
null
;
WebSession
.
Dispose
();
WebSession
.
Dispose
();
}
}
}
}
...
...
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
6a66e7b1
...
@@ -214,14 +214,10 @@ namespace Titanium.Web.Proxy.Http
...
@@ -214,14 +214,10 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
//not really needed since GC will collect it
ConnectHeaders
=
null
;
//but just to be on safe side
Request
.
RequestBody
=
null
;
Response
.
ResponseBody
=
null
;
Request
.
RequestBodyString
=
null
;
Response
.
ResponseBodyString
=
null
;
Request
.
Dispose
();
Response
.
Dispose
();
}
}
}
}
}
}
Titanium.Web.Proxy/Http/Request.cs
View file @
6a66e7b1
...
@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// A HTTP(S) request object
/// A HTTP(S) request object
/// </summary>
/// </summary>
public
class
Request
public
class
Request
:
IDisposable
{
{
/// <summary>
/// <summary>
/// Request Method
/// Request Method
...
@@ -294,5 +294,20 @@ namespace Titanium.Web.Proxy.Http
...
@@ -294,5 +294,20 @@ namespace Titanium.Web.Proxy.Http
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
RequestHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueRequestHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueRequestHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
/// <summary>
/// Dispose off
/// </summary>
public
void
Dispose
()
{
//not really needed since GC will collect it
//but just to be on safe side
RequestHeaders
=
null
;
NonUniqueRequestHeaders
=
null
;
RequestBody
=
null
;
RequestBody
=
null
;
}
}
}
}
}
Titanium.Web.Proxy/Http/Response.cs
View file @
6a66e7b1
...
@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Http(s) response object
/// Http(s) response object
/// </summary>
/// </summary>
public
class
Response
public
class
Response
:
IDisposable
{
{
/// <summary>
/// <summary>
/// Response Status Code.
/// Response Status Code.
...
@@ -234,5 +234,20 @@ namespace Titanium.Web.Proxy.Http
...
@@ -234,5 +234,20 @@ namespace Titanium.Web.Proxy.Http
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
ResponseHeaders
=
new
Dictionary
<
string
,
HttpHeader
>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
NonUniqueResponseHeaders
=
new
Dictionary
<
string
,
List
<
HttpHeader
>>(
StringComparer
.
OrdinalIgnoreCase
);
}
}
/// <summary>
/// Dispose off
/// </summary>
public
void
Dispose
()
{
//not really needed since GC will collect it
//but just to be on safe side
ResponseHeaders
=
null
;
NonUniqueResponseHeaders
=
null
;
ResponseBody
=
null
;
ResponseBodyString
=
null
;
}
}
}
}
}
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
6a66e7b1
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Diagnostics
;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Reflection
;
using
System.Reflection
;
...
@@ -30,7 +31,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -30,7 +31,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// <summary>
/// A class to manage SSL certificates used by this proxy server
/// A class to manage SSL certificates used by this proxy server
/// </summary>
/// </summary>
public
class
CertificateManager
:
IDisposable
public
sealed
class
CertificateManager
:
IDisposable
{
{
internal
CertificateEngine
Engine
internal
CertificateEngine
Engine
{
{
...
@@ -147,7 +148,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -147,7 +148,7 @@ namespace Titanium.Web.Proxy.Network
return
fileName
;
return
fileName
;
}
}
internal
X509Certificate2
LoadRootCertificate
()
private
X509Certificate2
LoadRootCertificate
()
{
{
var
fileName
=
GetRootCertificatePath
();
var
fileName
=
GetRootCertificatePath
();
if
(!
File
.
Exists
(
fileName
))
return
null
;
if
(!
File
.
Exists
(
fileName
))
return
null
;
...
@@ -218,6 +219,51 @@ namespace Titanium.Web.Proxy.Network
...
@@ -218,6 +219,51 @@ namespace Titanium.Web.Proxy.Network
TrustRootCertificate
(
StoreLocation
.
LocalMachine
);
TrustRootCertificate
(
StoreLocation
.
LocalMachine
);
}
}
/// <summary>
/// Puts the certificate to the local machine's certificate store.
/// Needs elevated permission. Works only on Windows.
/// </summary>
/// <returns></returns>
public
bool
TrustRootCertificateAsAdministrator
()
{
if
(
RunTime
.
IsRunningOnMono
())
{
return
false
;
}
var
fileName
=
Path
.
GetTempFileName
();
File
.
WriteAllBytes
(
fileName
,
RootCertificate
.
Export
(
X509ContentType
.
Pkcs12
));
var
info
=
new
ProcessStartInfo
{
FileName
=
"certutil.exe"
,
Arguments
=
"-importPFX -p \"\" -f \""
+
fileName
+
"\""
,
CreateNoWindow
=
true
,
UseShellExecute
=
true
,
Verb
=
"runas"
,
ErrorDialog
=
false
,
};
try
{
var
process
=
Process
.
Start
(
info
);
if
(
process
==
null
)
{
return
false
;
}
process
.
WaitForExit
();
File
.
Delete
(
fileName
);
}
catch
{
return
false
;
}
return
true
;
}
/// <summary>
/// <summary>
/// Removes the trusted certificates.
/// Removes the trusted certificates.
/// </summary>
/// </summary>
...
@@ -230,13 +276,49 @@ namespace Titanium.Web.Proxy.Network
...
@@ -230,13 +276,49 @@ namespace Titanium.Web.Proxy.Network
RemoveTrustedRootCertificates
(
StoreLocation
.
LocalMachine
);
RemoveTrustedRootCertificates
(
StoreLocation
.
LocalMachine
);
}
}
/// <summary>
/// Determines whether the root certificate is trusted.
/// </summary>
public
bool
IsRootCertificateTrusted
()
{
return
FindRootCertificate
(
StoreLocation
.
CurrentUser
)
||
IsRootCertificateMachineTrusted
();
}
/// <summary>
/// Determines whether the root certificate is machine trusted.
/// </summary>
public
bool
IsRootCertificateMachineTrusted
()
{
return
FindRootCertificate
(
StoreLocation
.
LocalMachine
);
}
private
bool
FindRootCertificate
(
StoreLocation
storeLocation
)
{
string
value
=
$"
{
RootCertificate
.
Issuer
}
"
;
return
FindCertificates
(
StoreName
.
Root
,
storeLocation
,
value
).
Count
>
0
;
}
private
X509Certificate2Collection
FindCertificates
(
StoreName
storeName
,
StoreLocation
storeLocation
,
string
findValue
)
{
X509Store
x509Store
=
new
X509Store
(
storeName
,
storeLocation
);
try
{
x509Store
.
Open
(
OpenFlags
.
OpenExistingOnly
);
return
x509Store
.
Certificates
.
Find
(
X509FindType
.
FindBySubjectDistinguishedName
,
findValue
,
false
);
}
finally
{
x509Store
.
Close
();
}
}
/// <summary>
/// <summary>
/// Create an SSL certificate
/// Create an SSL certificate
/// </summary>
/// </summary>
/// <param name="certificateName"></param>
/// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param>
/// <param name="isRootCertificate"></param>
/// <returns></returns>
/// <returns></returns>
internal
virtual
X509Certificate2
CreateCertificate
(
string
certificateName
,
bool
isRootCertificate
)
internal
X509Certificate2
CreateCertificate
(
string
certificateName
,
bool
isRootCertificate
)
{
{
if
(
certificateCache
.
ContainsKey
(
certificateName
))
if
(
certificateCache
.
ContainsKey
(
certificateName
))
{
{
...
@@ -317,7 +399,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -317,7 +399,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// </summary>
/// <param name="storeLocation"></param>
/// <param name="storeLocation"></param>
/// <returns></returns>
/// <returns></returns>
internal
void
TrustRootCertificate
(
StoreLocation
storeLocation
)
private
void
TrustRootCertificate
(
StoreLocation
storeLocation
)
{
{
if
(
RootCertificate
==
null
)
if
(
RootCertificate
==
null
)
{
{
...
@@ -328,7 +410,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -328,7 +410,7 @@ namespace Titanium.Web.Proxy.Network
return
;
return
;
}
}
X509Store
x509RootStore
=
new
X509Store
(
StoreName
.
Root
,
storeLocation
);
var
x509RootStore
=
new
X509Store
(
StoreName
.
Root
,
storeLocation
);
var
x509PersonalStore
=
new
X509Store
(
StoreName
.
My
,
storeLocation
);
var
x509PersonalStore
=
new
X509Store
(
StoreName
.
My
,
storeLocation
);
try
try
...
@@ -357,7 +439,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -357,7 +439,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// </summary>
/// <param name="storeLocation"></param>
/// <param name="storeLocation"></param>
/// <returns></returns>
/// <returns></returns>
internal
void
RemoveTrustedRootCertificates
(
StoreLocation
storeLocation
)
private
void
RemoveTrustedRootCertificates
(
StoreLocation
storeLocation
)
{
{
if
(
RootCertificate
==
null
)
if
(
RootCertificate
==
null
)
{
{
...
@@ -368,7 +450,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -368,7 +450,7 @@ namespace Titanium.Web.Proxy.Network
return
;
return
;
}
}
X509Store
x509RootStore
=
new
X509Store
(
StoreName
.
Root
,
storeLocation
);
var
x509RootStore
=
new
X509Store
(
StoreName
.
Root
,
storeLocation
);
var
x509PersonalStore
=
new
X509Store
(
StoreName
.
My
,
storeLocation
);
var
x509PersonalStore
=
new
X509Store
(
StoreName
.
My
,
storeLocation
);
try
try
...
@@ -382,7 +464,7 @@ namespace Titanium.Web.Proxy.Network
...
@@ -382,7 +464,7 @@ namespace Titanium.Web.Proxy.Network
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
exceptionFunc
(
exceptionFunc
(
new
Exception
(
"Failed to
make system trust root certificate
"
new
Exception
(
"Failed to
remove root certificate trust
"
+
$" for
{
storeLocation
}
store location. You may need admin rights."
,
e
));
+
$" for
{
storeLocation
}
store location. You may need admin rights."
,
e
));
}
}
finally
finally
...
@@ -392,6 +474,9 @@ namespace Titanium.Web.Proxy.Network
...
@@ -392,6 +474,9 @@ namespace Titanium.Web.Proxy.Network
}
}
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
}
}
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
6a66e7b1
...
@@ -647,46 +647,5 @@ namespace Titanium.Web.Proxy
...
@@ -647,46 +647,5 @@ namespace Titanium.Web.Proxy
endPoint
.
Listener
.
Server
.
Close
();
endPoint
.
Listener
.
Server
.
Close
();
endPoint
.
Listener
.
Server
.
Dispose
();
endPoint
.
Listener
.
Server
.
Dispose
();
}
}
/// <summary>
/// Invocator for BeforeRequest event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnBeforeRequest
(
object
sender
,
SessionEventArgs
e
)
{
BeforeRequest
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for BeforeResponse event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns></returns>
protected
virtual
void
OnBeforeResponse
(
object
sender
,
SessionEventArgs
e
)
{
BeforeResponse
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ServerCertificateValidationCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnServerCertificateValidationCallback
(
object
sender
,
CertificateValidationEventArgs
e
)
{
ServerCertificateValidationCallback
?.
Invoke
(
sender
,
e
);
}
/// <summary>
/// Invocator for ClientCertifcateSelectionCallback event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected
virtual
void
OnClientCertificateSelectionCallback
(
object
sender
,
CertificateSelectionEventArgs
e
)
{
ClientCertificateSelectionCallback
?.
Invoke
(
sender
,
e
);
}
}
}
}
}
Titanium.Web.Proxy/RequestHandler.cs
View file @
6a66e7b1
...
@@ -23,8 +23,13 @@ namespace Titanium.Web.Proxy
...
@@ -23,8 +23,13 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
partial
class
ProxyServer
partial
class
ProxyServer
{
{
//This is called when client is aware of proxy
/// <summary>
//So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
/// This is called when client is aware of proxy
/// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
/// </summary>
/// <param name="endPoint"></param>
/// <param name="tcpClient"></param>
/// <returns></returns>
private
async
Task
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
async
Task
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
{
var
disposed
=
false
;
var
disposed
=
false
;
...
@@ -139,7 +144,7 @@ namespace Titanium.Web.Proxy
...
@@ -139,7 +144,7 @@ namespace Titanium.Web.Proxy
{
{
//Siphon out CONNECT request headers
//Siphon out CONNECT request headers
await
clientStreamReader
.
ReadAndIgnoreAllLinesAsync
();
await
clientStreamReader
.
ReadAndIgnoreAllLinesAsync
();
//write back successfull CONNECT response
//write back successfull CONNECT response
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
...
@@ -170,8 +175,13 @@ namespace Titanium.Web.Proxy
...
@@ -170,8 +175,13 @@ namespace Titanium.Web.Proxy
}
}
}
}
//This is called when this proxy acts as a reverse proxy (like a real http server)
/// <summary>
//So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client
/// This is called when this proxy acts as a reverse proxy (like a real http server)
/// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client
/// </summary>
/// <param name="endPoint"></param>
/// <param name="tcpClient"></param>
/// <returns></returns>
private
async
Task
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
private
async
Task
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
{
bool
disposed
=
false
;
bool
disposed
=
false
;
...
@@ -219,162 +229,10 @@ namespace Titanium.Web.Proxy
...
@@ -219,162 +229,10 @@ namespace Titanium.Web.Proxy
}
}
}
}
/// <summary>
/// Create a Server Connection
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private
async
Task
<
TcpConnection
>
GetServerConnection
(
SessionEventArgs
args
)
{
ExternalProxy
customUpStreamHttpProxy
=
null
;
ExternalProxy
customUpStreamHttpsProxy
=
null
;
if
(
args
.
WebSession
.
Request
.
RequestUri
.
Scheme
==
"http"
)
{
if
(
GetCustomUpStreamHttpProxyFunc
!=
null
)
{
customUpStreamHttpProxy
=
await
GetCustomUpStreamHttpProxyFunc
(
args
);
}
}
else
{
if
(
GetCustomUpStreamHttpsProxyFunc
!=
null
)
{
customUpStreamHttpsProxy
=
await
GetCustomUpStreamHttpsProxyFunc
(
args
);
}
}
args
.
CustomUpStreamHttpProxyUsed
=
customUpStreamHttpProxy
;
args
.
CustomUpStreamHttpsProxyUsed
=
customUpStreamHttpsProxy
;
return
await
tcpConnectionFactory
.
CreateClient
(
this
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
IsHttps
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
,
args
.
ProxyClient
.
ClientStream
);
}
private
async
Task
<
bool
>
HandleHttpSessionRequestInternal
(
TcpConnection
connection
,
SessionEventArgs
args
,
bool
closeConnection
)
{
bool
disposed
=
false
;
bool
keepAlive
=
false
;
try
{
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
//If request was cancelled by user then dispose the client
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
return
true
;
}
//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
(
Enable100ContinueBehaviour
);
}
//If 100 continue was the response inform that to the client
if
(
Enable100ContinueBehaviour
)
{
if
(
args
.
WebSession
.
Request
.
Is100Continue
)
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
"Continue"
,
args
.
ProxyClient
.
ClientStreamWriter
);
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
}
else
if
(
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"417"
,
"Expectation Failed"
,
args
.
ProxyClient
.
ClientStreamWriter
);
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
);
await
args
.
WebSession
.
SendRequest
(
Enable100ContinueBehaviour
);
}
//If request was modified by user
if
(
args
.
WebSession
.
Request
.
RequestBodyRead
)
{
if
(
args
.
WebSession
.
Request
.
ContentEncoding
!=
null
)
{
args
.
WebSession
.
Request
.
RequestBody
=
await
GetCompressedResponseBody
(
args
.
WebSession
.
Request
.
ContentEncoding
,
args
.
WebSession
.
Request
.
RequestBody
);
}
//chunked send is not supported as of now
args
.
WebSession
.
Request
.
ContentLength
=
args
.
WebSession
.
Request
.
RequestBody
.
Length
;
var
newStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
await
newStream
.
WriteAsync
(
args
.
WebSession
.
Request
.
RequestBody
,
0
,
args
.
WebSession
.
Request
.
RequestBody
.
Length
);
}
else
{
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
//If its a post/put/patch request, then read the client html body and send it to server
var
method
=
args
.
WebSession
.
Request
.
Method
.
ToUpper
();
if
(
method
==
"POST"
||
method
==
"PUT"
||
method
==
"PATCH"
)
{
await
SendClientRequestBody
(
args
);
}
}
}
//If not expectation failed response was returned by server then parse response
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
disposed
=
await
HandleHttpSessionResponse
(
args
);
//already disposed inside above method
if
(
disposed
)
{
return
true
;
}
}
//if connection is closing exit
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
return
true
;
}
if
(!
closeConnection
)
{
keepAlive
=
true
;
return
false
;
}
}
catch
(
Exception
e
)
{
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request (internal)"
,
e
,
args
));
return
true
;
}
finally
{
if
(!
disposed
&&
!
keepAlive
)
{
//dispose
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
}
}
return
true
;
}
/// <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
/// Will create new session (request/response) sequence until
/// client/server abruptly terminates connection or by normal HTTP termination
/// </summary>
/// </summary>
/// <param name="client"></param>
/// <param name="client"></param>
/// <param name="httpCmd"></param>
/// <param name="httpCmd"></param>
...
@@ -533,6 +391,168 @@ namespace Titanium.Web.Proxy
...
@@ -533,6 +391,168 @@ namespace Titanium.Web.Proxy
return
true
;
return
true
;
}
}
/// <summary>
/// Handle a specific session (request/response sequence)
/// </summary>
/// <param name="connection"></param>
/// <param name="args"></param>
/// <param name="closeConnection"></param>
/// <returns></returns>
private
async
Task
<
bool
>
HandleHttpSessionRequestInternal
(
TcpConnection
connection
,
SessionEventArgs
args
,
bool
closeConnection
)
{
bool
disposed
=
false
;
bool
keepAlive
=
false
;
try
{
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
//If request was cancelled by user then dispose the client
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
return
true
;
}
//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
(
Enable100ContinueBehaviour
);
}
//If 100 continue was the response inform that to the client
if
(
Enable100ContinueBehaviour
)
{
if
(
args
.
WebSession
.
Request
.
Is100Continue
)
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"100"
,
"Continue"
,
args
.
ProxyClient
.
ClientStreamWriter
);
await
args
.
ProxyClient
.
ClientStreamWriter
.
WriteLineAsync
();
}
else
if
(
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
await
WriteResponseStatus
(
args
.
WebSession
.
Response
.
HttpVersion
,
"417"
,
"Expectation Failed"
,
args
.
ProxyClient
.
ClientStreamWriter
);
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
);
await
args
.
WebSession
.
SendRequest
(
Enable100ContinueBehaviour
);
}
//If request was modified by user
if
(
args
.
WebSession
.
Request
.
RequestBodyRead
)
{
if
(
args
.
WebSession
.
Request
.
ContentEncoding
!=
null
)
{
args
.
WebSession
.
Request
.
RequestBody
=
await
GetCompressedResponseBody
(
args
.
WebSession
.
Request
.
ContentEncoding
,
args
.
WebSession
.
Request
.
RequestBody
);
}
//chunked send is not supported as of now
args
.
WebSession
.
Request
.
ContentLength
=
args
.
WebSession
.
Request
.
RequestBody
.
Length
;
var
newStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
await
newStream
.
WriteAsync
(
args
.
WebSession
.
Request
.
RequestBody
,
0
,
args
.
WebSession
.
Request
.
RequestBody
.
Length
);
}
else
{
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
//If its a post/put/patch request, then read the client html body and send it to server
var
method
=
args
.
WebSession
.
Request
.
Method
.
ToUpper
();
if
(
method
==
"POST"
||
method
==
"PUT"
||
method
==
"PATCH"
)
{
await
SendClientRequestBody
(
args
);
}
}
}
//If not expectation failed response was returned by server then parse response
if
(!
args
.
WebSession
.
Request
.
ExpectationFailed
)
{
disposed
=
await
HandleHttpSessionResponse
(
args
);
//already disposed inside above method
if
(
disposed
)
{
return
true
;
}
}
//if connection is closing exit
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
return
true
;
}
if
(!
closeConnection
)
{
keepAlive
=
true
;
return
false
;
}
}
catch
(
Exception
e
)
{
ExceptionFunc
(
new
ProxyHttpException
(
"Error occured whilst handling session request (internal)"
,
e
,
args
));
return
true
;
}
finally
{
if
(!
disposed
&&
!
keepAlive
)
{
//dispose
Dispose
(
args
.
ProxyClient
.
ClientStream
,
args
.
ProxyClient
.
ClientStreamReader
,
args
.
ProxyClient
.
ClientStreamWriter
,
args
.
WebSession
.
ServerConnection
);
}
}
return
true
;
}
/// <summary>
/// Create a Server Connection
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private
async
Task
<
TcpConnection
>
GetServerConnection
(
SessionEventArgs
args
)
{
ExternalProxy
customUpStreamHttpProxy
=
null
;
ExternalProxy
customUpStreamHttpsProxy
=
null
;
if
(
args
.
WebSession
.
Request
.
RequestUri
.
Scheme
==
"http"
)
{
if
(
GetCustomUpStreamHttpProxyFunc
!=
null
)
{
customUpStreamHttpProxy
=
await
GetCustomUpStreamHttpProxyFunc
(
args
);
}
}
else
{
if
(
GetCustomUpStreamHttpsProxyFunc
!=
null
)
{
customUpStreamHttpsProxy
=
await
GetCustomUpStreamHttpsProxyFunc
(
args
);
}
}
args
.
CustomUpStreamHttpProxyUsed
=
customUpStreamHttpProxy
;
args
.
CustomUpStreamHttpsProxyUsed
=
customUpStreamHttpsProxy
;
return
await
tcpConnectionFactory
.
CreateClient
(
this
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
IsHttps
,
customUpStreamHttpProxy
??
UpStreamHttpProxy
,
customUpStreamHttpsProxy
??
UpStreamHttpsProxy
,
args
.
ProxyClient
.
ClientStream
);
}
/// <summary>
/// <summary>
/// Write successfull CONNECT response to client
/// Write successfull CONNECT response to client
/// </summary>
/// </summary>
...
...
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