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
e332c90d
Commit
e332c90d
authored
Oct 11, 2015
by
titanium007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cleanup
parent
887add69
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
590 additions
and
685 deletions
+590
-685
NuGet.Config
.nuget/NuGet.Config
+1
-0
App.config
Titanium.Web.Proxy.Test/App.config
+2
-1
Program.cs
Titanium.Web.Proxy.Test/Program.cs
+23
-30
AssemblyInfo.cs
Titanium.Web.Proxy.Test/Properties/AssemblyInfo.cs
+5
-2
ProxyTestController.cs
Titanium.Web.Proxy.Test/ProxyTestController.cs
+7
-26
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+135
-160
BodyNotFoundException.cs
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
+2
-7
HttpWebRequestExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
+6
-6
HttpWebResponseExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
+3
-7
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+12
-16
CertificateManager.cs
Titanium.Web.Proxy/Helpers/CertificateManager.cs
+12
-11
Compression.cs
Titanium.Web.Proxy/Helpers/Compression.cs
+28
-33
CustomBinaryReader.cs
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
+15
-27
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+20
-18
NetFramework.cs
Titanium.Web.Proxy/Helpers/NetFramework.cs
+14
-17
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+44
-32
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+21
-22
HttpHeader.cs
Titanium.Web.Proxy/Models/HttpHeader.cs
+8
-10
AssemblyInfo.cs
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
+5
-2
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+56
-58
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+106
-124
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+64
-76
packages.config
Titanium.Web.Proxy/packages.config
+1
-0
No files found.
.nuget/NuGet.Config
View file @
e332c90d
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
configuration
>
<
solution
>
<
solution
>
<
add
key
=
"disableSourceControlIntegration"
value
=
"true"
/>
<
add
key
=
"disableSourceControlIntegration"
value
=
"true"
/>
...
...
Titanium.Web.Proxy.Test/App.config
View file @
e332c90d
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
configuration
>
<
startup
>
<
startup
>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.0,Profile=Client"
/>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.0,Profile=Client"
/>
...
...
Titanium.Web.Proxy.Test/Program.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Reflection
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Text
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Test
namespace
Titanium.Web.Proxy.Test
{
{
public
class
Program
public
class
Program
{
{
static
ProxyTestController
controller
=
new
ProxyTestController
();
private
static
readonly
ProxyTestController
Controller
=
new
ProxyTestController
();
public
static
void
Main
(
string
[]
args
)
public
static
void
Main
(
string
[]
args
)
{
{
//On Console exit make sure we also exit the proxy
//On Console exit make sure we also exit the proxy
NativeMethods
.
handler
=
new
NativeMethods
.
ConsoleEventDelegate
(
ConsoleEventCallback
);
NativeMethods
.
Handler
=
ConsoleEventCallback
;
NativeMethods
.
SetConsoleCtrlHandler
(
NativeMethods
.
handler
,
true
);
NativeMethods
.
SetConsoleCtrlHandler
(
NativeMethods
.
Handler
,
true
);
Console
.
Write
(
"Do you want to monitor HTTPS? (Y/N):"
);
Console
.
Write
(
"Do you want to monitor HTTPS? (Y/N):"
);
if
(
Console
.
ReadLine
().
Trim
().
ToLower
()
==
"y"
)
var
readLine
=
Console
.
ReadLine
();
if
(
readLine
!=
null
&&
readLine
.
Trim
().
ToLower
()
==
"y"
)
{
{
controller
.
EnableSSL
=
true
;
Controller
.
EnableSsl
=
true
;
}
}
Console
.
Write
(
"Do you want to set this as a System Proxy? (Y/N):"
);
Console
.
Write
(
"Do you want to set this as a System Proxy? (Y/N):"
);
if
(
Console
.
ReadLine
().
Trim
().
ToLower
()
==
"y"
)
var
line
=
Console
.
ReadLine
();
if
(
line
!=
null
&&
line
.
Trim
().
ToLower
()
==
"y"
)
{
{
controller
.
SetAsSystemProxy
=
true
;
Controller
.
SetAsSystemProxy
=
true
;
}
}
//Start proxy controller
//Start proxy controller
c
ontroller
.
StartProxy
();
C
ontroller
.
StartProxy
();
Console
.
WriteLine
(
"Hit any key to exit.."
);
Console
.
WriteLine
(
"Hit any key to exit.."
);
Console
.
WriteLine
();
Console
.
WriteLine
();
Console
.
Read
();
Console
.
Read
();
c
ontroller
.
Stop
();
C
ontroller
.
Stop
();
}
}
static
bool
ConsoleEventCallback
(
int
eventType
)
private
static
bool
ConsoleEventCallback
(
int
eventType
)
{
{
if
(
eventType
==
2
)
if
(
eventType
==
2
)
{
{
try
try
{
{
controller
.
Stop
();
Controller
.
Stop
();
}
catch
{
// ignored
}
}
catch
{
}
}
}
return
false
;
return
false
;
}
}
}
}
internal
static
class
NativeMethods
internal
static
class
NativeMethods
{
{
// Keeps it from getting garbage collected
internal
static
ConsoleEventDelegate
Handler
;
[
DllImport
(
"kernel32.dll"
,
SetLastError
=
true
)]
[
DllImport
(
"kernel32.dll"
,
SetLastError
=
true
)]
internal
static
extern
bool
SetConsoleCtrlHandler
(
ConsoleEventDelegate
callback
,
bool
add
);
internal
static
extern
bool
SetConsoleCtrlHandler
(
ConsoleEventDelegate
callback
,
bool
add
);
// Pinvoke
// Pinvoke
internal
delegate
bool
ConsoleEventDelegate
(
int
eventType
);
internal
delegate
bool
ConsoleEventDelegate
(
int
eventType
);
// Keeps it from getting garbage collected
internal
static
ConsoleEventDelegate
handler
;
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy.Test/Properties/AssemblyInfo.cs
View file @
e332c90d
using
System.Reflection
;
using
System.Reflection
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
// associated with an assembly.
[assembly: AssemblyTitle("Demo")]
[assembly: AssemblyTitle("Demo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyConfiguration("")]
...
@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
...
@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("33a2109d-0312-4c94-aa51-fbb2a83e63ab")]
[assembly: Guid("33a2109d-0312-4c94-aa51-fbb2a83e63ab")]
// Version information for an assembly consists of the following four values:
// Version information for an assembly consists of the following four values:
...
@@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
...
@@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
Titanium.Web.Proxy.Test/ProxyTestController.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Net
;
using
System.Text.RegularExpressions
;
using
System.DirectoryServices.AccountManagement
;
using
System.DirectoryServices.ActiveDirectory
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Test
namespace
Titanium.Web.Proxy.Test
{
{
public
partial
class
ProxyTestController
public
class
ProxyTestController
{
{
public
int
ListeningPort
{
get
;
set
;
}
public
int
ListeningPort
{
get
;
set
;
}
public
bool
EnableS
SL
{
get
;
set
;
}
public
bool
EnableS
sl
{
get
;
set
;
}
public
bool
SetAsSystemProxy
{
get
;
set
;
}
public
bool
SetAsSystemProxy
{
get
;
set
;
}
public
void
StartProxy
()
public
void
StartProxy
()
{
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
EnableS
SL
=
EnableSSL
;
ProxyServer
.
EnableS
sl
=
EnableSsl
;
ProxyServer
.
SetAsSystemProxy
=
SetAsSystemProxy
;
ProxyServer
.
SetAsSystemProxy
=
SetAsSystemProxy
;
...
@@ -40,9 +27,9 @@ namespace Titanium.Web.Proxy.Test
...
@@ -40,9 +27,9 @@ namespace Titanium.Web.Proxy.Test
ProxyServer
.
ListeningPort
=
ProxyServer
.
ListeningPort
;
ProxyServer
.
ListeningPort
=
ProxyServer
.
ListeningPort
;
Console
.
WriteLine
(
String
.
Format
(
"Proxy listening on local machine port: {0} "
,
ProxyServer
.
ListeningPort
));
Console
.
WriteLine
(
"Proxy listening on local machine port: {0} "
,
ProxyServer
.
ListeningPort
);
}
}
public
void
Stop
()
public
void
Stop
()
{
{
ProxyServer
.
BeforeRequest
-=
OnRequest
;
ProxyServer
.
BeforeRequest
-=
OnRequest
;
...
@@ -52,13 +39,11 @@ namespace Titanium.Web.Proxy.Test
...
@@ -52,13 +39,11 @@ namespace Titanium.Web.Proxy.Test
}
}
//Test On Request, intecept requests
//Test On Request, intecept requests
//Read browser URL send back to proxy by the injection script in OnResponse event
//Read browser URL send back to proxy by the injection script in OnResponse event
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLine
(
e
.
RequestUrl
);
Console
.
WriteLine
(
e
.
RequestURL
);
////read request headers
////read request headers
//var requestHeaders = e.RequestHeaders;
//var requestHeaders = e.RequestHeaders;
...
@@ -82,7 +67,6 @@ namespace Titanium.Web.Proxy.Test
...
@@ -82,7 +67,6 @@ namespace Titanium.Web.Proxy.Test
//{
//{
// e.Ok("<!DOCTYPE html><html><body><h1>Website Blocked</h1><p>Blocked by titanium web proxy.</p></body></html>");
// e.Ok("<!DOCTYPE html><html><body><h1>Website Blocked</h1><p>Blocked by titanium web proxy.</p></body></html>");
//}
//}
}
}
//Test script injection
//Test script injection
...
@@ -112,9 +96,6 @@ namespace Titanium.Web.Proxy.Test
...
@@ -112,9 +96,6 @@ namespace Titanium.Web.Proxy.Test
// e.SetResponseBodyString(modified);
// e.SetResponseBodyString(modified);
// }
// }
//}
//}
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Text
;
using
System.Collections.Generic
;
using
System.Globalization
;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Text
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
using
System.Linq
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Collections.Generic
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.EventArguments
namespace
Titanium.Web.Proxy.EventArguments
{
{
public
class
SessionEventArgs
:
EventArgs
,
IDisposable
public
class
SessionEventArgs
:
EventArgs
,
IDisposable
{
{
readonly
int
_bufferSize
;
internal
int
BUFFER_SIZE
;
internal
SessionEventArgs
(
int
bufferSize
)
{
_bufferSize
=
bufferSize
;
}
internal
TcpClient
c
lient
{
get
;
set
;
}
internal
TcpClient
C
lient
{
get
;
set
;
}
internal
Stream
c
lientStream
{
get
;
set
;
}
internal
Stream
C
lientStream
{
get
;
set
;
}
internal
CustomBinaryReader
c
lientStreamReader
{
get
;
set
;
}
internal
CustomBinaryReader
C
lientStreamReader
{
get
;
set
;
}
internal
StreamWriter
c
lientStreamWriter
{
get
;
set
;
}
internal
StreamWriter
C
lientStreamWriter
{
get
;
set
;
}
internal
bool
isHttps
{
get
;
set
;
}
public
bool
IsHttps
{
get
;
internal
set
;
}
internal
string
requestURL
{
get
;
set
;
}
public
string
RequestUrl
{
get
;
internal
set
;
}
internal
string
requestHostname
{
get
;
set
;
}
public
string
RequestHostname
{
get
;
internal
set
;
}
internal
int
clientPort
{
get
;
set
;
}
public
int
ClientPort
{
get
;
internal
set
;
}
internal
IPAddress
clientIpAddress
{
get
;
set
;
}
public
IPAddress
ClientIpAddress
{
get
;
internal
set
;
}
internal
Encoding
r
equestEncoding
{
get
;
set
;
}
internal
Encoding
R
equestEncoding
{
get
;
set
;
}
internal
Version
r
equestHttpVersion
{
get
;
set
;
}
internal
Version
R
equestHttpVersion
{
get
;
set
;
}
internal
bool
r
equestIsAlive
{
get
;
set
;
}
internal
bool
R
equestIsAlive
{
get
;
set
;
}
internal
bool
c
ancelRequest
{
get
;
set
;
}
internal
bool
C
ancelRequest
{
get
;
set
;
}
internal
byte
[]
r
equestBody
{
get
;
set
;
}
internal
byte
[]
R
equestBody
{
get
;
set
;
}
internal
string
r
equestBodyString
{
get
;
set
;
}
internal
string
R
equestBodyString
{
get
;
set
;
}
internal
bool
r
equestBodyRead
{
get
;
set
;
}
internal
bool
R
equestBodyRead
{
get
;
set
;
}
internal
List
<
HttpHeader
>
requestHeaders
{
get
;
set
;
}
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
internal
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
internal
HttpWebRequest
p
roxyRequest
{
get
;
set
;
}
internal
HttpWebRequest
P
roxyRequest
{
get
;
set
;
}
internal
Encoding
r
esponseEncoding
{
get
;
set
;
}
internal
Encoding
R
esponseEncoding
{
get
;
set
;
}
internal
Stream
r
esponseStream
{
get
;
set
;
}
internal
Stream
R
esponseStream
{
get
;
set
;
}
internal
byte
[]
r
esponseBody
{
get
;
set
;
}
internal
byte
[]
R
esponseBody
{
get
;
set
;
}
internal
string
r
esponseBodyString
{
get
;
set
;
}
internal
string
R
esponseBodyString
{
get
;
set
;
}
internal
bool
r
esponseBodyRead
{
get
;
set
;
}
internal
bool
R
esponseBodyRead
{
get
;
set
;
}
internal
List
<
HttpHeader
>
responseHeaders
{
get
;
set
;
}
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
internal
set
;
}
internal
bool
ResponseLocked
{
get
;
set
;
}
internal
bool
ResponseLocked
{
get
;
set
;
}
internal
HttpWebResponse
serverResponse
{
get
;
set
;
}
internal
HttpWebResponse
ServerResponse
{
get
;
set
;
}
public
int
ClientPort
{
get
{
return
this
.
clientPort
;
}
}
public
IPAddress
ClientIpAddress
{
get
{
return
this
.
clientIpAddress
;
}
}
public
bool
IsHttps
{
get
{
return
this
.
isHttps
;
}
}
public
string
RequestURL
{
get
{
return
this
.
requestURL
;
}
}
public
string
RequestHostname
{
get
{
return
this
.
requestHostname
;
}
}
public
List
<
HttpHeader
>
RequestHeaders
{
get
{
return
this
.
requestHeaders
;
}
}
public
List
<
HttpHeader
>
ResponseHeaders
{
get
{
return
this
.
responseHeaders
;
}
}
public
int
RequestContentLength
public
int
RequestContentLength
{
{
get
get
{
{
if
(
this
.
requestHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
))
if
(
RequestHeaders
.
All
(
x
=>
x
.
Name
.
ToLower
()
!=
"content-length"
))
return
-
1
;
{
int
contentLen
;
int
contentLen
;
int
.
TryParse
(
this
.
r
equestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
).
Value
,
out
contentLen
);
int
.
TryParse
(
R
equestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-length"
).
Value
,
out
contentLen
);
if
(
contentLen
!=
0
)
if
(
contentLen
!=
0
)
return
contentLen
;
return
contentLen
;
}
return
-
1
;
return
-
1
;
}
}
}
}
public
string
RequestMethod
{
get
{
return
this
.
proxyRequest
.
Method
;
}
}
public
string
RequestMethod
{
get
{
return
ProxyRequest
.
Method
;
}
}
public
HttpStatusCode
ResponseStatusCode
{
get
{
return
this
.
serverResponse
.
StatusCode
;
}
}
public
HttpStatusCode
ResponseStatusCode
public
string
ResponseContentType
{
get
{
return
this
.
responseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
)
?
this
.
responseHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
).
Value
:
null
;
}
}
{
get
{
return
ServerResponse
.
StatusCode
;
}
}
public
string
ResponseContentType
{
get
{
return
ResponseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
)
?
ResponseHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-type"
).
Value
:
null
;
}
}
internal
SessionEventArgs
(
int
bufferSize
)
public
void
Dispose
(
)
{
{
BUFFER_SIZE
=
bufferSize
;
if
(
ProxyRequest
!=
null
)
ProxyRequest
.
Abort
();
if
(
ResponseStream
!=
null
)
ResponseStream
.
Dispose
();
if
(
ServerResponse
!=
null
)
ServerResponse
.
Close
();
}
}
private
void
r
eadRequestBody
()
private
void
R
eadRequestBody
()
{
{
if
((
proxyRequest
.
Method
.
ToUpper
()
!=
"POST"
&&
p
roxyRequest
.
Method
.
ToUpper
()
!=
"PUT"
))
if
((
ProxyRequest
.
Method
.
ToUpper
()
!=
"POST"
&&
P
roxyRequest
.
Method
.
ToUpper
()
!=
"PUT"
))
{
{
throw
new
BodyNotFoundException
(
"Request don't have a body."
+
throw
new
BodyNotFoundException
(
"Request don't have a body."
+
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body."
);
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body."
);
}
}
if
(
r
equestBody
==
null
)
if
(
R
equestBody
==
null
)
{
{
bool
isChunked
=
false
;
var
isChunked
=
false
;
string
requestContentEncoding
=
null
;
string
requestContentEncoding
=
null
;
if
(
r
equestHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"content-encoding"
))
if
(
R
equestHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"content-encoding"
))
{
{
requestContentEncoding
=
r
equestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-encoding"
).
Value
;
requestContentEncoding
=
R
equestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"content-encoding"
).
Value
;
}
}
if
(
r
equestHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
))
if
(
R
equestHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
))
{
{
var
transferEncoding
=
requestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
).
Value
.
ToLower
();
var
transferEncoding
=
RequestHeaders
.
First
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
).
Value
.
ToLower
();
if
(
transferEncoding
.
Contains
(
"chunked"
))
if
(
transferEncoding
.
Contains
(
"chunked"
))
{
{
isChunked
=
true
;
isChunked
=
true
;
}
}
}
}
if
(
requestContentEncoding
==
null
&&
!
isChunked
)
if
(
requestContentEncoding
==
null
&&
!
isChunked
)
requestBody
=
c
lientStreamReader
.
ReadBytes
(
RequestContentLength
);
RequestBody
=
C
lientStreamReader
.
ReadBytes
(
RequestContentLength
);
else
else
{
{
using
(
var
requestBodyStream
=
new
MemoryStream
())
using
(
var
requestBodyStream
=
new
MemoryStream
())
...
@@ -128,76 +140,72 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -128,76 +140,72 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
while
(
true
)
while
(
true
)
{
{
var
chuchkHead
=
c
lientStreamReader
.
ReadLine
();
var
chuchkHead
=
C
lientStreamReader
.
ReadLine
();
var
chunkSize
=
int
.
Parse
(
chuchkHead
,
System
.
Globalization
.
NumberStyles
.
HexNumber
);
var
chunkSize
=
int
.
Parse
(
chuchkHead
,
NumberStyles
.
HexNumber
);
if
(
chunkSize
!=
0
)
if
(
chunkSize
!=
0
)
{
{
var
buffer
=
c
lientStreamReader
.
ReadBytes
(
chunkSize
);
var
buffer
=
C
lientStreamReader
.
ReadBytes
(
chunkSize
);
requestBodyStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
requestBodyStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
//chunk trail
var
chunkTrail
=
c
lientStreamReader
.
ReadLine
();
C
lientStreamReader
.
ReadLine
();
}
}
else
else
{
{
c
lientStreamReader
.
ReadLine
();
C
lientStreamReader
.
ReadLine
();
break
;
break
;
}
}
}
}
}
}
try
try
{
{
switch
(
requestContentEncoding
)
switch
(
requestContentEncoding
)
{
{
case
"gzip"
:
case
"gzip"
:
r
equestBody
=
CompressionHelper
.
DecompressGzip
(
requestBodyStream
);
R
equestBody
=
CompressionHelper
.
DecompressGzip
(
requestBodyStream
);
break
;
break
;
case
"deflate"
:
case
"deflate"
:
r
equestBody
=
CompressionHelper
.
DecompressDeflate
(
requestBodyStream
);
R
equestBody
=
CompressionHelper
.
DecompressDeflate
(
requestBodyStream
);
break
;
break
;
case
"zlib"
:
case
"zlib"
:
r
equestBody
=
CompressionHelper
.
DecompressGzip
(
requestBodyStream
);
R
equestBody
=
CompressionHelper
.
DecompressGzip
(
requestBodyStream
);
break
;
break
;
default
:
default
:
r
equestBody
=
requestBodyStream
.
ToArray
();
R
equestBody
=
requestBodyStream
.
ToArray
();
break
;
break
;
}
}
}
}
catch
{
catch
requestBody
=
requestBodyStream
.
ToArray
();
{
RequestBody
=
requestBodyStream
.
ToArray
();
}
}
}
}
}
}
}
}
r
equestBodyRead
=
true
;
R
equestBodyRead
=
true
;
}
}
private
void
readResponseBody
()
private
void
ReadResponseBody
()
{
{
if
(
r
esponseBody
==
null
)
if
(
R
esponseBody
==
null
)
{
{
switch
(
ServerResponse
.
ContentEncoding
)
switch
(
serverResponse
.
ContentEncoding
)
{
{
case
"gzip"
:
case
"gzip"
:
responseBody
=
CompressionHelper
.
DecompressGzip
(
r
esponseStream
);
ResponseBody
=
CompressionHelper
.
DecompressGzip
(
R
esponseStream
);
break
;
break
;
case
"deflate"
:
case
"deflate"
:
responseBody
=
CompressionHelper
.
DecompressDeflate
(
r
esponseStream
);
ResponseBody
=
CompressionHelper
.
DecompressDeflate
(
R
esponseStream
);
break
;
break
;
case
"zlib"
:
case
"zlib"
:
responseBody
=
CompressionHelper
.
DecompressZlib
(
r
esponseStream
);
ResponseBody
=
CompressionHelper
.
DecompressZlib
(
R
esponseStream
);
break
;
break
;
default
:
default
:
responseBody
=
DecodeData
(
r
esponseStream
);
ResponseBody
=
DecodeData
(
R
esponseStream
);
break
;
break
;
}
}
responseBodyRead
=
true
;
ResponseBodyRead
=
true
;
}
}
}
}
...
@@ -205,8 +213,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -205,8 +213,8 @@ namespace Titanium.Web.Proxy.EventArguments
//stream reader not recomended for images
//stream reader not recomended for images
private
byte
[]
DecodeData
(
Stream
responseStream
)
private
byte
[]
DecodeData
(
Stream
responseStream
)
{
{
byte
[]
buffer
=
new
byte
[
BUFFER_SIZE
];
var
buffer
=
new
byte
[
_bufferSize
];
using
(
MemoryStream
ms
=
new
MemoryStream
())
using
(
var
ms
=
new
MemoryStream
())
{
{
int
read
;
int
read
;
while
((
read
=
responseStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
responseStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
...
@@ -215,117 +223,105 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -215,117 +223,105 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
return
ms
.
ToArray
();
return
ms
.
ToArray
();
}
}
}
}
public
Encoding
GetRequestBodyEncoding
()
public
Encoding
GetRequestBodyEncoding
()
{
{
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
return
r
equestEncoding
;
return
R
equestEncoding
;
}
}
public
byte
[]
GetRequestBody
()
public
byte
[]
GetRequestBody
()
{
{
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
readRequestBody
();
ReadRequestBody
();
return
requestBody
;
return
RequestBody
;
}
}
public
string
GetRequestBodyAsString
()
public
string
GetRequestBodyAsString
()
{
{
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
readRequestBody
();
ReadRequestBody
();
if
(
requestBodyString
==
null
)
{
requestBodyString
=
requestEncoding
.
GetString
(
requestBody
);
}
return
requestBodyString
;
return
RequestBodyString
??
(
RequestBodyString
=
RequestEncoding
.
GetString
(
RequestBody
));
}
}
public
void
SetRequestBody
(
byte
[]
body
)
public
void
SetRequestBody
(
byte
[]
body
)
{
{
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(
RequestLocked
)
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(!
r
equestBodyRead
)
if
(!
R
equestBodyRead
)
{
{
r
eadRequestBody
();
R
eadRequestBody
();
}
}
r
equestBody
=
body
;
R
equestBody
=
body
;
r
equestBodyRead
=
true
;
R
equestBodyRead
=
true
;
}
}
public
void
SetRequestBodyString
(
string
body
)
public
void
SetRequestBodyString
(
string
body
)
{
{
if
(
RequestLocked
)
throw
new
Exception
(
"Youcannot call this function after request is made to server."
);
if
(
RequestLocked
)
throw
new
Exception
(
"Youcannot call this function after request is made to server."
);
if
(!
r
equestBodyRead
)
if
(!
R
equestBodyRead
)
{
{
r
eadRequestBody
();
R
eadRequestBody
();
}
}
this
.
requestBody
=
r
equestEncoding
.
GetBytes
(
body
);
RequestBody
=
R
equestEncoding
.
GetBytes
(
body
);
r
equestBodyRead
=
true
;
R
equestBodyRead
=
true
;
}
}
public
Encoding
GetResponseBodyEncoding
()
public
Encoding
GetResponseBodyEncoding
()
{
{
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
return
r
esponseEncoding
;
return
R
esponseEncoding
;
}
}
public
byte
[]
GetResponseBody
()
public
byte
[]
GetResponseBody
()
{
{
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
r
eadResponseBody
();
R
eadResponseBody
();
return
r
esponseBody
;
return
R
esponseBody
;
}
}
public
string
GetResponseBodyAsString
()
public
string
GetResponseBodyAsString
()
{
{
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
GetResponseBody
();
GetResponseBody
();
if
(
responseBodyString
==
null
)
return
ResponseBodyString
??
(
ResponseBodyString
=
ResponseEncoding
.
GetString
(
ResponseBody
));
{
responseBodyString
=
responseEncoding
.
GetString
(
responseBody
);
}
return
responseBodyString
;
}
}
public
void
SetResponseBody
(
byte
[]
body
)
public
void
SetResponseBody
(
byte
[]
body
)
{
{
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(
r
esponseBody
==
null
)
if
(
R
esponseBody
==
null
)
{
{
GetResponseBody
();
GetResponseBody
();
}
}
responseBody
=
body
;
ResponseBody
=
body
;
}
}
public
void
SetResponseBodyString
(
string
body
)
public
void
SetResponseBodyString
(
string
body
)
{
{
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(!
RequestLocked
)
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
if
(
r
esponseBody
==
null
)
if
(
R
esponseBody
==
null
)
{
{
GetResponseBody
();
GetResponseBody
();
}
}
var
bodyBytes
=
r
esponseEncoding
.
GetBytes
(
body
);
var
bodyBytes
=
R
esponseEncoding
.
GetBytes
(
body
);
SetResponseBody
(
bodyBytes
);
SetResponseBody
(
bodyBytes
);
}
}
...
@@ -339,45 +335,24 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -339,45 +335,24 @@ namespace Titanium.Web.Proxy.EventArguments
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
var
result
=
Encoding
.
Default
.
GetBytes
(
html
);
StreamWriter
connectStreamWriter
=
new
StreamWriter
(
c
lientStream
);
var
connectStreamWriter
=
new
StreamWriter
(
C
lientStream
);
var
s
=
String
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
requestHttpVersion
.
Major
,
r
equestHttpVersion
.
Minor
,
200
,
"Ok"
);
var
s
=
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
RequestHttpVersion
.
Major
,
R
equestHttpVersion
.
Minor
,
200
,
"Ok"
);
connectStreamWriter
.
WriteLine
(
s
);
connectStreamWriter
.
WriteLine
(
s
);
connectStreamWriter
.
WriteLine
(
String
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
.
ToString
())
);
connectStreamWriter
.
WriteLine
(
"Timestamp: {0}"
,
DateTime
.
Now
);
connectStreamWriter
.
WriteLine
(
"content-length: "
+
result
.
Length
);
connectStreamWriter
.
WriteLine
(
"content-length: "
+
result
.
Length
);
connectStreamWriter
.
WriteLine
(
"Cache-Control: no-cache, no-store, must-revalidate"
);
connectStreamWriter
.
WriteLine
(
"Cache-Control: no-cache, no-store, must-revalidate"
);
connectStreamWriter
.
WriteLine
(
"Pragma: no-cache"
);
connectStreamWriter
.
WriteLine
(
"Pragma: no-cache"
);
connectStreamWriter
.
WriteLine
(
"Expires: 0"
);
connectStreamWriter
.
WriteLine
(
"Expires: 0"
);
if
(
requestIsAlive
)
connectStreamWriter
.
WriteLine
(
RequestIsAlive
?
"Connection: Keep-Alive"
:
"Connection: close"
);
{
connectStreamWriter
.
WriteLine
(
"Connection: Keep-Alive"
);
}
else
connectStreamWriter
.
WriteLine
(
"Connection: close"
);
connectStreamWriter
.
WriteLine
();
connectStreamWriter
.
WriteLine
();
connectStreamWriter
.
Flush
();
connectStreamWriter
.
Flush
();
clientStream
.
Write
(
result
,
0
,
result
.
Length
);
ClientStream
.
Write
(
result
,
0
,
result
.
Length
);
cancelRequest
=
true
;
CancelRequest
=
true
;
}
}
public
void
Dispose
()
{
if
(
this
.
proxyRequest
!=
null
)
this
.
proxyRequest
.
Abort
();
if
(
this
.
responseStream
!=
null
)
this
.
responseStream
.
Dispose
();
if
(
this
.
serverResponse
!=
null
)
this
.
serverResponse
.
Close
();
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Exceptions
namespace
Titanium.Web.Proxy.Exceptions
{
{
public
class
BodyNotFoundException
:
Exception
public
class
BodyNotFoundException
:
Exception
{
{
public
BodyNotFoundException
(
string
message
)
public
BodyNotFoundException
(
string
message
)
:
base
(
message
)
:
base
(
message
)
{
{
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Extensions/HttpWebRequestExtensions.cs
View file @
e332c90d
using
System
;
using
System.Net
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Extensions
namespace
Titanium.Web.Proxy.Extensions
...
@@ -24,7 +21,10 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -24,7 +21,10 @@ namespace Titanium.Web.Proxy.Extensions
}
}
}
}
}
}
catch
{
}
catch
{
// ignored
}
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
}
...
...
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
View file @
e332c90d
using
System
;
using
System.Net
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Extensions
namespace
Titanium.Web.Proxy.Extensions
...
@@ -11,7 +8,6 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -11,7 +8,6 @@ namespace Titanium.Web.Proxy.Extensions
public
static
Encoding
GetEncoding
(
this
HttpWebResponse
response
)
public
static
Encoding
GetEncoding
(
this
HttpWebResponse
response
)
{
{
if
(
string
.
IsNullOrEmpty
(
response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
if
(
string
.
IsNullOrEmpty
(
response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
else
return
Encoding
.
GetEncoding
(
response
.
CharacterSet
);
return
Encoding
.
GetEncoding
(
response
.
CharacterSet
);
}
}
}
}
...
...
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.IO
;
using
System.IO
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Extensions
namespace
Titanium.Web.Proxy.Extensions
{
{
public
static
class
StreamHelper
public
static
class
StreamHelper
{
{
private
const
int
DEFAULT_BUFFER_SIZE
=
8192
;
// +32767
public
static
void
CopyToAsync
(
this
Stream
input
,
string
initialData
,
Stream
output
,
int
bufferSize
)
public
static
void
CopyToAsync
(
this
Stream
input
,
string
initialData
,
Stream
output
,
int
bufferSize
)
{
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
CopyToAsync
(
input
,
output
,
bufferSize
);
CopyToAsync
(
input
,
output
,
bufferSize
);
}
}
...
@@ -25,15 +21,14 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -25,15 +21,14 @@ namespace Titanium.Web.Proxy.Extensions
if
(!
input
.
CanRead
)
throw
new
InvalidOperationException
(
"input must be open for reading"
);
if
(!
input
.
CanRead
)
throw
new
InvalidOperationException
(
"input must be open for reading"
);
if
(!
output
.
CanWrite
)
throw
new
InvalidOperationException
(
"output must be open for writing"
);
if
(!
output
.
CanWrite
)
throw
new
InvalidOperationException
(
"output must be open for writing"
);
byte
[][]
buf
=
{
new
byte
[
bufferSize
],
new
byte
[
bufferSize
]
};
byte
[][]
buf
=
{
new
byte
[
bufferSize
],
new
byte
[
bufferSize
]
};
int
[]
bufl
=
{
0
,
0
};
int
[]
bufl
=
{
0
,
0
};
int
bufno
=
0
;
var
bufno
=
0
;
IAsyncResult
read
=
input
.
BeginRead
(
buf
[
bufno
],
0
,
buf
[
bufno
].
Length
,
null
,
null
);
var
read
=
input
.
BeginRead
(
buf
[
bufno
],
0
,
buf
[
bufno
].
Length
,
null
,
null
);
IAsyncResult
write
=
null
;
IAsyncResult
write
=
null
;
while
(
true
)
while
(
true
)
{
{
// wait for the read operation to complete
// wait for the read operation to complete
read
.
AsyncWaitHandle
.
WaitOne
();
read
.
AsyncWaitHandle
.
WaitOne
();
bufl
[
bufno
]
=
input
.
EndRead
(
read
);
bufl
[
bufno
]
=
input
.
EndRead
(
read
);
...
@@ -62,7 +57,6 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -62,7 +57,6 @@ namespace Titanium.Web.Proxy.Extensions
// A little speedier than using a ternary expression.
// A little speedier than using a ternary expression.
bufno
^=
1
;
// bufno = ( bufno == 0 ? 1 : 0 ) ;
bufno
^=
1
;
// bufno = ( bufno == 0 ? 1 : 0 ) ;
read
=
input
.
BeginRead
(
buf
[
bufno
],
0
,
buf
[
bufno
].
Length
,
null
,
null
);
read
=
input
.
BeginRead
(
buf
[
bufno
],
0
,
buf
[
bufno
].
Length
,
null
,
null
);
}
}
// wait for the final in-flight write operation, if one exists, to complete
// wait for the final in-flight write operation, if one exists, to complete
...
@@ -75,9 +69,11 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -75,9 +69,11 @@ namespace Titanium.Web.Proxy.Extensions
output
.
Flush
();
output
.
Flush
();
}
}
catch
{
}
catch
{
// ignored
}
// return to the caller ;
// return to the caller ;
return
;
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Helpers/CertificateManager.cs
View file @
e332c90d
...
@@ -8,10 +8,10 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -8,10 +8,10 @@ namespace Titanium.Web.Proxy.Helpers
{
{
public
class
CertificateManager
:
IDisposable
public
class
CertificateManager
:
IDisposable
{
{
private
const
string
C
ERT_CREATE_FORMAT
=
private
const
string
C
ertCreateFormat
=
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 -b {5:MM/dd/yyyy} {6}"
;
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 -b {5:MM/dd/yyyy} {6}"
;
private
readonly
IDictionary
<
string
,
X509Certificate2
>
certificateCache
;
private
readonly
IDictionary
<
string
,
X509Certificate2
>
_
certificateCache
;
public
string
Issuer
{
get
;
private
set
;
}
public
string
Issuer
{
get
;
private
set
;
}
public
string
RootCertificateName
{
get
;
private
set
;
}
public
string
RootCertificateName
{
get
;
private
set
;
}
...
@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
MyStore
=
new
X509Store
(
StoreName
.
My
,
StoreLocation
.
CurrentUser
);
MyStore
=
new
X509Store
(
StoreName
.
My
,
StoreLocation
.
CurrentUser
);
RootStore
=
new
X509Store
(
StoreName
.
Root
,
StoreLocation
.
CurrentUser
);
RootStore
=
new
X509Store
(
StoreName
.
Root
,
StoreLocation
.
CurrentUser
);
certificateCache
=
new
Dictionary
<
string
,
X509Certificate2
>();
_
certificateCache
=
new
Dictionary
<
string
,
X509Certificate2
>();
}
}
/// <summary>
/// <summary>
...
@@ -69,8 +69,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -69,8 +69,9 @@ namespace Titanium.Web.Proxy.Helpers
}
}
protected
virtual
X509Certificate2
CreateCertificate
(
X509Store
store
,
string
certificateName
)
protected
virtual
X509Certificate2
CreateCertificate
(
X509Store
store
,
string
certificateName
)
{
{
if
(
certificateCache
.
ContainsKey
(
certificateName
))
return
certificateCache
[
certificateName
];
if
(
_certificateCache
.
ContainsKey
(
certificateName
))
return
_certificateCache
[
certificateName
];
lock
(
store
)
lock
(
store
)
{
{
...
@@ -80,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -80,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
store
.
Open
(
OpenFlags
.
ReadWrite
);
store
.
Open
(
OpenFlags
.
ReadWrite
);
string
certificateSubject
=
string
.
Format
(
"CN={0}, O={1}"
,
certificateName
,
Issuer
);
string
certificateSubject
=
string
.
Format
(
"CN={0}, O={1}"
,
certificateName
,
Issuer
);
X509Certificate2Collection
certificates
=
var
certificates
=
FindCertificates
(
store
,
certificateSubject
);
FindCertificates
(
store
,
certificateSubject
);
if
(
certificates
!=
null
)
if
(
certificates
!=
null
)
...
@@ -102,8 +103,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -102,8 +103,8 @@ namespace Titanium.Web.Proxy.Helpers
finally
finally
{
{
store
.
Close
();
store
.
Close
();
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
if
(
certificate
!=
null
&&
!
_
certificateCache
.
ContainsKey
(
certificateName
))
certificateCache
.
Add
(
certificateName
,
certificate
);
_
certificateCache
.
Add
(
certificateName
,
certificate
);
}
}
}
}
}
}
...
@@ -151,9 +152,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -151,9 +152,9 @@ namespace Titanium.Web.Proxy.Helpers
{
{
store
.
Close
();
store
.
Close
();
if
(
certificates
==
null
&&
if
(
certificates
==
null
&&
certificateCache
.
ContainsKey
(
certificateName
))
_
certificateCache
.
ContainsKey
(
certificateName
))
{
{
certificateCache
.
Remove
(
certificateName
);
_
certificateCache
.
Remove
(
certificateName
);
}
}
}
}
}
}
...
@@ -164,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -164,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers
bool
isRootCertificate
=
bool
isRootCertificate
=
(
certificateName
==
RootCertificateName
);
(
certificateName
==
RootCertificateName
);
string
certCreatArgs
=
string
.
Format
(
C
ERT_CREATE_FORMAT
,
string
certCreatArgs
=
string
.
Format
(
C
ertCreateFormat
,
store
.
Name
,
certificateName
,
Issuer
,
store
.
Name
,
certificateName
,
Issuer
,
isRootCertificate
?
"signature"
:
"exchange"
,
isRootCertificate
?
"signature"
:
"exchange"
,
isRootCertificate
?
"authority"
:
"end"
,
DateTime
.
Now
,
isRootCertificate
?
"authority"
:
"end"
,
DateTime
.
Now
,
...
...
Titanium.Web.Proxy/Helpers/Compression.cs
View file @
e332c90d
using
System
;
using
System.Diagnostics.CodeAnalysis
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.IO
;
using
System.IO
;
using
System.Diagnostics.CodeAnalysis
;
using
Ionic.Zlib
;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
public
class
CompressionHelper
public
class
CompressionHelper
{
{
private
static
readonly
int
BUFFER_SIZE
=
8192
;
private
const
int
BufferSize
=
8192
;
[
S
ystem
.
Diagnostics
.
CodeAnalysis
.
S
uppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
[
SuppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
public
static
byte
[]
CompressZlib
(
byte
[]
bytes
)
public
static
byte
[]
CompressZlib
(
byte
[]
bytes
)
{
{
using
(
var
ms
=
new
MemoryStream
())
using
(
MemoryStream
ms
=
new
MemoryStream
())
{
{
using
(
Ionic
.
Zlib
.
ZlibStream
zip
=
new
Ionic
.
Zlib
.
ZlibStream
(
ms
,
Ionic
.
Zlib
.
CompressionMode
.
Compress
,
true
))
using
(
var
zip
=
new
ZlibStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
{
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
}
}
...
@@ -26,13 +22,12 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -26,13 +22,12 @@ namespace Titanium.Web.Proxy.Helpers
}
}
}
}
[
S
ystem
.
Diagnostics
.
CodeAnalysis
.
S
uppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
[
SuppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
public
static
byte
[]
CompressDeflate
(
byte
[]
bytes
)
public
static
byte
[]
CompressDeflate
(
byte
[]
bytes
)
{
{
using
(
var
ms
=
new
MemoryStream
())
using
(
MemoryStream
ms
=
new
MemoryStream
())
{
{
using
(
Ionic
.
Zlib
.
DeflateStream
zip
=
new
Ionic
.
Zlib
.
DeflateStream
(
ms
,
Ionic
.
Zlib
.
CompressionMode
.
Compress
,
true
))
using
(
var
zip
=
new
DeflateStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
{
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
}
}
...
@@ -41,32 +36,31 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -41,32 +36,31 @@ namespace Titanium.Web.Proxy.Helpers
}
}
}
}
[
S
ystem
.
Diagnostics
.
CodeAnalysis
.
S
uppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
[
SuppressMessage
(
"Microsoft.Usage"
,
"CA2202:Do not dispose objects multiple times"
)]
public
static
byte
[]
CompressGzip
(
byte
[]
bytes
)
public
static
byte
[]
CompressGzip
(
byte
[]
bytes
)
{
{
using
(
var
ms
=
new
MemoryStream
())
using
(
MemoryStream
ms
=
new
MemoryStream
())
{
{
using
(
Ionic
.
Zlib
.
GZipStream
zip
=
new
Ionic
.
Zlib
.
GZipStream
(
ms
,
Ionic
.
Zlib
.
CompressionMode
.
Compress
,
true
))
using
(
var
zip
=
new
GZipStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
{
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
zip
.
Write
(
bytes
,
0
,
bytes
.
Length
);
}
}
return
ms
.
ToArray
();
return
ms
.
ToArray
();
}
}
}
}
public
static
byte
[]
DecompressGzip
(
Stream
input
)
public
static
byte
[]
DecompressGzip
(
Stream
input
)
{
{
using
(
var
decompressor
=
new
System
.
IO
.
Compression
.
GZipStream
(
input
,
System
.
IO
.
Compression
.
CompressionMode
.
Decompress
))
using
(
var
decompressor
=
new
System
.
IO
.
Compression
.
GZipStream
(
input
,
System
.
IO
.
Compression
.
CompressionMode
.
Decompress
))
{
{
var
buffer
=
new
byte
[
BufferSize
];
int
read
=
0
;
using
(
var
output
=
new
MemoryStream
())
var
buffer
=
new
byte
[
BUFFER_SIZE
];
using
(
MemoryStream
output
=
new
MemoryStream
())
{
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
{
output
.
Write
(
buffer
,
0
,
read
);
output
.
Write
(
buffer
,
0
,
read
);
...
@@ -78,13 +72,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -78,13 +72,13 @@ namespace Titanium.Web.Proxy.Helpers
public
static
byte
[]
DecompressDeflate
(
Stream
input
)
public
static
byte
[]
DecompressDeflate
(
Stream
input
)
{
{
using
(
Ionic
.
Zlib
.
DeflateStream
decompressor
=
new
Ionic
.
Zlib
.
DeflateStream
(
input
,
Ionic
.
Zlib
.
CompressionMode
.
Decompress
))
using
(
var
decompressor
=
new
DeflateStream
(
input
,
CompressionMode
.
Decompress
))
{
{
int
read
=
0
;
var
buffer
=
new
byte
[
BufferSize
];
var
buffer
=
new
byte
[
BUFFER_SIZE
];
using
(
MemoryStream
output
=
new
MemoryStream
())
using
(
var
output
=
new
MemoryStream
())
{
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
{
output
.
Write
(
buffer
,
0
,
read
);
output
.
Write
(
buffer
,
0
,
read
);
...
@@ -93,15 +87,16 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -93,15 +87,16 @@ namespace Titanium.Web.Proxy.Helpers
}
}
}
}
}
}
public
static
byte
[]
DecompressZlib
(
Stream
input
)
public
static
byte
[]
DecompressZlib
(
Stream
input
)
{
{
using
(
Ionic
.
Zlib
.
ZlibStream
decompressor
=
new
Ionic
.
Zlib
.
ZlibStream
(
input
,
Ionic
.
Zlib
.
CompressionMode
.
Decompress
))
using
(
var
decompressor
=
new
ZlibStream
(
input
,
CompressionMode
.
Decompress
))
{
{
int
read
=
0
;
var
buffer
=
new
byte
[
BufferSize
];
var
buffer
=
new
byte
[
BUFFER_SIZE
];
using
(
MemoryStream
output
=
new
MemoryStream
())
using
(
var
output
=
new
MemoryStream
())
{
{
int
read
;
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
read
=
decompressor
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
{
output
.
Write
(
buffer
,
0
,
read
);
output
.
Write
(
buffer
,
0
,
read
);
...
...
Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.IO
;
using
System.IO
;
using
System.
Diagnostics
;
using
System.
Text
;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
internal
class
CustomBinaryReader
:
BinaryReader
internal
class
CustomBinaryReader
:
BinaryReader
{
{
internal
CustomBinaryReader
(
Stream
stream
,
Encoding
encoding
)
internal
CustomBinaryReader
(
Stream
stream
,
Encoding
encoding
)
:
base
(
stream
,
encoding
)
:
base
(
stream
,
encoding
)
{
{
}
}
internal
string
ReadLine
()
internal
string
ReadLine
()
{
{
char
[]
buf
=
new
char
[
1
];
var
buf
=
new
char
[
1
];
StringBuilde
r
readBuffer
=
new
StringBuilder
();
va
r
readBuffer
=
new
StringBuilder
();
try
try
{
{
var
charsRead
=
0
;
var
lastChar
=
new
char
();
char
lastChar
=
new
char
();
while
((
charsRead
=
base
.
Read
(
buf
,
0
,
1
))
>
0
)
while
((
Read
(
buf
,
0
,
1
))
>
0
)
{
{
if
(
lastChar
==
'\r'
&&
buf
[
0
]
==
'\n'
)
if
(
lastChar
==
'\r'
&&
buf
[
0
]
==
'\n'
)
{
{
return
readBuffer
.
Remove
(
readBuffer
.
Length
-
1
,
1
).
ToString
();
return
readBuffer
.
Remove
(
readBuffer
.
Length
-
1
,
1
).
ToString
();
}
}
else
if
(
buf
[
0
]
==
'\0'
)
if
(
buf
[
0
]
==
'\0'
)
{
{
return
readBuffer
.
ToString
();
return
readBuffer
.
ToString
();
}
}
else
readBuffer
.
Append
(
buf
[
0
]);
readBuffer
.
Append
(
buf
[
0
]);
lastChar
=
buf
[
0
];
lastChar
=
buf
[
0
];
...
@@ -47,19 +40,14 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -47,19 +40,14 @@ namespace Titanium.Web.Proxy.Helpers
{
{
return
readBuffer
.
ToString
();
return
readBuffer
.
ToString
();
}
}
catch
(
Exception
)
{
throw
;
}
}
}
internal
List
<
string
>
ReadAllLines
()
internal
List
<
string
>
ReadAllLines
()
{
{
string
tmpLine
=
null
;
string
tmpLine
;
List
<
string
>
requestLines
=
new
List
<
string
>();
var
requestLines
=
new
List
<
string
>();
while
(!
S
tring
.
IsNullOrEmpty
(
tmpLine
=
ReadLine
()))
while
(!
s
tring
.
IsNullOrEmpty
(
tmpLine
=
ReadLine
()))
{
{
requestLines
.
Add
(
tmpLine
);
requestLines
.
Add
(
tmpLine
);
}
}
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.IO
;
using
System.IO
;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
...
@@ -12,21 +9,23 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -12,21 +9,23 @@ namespace Titanium.Web.Proxy.Helpers
{
{
try
try
{
{
DirectoryInfo
[]
myProfileDirectory
=
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myProfileDirectory
=
string
myFFPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
if
(
File
.
Exists
(
myFFPrefFile
))
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
{
// We have a pref file so let''s make sure it has the proxy setting
// We have a pref file so let''s make sure it has the proxy setting
StreamReader
myReader
=
new
StreamReader
(
myFF
PrefFile
);
var
myReader
=
new
StreamReader
(
myFf
PrefFile
);
string
myPrefContents
=
myReader
.
ReadToEnd
();
var
myPrefContents
=
myReader
.
ReadToEnd
();
myReader
.
Close
();
myReader
.
Close
();
if
(
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
if
(
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
{
{
// Add the proxy enable line and write it back to the file
// Add the proxy enable line and write it back to the file
myPrefContents
=
myPrefContents
.
Replace
(
"user_pref(\"network.proxy.type\", 0);"
,
""
);
myPrefContents
=
myPrefContents
.
Replace
(
"user_pref(\"network.proxy.type\", 0);"
,
""
);
File
.
Delete
(
myF
F
PrefFile
);
File
.
Delete
(
myF
f
PrefFile
);
File
.
WriteAllText
(
myF
F
PrefFile
,
myPrefContents
);
File
.
WriteAllText
(
myF
f
PrefFile
,
myPrefContents
);
}
}
}
}
}
}
...
@@ -35,25 +34,28 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -35,25 +34,28 @@ namespace Titanium.Web.Proxy.Helpers
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
}
}
}
}
public
static
void
RemoveFirefox
()
public
static
void
RemoveFirefox
()
{
{
try
try
{
{
DirectoryInfo
[]
myProfileDirectory
=
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myProfileDirectory
=
string
myFFPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
new
DirectoryInfo
(
Environment
.
GetFolderPath
(
Environment
.
SpecialFolder
.
ApplicationData
)
+
if
(
File
.
Exists
(
myFFPrefFile
))
"\\Mozilla\\Firefox\\Profiles\\"
).
GetDirectories
(
"*.default"
);
var
myFfPrefFile
=
myProfileDirectory
[
0
].
FullName
+
"\\prefs.js"
;
if
(
File
.
Exists
(
myFfPrefFile
))
{
{
// We have a pref file so let''s make sure it has the proxy setting
// We have a pref file so let''s make sure it has the proxy setting
StreamReader
myReader
=
new
StreamReader
(
myFF
PrefFile
);
var
myReader
=
new
StreamReader
(
myFf
PrefFile
);
string
myPrefContents
=
myReader
.
ReadToEnd
();
var
myPrefContents
=
myReader
.
ReadToEnd
();
myReader
.
Close
();
myReader
.
Close
();
if
(!
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
if
(!
myPrefContents
.
Contains
(
"user_pref(\"network.proxy.type\", 0);"
))
{
{
// Add the proxy enable line and write it back to the file
// Add the proxy enable line and write it back to the file
myPrefContents
=
myPrefContents
+
"\n\r"
+
"user_pref(\"network.proxy.type\", 0);"
;
myPrefContents
=
myPrefContents
+
"\n\r"
+
"user_pref(\"network.proxy.type\", 0);"
;
File
.
Delete
(
myF
F
PrefFile
);
File
.
Delete
(
myF
f
PrefFile
);
File
.
WriteAllText
(
myF
F
PrefFile
,
myPrefContents
);
File
.
WriteAllText
(
myF
f
PrefFile
,
myPrefContents
);
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Helpers/NetFramework.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net.Configuration
;
using
System.Net.Configuration
;
using
System.Reflection
;
using
System.Reflection
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
...
@@ -11,25 +8,24 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -11,25 +8,24 @@ namespace Titanium.Web.Proxy.Helpers
{
{
//Fix bug in .Net 4.0 HttpWebRequest (don't use this for 4.5 and above)
//Fix bug in .Net 4.0 HttpWebRequest (don't use this for 4.5 and above)
//http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end
//http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end
public
static
void
U
RL
PeriodFix
()
public
static
void
U
rl
PeriodFix
()
{
{
MethodInfo
getSyntax
=
typeof
(
UriParser
).
GetMethod
(
"GetSyntax"
,
System
.
Reflection
.
BindingFlags
.
Static
|
System
.
Reflection
.
BindingFlags
.
NonPublic
);
var
getSyntax
=
typeof
(
UriParser
).
GetMethod
(
"GetSyntax"
,
BindingFlags
.
Static
|
BindingFlags
.
NonPublic
);
FieldInfo
flagsField
=
typeof
(
UriParser
).
GetField
(
"m_Flags"
,
System
.
Reflection
.
BindingFlags
.
Instance
|
System
.
Reflection
.
BindingFlags
.
NonPublic
);
var
flagsField
=
typeof
(
UriParser
).
GetField
(
"m_Flags"
,
BindingFlags
.
Instance
|
BindingFlags
.
NonPublic
);
if
(
getSyntax
!=
null
&&
flagsField
!=
null
)
if
(
getSyntax
!=
null
&&
flagsField
!=
null
)
{
{
foreach
(
string
scheme
in
new
[]
{
"http"
,
"https"
})
foreach
(
var
scheme
in
new
[]
{
"http"
,
"https"
})
{
{
UriParser
parser
=
(
UriParser
)
getSyntax
.
Invoke
(
null
,
new
object
[]
{
scheme
});
var
parser
=
(
UriParser
)
getSyntax
.
Invoke
(
null
,
new
object
[]
{
scheme
});
if
(
parser
!=
null
)
if
(
parser
!=
null
)
{
{
int
flagsValue
=
(
int
)
flagsField
.
GetValue
(
parser
);
var
flagsValue
=
(
int
)
flagsField
.
GetValue
(
parser
);
if
((
flagsValue
&
0x1000000
)
!=
0
)
if
((
flagsValue
&
0x1000000
)
!=
0
)
flagsField
.
SetValue
(
parser
,
flagsValue
&
~
0x1000000
);
flagsField
.
SetValue
(
parser
,
flagsValue
&
~
0x1000000
);
}
}
}
}
}
}
}
}
// Enable/disable useUnsafeHeaderParsing.
// Enable/disable useUnsafeHeaderParsing.
...
@@ -37,27 +33,28 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -37,27 +33,28 @@ namespace Titanium.Web.Proxy.Helpers
public
static
bool
ToggleAllowUnsafeHeaderParsing
(
bool
enable
)
public
static
bool
ToggleAllowUnsafeHeaderParsing
(
bool
enable
)
{
{
//Get the assembly that contains the internal class
//Get the assembly that contains the internal class
Assembly
assembly
=
Assembly
.
GetAssembly
(
typeof
(
SettingsSection
));
var
assembly
=
Assembly
.
GetAssembly
(
typeof
(
SettingsSection
));
if
(
assembly
!=
null
)
if
(
assembly
!=
null
)
{
{
//Use the assembly in order to get the internal type for the internal class
//Use the assembly in order to get the internal type for the internal class
Type
settingsSectionType
=
assembly
.
GetType
(
"System.Net.Configuration.SettingsSectionInternal"
);
var
settingsSectionType
=
assembly
.
GetType
(
"System.Net.Configuration.SettingsSectionInternal"
);
if
(
settingsSectionType
!=
null
)
if
(
settingsSectionType
!=
null
)
{
{
//Use the internal static property to get an instance of the internal settings class.
//Use the internal static property to get an instance of the internal settings class.
//If the static instance isn't created already invoking the property will create it for us.
//If the static instance isn't created already invoking the property will create it for us.
object
anInstance
=
settingsSectionType
.
InvokeMember
(
"Section"
,
var
anInstance
=
settingsSectionType
.
InvokeMember
(
"Section"
,
BindingFlags
.
Static
|
BindingFlags
.
GetProperty
|
BindingFlags
.
NonPublic
,
null
,
null
,
new
object
[]
{
});
BindingFlags
.
Static
|
BindingFlags
.
GetProperty
|
BindingFlags
.
NonPublic
,
null
,
null
,
new
object
[]
{});
if
(
anInstance
!=
null
)
if
(
anInstance
!=
null
)
{
{
//Locate the private bool field that tells the framework if unsafe header parsing is allowed
//Locate the private bool field that tells the framework if unsafe header parsing is allowed
FieldInfo
aUseUnsafeHeaderParsing
=
settingsSectionType
.
GetField
(
"useUnsafeHeaderParsing"
,
BindingFlags
.
NonPublic
|
BindingFlags
.
Instance
);
var
aUseUnsafeHeaderParsing
=
settingsSectionType
.
GetField
(
"useUnsafeHeaderParsing"
,
BindingFlags
.
NonPublic
|
BindingFlags
.
Instance
);
if
(
aUseUnsafeHeaderParsing
!=
null
)
if
(
aUseUnsafeHeaderParsing
!=
null
)
{
{
aUseUnsafeHeaderParsing
.
SetValue
(
anInstance
,
enable
);
aUseUnsafeHeaderParsing
.
SetValue
(
anInstance
,
enable
);
return
true
;
return
true
;
}
}
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
Microsoft.Win32
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
using
Microsoft.Win32
;
namespace
Titanium.Web.Proxy.Helpers
namespace
Titanium.Web.Proxy.Helpers
{
{
internal
static
class
NativeMethods
internal
static
class
NativeMethods
{
{
[
DllImport
(
"wininet.dll"
)]
[
DllImport
(
"wininet.dll"
)]
internal
static
extern
bool
InternetSetOption
(
IntPtr
hInternet
,
int
dwOption
,
IntPtr
lpBuffer
,
int
dwBufferLength
);
internal
static
extern
bool
InternetSetOption
(
IntPtr
hInternet
,
int
dwOption
,
IntPtr
lpBuffer
,
int
dwBufferLength
);
}
}
public
static
class
SystemProxyHelper
public
static
class
SystemProxyHelper
{
{
public
const
int
InternetOptionSettingsChanged
=
39
;
public
const
int
InternetOptionRefresh
=
37
;
private
static
object
_prevProxyServer
;
private
static
object
_prevProxyEnable
;
public
const
int
INTERNET_OPTION_SETTINGS_CHANGED
=
39
;
public
static
void
EnableProxyHttp
(
string
hostname
,
int
port
)
public
const
int
INTERNET_OPTION_REFRESH
=
37
;
static
bool
settingsReturn
,
refreshReturn
;
static
object
prevProxyServer
;
static
object
prevProxyEnable
;
public
static
void
EnableProxyHTTP
(
string
hostname
,
int
port
)
{
{
RegistryKey
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
prevProxyEnable
=
reg
.
GetValue
(
"ProxyEnable"
);
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
prevProxyServer
=
reg
.
GetValue
(
"ProxyServer"
);
if
(
reg
!=
null
)
{
_prevProxyEnable
=
reg
.
GetValue
(
"ProxyEnable"
);
_prevProxyServer
=
reg
.
GetValue
(
"ProxyServer"
);
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";"
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";"
);
refresh
();
}
}
public
static
void
EnableProxyHTTPS
(
string
hostname
,
int
port
)
Refresh
();
}
public
static
void
EnableProxyHttps
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
{
RegistryKey
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";https="
+
hostname
+
":"
+
port
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";https="
+
hostname
+
":"
+
port
);
refresh
();
}
}
Refresh
();
}
public
static
void
DisableAllProxy
()
public
static
void
DisableAllProxy
()
{
{
RegistryKey
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
reg
.
SetValue
(
"ProxyEnable"
,
prevProxyEnable
);
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
prevProxyServer
!=
null
)
if
(
reg
!=
null
)
reg
.
SetValue
(
"ProxyServer"
,
prevProxyServer
);
{
refresh
();
reg
.
SetValue
(
"ProxyEnable"
,
_prevProxyEnable
);
if
(
_prevProxyServer
!=
null
)
reg
.
SetValue
(
"ProxyServer"
,
_prevProxyServer
);
}
Refresh
();
}
}
private
static
void
refresh
()
private
static
void
Refresh
()
{
{
settingsReturn
=
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
INTERNET_OPTION_SETTINGS_CHANGED
,
IntPtr
.
Zero
,
0
);
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionSettingsChanged
,
IntPtr
.
Zero
,
0
);
refreshReturn
=
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
INTERNET_OPTION_REFRESH
,
IntPtr
.
Zero
,
0
);
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionRefresh
,
IntPtr
.
Zero
,
0
);
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Text
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.IO
;
using
System.Net
;
using
System.Threading.Tasks
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -15,9 +14,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -15,9 +14,9 @@ namespace Titanium.Web.Proxy.Helpers
public
class
TcpHelper
public
class
TcpHelper
{
{
private
static
readonly
int
BUFFER_SIZE
=
8192
;
private
static
readonly
int
BUFFER_SIZE
=
8192
;
private
static
readonly
String
[]
colonSpaceSplit
=
new
string
[]
{
": "
};
public
static
void
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
)
public
static
void
SendRaw
(
Stream
clientStream
,
string
httpCmd
,
List
<
HttpHeader
>
requestHeaders
,
string
hostName
,
int
tunnelPort
,
bool
isHttps
)
{
{
StringBuilder
sb
=
null
;
StringBuilder
sb
=
null
;
if
(
httpCmd
!=
null
||
requestHeaders
!=
null
)
if
(
httpCmd
!=
null
||
requestHeaders
!=
null
)
...
@@ -29,9 +28,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -29,9 +28,8 @@ namespace Titanium.Web.Proxy.Helpers
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
Environment
.
NewLine
);
}
}
if
(
requestHeaders
!=
null
)
if
(
requestHeaders
!=
null
)
for
(
int
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++
)
foreach
(
var
header
in
requestHeaders
.
Select
(
t
=>
t
.
ToString
())
)
{
{
var
header
=
requestHeaders
[
i
].
ToString
();
sb
.
Append
(
header
);
sb
.
Append
(
header
);
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
Environment
.
NewLine
);
}
}
...
@@ -39,13 +37,13 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -39,13 +37,13 @@ namespace Titanium.Web.Proxy.Helpers
}
}
System
.
Net
.
Sockets
.
TcpClient
tunnelClient
=
null
;
TcpClient
tunnelClient
=
null
;
Stream
tunnelStream
=
null
;
Stream
tunnelStream
=
null
;
try
try
{
{
tunnelClient
=
new
System
.
Net
.
Sockets
.
TcpClient
(
hostName
,
tunnelPort
);
tunnelClient
=
new
TcpClient
(
hostName
,
tunnelPort
);
tunnelStream
=
tunnelClient
.
GetStream
()
as
Stream
;
tunnelStream
=
tunnelClient
.
GetStream
();
if
(
isHttps
)
if
(
isHttps
)
{
{
...
@@ -60,12 +58,15 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -60,12 +58,15 @@ namespace Titanium.Web.Proxy.Helpers
{
{
if
(
sslStream
!=
null
)
if
(
sslStream
!=
null
)
sslStream
.
Dispose
();
sslStream
.
Dispose
();
throw
;
}
}
}
}
var
sendRelay
=
Task
.
Factory
.
StartNew
(()
=>
{
var
sendRelay
=
Task
.
Factory
.
StartNew
(()
=>
if
(
sb
!=
null
)
{
if
(
sb
!=
null
)
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
,
BUFFER_SIZE
);
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
,
BUFFER_SIZE
);
else
else
clientStream
.
CopyToAsync
(
tunnelStream
,
BUFFER_SIZE
);
clientStream
.
CopyToAsync
(
tunnelStream
,
BUFFER_SIZE
);
...
@@ -89,7 +90,5 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -89,7 +90,5 @@ namespace Titanium.Web.Proxy.Helpers
throw
;
throw
;
}
}
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Models/HttpHeader.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Models
namespace
Titanium.Web.Proxy.Models
{
{
public
class
HttpHeader
public
class
HttpHeader
{
{
public
string
Name
{
get
;
set
;
}
public
string
Value
{
get
;
set
;
}
public
HttpHeader
(
string
name
,
string
value
)
public
HttpHeader
(
string
name
,
string
value
)
{
{
if
(
string
.
IsNullOrEmpty
(
name
))
throw
new
Exception
(
"Name cannot be null"
);
if
(
string
.
IsNullOrEmpty
(
name
))
throw
new
Exception
(
"Name cannot be null"
);
this
.
Name
=
name
.
Trim
();
Name
=
name
.
Trim
();
this
.
Value
=
value
.
Trim
();
Value
=
value
.
Trim
();
}
}
public
string
Name
{
get
;
set
;
}
public
string
Value
{
get
;
set
;
}
public
override
string
ToString
()
public
override
string
ToString
()
{
{
return
String
.
Format
(
"{0}: {1}"
,
this
.
Name
,
this
.
Value
);
return
string
.
Format
(
"{0}: {1}"
,
Name
,
Value
);
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Properties/AssemblyInfo.cs
View file @
e332c90d
using
System.Reflection
;
using
System.Reflection
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
// associated with an assembly.
[assembly: AssemblyTitle("Titanium.Web.Proxy.Properties")]
[assembly: AssemblyTitle("Titanium.Web.Proxy.Properties")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyConfiguration("")]
...
@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
...
@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5036e0b7-a0d0-4070-8eb0-72c129dee9b3")]
[assembly: Guid("5036e0b7-a0d0-4070-8eb0-72c129dee9b3")]
// Version information for an assembly consists of the following four values:
// Version information for an assembly consists of the following four values:
...
@@ -29,5 +31,6 @@ using System.Runtime.InteropServices;
...
@@ -29,5 +31,6 @@ using System.Runtime.InteropServices;
// Build Number
// Build Number
// Revision
// Revision
//
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
Titanium.Web.Proxy/ProxyServer.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Text.RegularExpressions
;
using
System.Threading
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.
Security.Authentication
;
using
System.
Net.Sockets
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Diagnostics
;
using
System.Text
;
using
System.Text.RegularExpressions
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Text
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
{
{
...
@@ -23,33 +18,22 @@ namespace Titanium.Web.Proxy
...
@@ -23,33 +18,22 @@ namespace Titanium.Web.Proxy
public
partial
class
ProxyServer
public
partial
class
ProxyServer
{
{
private
static
readonly
int
BUFFER_SIZE
=
8192
;
private
static
readonly
int
BUFFER_SIZE
=
8192
;
private
static
readonly
char
[]
semiSplit
=
new
char
[]
{
';'
};
private
static
readonly
char
[]
SemiSplit
=
{
';'
};
private
static
readonly
String
[]
colonSpaceSplit
=
new
string
[]
{
": "
};
private
static
readonly
string
[]
ColonSpaceSplit
=
{
": "
};
private
static
readonly
char
[]
spaceSplit
=
new
char
[]
{
' '
};
private
static
readonly
char
[]
SpaceSplit
=
{
' '
};
private
static
readonly
Regex
c
ookieSplitRegEx
=
new
Regex
(
@",(?! )"
);
private
static
readonly
Regex
C
ookieSplitRegEx
=
new
Regex
(
@",(?! )"
);
private
static
readonly
byte
[]
chunkTrail
=
Encoding
.
ASCII
.
GetBytes
(
Environment
.
NewLine
);
private
static
readonly
byte
[]
ChunkTrail
=
Encoding
.
ASCII
.
GetBytes
(
Environment
.
NewLine
);
private
static
readonly
byte
[]
ChunkEnd
=
Encoding
.
ASCII
.
GetBytes
(
0.
ToString
(
"x2"
)
+
Environment
.
NewLine
+
Environment
.
NewLine
);
private
static
object
certificateAccessLock
=
new
object
();
private
static
readonly
byte
[]
ChunkEnd
=
Encoding
.
ASCII
.
GetBytes
(
0.
ToString
(
"x2"
)
+
Environment
.
NewLine
+
Environment
.
NewLine
);
private
static
TcpListener
listener
;
private
static
TcpListener
_listener
;
private
static
CertificateManager
CertManager
{
get
;
set
;
}
public
static
List
<
string
>
ExcludedHttpsHostNameRegex
=
new
List
<
string
>();
public
static
List
<
string
>
ExcludedHttpsHostNameRegex
=
new
List
<
string
>();
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeRequest
;
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
static
string
RootCertificateName
{
get
;
set
;
}
public
static
bool
EnableSSL
{
get
;
set
;
}
public
static
bool
SetAsSystemProxy
{
get
;
set
;
}
public
static
Int32
ListeningPort
{
get
;
set
;
}
public
static
IPAddress
ListeningIpAddress
{
get
;
set
;
}
static
ProxyServer
()
static
ProxyServer
()
{
{
CertManager
=
new
CertificateManager
(
"Titanium"
,
CertManager
=
new
CertificateManager
(
"Titanium"
,
...
@@ -61,74 +45,89 @@ namespace Titanium.Web.Proxy
...
@@ -61,74 +45,89 @@ namespace Titanium.Web.Proxy
Initialize
();
Initialize
();
}
}
private
static
CertificateManager
CertManager
{
get
;
set
;
}
public
static
string
RootCertificateName
{
get
;
set
;
}
public
static
bool
EnableSsl
{
get
;
set
;
}
public
static
bool
SetAsSystemProxy
{
get
;
set
;
}
public
static
int
ListeningPort
{
get
;
set
;
}
public
static
IPAddress
ListeningIpAddress
{
get
;
set
;
}
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeRequest
;
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
static
void
Initialize
()
public
static
void
Initialize
()
{
{
ServicePointManager
.
Expect100Continue
=
false
;
System
.
Net
.
ServicePointManager
.
Expect100Continue
=
false
;
WebRequest
.
DefaultWebProxy
=
null
;
System
.
Net
.
WebRequest
.
DefaultWebProxy
=
null
;
ServicePointManager
.
DefaultConnectionLimit
=
10
;
System
.
Net
.
ServicePointManager
.
DefaultConnectionLimit
=
10
;
ServicePointManager
.
DnsRefreshTimeout
=
3
*
60
*
1000
;
//3 minutes
ServicePointManager
.
DnsRefreshTimeout
=
3
*
60
*
1000
;
//3 minutes
ServicePointManager
.
MaxServicePointIdleTime
=
3
*
60
*
1000
;
ServicePointManager
.
MaxServicePointIdleTime
=
3
*
60
*
1000
;
//HttpWebRequest certificate validation callback
//HttpWebRequest certificate validation callback
ServicePointManager
.
ServerCertificateValidationCallback
=
delegate
(
object
s
,
X509Certificate
certificate
,
X509Chain
chain
,
SslPolicyErrors
sslPolicyErrors
)
ServicePointManager
.
ServerCertificateValidationCallback
=
delegate
(
object
s
,
X509Certificate
certificate
,
X509Chain
chain
,
SslPolicyErrors
sslPolicyErrors
)
{
{
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
return
true
;
if
(
sslPolicyErrors
==
SslPolicyErrors
.
None
)
return
true
;
else
return
false
;
return
false
;
};
};
//Fix a bug in .NET 4.0
//Fix a bug in .NET 4.0
NetFrameworkHelper
.
U
RL
PeriodFix
();
NetFrameworkHelper
.
U
rl
PeriodFix
();
//useUnsafeHeaderParsing
//useUnsafeHeaderParsing
NetFrameworkHelper
.
ToggleAllowUnsafeHeaderParsing
(
true
);
NetFrameworkHelper
.
ToggleAllowUnsafeHeaderParsing
(
true
);
}
}
public
static
bool
Start
()
public
static
bool
Start
()
{
{
listener
=
new
TcpListener
(
ListeningIpAddress
,
ListeningPort
);
_
listener
=
new
TcpListener
(
ListeningIpAddress
,
ListeningPort
);
listener
.
Start
();
_
listener
.
Start
();
ListeningPort
=
((
IPEndPoint
)
listener
.
LocalEndpoint
).
Port
;
ListeningPort
=
((
IPEndPoint
)
_
listener
.
LocalEndpoint
).
Port
;
// accept clients asynchronously
// accept clients asynchronously
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
listener
);
_listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
_
listener
);
if
(
SetAsSystemProxy
)
if
(
SetAsSystemProxy
)
{
{
SystemProxyHelper
.
EnableProxyHTTP
(
ListeningIpAddress
==
IPAddress
.
Any
?
"127.0.0.1"
:
ListeningIpAddress
.
ToString
(),
ListeningPort
);
SystemProxyHelper
.
EnableProxyHttp
(
Equals
(
ListeningIpAddress
,
IPAddress
.
Any
)
?
"127.0.0.1"
:
ListeningIpAddress
.
ToString
(),
ListeningPort
);
FireFoxHelper
.
AddFirefox
();
FireFoxHelper
.
AddFirefox
();
if
(
EnableS
SL
)
if
(
EnableS
sl
)
{
{
RootCertificateName
=
RootCertificateName
==
null
?
"Titanium_Proxy_Test_Root"
:
RootCertificateName
;
RootCertificateName
=
RootCertificateName
??
"Titanium_Proxy_Test_Root"
;
bool
certTrusted
=
CertManager
.
CreateTrustedRootCertificate
();
var
certTrusted
=
CertManager
.
CreateTrustedRootCertificate
();
//If certificate was trusted by the machine
//If certificate was trusted by the machine
if
(
certTrusted
)
if
(
certTrusted
)
{
{
SystemProxyHelper
.
EnableProxyHTTPS
(
ListeningIpAddress
==
IPAddress
.
Any
?
"127.0.0.1"
:
ListeningIpAddress
.
ToString
(),
ListeningPort
);
SystemProxyHelper
.
EnableProxyHttps
(
Equals
(
ListeningIpAddress
,
IPAddress
.
Any
)
?
"127.0.0.1"
:
ListeningIpAddress
.
ToString
(),
ListeningPort
);
}
}
}
}
}
}
return
true
;
return
true
;
}
}
private
static
void
OnAcceptConnection
(
IAsyncResult
asyn
)
private
static
void
OnAcceptConnection
(
IAsyncResult
asyn
)
{
{
try
try
{
{
// Get the listener that handles the client request.
// Get the listener that handles the client request.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
listener
);
_listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
_
listener
);
TcpClient
client
=
listener
.
EndAcceptTcpClient
(
asyn
);
var
client
=
_
listener
.
EndAcceptTcpClient
(
asyn
);
Task
.
Factory
.
StartNew
(()
=>
HandleClient
(
client
));
Task
.
Factory
.
StartNew
(()
=>
HandleClient
(
client
));
}
}
catch
{
}
catch
{
// ignored
}
}
}
...
@@ -140,9 +139,8 @@ namespace Titanium.Web.Proxy
...
@@ -140,9 +139,8 @@ namespace Titanium.Web.Proxy
FireFoxHelper
.
RemoveFirefox
();
FireFoxHelper
.
RemoveFirefox
();
}
}
listener
.
Stop
();
_
listener
.
Stop
();
CertManager
.
Dispose
();
CertManager
.
Dispose
();
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/RequestHandler.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Globalization
;
using
System.Text
;
using
System.Threading
;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Security.Authentication
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Diagnostics
;
using
System.Security.Authentication
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Text
;
using
System.Reflection
;
using
System.Text.RegularExpressions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.EventArguments
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
System.Text.RegularExpression
s
;
using
Titanium.Web.Proxy.Helper
s
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
...
@@ -25,22 +22,22 @@ namespace Titanium.Web.Proxy
...
@@ -25,22 +22,22 @@ namespace Titanium.Web.Proxy
private
static
void
HandleClient
(
TcpClient
client
)
private
static
void
HandleClient
(
TcpClient
client
)
{
{
Stream
clientStream
=
client
.
GetStream
();
Stream
clientStream
=
client
.
GetStream
();
CustomBinaryReade
r
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
Encoding
.
ASCII
);
va
r
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
Encoding
.
ASCII
);
StreamWrite
r
clientStreamWriter
=
new
StreamWriter
(
clientStream
);
va
r
clientStreamWriter
=
new
StreamWriter
(
clientStream
);
Uri
httpRemoteUri
;
Uri
httpRemoteUri
;
try
try
{
{
//read the first line HTTP command
//read the first line HTTP command
String
httpCmd
=
clientStreamReader
.
ReadLine
();
var
httpCmd
=
clientStreamReader
.
ReadLine
();
if
(
S
tring
.
IsNullOrEmpty
(
httpCmd
))
if
(
s
tring
.
IsNullOrEmpty
(
httpCmd
))
{
{
throw
new
EndOfStreamException
();
throw
new
EndOfStreamException
();
}
}
//break up the line into three components (method, remote URL & Http Version)
//break up the line into three components (method, remote URL & Http Version)
String
[]
httpCmdSplit
=
httpCmd
.
Split
(
s
paceSplit
,
3
);
var
httpCmdSplit
=
httpCmd
.
Split
(
S
paceSplit
,
3
);
var
httpVerb
=
httpCmdSplit
[
0
];
var
httpVerb
=
httpCmdSplit
[
0
];
...
@@ -56,13 +53,12 @@ namespace Titanium.Web.Proxy
...
@@ -56,13 +53,12 @@ namespace Titanium.Web.Proxy
//Client wants to create a secure tcp tunnel (its a HTTPS request)
//Client wants to create a secure tcp tunnel (its a HTTPS request)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
==
443
)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
==
443
)
{
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
clientStreamReader
.
ReadAllLines
();
clientStreamReader
.
ReadAllLines
();
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
var
certificate
=
ProxyServer
.
CertManager
.
CreateCertificate
(
httpRemoteUri
.
Host
);
var
certificate
=
CertManager
.
CreateCertificate
(
httpRemoteUri
.
Host
);
SslStream
sslStream
=
null
;
SslStream
sslStream
=
null
;
...
@@ -70,7 +66,8 @@ namespace Titanium.Web.Proxy
...
@@ -70,7 +66,8 @@ namespace Titanium.Web.Proxy
{
{
sslStream
=
new
SslStream
(
clientStream
,
true
);
sslStream
=
new
SslStream
(
clientStream
,
true
);
//Successfully managed to authenticate the client using the fake certificate
//Successfully managed to authenticate the client using the fake certificate
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
|
SslProtocols
.
Ssl3
|
SslProtocols
.
Ssl2
,
false
);
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
|
SslProtocols
.
Ssl3
|
SslProtocols
.
Ssl2
,
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
@@ -87,52 +84,52 @@ namespace Titanium.Web.Proxy
...
@@ -87,52 +84,52 @@ namespace Titanium.Web.Proxy
}
}
httpCmd
=
clientStreamReader
.
ReadLine
();
httpCmd
=
clientStreamReader
.
ReadLine
();
}
}
else
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
else
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
)
{
{
clientStreamReader
.
ReadAllLines
();
clientStreamReader
.
ReadAllLines
();
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
}
}
//Now create the request
//Now create the request
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
httpRemoteUri
.
OriginalString
:
null
));
Task
.
Factory
.
StartNew
(
()
=>
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
httpRemoteUri
.
OriginalString
:
null
));
}
}
catch
catch
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
}
}
}
}
private
static
void
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
secureTunnelHostName
)
private
static
void
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
secureTunnelHostName
)
{
{
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
if
(
String
.
IsNullOrEmpty
(
httpCmd
))
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
return
;
}
}
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
);
var
args
=
new
SessionEventArgs
(
BUFFER_SIZE
);
args
.
c
lient
=
client
;
args
.
C
lient
=
client
;
try
try
{
{
//break up the line into three components (method, remote URL & Http Version)
//break up the line into three components (method, remote URL & Http Version)
String
[]
httpCmdSplit
=
httpCmd
.
Split
(
s
paceSplit
,
3
);
var
httpCmdSplit
=
httpCmd
.
Split
(
S
paceSplit
,
3
);
var
httpMethod
=
httpCmdSplit
[
0
];
var
httpMethod
=
httpCmdSplit
[
0
];
var
httpRemoteUri
=
new
Uri
(
secureTunnelHostName
==
null
?
httpCmdSplit
[
1
]
:
(
secureTunnelHostName
+
httpCmdSplit
[
1
]));
var
httpRemoteUri
=
new
Uri
(
secureTunnelHostName
==
null
?
httpCmdSplit
[
1
]
:
(
secureTunnelHostName
+
httpCmdSplit
[
1
]));
var
httpVersion
=
httpCmdSplit
[
2
];
var
httpVersion
=
httpCmdSplit
[
2
];
Version
version
;
Version
version
;
...
@@ -147,29 +144,29 @@ namespace Titanium.Web.Proxy
...
@@ -147,29 +144,29 @@ namespace Titanium.Web.Proxy
if
(
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
)
if
(
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
)
{
{
args
.
i
sHttps
=
true
;
args
.
I
sHttps
=
true
;
}
}
args
.
r
equestHeaders
=
new
List
<
HttpHeader
>();
args
.
R
equestHeaders
=
new
List
<
HttpHeader
>();
string
tmpLine
=
null
;
string
tmpLine
;
while
(!
S
tring
.
IsNullOrEmpty
(
tmpLine
=
clientStreamReader
.
ReadLine
()))
while
(!
s
tring
.
IsNullOrEmpty
(
tmpLine
=
clientStreamReader
.
ReadLine
()))
{
{
String
[]
header
=
tmpLine
.
Split
(
c
olonSpaceSplit
,
2
,
StringSplitOptions
.
None
);
var
header
=
tmpLine
.
Split
(
C
olonSpaceSplit
,
2
,
StringSplitOptions
.
None
);
args
.
r
equestHeaders
.
Add
(
new
HttpHeader
(
header
[
0
],
header
[
1
]));
args
.
R
equestHeaders
.
Add
(
new
HttpHeader
(
header
[
0
],
header
[
1
]));
}
}
for
(
int
i
=
0
;
i
<
args
.
r
equestHeaders
.
Count
;
i
++)
for
(
var
i
=
0
;
i
<
args
.
R
equestHeaders
.
Count
;
i
++)
{
{
var
rawHeader
=
args
.
r
equestHeaders
[
i
];
var
rawHeader
=
args
.
R
equestHeaders
[
i
];
//if request was upgrade to web-socket protocol then relay the request without proxying
//if request was upgrade to web-socket protocol then relay the request without proxying
if
((
rawHeader
.
Name
.
ToLower
()
==
"upgrade"
)
&&
(
rawHeader
.
Value
.
ToLower
()
==
"websocket"
))
if
((
rawHeader
.
Name
.
ToLower
()
==
"upgrade"
)
&&
(
rawHeader
.
Value
.
ToLower
()
==
"websocket"
))
{
{
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
httpCmd
,
args
.
RequestHeaders
,
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
httpCmd
,
args
.
requestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
);
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
return
;
}
}
...
@@ -177,52 +174,51 @@ namespace Titanium.Web.Proxy
...
@@ -177,52 +174,51 @@ 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.
args
.
proxyRequest
=
(
HttpWebRequest
)
Http
WebRequest
.
Create
(
httpRemoteUri
);
args
.
ProxyRequest
=
(
HttpWebRequest
)
WebRequest
.
Create
(
httpRemoteUri
);
args
.
p
roxyRequest
.
Proxy
=
null
;
args
.
P
roxyRequest
.
Proxy
=
null
;
args
.
p
roxyRequest
.
UseDefaultCredentials
=
true
;
args
.
P
roxyRequest
.
UseDefaultCredentials
=
true
;
args
.
p
roxyRequest
.
Method
=
httpMethod
;
args
.
P
roxyRequest
.
Method
=
httpMethod
;
args
.
p
roxyRequest
.
ProtocolVersion
=
version
;
args
.
P
roxyRequest
.
ProtocolVersion
=
version
;
args
.
c
lientStream
=
clientStream
;
args
.
C
lientStream
=
clientStream
;
args
.
c
lientStreamReader
=
clientStreamReader
;
args
.
C
lientStreamReader
=
clientStreamReader
;
args
.
c
lientStreamWriter
=
clientStreamWriter
;
args
.
C
lientStreamWriter
=
clientStreamWriter
;
args
.
p
roxyRequest
.
AllowAutoRedirect
=
false
;
args
.
P
roxyRequest
.
AllowAutoRedirect
=
false
;
args
.
p
roxyRequest
.
AutomaticDecompression
=
DecompressionMethods
.
None
;
args
.
P
roxyRequest
.
AutomaticDecompression
=
DecompressionMethods
.
None
;
args
.
requestHostname
=
args
.
p
roxyRequest
.
RequestUri
.
Host
;
args
.
RequestHostname
=
args
.
P
roxyRequest
.
RequestUri
.
Host
;
args
.
requestURL
=
args
.
p
roxyRequest
.
RequestUri
.
OriginalString
;
args
.
RequestUrl
=
args
.
P
roxyRequest
.
RequestUri
.
OriginalString
;
args
.
clientPort
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Port
;
args
.
ClientPort
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Port
;
args
.
clientIpAddress
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Address
;
args
.
ClientIpAddress
=
((
IPEndPoint
)
client
.
Client
.
RemoteEndPoint
).
Address
;
args
.
r
equestHttpVersion
=
version
;
args
.
R
equestHttpVersion
=
version
;
args
.
requestIsAlive
=
args
.
p
roxyRequest
.
KeepAlive
;
args
.
RequestIsAlive
=
args
.
P
roxyRequest
.
KeepAlive
;
args
.
proxyRequest
.
ConnectionGroupName
=
args
.
r
equestHostname
;
args
.
ProxyRequest
.
ConnectionGroupName
=
args
.
R
equestHostname
;
args
.
p
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
args
.
P
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
//If requested interception
//If requested interception
if
(
BeforeRequest
!=
null
)
if
(
BeforeRequest
!=
null
)
{
{
args
.
requestEncoding
=
args
.
p
roxyRequest
.
GetEncoding
();
args
.
RequestEncoding
=
args
.
P
roxyRequest
.
GetEncoding
();
BeforeRequest
(
null
,
args
);
BeforeRequest
(
null
,
args
);
}
}
args
.
RequestLocked
=
true
;
args
.
RequestLocked
=
true
;
if
(
args
.
c
ancelRequest
)
if
(
args
.
C
ancelRequest
)
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
return
;
}
}
SetRequestHeaders
(
args
.
requestHeaders
,
args
.
p
roxyRequest
);
SetRequestHeaders
(
args
.
RequestHeaders
,
args
.
P
roxyRequest
);
//If request was modified by user
//If request was modified by user
if
(
args
.
r
equestBodyRead
)
if
(
args
.
R
equestBodyRead
)
{
{
args
.
proxyRequest
.
ContentLength
=
args
.
requestBody
.
Length
;
args
.
ProxyRequest
.
ContentLength
=
args
.
RequestBody
.
Length
;
Stream
newStream
=
args
.
proxyRequest
.
GetRequestStream
();
var
newStream
=
args
.
ProxyRequest
.
GetRequestStream
();
newStream
.
Write
(
args
.
requestBody
,
0
,
args
.
requestBody
.
Length
);
newStream
.
Write
(
args
.
RequestBody
,
0
,
args
.
RequestBody
.
Length
);
args
.
proxyRequest
.
BeginGetResponse
(
new
AsyncCallback
(
HandleHttpSessionResponse
),
args
);
args
.
ProxyRequest
.
BeginGetResponse
(
HandleHttpSessionResponse
,
args
);
}
}
else
else
{
{
...
@@ -232,38 +228,36 @@ namespace Titanium.Web.Proxy
...
@@ -232,38 +228,36 @@ namespace Titanium.Web.Proxy
SendClientRequestBody
(
args
);
SendClientRequestBody
(
args
);
}
}
//Http request body sent, now wait asynchronously for response
//Http request body sent, now wait asynchronously for response
args
.
proxyRequest
.
BeginGetResponse
(
new
AsyncCallback
(
HandleHttpSessionResponse
),
args
);
args
.
ProxyRequest
.
BeginGetResponse
(
HandleHttpSessionResponse
,
args
);
}
}
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
//If client is pipeling the request, this will be immediately hit before response for previous request was made
//If client is pipeling the request, this will be immediately hit before response for previous request was made
httpCmd
=
clientStreamReader
.
ReadLine
();
httpCmd
=
clientStreamReader
.
ReadLine
();
//Http request body sent, now wait for next request
//Http request body sent, now wait for next request
Task
.
Factory
.
StartNew
(()
=>
HandleHttpSessionRequest
(
args
.
client
,
httpCmd
,
args
.
clientStream
,
args
.
clientStreamReader
,
args
.
clientStreamWriter
,
secureTunnelHostName
));
Task
.
Factory
.
StartNew
(
()
=>
HandleHttpSessionRequest
(
args
.
Client
,
httpCmd
,
args
.
ClientStream
,
args
.
ClientStreamReader
,
args
.
ClientStreamWriter
,
secureTunnelHostName
));
}
}
catch
catch
{
{
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
}
}
}
}
private
static
void
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
string
httpVersion
)
private
static
void
WriteConnectResponse
(
StreamWriter
clientStreamWriter
,
string
httpVersion
)
{
{
clientStreamWriter
.
WriteLine
(
httpVersion
+
" 200 Connection established"
);
clientStreamWriter
.
WriteLine
(
httpVersion
+
" 200 Connection established"
);
clientStreamWriter
.
WriteLine
(
String
.
Format
(
"Timestamp: {0}"
,
DateTime
.
Now
.
ToString
())
);
clientStreamWriter
.
WriteLine
(
"Timestamp: {0}"
,
DateTime
.
Now
);
clientStreamWriter
.
WriteLine
(
String
.
Format
(
"connection:close"
)
);
clientStreamWriter
.
WriteLine
(
"connection:close"
);
clientStreamWriter
.
WriteLine
();
clientStreamWriter
.
WriteLine
();
clientStreamWriter
.
Flush
();
clientStreamWriter
.
Flush
();
}
}
private
static
void
SetRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebRequest
webRequest
)
private
static
void
SetRequestHeaders
(
List
<
HttpHeader
>
requestHeaders
,
HttpWebRequest
webRequest
)
{
{
for
(
var
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++)
for
(
int
i
=
0
;
i
<
requestHeaders
.
Count
;
i
++)
{
{
switch
(
requestHeaders
[
i
].
Name
.
ToLower
())
switch
(
requestHeaders
[
i
].
Name
.
ToLower
())
{
{
...
@@ -300,7 +294,7 @@ namespace Titanium.Web.Proxy
...
@@ -300,7 +294,7 @@ namespace Titanium.Web.Proxy
webRequest
.
Host
=
requestHeaders
[
i
].
Value
;
webRequest
.
Host
=
requestHeaders
[
i
].
Value
;
break
;
break
;
case
"if-modified-since"
:
case
"if-modified-since"
:
String
[]
sb
=
requestHeaders
[
i
].
Value
.
Trim
().
Split
(
s
emiSplit
);
var
sb
=
requestHeaders
[
i
].
Value
.
Trim
().
Split
(
S
emiSplit
);
DateTime
d
;
DateTime
d
;
if
(
DateTime
.
TryParse
(
sb
[
0
],
out
d
))
if
(
DateTime
.
TryParse
(
sb
[
0
],
out
d
))
webRequest
.
IfModifiedSince
=
d
;
webRequest
.
IfModifiedSince
=
d
;
...
@@ -311,7 +305,12 @@ namespace Titanium.Web.Proxy
...
@@ -311,7 +305,12 @@ namespace Titanium.Web.Proxy
break
;
break
;
case
"range"
:
case
"range"
:
var
startEnd
=
requestHeaders
[
i
].
Value
.
Replace
(
Environment
.
NewLine
,
""
).
Remove
(
0
,
6
).
Split
(
'-'
);
var
startEnd
=
requestHeaders
[
i
].
Value
.
Replace
(
Environment
.
NewLine
,
""
).
Remove
(
0
,
6
).
Split
(
'-'
);
if
(
startEnd
.
Length
>
1
)
{
if
(!
String
.
IsNullOrEmpty
(
startEnd
[
1
]))
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]),
int
.
Parse
(
startEnd
[
1
]));
else
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]));
}
if
(
startEnd
.
Length
>
1
)
{
if
(!
string
.
IsNullOrEmpty
(
startEnd
[
1
]))
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]),
int
.
Parse
(
startEnd
[
1
]));
else
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]));
}
else
else
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]));
webRequest
.
AddRange
(
int
.
Parse
(
startEnd
[
0
]));
break
;
break
;
...
@@ -340,109 +339,92 @@ namespace Titanium.Web.Proxy
...
@@ -340,109 +339,92 @@ namespace Titanium.Web.Proxy
break
;
break
;
}
}
}
}
}
}
//This is called when the request is PUT/POST to read the body
//This is called when the request is PUT/POST to read the body
private
static
void
SendClientRequestBody
(
SessionEventArgs
args
)
private
static
void
SendClientRequestBody
(
SessionEventArgs
args
)
{
{
// End the operation
// End the operation
Stream
postStream
=
args
.
p
roxyRequest
.
GetRequestStream
();
var
postStream
=
args
.
P
roxyRequest
.
GetRequestStream
();
if
(
args
.
p
roxyRequest
.
ContentLength
>
0
)
if
(
args
.
P
roxyRequest
.
ContentLength
>
0
)
{
{
args
.
p
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
args
.
P
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
try
try
{
{
var
totalbytesRead
=
0
;
int
totalbytesRead
=
0
;
int
bytesToRead
;
int
bytesToRead
;
if
(
args
.
p
roxyRequest
.
ContentLength
<
BUFFER_SIZE
)
if
(
args
.
P
roxyRequest
.
ContentLength
<
BUFFER_SIZE
)
{
{
bytesToRead
=
(
int
)
args
.
p
roxyRequest
.
ContentLength
;
bytesToRead
=
(
int
)
args
.
P
roxyRequest
.
ContentLength
;
}
}
else
else
bytesToRead
=
BUFFER_SIZE
;
bytesToRead
=
BUFFER_SIZE
;
while
(
totalbytesRead
<
(
int
)
args
.
p
roxyRequest
.
ContentLength
)
while
(
totalbytesRead
<
(
int
)
args
.
P
roxyRequest
.
ContentLength
)
{
{
var
buffer
=
args
.
c
lientStreamReader
.
ReadBytes
(
bytesToRead
);
var
buffer
=
args
.
C
lientStreamReader
.
ReadBytes
(
bytesToRead
);
totalbytesRead
+=
buffer
.
Length
;
totalbytesRead
+=
buffer
.
Length
;
int
RemainingBytes
=
(
int
)
args
.
p
roxyRequest
.
ContentLength
-
totalbytesRead
;
var
remainingBytes
=
(
int
)
args
.
P
roxyRequest
.
ContentLength
-
totalbytesRead
;
if
(
R
emainingBytes
<
bytesToRead
)
if
(
r
emainingBytes
<
bytesToRead
)
{
{
bytesToRead
=
R
emainingBytes
;
bytesToRead
=
r
emainingBytes
;
}
}
postStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
postStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
}
}
postStream
.
Close
();
postStream
.
Close
();
}
}
catch
catch
{
if
(
postStream
!=
null
)
{
{
postStream
.
Close
();
postStream
.
Close
();
postStream
.
Dispose
();
postStream
.
Dispose
();
}
throw
;
throw
;
}
}
}
}
//Need to revist, find any potential bugs
//Need to revist, find any potential bugs
else
if
(
args
.
p
roxyRequest
.
SendChunked
)
else
if
(
args
.
P
roxyRequest
.
SendChunked
)
{
{
args
.
p
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
args
.
P
roxyRequest
.
AllowWriteStreamBuffering
=
true
;
try
try
{
{
while
(
true
)
while
(
true
)
{
{
var
chuchkHead
=
args
.
c
lientStreamReader
.
ReadLine
();
var
chuchkHead
=
args
.
C
lientStreamReader
.
ReadLine
();
var
chunkSize
=
int
.
Parse
(
chuchkHead
,
System
.
Globalization
.
NumberStyles
.
HexNumber
);
var
chunkSize
=
int
.
Parse
(
chuchkHead
,
NumberStyles
.
HexNumber
);
if
(
chunkSize
!=
0
)
if
(
chunkSize
!=
0
)
{
{
var
buffer
=
args
.
c
lientStreamReader
.
ReadBytes
(
chunkSize
);
var
buffer
=
args
.
C
lientStreamReader
.
ReadBytes
(
chunkSize
);
postStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
postStream
.
Write
(
buffer
,
0
,
buffer
.
Length
);
//chunk trail
var
chunkTrail
=
args
.
c
lientStreamReader
.
ReadLine
();
args
.
C
lientStreamReader
.
ReadLine
();
}
}
else
else
{
{
args
.
c
lientStreamReader
.
ReadLine
();
args
.
C
lientStreamReader
.
ReadLine
();
break
;
break
;
}
}
}
}
postStream
.
Close
();
postStream
.
Close
();
}
}
catch
catch
{
if
(
postStream
!=
null
)
{
{
postStream
.
Close
();
postStream
.
Close
();
postStream
.
Dispose
();
postStream
.
Dispose
();
}
throw
;
throw
;
}
}
}
}
}
}
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e332c90d
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Net.Sockets
;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Threading
;
using
System.Text
;
using
System.Security.Authentication
;
using
System.Diagnostics
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy
namespace
Titanium.Web.Proxy
...
@@ -22,94 +17,89 @@ namespace Titanium.Web.Proxy
...
@@ -22,94 +17,89 @@ namespace Titanium.Web.Proxy
//Called asynchronously when a request was successfully and we received the response
//Called asynchronously when a request was successfully and we received the response
private
static
void
HandleHttpSessionResponse
(
IAsyncResult
asynchronousResult
)
private
static
void
HandleHttpSessionResponse
(
IAsyncResult
asynchronousResult
)
{
{
SessionEventArgs
args
=
(
SessionEventArgs
)
asynchronousResult
.
AsyncState
;
var
args
=
(
SessionEventArgs
)
asynchronousResult
.
AsyncState
;
try
try
{
{
args
.
serverResponse
=
(
HttpWebResponse
)
args
.
p
roxyRequest
.
EndGetResponse
(
asynchronousResult
);
args
.
ServerResponse
=
(
HttpWebResponse
)
args
.
P
roxyRequest
.
EndGetResponse
(
asynchronousResult
);
}
}
catch
(
WebException
webEx
)
catch
(
WebException
webEx
)
{
{
//Things line 404, 500 etc
//Things line 404, 500 etc
args
.
s
erverResponse
=
webEx
.
Response
as
HttpWebResponse
;
args
.
S
erverResponse
=
webEx
.
Response
as
HttpWebResponse
;
}
}
try
try
{
{
if
(
args
.
s
erverResponse
!=
null
)
if
(
args
.
S
erverResponse
!=
null
)
{
{
args
.
responseHeaders
=
ReadResponseHeaders
(
args
.
s
erverResponse
);
args
.
ResponseHeaders
=
ReadResponseHeaders
(
args
.
S
erverResponse
);
args
.
responseStream
=
args
.
s
erverResponse
.
GetResponseStream
();
args
.
ResponseStream
=
args
.
S
erverResponse
.
GetResponseStream
();
if
(
BeforeResponse
!=
null
)
if
(
BeforeResponse
!=
null
)
{
{
args
.
responseEncoding
=
args
.
s
erverResponse
.
GetEncoding
();
args
.
ResponseEncoding
=
args
.
S
erverResponse
.
GetEncoding
();
BeforeResponse
(
null
,
args
);
BeforeResponse
(
null
,
args
);
}
}
args
.
ResponseLocked
=
true
;
args
.
ResponseLocked
=
true
;
if
(
args
.
r
esponseBodyRead
)
if
(
args
.
R
esponseBodyRead
)
{
{
bool
isChunked
=
args
.
serverResponse
.
GetResponseHeader
(
"transfer-encoding"
)
==
null
?
false
:
args
.
serverResponse
.
GetResponseHeader
(
"transfer-encoding"
).
ToLower
().
Contains
(
"chunked"
)
?
true
:
false
;
var
isChunked
=
args
.
ServerResponse
.
GetResponseHeader
(
"transfer-encoding"
).
ToLower
().
Contains
(
"chunked"
)
;
var
contentEncoding
=
args
.
s
erverResponse
.
ContentEncoding
;
var
contentEncoding
=
args
.
S
erverResponse
.
ContentEncoding
;
if
(
contentEncoding
!=
null
)
switch
(
contentEncoding
.
ToLower
())
switch
(
contentEncoding
.
ToLower
())
{
{
case
"gzip"
:
case
"gzip"
:
args
.
responseBody
=
CompressionHelper
.
CompressGzip
(
args
.
r
esponseBody
);
args
.
ResponseBody
=
CompressionHelper
.
CompressGzip
(
args
.
R
esponseBody
);
break
;
break
;
case
"deflate"
:
case
"deflate"
:
args
.
responseBody
=
CompressionHelper
.
CompressDeflate
(
args
.
r
esponseBody
);
args
.
ResponseBody
=
CompressionHelper
.
CompressDeflate
(
args
.
R
esponseBody
);
break
;
break
;
case
"zlib"
:
case
"zlib"
:
args
.
responseBody
=
CompressionHelper
.
CompressZlib
(
args
.
responseBody
);
args
.
ResponseBody
=
CompressionHelper
.
CompressZlib
(
args
.
ResponseBody
);
break
;
default
:
break
;
break
;
}
}
WriteResponseStatus
(
args
.
serverResponse
.
ProtocolVersion
,
args
.
serverResponse
.
StatusCode
,
args
.
serverResponse
.
StatusDescription
,
args
.
clientStreamWriter
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
WriteResponseHeaders
(
args
.
clientStreamWriter
,
args
.
responseHeaders
,
args
.
responseBody
.
Length
,
isChunked
);
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseBody
(
args
.
clientStream
,
args
.
responseBody
,
isChunked
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
args
.
ResponseHeaders
,
args
.
ResponseBody
.
Length
,
isChunked
);
WriteResponseBody
(
args
.
ClientStream
,
args
.
ResponseBody
,
isChunked
);
}
}
else
else
{
{
bool
isChunked
=
args
.
serverResponse
.
GetResponseHeader
(
"transfer-encoding"
)
==
null
?
false
:
args
.
serverResponse
.
GetResponseHeader
(
"transfer-encoding"
).
ToLower
().
Contains
(
"chunked"
)
?
true
:
false
;
var
isChunked
=
args
.
ServerResponse
.
GetResponseHeader
(
"transfer-encoding"
).
ToLower
().
Contains
(
"chunked"
);
WriteResponseStatus
(
args
.
serverResponse
.
ProtocolVersion
,
args
.
serverResponse
.
StatusCode
,
args
.
serverResponse
.
StatusDescription
,
args
.
clientStreamWriter
);
WriteResponseHeaders
(
args
.
clientStreamWriter
,
args
.
responseHeaders
);
WriteResponseBody
(
args
.
responseStream
,
args
.
clientStream
,
isChunked
);
WriteResponseStatus
(
args
.
ServerResponse
.
ProtocolVersion
,
args
.
ServerResponse
.
StatusCode
,
args
.
ServerResponse
.
StatusDescription
,
args
.
ClientStreamWriter
);
WriteResponseHeaders
(
args
.
ClientStreamWriter
,
args
.
ResponseHeaders
);
WriteResponseBody
(
args
.
ResponseStream
,
args
.
ClientStream
,
isChunked
);
}
}
args
.
clientStream
.
Flush
();
args
.
ClientStream
.
Flush
();
}
}
}
}
catch
catch
{
{
Dispose
(
args
.
client
,
args
.
clientStream
,
args
.
clientStreamReader
,
args
.
c
lientStreamWriter
,
args
);
Dispose
(
args
.
Client
,
args
.
ClientStream
,
args
.
ClientStreamReader
,
args
.
C
lientStreamWriter
,
args
);
}
}
finally
finally
{
{
if
(
args
!=
null
)
args
.
Dispose
();
args
.
Dispose
();
}
}
}
}
private
static
List
<
HttpHeader
>
ReadResponseHeaders
(
HttpWebResponse
response
)
private
static
List
<
HttpHeader
>
ReadResponseHeaders
(
HttpWebResponse
response
)
{
{
var
returnHeaders
=
new
List
<
HttpHeader
>();
var
returnHeaders
=
new
List
<
HttpHeader
>();
S
tring
cookieHeaderName
=
null
;
s
tring
cookieHeaderName
=
null
;
S
tring
cookieHeaderValue
=
null
;
s
tring
cookieHeaderValue
=
null
;
foreach
(
S
tring
headerKey
in
response
.
Headers
.
Keys
)
foreach
(
s
tring
headerKey
in
response
.
Headers
.
Keys
)
{
{
if
(
headerKey
.
ToLower
()
==
"set-cookie"
)
if
(
headerKey
.
ToLower
()
==
"set-cookie"
)
{
{
...
@@ -120,21 +110,21 @@ namespace Titanium.Web.Proxy
...
@@ -120,21 +110,21 @@ namespace Titanium.Web.Proxy
returnHeaders
.
Add
(
new
HttpHeader
(
headerKey
,
response
.
Headers
[
headerKey
]));
returnHeaders
.
Add
(
new
HttpHeader
(
headerKey
,
response
.
Headers
[
headerKey
]));
}
}
if
(!
S
tring
.
IsNullOrWhiteSpace
(
cookieHeaderValue
))
if
(!
s
tring
.
IsNullOrWhiteSpace
(
cookieHeaderValue
))
{
{
response
.
Headers
.
Remove
(
cookieHeaderName
);
response
.
Headers
.
Remove
(
cookieHeaderName
);
String
[]
cookies
=
c
ookieSplitRegEx
.
Split
(
cookieHeaderValue
);
var
cookies
=
C
ookieSplitRegEx
.
Split
(
cookieHeaderValue
);
foreach
(
String
cookie
in
cookies
)
foreach
(
var
cookie
in
cookies
)
returnHeaders
.
Add
(
new
HttpHeader
(
"Set-Cookie"
,
cookie
));
returnHeaders
.
Add
(
new
HttpHeader
(
"Set-Cookie"
,
cookie
));
}
}
return
returnHeaders
;
return
returnHeaders
;
}
}
private
static
void
WriteResponseStatus
(
Version
version
,
HttpStatusCode
code
,
String
description
,
StreamWriter
responseWriter
)
private
static
void
WriteResponseStatus
(
Version
version
,
HttpStatusCode
code
,
string
description
,
StreamWriter
responseWriter
)
{
{
String
s
=
String
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
(
Int32
)
code
,
description
);
var
s
=
string
.
Format
(
"HTTP/{0}.{1} {2} {3}"
,
version
.
Major
,
version
.
Minor
,
(
int
)
code
,
description
);
responseWriter
.
WriteLine
(
s
);
responseWriter
.
WriteLine
(
s
);
}
}
...
@@ -150,9 +140,10 @@ namespace Titanium.Web.Proxy
...
@@ -150,9 +140,10 @@ namespace Titanium.Web.Proxy
responseWriter
.
WriteLine
();
responseWriter
.
WriteLine
();
responseWriter
.
Flush
();
responseWriter
.
Flush
();
}
}
private
static
void
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
,
int
length
,
bool
isChunked
)
private
static
void
WriteResponseHeaders
(
StreamWriter
responseWriter
,
List
<
HttpHeader
>
headers
,
int
length
,
bool
isChunked
)
{
{
if
(!
isChunked
)
if
(!
isChunked
)
{
{
...
@@ -175,7 +166,6 @@ namespace Titanium.Web.Proxy
...
@@ -175,7 +166,6 @@ namespace Titanium.Web.Proxy
responseWriter
.
WriteLine
();
responseWriter
.
WriteLine
();
responseWriter
.
Flush
();
responseWriter
.
Flush
();
}
}
private
static
void
WriteResponseBody
(
Stream
clientStream
,
byte
[]
data
,
bool
isChunked
)
private
static
void
WriteResponseBody
(
Stream
clientStream
,
byte
[]
data
,
bool
isChunked
)
...
@@ -192,7 +182,7 @@ namespace Titanium.Web.Proxy
...
@@ -192,7 +182,7 @@ namespace Titanium.Web.Proxy
{
{
if
(!
isChunked
)
if
(!
isChunked
)
{
{
Byte
[]
buffer
=
new
B
yte
[
BUFFER_SIZE
];
var
buffer
=
new
b
yte
[
BUFFER_SIZE
];
int
bytesRead
;
int
bytesRead
;
while
((
bytesRead
=
inStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
bytesRead
=
inStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
...
@@ -203,11 +193,11 @@ namespace Titanium.Web.Proxy
...
@@ -203,11 +193,11 @@ namespace Titanium.Web.Proxy
else
else
WriteResponseBodyChunked
(
inStream
,
outStream
);
WriteResponseBodyChunked
(
inStream
,
outStream
);
}
}
//Send chunked response
//Send chunked response
private
static
void
WriteResponseBodyChunked
(
Stream
inStream
,
Stream
outStream
)
private
static
void
WriteResponseBodyChunked
(
Stream
inStream
,
Stream
outStream
)
{
{
var
buffer
=
new
byte
[
BUFFER_SIZE
];
Byte
[]
buffer
=
new
Byte
[
BUFFER_SIZE
];
int
bytesRead
;
int
bytesRead
;
while
((
bytesRead
=
inStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
while
((
bytesRead
=
inStream
.
Read
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
...
@@ -215,31 +205,29 @@ namespace Titanium.Web.Proxy
...
@@ -215,31 +205,29 @@ namespace Titanium.Web.Proxy
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
bytesRead
.
ToString
(
"x2"
));
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
bytesRead
.
ToString
(
"x2"
));
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
chunkTrail
,
0
,
c
hunkTrail
.
Length
);
outStream
.
Write
(
ChunkTrail
,
0
,
C
hunkTrail
.
Length
);
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
outStream
.
Write
(
chunkTrail
,
0
,
chunkTrail
.
Length
);
outStream
.
Write
(
ChunkTrail
,
0
,
ChunkTrail
.
Length
);
}
}
outStream
.
Write
(
ChunkEnd
,
0
,
ChunkEnd
.
Length
);
outStream
.
Write
(
ChunkEnd
,
0
,
ChunkEnd
.
Length
);
}
}
private
static
void
WriteResponseBodyChunked
(
byte
[]
data
,
Stream
outStream
)
private
static
void
WriteResponseBodyChunked
(
byte
[]
data
,
Stream
outStream
)
{
{
Byte
[]
buffer
=
new
Byte
[
BUFFER_SIZE
];
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
data
.
Length
.
ToString
(
"x2"
));
var
chunkHead
=
Encoding
.
ASCII
.
GetBytes
(
data
.
Length
.
ToString
(
"x2"
));
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
chunkHead
,
0
,
chunkHead
.
Length
);
outStream
.
Write
(
chunkTrail
,
0
,
c
hunkTrail
.
Length
);
outStream
.
Write
(
ChunkTrail
,
0
,
C
hunkTrail
.
Length
);
outStream
.
Write
(
data
,
0
,
data
.
Length
);
outStream
.
Write
(
data
,
0
,
data
.
Length
);
outStream
.
Write
(
chunkTrail
,
0
,
c
hunkTrail
.
Length
);
outStream
.
Write
(
ChunkTrail
,
0
,
C
hunkTrail
.
Length
);
outStream
.
Write
(
ChunkEnd
,
0
,
ChunkEnd
.
Length
);
outStream
.
Write
(
ChunkEnd
,
0
,
ChunkEnd
.
Length
);
}
}
private
static
void
Dispose
(
TcpClient
client
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
SessionEventArgs
args
)
private
static
void
Dispose
(
TcpClient
client
,
IDisposable
clientStream
,
IDisposable
clientStreamReader
,
IDisposable
clientStreamWriter
,
IDisposable
args
)
{
{
if
(
args
!=
null
)
if
(
args
!=
null
)
args
.
Dispose
();
args
.
Dispose
();
...
...
Titanium.Web.Proxy/packages.config
View file @
e332c90d
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
packages
>
<
packages
>
<
package
id
=
"DotNetZip"
version
=
"1.9.3"
targetFramework
=
"net40-Client"
/>
<
package
id
=
"DotNetZip"
version
=
"1.9.3"
targetFramework
=
"net40-Client"
/>
</
packages
>
</
packages
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment