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
23f1d181
Commit
23f1d181
authored
Sep 05, 2015
by
justcoding121
Committed by
justcoding121
Sep 05, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix request body modification
parent
3c1c351e
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
230 additions
and
179 deletions
+230
-179
README.md
README.md
+35
-16
ProxyTestController.cs
Titanium.Web.Proxy.Test/ProxyTestController.cs
+35
-22
BodyNotFoundException.cs
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
+17
-0
HttpWebRequestExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
+32
-0
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+0
-6
SessionEventArgs.cs
Titanium.Web.Proxy/Models/SessionEventArgs.cs
+46
-49
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+12
-13
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+42
-62
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+9
-11
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+2
-0
No files found.
README.md
View file @
23f1d181
...
...
@@ -64,30 +64,49 @@ Sample request and response event handlers
```
csharp
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
//Test On Request, intecept requests
//Read browser URL send back to proxy by the injection script in OnResponse event
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
//To cancel a request with a custom HTML content
//Filter URL
Console
.
WriteLine
(
e
.
RequestURL
);
if
(
e
.
RequestURL
.
Contains
(
"somewebsite.com"
))
if
((
e
.
ProxyRequest
.
Method
.
ToUpper
()
==
"POST"
||
e
.
ProxyRequest
.
Method
.
ToUpper
()
==
"PUT"
)
&&
e
.
ProxyRequest
.
ContentLength
>
0
)
{
var
m
=
e
.
GetRequestBody
().
Replace
(
"a"
,
"b"
);
e
.
SetRequestBody
(
m
);
}
//To cancel a request with a custom HTML content
//Filter URL
if
(
e
.
RequestURL
.
Contains
(
"somewebsite.com"
))
{
e
.
Ok
(
"<!DOCTYPE html><html><body><h1>Blocked</h1><p>
w
ebsite blocked.</p></body></html>"
);
e
.
Ok
(
"<!DOCTYPE html><html><body><h1>Blocked</h1><p>
W
ebsite blocked.</p></body></html>"
);
}
}
public
void
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
if
(
e
.
ServerResponse
.
StatusCode
==
HttpStatusCode
.
OK
)
{
if
(
e
.
ServerResponse
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
//Get response body
string
responseHtmlBody
=
e
.
GetResponseHtmlBody
();
//Modify e.ServerResponse
responseHtmlBody
=
"<html><head></head><body>Response is modified!</body></html>"
;
//Set modifed response Html Body
e
.
SetResponseHtmlBody
(
responseHtmlBody
);
}
}
if
(
e
.
ServerResponse
.
StatusCode
==
HttpStatusCode
.
OK
)
{
if
(
e
.
ServerResponse
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
//Get response body
string
responseBody
=
e
.
GetResponseBody
();
//Modify e.ServerResponse
Regex
rex
=
new
Regex
(
"</body>"
,
RegexOptions
.
RightToLeft
|
RegexOptions
.
IgnoreCase
|
RegexOptions
.
Multiline
);
string
modified
=
rex
.
Replace
(
responseBody
,
"<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>"
,
1
);
//Set modifed response Html Body
e
.
SetResponseBody
(
modified
);
}
}
}
```
Future updates
...
...
Titanium.Web.Proxy.Test/ProxyTestController.cs
View file @
23f1d181
...
...
@@ -24,23 +24,24 @@ namespace Titanium.Web.Proxy.Test
public
void
StartProxy
()
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
EnableSSL
=
EnableSSL
;
ProxyServer
.
SetAsSystemProxy
=
SetAsSystemProxy
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
ProxyServer
.
ExcludedHttpsHostNameRegex
.
Add
(
".dropbox.com"
);
ProxyServer
.
Start
();
ListeningPort
=
ProxyServer
.
ListeningPort
;
ProxyServer
.
ListeningPort
=
ProxyServer
.
ListeningPort
;
Console
.
WriteLine
(
String
.
Format
(
"Proxy listening on local machine port: {0} "
,
ProxyServer
.
ListeningPort
));
}
public
void
Stop
()
{
...
...
@@ -59,14 +60,23 @@ namespace Titanium.Web.Proxy.Test
Console
.
WriteLine
(
e
.
RequestURL
);
if
(
e
.
RequestURL
.
Contains
(
"somewebsite.com"
))
if
((
e
.
ProxyRequest
.
Method
.
ToUpper
()
==
"POST"
||
e
.
ProxyRequest
.
Method
.
ToUpper
()
==
"PUT"
)
&&
e
.
ProxyRequest
.
ContentLength
>
0
)
{
var
m
=
e
.
GetRequestBody
().
Replace
(
"a"
,
"b"
);
e
.
SetRequestBody
(
m
);
}
//To cancel a request with a custom HTML content
//Filter URL
//
if (e.RequestURL.Contains("somewebsite.com"))
//
{
// e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>w
ebsite blocked.</p></body></html>");
//
}
if
(
e
.
RequestURL
.
Contains
(
"somewebsite.com"
))
{
e
.
Ok
(
"<!DOCTYPE html><html><body><h1>Blocked</h1><p>W
ebsite blocked.</p></body></html>"
);
}
}
//Test script injection
...
...
@@ -75,18 +85,21 @@ namespace Titanium.Web.Proxy.Test
{
//To modify a response
//if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
//{
// if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
// {
// //Get response body
// string responseHtmlBody = e.GetResponseHtmlBody();
// //Modify e.ServerResponse
// responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>";
// //Set modifed response Html Body
// e.SetResponseHtmlBody(responseHtmlBody);
// }
//}
if
(
e
.
ServerResponse
.
StatusCode
==
HttpStatusCode
.
OK
)
{
if
(
e
.
ServerResponse
.
ContentType
.
Trim
().
ToLower
().
Contains
(
"text/html"
))
{
//Get response body
string
responseBody
=
e
.
GetResponseBody
();
//Modify e.ServerResponse
Regex
rex
=
new
Regex
(
"</body>"
,
RegexOptions
.
RightToLeft
|
RegexOptions
.
IgnoreCase
|
RegexOptions
.
Multiline
);
string
modified
=
rex
.
Replace
(
responseBody
,
"<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>"
,
1
);
//Set modifed response Html Body
e
.
SetResponseBody
(
modified
);
}
}
}
...
...
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
0 → 100644
View file @
23f1d181
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Exceptions
{
public
class
BodyNotFoundException
:
Exception
{
public
BodyNotFoundException
(
string
message
)
:
base
(
message
)
{
}
}
}
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
0 → 100644
View file @
23f1d181
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Extensions
{
public
static
class
HttpWebRequestExtensions
{
public
static
Encoding
GetEncoding
(
this
HttpWebRequest
request
)
{
try
{
if
(
request
.
ContentType
==
null
)
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
var
contentTypes
=
request
.
ContentType
.
Split
(
';'
);
foreach
(
var
contentType
in
contentTypes
)
{
var
encodingSplit
=
contentType
.
Split
(
'='
);
if
(
encodingSplit
.
Length
==
2
&&
encodingSplit
[
0
].
ToLower
().
Trim
()
==
"charset"
)
{
return
Encoding
.
GetEncoding
(
encodingSplit
[
1
]);
}
}
}
catch
{
}
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
}
}
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
23f1d181
...
...
@@ -31,9 +31,6 @@ namespace Titanium.Web.Proxy.Helpers
Task
sendRelay
=
Task
.
Factory
.
StartNew
(()
=>
StreamHelper
.
CopyTo
(
clientStream
,
tunnelStream
,
BUFFER_SIZE
));
Task
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
StreamHelper
.
CopyTo
(
tunnelStream
,
clientStream
,
BUFFER_SIZE
));
sendRelay
.
Start
();
receiveRelay
.
Start
();
Task
.
WaitAll
(
sendRelay
,
receiveRelay
);
}
catch
...
...
@@ -118,9 +115,6 @@ namespace Titanium.Web.Proxy.Helpers
var
sendRelay
=
new
Task
(()
=>
StreamHelper
.
CopyTo
(
sb
.
ToString
(),
clientStream
,
tunnelStream
,
BUFFER_SIZE
));
var
receiveRelay
=
new
Task
(()
=>
StreamHelper
.
CopyTo
(
tunnelStream
,
clientStream
,
BUFFER_SIZE
));
sendRelay
.
Start
();
receiveRelay
.
Start
();
Task
.
WaitAll
(
sendRelay
,
receiveRelay
);
}
catch
...
...
Titanium.Web.Proxy/Models/SessionEventArgs.cs
View file @
23f1d181
...
...
@@ -4,6 +4,7 @@ using System.IO;
using
System.Net
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Net.Sockets
;
using
Titanium.Web.Proxy.Exceptions
;
namespace
Titanium.Web.Proxy.Models
...
...
@@ -18,25 +19,25 @@ namespace Titanium.Web.Proxy.Models
internal
CustomBinaryReader
ClientStreamReader
{
get
;
set
;
}
internal
StreamWriter
ClientStreamWriter
{
get
;
set
;
}
internal
string
UpgradeProtocol
{
get
;
set
;
}
internal
Encoding
Encoding
{
get
;
set
;
}
internal
int
RequestLength
{
get
;
set
;
}
internal
string
HttpsHostName
{
get
;
set
;
}
internal
string
HttpsDecoratedHostName
{
get
;
set
;
}
internal
int
RequestContentLength
{
get
;
set
;
}
internal
Encoding
RequestEncoding
{
get
;
set
;
}
internal
Version
RequestHttpVersion
{
get
;
set
;
}
internal
bool
RequestIsAlive
{
get
;
set
;
}
internal
bool
CancelRequest
{
get
;
set
;
}
internal
string
Request
Html
Body
{
get
;
set
;
}
internal
bool
Request
WasModifie
d
{
get
;
set
;
}
internal
string
RequestBody
{
get
;
set
;
}
internal
bool
Request
BodyRea
d
{
get
;
set
;
}
internal
Stream
ServerResponseStream
{
get
;
set
;
}
internal
string
ResponseHtmlBody
{
get
;
set
;
}
internal
bool
ResponseWasModified
{
get
;
set
;
}
internal
Encoding
ResponseEncoding
{
get
;
set
;
}
internal
Stream
ResponseStream
{
get
;
set
;
}
internal
string
ResponseBody
{
get
;
set
;
}
internal
bool
ResponseBodyRead
{
get
;
set
;
}
public
int
ClientPort
{
get
;
set
;
}
public
IPAddress
ClientIpAddress
{
get
;
set
;
}
public
string
tunnelHostName
{
get
;
set
;
}
public
string
securehost
{
get
;
set
;
}
public
bool
IsSSLRequest
{
get
;
set
;
}
public
bool
IsHttps
{
get
;
set
;
}
public
string
RequestURL
{
get
;
set
;
}
public
string
RequestHostname
{
get
;
set
;
}
...
...
@@ -48,8 +49,8 @@ namespace Titanium.Web.Proxy.Models
if
(
this
.
ProxyRequest
!=
null
)
this
.
ProxyRequest
.
Abort
();
if
(
this
.
Server
ResponseStream
!=
null
)
this
.
Server
ResponseStream
.
Dispose
();
if
(
this
.
ResponseStream
!=
null
)
this
.
ResponseStream
.
Dispose
();
if
(
this
.
ServerResponse
!=
null
)
this
.
ServerResponse
.
Close
();
...
...
@@ -60,70 +61,66 @@ namespace Titanium.Web.Proxy.Models
{
BUFFER_SIZE
=
bufferSize
;
}
public
string
GetRequest
Html
Body
()
public
string
GetRequestBody
()
{
if
(
RequestHtmlBody
==
null
)
if
(
(
ProxyRequest
.
Method
.
ToUpper
()
==
"POST"
||
ProxyRequest
.
Method
.
ToUpper
()
==
"PUT"
)
&&
RequestContentLength
>
0
)
{
int
bytesRead
;
int
totalBytesRead
=
0
;
MemoryStream
mw
=
new
MemoryStream
();
var
buffer
=
ClientStreamReader
.
ReadBytes
(
RequestLength
);
while
(
totalBytesRead
<
RequestLength
&&
(
bytesRead
=
buffer
.
Length
)
>
0
)
if
(
RequestBody
==
null
)
{
totalBytesRead
+=
bytesRead
;
mw
.
Write
(
buffer
,
0
,
bytesRead
);
var
buffer
=
ClientStreamReader
.
ReadBytes
(
RequestContentLength
);
RequestBody
=
RequestEncoding
.
GetString
(
buffer
);
}
mw
.
Close
();
RequestHtmlBody
=
Encoding
.
Default
.
GetString
(
mw
.
ToArray
());
RequestBodyRead
=
true
;
return
RequestBody
;
}
RequestWasModified
=
true
;
return
RequestHtmlBody
;
else
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."
);
}
public
void
SetRequest
Html
Body
(
string
body
)
public
void
SetRequestBody
(
string
body
)
{
this
.
Request
Html
Body
=
body
;
Request
WasModifie
d
=
true
;
this
.
RequestBody
=
body
;
Request
BodyRea
d
=
true
;
}
public
string
GetResponse
Html
Body
()
public
string
GetResponseBody
()
{
if
(
Response
Html
Body
==
null
)
if
(
ResponseBody
==
null
)
{
Encoding
=
Encoding
.
GetEncoding
(
ServerResponse
.
CharacterSet
);
if
(
ResponseEncoding
==
null
)
Response
Encoding
=
Encoding
.
GetEncoding
(
ServerResponse
.
CharacterSet
);
if
(
ResponseEncoding
==
null
)
ResponseEncoding
=
Encoding
.
Default
;
if
(
Encoding
==
null
)
Encoding
=
Encoding
.
Default
;
switch
(
ServerResponse
.
ContentEncoding
)
{
case
"gzip"
:
Response
HtmlBody
=
CompressionHelper
.
DecompressGzip
(
ServerResponseStream
,
Encoding
);
Response
Body
=
CompressionHelper
.
DecompressGzip
(
ResponseStream
,
Response
Encoding
);
break
;
case
"deflate"
:
Response
HtmlBody
=
CompressionHelper
.
DecompressDeflate
(
ServerResponseStream
,
Encoding
);
Response
Body
=
CompressionHelper
.
DecompressDeflate
(
ResponseStream
,
Response
Encoding
);
break
;
case
"zlib"
:
Response
HtmlBody
=
CompressionHelper
.
DecompressZlib
(
ServerResponseStream
,
Encoding
);
Response
Body
=
CompressionHelper
.
DecompressZlib
(
ResponseStream
,
Response
Encoding
);
break
;
default
:
Response
HtmlBody
=
DecodeData
(
ServerResponseStream
,
Encoding
);
Response
Body
=
DecodeData
(
ResponseStream
,
Response
Encoding
);
break
;
}
Response
WasModifie
d
=
true
;
Response
BodyRea
d
=
true
;
}
return
Response
Html
Body
;
return
ResponseBody
;
}
public
void
SetResponse
Html
Body
(
string
body
)
public
void
SetResponseBody
(
string
body
)
{
this
.
ResponseHtmlBody
=
body
;
ResponseWasModified
=
true
;
if
(
ResponseEncoding
==
null
)
ResponseEncoding
=
Encoding
.
GetEncoding
(
ServerResponse
.
CharacterSet
);
if
(
ResponseEncoding
==
null
)
ResponseEncoding
=
Encoding
.
Default
;
this
.
ResponseBody
=
body
;
ResponseBodyRead
=
true
;
}
//stream reader not recomended for images
private
string
DecodeData
(
Stream
responseStream
,
Encoding
e
)
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
23f1d181
...
...
@@ -31,29 +31,23 @@ namespace Titanium.Web.Proxy
private
static
readonly
Regex
cookieSplitRegEx
=
new
Regex
(
@",(?! )"
);
private
static
object
certificateAccessLock
=
new
object
();
private
static
List
<
string
>
pinnedCertificateClients
=
new
List
<
string
>();
private
static
TcpListener
listener
;
private
static
Thread
listenerThread
;
private
static
bool
ShouldListen
{
get
;
set
;
}
public
static
List
<
string
>
ExcludedHttpsHostNameRegex
=
new
List
<
string
>();
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeRequest
;
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
static
IPAddress
ListeningIPInterface
{
get
;
set
;
}
public
static
string
RootCertificateName
{
get
;
set
;
}
public
static
bool
EnableSSL
{
get
;
set
;
}
public
static
bool
SetAsSystemProxy
{
get
;
set
;
}
public
static
Int32
ListeningPort
{
get
{
return
((
IPEndPoint
)
listener
.
LocalEndpoint
).
Port
;
}
}
public
static
Int32
ListeningPort
{
get
;
set
;
}
public
static
IPAddress
ListeningIpAddress
{
get
;
set
;
}
public
static
CertificateManager
CertManager
{
get
;
set
;
}
...
...
@@ -61,12 +55,14 @@ namespace Titanium.Web.Proxy
{
CertManager
=
new
CertificateManager
(
"Titanium"
,
"Titanium Root Certificate Authority"
);
ListeningIpAddress
=
IPAddress
.
Any
;
ListeningPort
=
0
;
}
public
ProxyServer
()
{
System
.
Net
.
ServicePointManager
.
Expect100Continue
=
false
;
System
.
Net
.
WebRequest
.
DefaultWebProxy
=
null
;
System
.
Net
.
ServicePointManager
.
DefaultConnectionLimit
=
10
;
...
...
@@ -111,13 +107,16 @@ namespace Titanium.Web.Proxy
public
static
bool
Start
()
{
listener
=
new
TcpListener
(
IPAddress
.
Any
,
0
);
listener
=
new
TcpListener
(
ListeningIpAddress
,
ListeningPort
);
listener
.
Start
();
listenerThread
=
new
Thread
(
new
ParameterizedThreadStart
(
Listen
));
listenerThread
.
IsBackground
=
true
;
ShouldListen
=
true
;
listenerThread
.
Start
(
listener
);
ListeningPort
=
((
IPEndPoint
)
listener
.
LocalEndpoint
).
Port
;
if
(
SetAsSystemProxy
)
{
SystemProxyHelper
.
EnableProxyHTTP
(
"localhost"
,
ListeningPort
);
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
23f1d181
...
...
@@ -14,7 +14,8 @@ using System.Reflection;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Text.RegularExpressions
;
namespace
Titanium.Web.Proxy
{
...
...
@@ -30,17 +31,14 @@ namespace Titanium.Web.Proxy
CustomBinaryReader
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
Encoding
.
ASCII
);
StreamWriter
clientStreamWriter
=
new
StreamWriter
(
clientStream
);
string
tunnelHostName
=
null
;
int
tunnelPort
=
0
;
string
HttpsHostName
=
null
;
int
httpsPort
=
443
;
try
{
string
securehost
=
null
;
string
httpsDecoratedHostName
=
null
,
tmpLine
=
null
;
List
<
string
>
requestLines
=
new
List
<
string
>();
string
tmpLine
;
while
(!
String
.
IsNullOrEmpty
(
tmpLine
=
clientStreamReader
.
ReadLine
()))
{
requestLines
.
Add
(
tmpLine
);
...
...
@@ -79,12 +77,10 @@ namespace Titanium.Web.Proxy
//to avoid that we need to install our root certficate in users machine as Certificate Authority.
remoteUri
=
"https://"
+
splitBuffer
[
1
];
tunnel
HostName
=
splitBuffer
[
1
].
Split
(
':'
)[
0
];
Https
HostName
=
splitBuffer
[
1
].
Split
(
':'
)[
0
];
int
.
TryParse
(
splitBuffer
[
1
].
Split
(
':'
)[
1
],
out
tunnel
Port
);
int
.
TryParse
(
splitBuffer
[
1
].
Split
(
':'
)[
1
],
out
https
Port
);
if
(
tunnelPort
==
0
)
tunnelPort
=
443
;
requestLines
.
Clear
();
clientStreamWriter
.
WriteLine
(
RequestVersion
+
" 200 Connection established"
);
...
...
@@ -94,10 +90,10 @@ namespace Titanium.Web.Proxy
clientStreamWriter
.
Flush
();
//If port is not 443 its not a HTTP request, so just relay
if
(
tunnel
Port
!=
443
)
//If port is not 443 its not a HTTP request
(may be tcp)
, so just relay
if
(
https
Port
!=
443
)
{
TcpHelper
.
SendRaw
(
tunnelHostName
,
tunnel
Port
,
clientStreamReader
.
BaseStream
);
TcpHelper
.
SendRaw
(
HttpsHostName
,
https
Port
,
clientStreamReader
.
BaseStream
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
...
...
@@ -106,16 +102,16 @@ namespace Titanium.Web.Proxy
//Create the fake certificate signed using our fake certificate authority
Monitor
.
Enter
(
certificateAccessLock
);
var
certificate
=
ProxyServer
.
CertManager
.
CreateCertificate
(
tunnel
HostName
);
var
certificate
=
ProxyServer
.
CertManager
.
CreateCertificate
(
Https
HostName
);
Monitor
.
Exit
(
certificateAccessLock
);
SslStream
sslStream
=
null
;
//Pinned certificate clients cannot be proxied
//
Example dropbox.com uses
certificate pinning
//So just relay the request
after identifying it by first failure
if
(!
pinnedCertificateClients
.
Contains
(
tunnelHostName
))
//
For example dropbox clients use
certificate pinning
//So just relay the request
if
(!
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
HttpsHostName
,
x
)
))
{
try
{
sslStream
=
new
SslStream
(
clientStream
,
true
);
...
...
@@ -129,14 +125,7 @@ namespace Titanium.Web.Proxy
}
catch
{
//if authentication failed it could be because client uses pinned certificates
//So add the hostname to this list so that next time we can relay without touching it (tunnel the request)
if
(
pinnedCertificateClients
.
Contains
(
tunnelHostName
)
==
false
)
{
pinnedCertificateClients
.
Add
(
tunnelHostName
);
}
{
if
(
sslStream
!=
null
)
sslStream
.
Dispose
();
...
...
@@ -147,14 +136,11 @@ namespace Titanium.Web.Proxy
else
{
//Hostname was a previously failed request due to certificate pinning, just relay (tunnel the request)
TcpHelper
.
SendRaw
(
tunnelHostName
,
tunnelPort
,
clientStreamReader
.
BaseStream
);
TcpHelper
.
SendRaw
(
HttpsHostName
,
httpsPort
,
clientStreamReader
.
BaseStream
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
}
while
(!
String
.
IsNullOrEmpty
(
tmpLine
=
clientStreamReader
.
ReadLine
()))
{
requestLines
.
Add
(
tmpLine
);
...
...
@@ -167,13 +153,11 @@ namespace Titanium.Web.Proxy
throw
new
EndOfStreamException
();
}
securehost
=
remoteUri
;
httpsDecoratedHostName
=
remoteUri
;
}
//Now create the request
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
tunnelHostName
,
requestLines
,
clientStreamReader
,
clientStreamWriter
,
securehost
));
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
HttpsHostName
,
requestLines
,
clientStreamReader
,
clientStreamWriter
,
httpsDecoratedHostName
));
}
catch
...
...
@@ -183,7 +167,7 @@ namespace Titanium.Web.Proxy
}
private
static
void
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
string
tunnelHostName
,
List
<
string
>
requestLines
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
securehost
)
private
static
void
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
string
httpsHostName
,
List
<
string
>
requestLines
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
httpsDecoratedHostName
)
{
...
...
@@ -197,8 +181,8 @@ namespace Titanium.Web.Proxy
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
);
args
.
Client
=
client
;
args
.
tunnelHostName
=
tunnel
HostName
;
args
.
securehost
=
securehost
;
args
.
HttpsHostName
=
https
HostName
;
args
.
HttpsDecoratedHostName
=
httpsDecoratedHostName
;
try
{
...
...
@@ -207,7 +191,7 @@ namespace Titanium.Web.Proxy
if
(
splitBuffer
.
Length
!=
3
)
{
TcpHelper
.
SendRaw
(
httpCmd
,
tunnelHostName
,
requestLines
,
args
.
IsSSLRequest
,
clientStreamReader
.
BaseStream
);
TcpHelper
.
SendRaw
(
httpCmd
,
httpsHostName
,
requestLines
,
args
.
IsHttps
,
clientStreamReader
.
BaseStream
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
...
...
@@ -225,10 +209,10 @@ namespace Titanium.Web.Proxy
version
=
new
Version
(
1
,
0
);
}
if
(
securehost
!=
null
)
if
(
httpsDecoratedHostName
!=
null
)
{
remoteUri
=
securehost
+
remoteUri
;
args
.
Is
SSLRequest
=
true
;
remoteUri
=
httpsDecoratedHostName
+
remoteUri
;
args
.
Is
Https
=
true
;
}
//construct the web request that we are going to issue on behalf of the client.
...
...
@@ -250,7 +234,7 @@ namespace Titanium.Web.Proxy
if
((
header
[
0
]
==
"upgrade"
)
&&
(
header
[
1
]
==
"websocket"
))
{
TcpHelper
.
SendRaw
(
httpCmd
,
tunnelHostName
,
requestLines
,
args
.
IsSSLRequest
,
clientStreamReader
.
BaseStream
);
TcpHelper
.
SendRaw
(
httpCmd
,
httpsHostName
,
requestLines
,
args
.
IsHttps
,
clientStreamReader
.
BaseStream
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
...
...
@@ -260,24 +244,20 @@ namespace Titanium.Web.Proxy
SetClientRequestHeaders
(
requestLines
,
args
.
ProxyRequest
);
int
contentLen
=
(
int
)
args
.
ProxyRequest
.
ContentLength
;
args
.
ProxyRequest
.
AllowAutoRedirect
=
false
;
args
.
ProxyRequest
.
AutomaticDecompression
=
DecompressionMethods
.
None
;
args
.
RequestHostname
=
args
.
ProxyRequest
.
RequestUri
.
Host
;
args
.
RequestURL
=
args
.
ProxyRequest
.
RequestUri
.
OriginalString
;
args
.
ClientPort
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Port
;
args
.
ClientIpAddress
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Address
;
args
.
RequestHttpVersion
=
version
;
args
.
RequestIsAlive
=
args
.
ProxyRequest
.
KeepAlive
;
//If requested interception
if
(
BeforeRequest
!=
null
)
{
args
.
RequestHostname
=
args
.
ProxyRequest
.
RequestUri
.
Host
;
args
.
RequestURL
=
args
.
ProxyRequest
.
RequestUri
.
OriginalString
;
args
.
RequestLength
=
contentLen
;
args
.
RequestHttpVersion
=
version
;
args
.
ClientPort
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Port
;
args
.
ClientIpAddress
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Address
;
args
.
RequestIsAlive
=
args
.
ProxyRequest
.
KeepAlive
;
args
.
RequestContentLength
=
(
int
)
args
.
ProxyRequest
.
ContentLength
;
args
.
RequestEncoding
=
args
.
ProxyRequest
.
GetEncoding
();
BeforeRequest
(
null
,
args
);
}
...
...
@@ -294,13 +274,13 @@ namespace Titanium.Web.Proxy
args
.
ProxyRequest
.
AllowWriteStreamBuffering
=
true
;
//If request was modified by user
if
(
args
.
Request
WasModifie
d
)
if
(
args
.
Request
BodyRea
d
)
{
ASCIIEncoding
encoding
=
new
ASCIIEncoding
();
byte
[]
requestBytes
=
encoding
.
GetBytes
(
args
.
RequestHtmlBody
);
byte
[]
requestBytes
=
args
.
RequestEncoding
.
GetBytes
(
args
.
RequestBody
);
args
.
ProxyRequest
.
ContentLength
=
requestBytes
.
Length
;
Stream
newStream
=
args
.
ProxyRequest
.
GetRequestStream
();
newStream
.
Write
(
requestBytes
,
0
,
requestBytes
.
Length
);
args
.
ProxyRequest
.
BeginGetResponse
(
new
AsyncCallback
(
HandleHttpSessionResponse
),
args
);
}
...
...
@@ -331,7 +311,7 @@ namespace Titanium.Web.Proxy
TcpClient
Client
=
args
.
Client
;
//Http request body sent, now wait for next request
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
Client
,
httpCmd
,
args
.
ClientStream
,
args
.
tunnelHostName
,
requestLines
,
args
.
ClientStreamReader
,
args
.
ClientStreamWriter
,
args
.
securehost
));
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
Client
,
httpCmd
,
args
.
ClientStream
,
args
.
HttpsHostName
,
requestLines
,
args
.
ClientStreamReader
,
args
.
ClientStreamWriter
,
args
.
HttpsDecoratedHostName
));
}
catch
...
...
@@ -392,7 +372,7 @@ namespace Titanium.Web.Proxy
webRequest
.
ContentLength
=
contentLen
;
break
;
case
"content-type"
:
webRequest
.
ContentType
=
header
[
1
];
webRequest
.
ContentType
=
header
[
1
];
break
;
case
"expect"
:
if
(
header
[
1
].
ToLower
()
==
"100-continue"
)
...
...
@@ -491,7 +471,7 @@ namespace Titanium.Web.Proxy
}
postStream
.
Close
();
postStream
.
Dispose
();
}
catch
{
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
23f1d181
...
...
@@ -38,41 +38,39 @@ namespace Titanium.Web.Proxy
if
(
args
.
ServerResponse
!=
null
)
{
List
<
Tuple
<
String
,
String
>>
responseHeaders
=
ProcessResponse
(
args
.
ServerResponse
);
args
.
Server
ResponseStream
=
args
.
ServerResponse
.
GetResponseStream
();
args
.
ResponseStream
=
args
.
ServerResponse
.
GetResponseStream
();
bool
isChunked
=
args
.
ServerResponse
.
GetResponseHeader
(
"transfer-encoding"
)
==
null
?
false
:
args
.
ServerResponse
.
GetResponseHeader
(
"transfer-encoding"
).
ToLower
()
==
"chunked"
?
true
:
false
;
args
.
UpgradeProtocol
=
args
.
ServerResponse
.
GetResponseHeader
(
"upgrade"
)
==
null
?
null
:
args
.
ServerResponse
.
GetResponseHeader
(
"upgrade"
);
if
(
BeforeResponse
!=
null
)
BeforeResponse
(
null
,
args
);
if
(
args
.
Response
WasModifie
d
)
if
(
args
.
Response
BodyRea
d
)
{
byte
[]
data
;
switch
(
args
.
ServerResponse
.
ContentEncoding
)
{
case
"gzip"
:
data
=
CompressionHelper
.
CompressGzip
(
args
.
Response
HtmlBody
,
args
.
Encoding
);
data
=
CompressionHelper
.
CompressGzip
(
args
.
Response
Body
,
args
.
Response
Encoding
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
responseHeaders
,
data
.
Length
);
SendData
(
args
.
ClientStream
,
data
,
isChunked
);
break
;
case
"deflate"
:
data
=
CompressionHelper
.
CompressDeflate
(
args
.
Response
HtmlBody
,
args
.
Encoding
);
data
=
CompressionHelper
.
CompressDeflate
(
args
.
Response
Body
,
args
.
Response
Encoding
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
responseHeaders
,
data
.
Length
);
SendData
(
args
.
ClientStream
,
data
,
isChunked
);
break
;
case
"zlib"
:
data
=
CompressionHelper
.
CompressZlib
(
args
.
Response
HtmlBody
,
args
.
Encoding
);
data
=
CompressionHelper
.
CompressZlib
(
args
.
Response
Body
,
args
.
Response
Encoding
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
responseHeaders
,
data
.
Length
);
SendData
(
args
.
ClientStream
,
data
,
isChunked
);
break
;
default
:
data
=
EncodeData
(
args
.
Response
HtmlBody
,
args
.
Encoding
);
data
=
EncodeData
(
args
.
Response
Body
,
args
.
Response
Encoding
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
responseHeaders
,
data
.
Length
);
SendData
(
args
.
ClientStream
,
data
,
isChunked
);
...
...
@@ -86,9 +84,9 @@ namespace Titanium.Web.Proxy
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
responseHeaders
);
if
(
isChunked
)
SendChunked
(
args
.
Server
ResponseStream
,
args
.
ClientStream
);
SendChunked
(
args
.
ResponseStream
,
args
.
ClientStream
);
else
SendNormal
(
args
.
Server
ResponseStream
,
args
.
ClientStream
);
SendNormal
(
args
.
ResponseStream
,
args
.
ClientStream
);
}
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
23f1d181
...
...
@@ -76,6 +76,8 @@
<Reference
Include=
"System.Xml"
/>
</ItemGroup>
<ItemGroup>
<Compile
Include=
"Exceptions\BodyNotFoundException.cs"
/>
<Compile
Include=
"Extensions\HttpWebRequestExtensions.cs"
/>
<Compile
Include=
"Helpers\CertificateManager.cs"
/>
<Compile
Include=
"Helpers\Firefox.cs"
/>
<Compile
Include=
"Helpers\SystemProxy.cs"
/>
...
...
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