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
f26c5605
Commit
f26c5605
authored
Feb 06, 2016
by
titanium007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
issue #31, #32, #35
fix multiple issues reported
parent
37714ced
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
92 additions
and
65 deletions
+92
-65
Program.cs
Titanium.Web.Proxy.Test/Program.cs
+0
-16
ProxyTestController.cs
Titanium.Web.Proxy.Test/ProxyTestController.cs
+14
-9
HttpWebResponseExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
+8
-2
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+7
-3
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+3
-3
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+21
-5
TcpConnectionManager.cs
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
+2
-1
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+23
-16
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+11
-8
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+1
-1
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+2
-1
No files found.
Titanium.Web.Proxy.Test/Program.cs
View file @
f26c5605
...
...
@@ -14,22 +14,6 @@ namespace Titanium.Web.Proxy.Test
NativeMethods
.
SetConsoleCtrlHandler
(
NativeMethods
.
Handler
,
true
);
Console
.
Write
(
"Do you want to monitor HTTPS? (Y/N):"
);
var
readLine
=
Console
.
ReadLine
();
if
(
readLine
!=
null
&&
readLine
.
Trim
().
ToLower
()
==
"y"
)
{
Controller
.
EnableSsl
=
true
;
}
Console
.
Write
(
"Do you want to set this as a System Proxy? (Y/N):"
);
var
line
=
Console
.
ReadLine
();
if
(
line
!=
null
&&
line
.
Trim
().
ToLower
()
==
"y"
)
{
Controller
.
SetAsSystemProxy
=
true
;
}
//Start proxy controller
Controller
.
StartProxy
();
...
...
Titanium.Web.Proxy.Test/ProxyTestController.cs
View file @
f26c5605
using
System
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Text.RegularExpressions
;
using
Titanium.Web.Proxy.EventArguments
;
...
...
@@ -8,29 +9,33 @@ namespace Titanium.Web.Proxy.Test
{
public
class
ProxyTestController
{
public
int
ListeningPort
{
get
;
set
;
}
public
bool
EnableSsl
{
get
;
set
;
}
public
bool
SetAsSystemProxy
{
get
;
set
;
}
public
void
StartProxy
()
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
// ProxyServer.ExcludedHttpsHostNameRegex.Add(".dropbox.com");
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
{
EnableSsl
=
true
,
IpAddress
=
IPAddress
.
Any
,
Port
=
8000
};
var
transparentEndPoint
=
new
TransparentProxyEndPoint
{
EnableSsl
=
true
,
IpAddress
=
IPAddress
.
Loopback
,
Port
=
443
};
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Loopback
,
8000
,
true
){
ExcludedHostNameRegex
=
new
List
<
string
>()
{
"dropbox.com"
}
};
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Loopback
,
8001
,
true
)
{
};
ProxyServer
.
AddEndPoint
(
explicitEndPoint
);
ProxyServer
.
AddEndPoint
(
transparentEndPoint
);
ProxyServer
.
Start
();
ProxyServer
.
SetAsSystemProxy
(
explicitEndPoint
);
foreach
(
var
endPoint
in
ProxyServer
.
ProxyEndPoints
)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
ProxyServer
.
SetAsSystemProxy
(
explicitEndPoint
);
// Console.WriteLine("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort);
}
public
void
Stop
()
...
...
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
View file @
f26c5605
...
...
@@ -8,8 +8,14 @@ namespace Titanium.Web.Proxy.Extensions
{
public
static
Encoding
GetResponseEncoding
(
this
HttpWebSession
response
)
{
if
(
string
.
IsNullOrEmpty
(
response
.
Response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
return
Encoding
.
GetEncoding
(
response
.
Response
.
CharacterSet
.
Replace
(
@""""
,
string
.
Empty
));
if
(
string
.
IsNullOrEmpty
(
response
.
Response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
try
{
return
Encoding
.
GetEncoding
(
response
.
Response
.
CharacterSet
.
Replace
(
@""""
,
string
.
Empty
));
}
catch
{
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
f26c5605
...
...
@@ -8,13 +8,17 @@ namespace Titanium.Web.Proxy.Extensions
{
public
static
void
CopyToAsync
(
this
Stream
input
,
string
initialData
,
Stream
output
,
int
bufferSize
)
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
if
(!
string
.
IsNullOrEmpty
(
initialData
))
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
}
CopyToAsync
(
input
,
output
,
bufferSize
);
}
//http://stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write
p
ublic
static
void
CopyToAsync
(
this
Stream
input
,
Stream
output
,
int
bufferSize
)
p
rivate
static
void
CopyToAsync
(
this
Stream
input
,
Stream
output
,
int
bufferSize
)
{
try
{
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
f26c5605
...
...
@@ -51,7 +51,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
sslStream
=
new
SslStream
(
tunnelStream
);
sslStream
.
AuthenticateAsClient
(
hostName
);
sslStream
.
AuthenticateAsClient
(
hostName
,
null
,
ProxyServer
.
SupportedProtocols
,
false
);
tunnelStream
=
sslStream
;
}
catch
...
...
@@ -69,10 +69,10 @@ namespace Titanium.Web.Proxy.Helpers
if
(
sb
!=
null
)
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
,
BUFFER_SIZE
);
else
clientStream
.
CopyToAsync
(
tunnelStream
,
BUFFER_SIZE
);
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
,
BUFFER_SIZE
);
});
var
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
tunnelStream
.
CopyToAsync
(
clientStream
,
BUFFER_SIZE
));
var
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
,
BUFFER_SIZE
));
Task
.
WaitAll
(
sendRelay
,
receiveRelay
);
}
...
...
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
f26c5605
...
...
@@ -9,9 +9,16 @@ namespace Titanium.Web.Proxy.Models
{
public
abstract
class
ProxyEndPoint
{
public
IPAddress
IpAddress
{
get
;
set
;
}
public
int
Port
{
get
;
set
;
}
public
bool
EnableSsl
{
get
;
set
;
}
public
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
{
this
.
IpAddress
=
IpAddress
;
this
.
Port
=
Port
;
this
.
EnableSsl
=
EnableSsl
;
}
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
public
int
Port
{
get
;
internal
set
;
}
public
bool
EnableSsl
{
get
;
internal
set
;
}
internal
TcpListener
listener
{
get
;
set
;
}
}
...
...
@@ -20,11 +27,20 @@ namespace Titanium.Web.Proxy.Models
{
internal
bool
IsSystemProxy
{
get
;
set
;
}
public
List
<
string
>
ExcludedHostNameRegex
{
get
;
set
;
}
public
ExplicitProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
}
}
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
public
TransparentProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
}
}
}
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
View file @
f26c5605
...
...
@@ -9,6 +9,7 @@ using System.IO;
using
System.Net.Security
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Threading
;
using
System.Security.Authentication
;
namespace
Titanium.Web.Proxy.Network
{
...
...
@@ -76,7 +77,7 @@ namespace Titanium.Web.Proxy.Network
try
{
sslStream
=
new
SslStream
(
stream
);
sslStream
.
AuthenticateAsClient
(
Hostname
);
sslStream
.
AuthenticateAsClient
(
Hostname
,
null
,
ProxyServer
.
SupportedProtocols
,
false
);
stream
=
(
Stream
)
sslStream
;
}
catch
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
f26c5605
...
...
@@ -12,6 +12,7 @@ using Titanium.Web.Proxy.Helpers;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Network
;
using
System.Linq
;
using
System.Security.Authentication
;
namespace
Titanium.Web.Proxy
{
...
...
@@ -33,15 +34,18 @@ namespace Titanium.Web.Proxy
private
static
readonly
byte
[]
ChunkEnd
=
Encoding
.
ASCII
.
GetBytes
(
0.
ToString
(
"x2"
)
+
Environment
.
NewLine
+
Environment
.
NewLine
);
private
static
List
<
ProxyEndPoint
>
_proxyEndPoints
{
get
;
set
;
}
#if NET45
internal
static
SslProtocols
SupportedProtocols
=
SslProtocols
.
Tls
|
SslProtocols
.
Tls11
|
SslProtocols
.
Tls12
|
SslProtocols
.
Ssl3
;
#else
public
static
SslProtocols
SupportedProtocols
=
SslProtocols
.
Tls
|
SslProtocols
.
Ssl3
;
#endif
static
ProxyServer
()
{
CertManager
=
new
CertificateManager
(
"Titanium"
,
"Titanium Root Certificate Authority"
);
_p
roxyEndPoints
=
new
List
<
ProxyEndPoint
>();
P
roxyEndPoints
=
new
List
<
ProxyEndPoint
>();
Initialize
();
}
...
...
@@ -56,6 +60,7 @@ namespace Titanium.Web.Proxy
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeRequest
;
public
static
event
EventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
static
List
<
ProxyEndPoint
>
ProxyEndPoints
{
get
;
set
;
}
public
static
void
Initialize
()
{
...
...
@@ -67,25 +72,25 @@ namespace Titanium.Web.Proxy
if
(
proxyStarted
)
throw
new
Exception
(
"Cannot add end points after proxy started."
);
_p
roxyEndPoints
.
Add
(
endPoint
);
P
roxyEndPoints
.
Add
(
endPoint
);
}
public
static
void
SetAsSystemProxy
(
ExplicitProxyEndPoint
endPoint
)
{
if
(
_p
roxyEndPoints
.
Contains
(
endPoint
)
==
false
)
if
(
P
roxyEndPoints
.
Contains
(
endPoint
)
==
false
)
throw
new
Exception
(
"Cannot set endPoints not added to proxy as system proxy"
);
if
(!
proxyStarted
)
throw
new
Exception
(
"Cannot set system proxy settings before proxy has been started."
);
//clear any settings previously added
_p
roxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemProxy
=
false
);
P
roxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
ToList
().
ForEach
(
x
=>
x
.
IsSystemProxy
=
false
);
endPoint
.
IsSystemProxy
=
true
;
SystemProxyHelper
.
EnableProxyHttp
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
#if !DEBUG
FireFoxHelper
.
AddFirefox
();
...
...
@@ -99,21 +104,23 @@ namespace Titanium.Web.Proxy
if
(
certTrusted
)
{
SystemProxyHelper
.
EnableProxyHttps
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Loopback
)
?
"127.0.0.1"
:
endPoint
.
IpAddress
.
ToString
(),
endPoint
.
Port
);
}
}
Console
.
WriteLine
(
"Set endpoint at Ip {1} and port: {2} as System Proxy"
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
}
public
static
void
Start
()
{
EnableSsl
=
_p
roxyEndPoints
.
Any
(
x
=>
x
.
EnableSsl
);
EnableSsl
=
P
roxyEndPoints
.
Any
(
x
=>
x
.
EnableSsl
);
if
(
EnableSsl
)
certTrusted
=
CertManager
.
CreateTrustedRootCertificate
();
foreach
(
var
endPoint
in
_p
roxyEndPoints
)
foreach
(
var
endPoint
in
P
roxyEndPoints
)
{
endPoint
.
listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
...
...
@@ -130,10 +137,7 @@ namespace Titanium.Web.Proxy
private
static
void
OnAcceptConnection
(
IAsyncResult
asyn
)
{
var
endPoint
=
(
ProxyEndPoint
)
asyn
.
AsyncState
;
// Get the listener that handles the client request.
endPoint
.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
var
client
=
endPoint
.
listener
.
EndAcceptTcpClient
(
asyn
);
try
...
...
@@ -147,12 +151,15 @@ namespace Titanium.Web.Proxy
{
// ignored
}
// Get the listener that handles the client request.
endPoint
.
listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
public
static
void
Stop
()
{
var
SetAsSystemProxy
=
_p
roxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemProxy
);
var
SetAsSystemProxy
=
P
roxyEndPoints
.
OfType
<
ExplicitProxyEndPoint
>().
Any
(
x
=>
x
.
IsSystemProxy
);
if
(
SetAsSystemProxy
)
{
...
...
@@ -162,7 +169,7 @@ namespace Titanium.Web.Proxy
#endif
}
foreach
(
var
endPoint
in
_p
roxyEndPoints
)
foreach
(
var
endPoint
in
P
roxyEndPoints
)
{
endPoint
.
listener
.
Stop
();
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
f26c5605
...
...
@@ -51,11 +51,10 @@ namespace Titanium.Web.Proxy
var
httpVersion
=
httpCmdSplit
[
2
];
var
excluded
=
endPoint
.
ExcludedHostNameRegex
!=
null
?
endPoint
.
ExcludedHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
:
false
;
//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
!=
80
)
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
clientStreamReader
.
ReadAllLines
();
...
...
@@ -69,9 +68,10 @@ namespace Titanium.Web.Proxy
try
{
sslStream
=
new
SslStream
(
clientStream
,
true
);
//Successfully managed to authenticate the client using the fake certificate
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
|
SslProtocols
.
Ssl3
|
SslProtocols
.
Ssl2
,
false
);
SupportedProtocols
,
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
...
@@ -96,13 +96,16 @@ namespace Titanium.Web.Proxy
{
clientStreamReader
.
ReadAllLines
();
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
}
//Now create the request
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
true
:
false
);
}
...
...
@@ -125,8 +128,8 @@ namespace Titanium.Web.Proxy
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
,
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
//HTTPS server created - we can now decrypt the client's traffic
}
...
...
@@ -201,8 +204,8 @@ namespace Titanium.Web.Proxy
if
(
args
.
ProxySession
.
Request
.
UpgradeToWebSocket
)
{
TcpHelper
.
SendRaw
(
clientStream
Reader
.
BaseStream
,
httpCmd
,
args
.
ProxySession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpRemoteUri
.
Scheme
==
Uri
.
UriScheme
Https
);
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
ProxySession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
Is
Https
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
f26c5605
...
...
@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy
if
(
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Contains
(
";"
))
{
response
.
Response
.
ContentType
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
0
].
Trim
();
response
.
Response
.
CharacterSet
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
1
].
ToLower
().
Replace
(
"charset="
,
string
.
Empty
).
Trim
();
response
.
Response
.
CharacterSet
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
1
].
Substring
(
9
).
Trim
();
}
else
response
.
Response
.
ContentType
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
ToLower
().
Trim
();
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
f26c5605
...
...
@@ -33,7 +33,7 @@
<PropertyGroup
Condition=
"'$(Configuration)|$(Platform)' == 'Debug-Net45|AnyCPU'"
>
<DebugSymbols>
true
</DebugSymbols>
<OutputPath>
bin\Debug-Net45\
</OutputPath>
<DefineConstants>
DEBUG
</DefineConstants>
<DefineConstants>
DEBUG
;NET45
</DefineConstants>
<AllowUnsafeBlocks>
true
</AllowUnsafeBlocks>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<CodeAnalysisRuleSet>
MinimumRecommendedRules.ruleset
</CodeAnalysisRuleSet>
...
...
@@ -44,6 +44,7 @@
<PlatformTarget>
AnyCPU
</PlatformTarget>
<CodeAnalysisRuleSet>
MinimumRecommendedRules.ruleset
</CodeAnalysisRuleSet>
<TargetFrameworkVersion>
v4.5
</TargetFrameworkVersion>
<DefineConstants>
NET45
</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference
Include=
"Ionic.Zip, Version=1.9.7.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL"
>
...
...
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