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
e1543300
Commit
e1543300
authored
Jun 16, 2017
by
Jehonathan Thomas
Committed by
GitHub
Jun 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #275 from justcoding121/beta
Stable
parents
acad670d
ac2877be
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1241 additions
and
262 deletions
+1241
-262
.gitignore
.gitignore
+1
-1
Program.cs
Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs
+0
-33
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+8
-4
README.md
README.md
+2
-1
SystemProxyTest.cs
Tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs
+128
-0
Titanium.Web.Proxy.UnitTests.csproj
...m.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
+1
-0
ProxyInfo.cs
Titanium.Web.Proxy/Helpers/ProxyInfo.cs
+200
-0
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+236
-103
NativeMethods.WinHttp.cs
Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs
+131
-0
WinHttpHandle.cs
Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs
+19
-0
WinHttpWebProxyFinder.cs
Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs
+332
-0
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+6
-9
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+8
-6
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+13
-13
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+124
-63
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+22
-18
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+0
-5
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+7
-3
Titanium.Web.Proxy.nuspec
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
+3
-3
No files found.
.gitignore
View file @
e1543300
...
@@ -202,4 +202,4 @@ FakesAssemblies/
...
@@ -202,4 +202,4 @@ FakesAssemblies/
*.plg
*.plg
# Visual Studio 6 workspace options file
# Visual Studio 6 workspace options file
*.opt
*.opt
\ No newline at end of file
Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs
View file @
e1543300
...
@@ -14,10 +14,6 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -14,10 +14,6 @@ namespace Titanium.Web.Proxy.Examples.Basic
//fix console hang due to QuickEdit mode
//fix console hang due to QuickEdit mode
ConsoleHelper
.
DisableQuickEditMode
();
ConsoleHelper
.
DisableQuickEditMode
();
//On Console exit make sure we also exit the proxy
NativeMethods
.
Handler
=
ConsoleEventCallback
;
NativeMethods
.
SetConsoleCtrlHandler
(
NativeMethods
.
Handler
,
true
);
//Start proxy controller
//Start proxy controller
controller
.
StartProxy
();
controller
.
StartProxy
();
...
@@ -27,34 +23,5 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -27,34 +23,5 @@ namespace Titanium.Web.Proxy.Examples.Basic
controller
.
Stop
();
controller
.
Stop
();
}
}
private
static
bool
ConsoleEventCallback
(
int
eventType
)
{
if
(
eventType
!=
2
)
return
false
;
try
{
controller
.
Stop
();
}
catch
{
// ignored
}
return
false
;
}
}
internal
static
class
NativeMethods
{
// Keeps it from getting garbage collected
internal
static
ConsoleEventDelegate
Handler
;
[
DllImport
(
"kernel32.dll"
,
SetLastError
=
true
)]
internal
static
extern
bool
SetConsoleCtrlHandler
(
ConsoleEventDelegate
callback
,
bool
add
);
// Pinvoke
internal
delegate
bool
ConsoleEventDelegate
(
int
eventType
);
}
}
}
}
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
e1543300
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Net
;
using
System.Net.Security
;
using
System.Net.Security
;
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.Models
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Examples.Basic
namespace
Titanium.Web.Proxy.Examples.Basic
...
@@ -15,8 +17,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -15,8 +17,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
//share requestBody outside handlers
//share requestBody outside handlers
//Using a dictionary is not a good idea since it can cause memory overflow
//Using a dictionary is not a good idea since it can cause memory overflow
//ideally the data should be moved out of memory
//ideally the data should be moved out of memory
//private readonly Dictionary<Guid, string> requestBodyHistory
//private readonly
I
Dictionary<Guid, string> requestBodyHistory
// = new Dictionary<Guid, string>();
// = new
Concurrent
Dictionary<Guid, string>();
public
ProxyTestController
()
public
ProxyTestController
()
{
{
...
@@ -29,6 +31,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -29,6 +31,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer
.
ExceptionFunc
=
exception
=>
Console
.
WriteLine
(
exception
.
Message
);
proxyServer
.
ExceptionFunc
=
exception
=>
Console
.
WriteLine
(
exception
.
Message
);
proxyServer
.
TrustRootCertificate
=
true
;
proxyServer
.
TrustRootCertificate
=
true
;
proxyServer
.
ForwardToUpstreamGateway
=
true
;
//optionally set the Certificate Engine
//optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported
//Under Mono only BouncyCastle will be supported
...
@@ -92,8 +95,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -92,8 +95,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
//Only explicit proxies can be set as system proxy!
//Only explicit proxies can be set as system proxy!
proxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
//proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
proxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
//proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
proxyServer
.
SetAsSystemProxy
(
explicitEndPoint
,
ProxyProtocolType
.
AllHttp
);
}
}
public
void
Stop
()
public
void
Stop
()
...
...
README.md
View file @
e1543300
...
@@ -112,7 +112,8 @@ Sample request and response event handlers
...
@@ -112,7 +112,8 @@ Sample request and response event handlers
```
csharp
```
csharp
//To access requestBody from OnResponse handler
//To access requestBody from OnResponse handler
private
Dictionary
<
Guid
,
string
>
requestBodyHistory
=
new
Dictionary
<
Guid
,
string
>();
private
IDictionary
<
Guid
,
string
>
requestBodyHistory
=
new
ConcurrentDictionary
<
Guid
,
string
>();
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
...
...
Tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs
0 → 100644
View file @
e1543300
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers.WinHttp
;
namespace
Titanium.Web.Proxy.UnitTests
{
[
TestClass
]
public
class
SystemProxyTest
{
[
TestMethod
]
public
void
CompareProxyAdddressReturendByWebProxyAndWinHttpProxyResolver
()
{
var
proxyManager
=
new
SystemProxyManager
();
try
{
CompareUrls
();
proxyManager
.
SetProxy
(
"127.0.0.1"
,
8000
,
ProxyProtocolType
.
Http
);
CompareUrls
();
proxyManager
.
SetProxy
(
"127.0.0.1"
,
8000
,
ProxyProtocolType
.
Https
);
CompareUrls
();
proxyManager
.
SetProxy
(
"127.0.0.1"
,
8000
,
ProxyProtocolType
.
AllHttp
);
CompareUrls
();
// for this test you need to add a proxy.pac file to a local webserver
//function FindProxyForURL(url, host)
//{
// if (shExpMatch(host, "google.com"))
// {
// return "PROXY 127.0.0.1:8888";
// }
// return "DIRECT";
//}
//proxyManager.SetAutoProxyUrl("http://localhost/proxy.pac");
//CompareUrls();
proxyManager
.
SetProxyOverride
(
"<-loopback>"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"<local>"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"yahoo.com"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"*.local"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"http://*.local"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"<-loopback>;*.local"
);
CompareUrls
();
proxyManager
.
SetProxyOverride
(
"<-loopback>;*.local;<local>"
);
CompareUrls
();
}
finally
{
proxyManager
.
RestoreOriginalSettings
();
}
}
private
void
CompareUrls
()
{
var
webProxy
=
WebRequest
.
GetSystemWebProxy
();
var
resolver
=
new
WinHttpWebProxyFinder
();
resolver
.
LoadFromIE
();
CompareProxy
(
webProxy
,
resolver
,
"http://127.0.0.1"
);
CompareProxy
(
webProxy
,
resolver
,
"https://127.0.0.1"
);
CompareProxy
(
webProxy
,
resolver
,
"http://localhost"
);
CompareProxy
(
webProxy
,
resolver
,
"https://localhost"
);
string
hostName
=
null
;
try
{
hostName
=
Dns
.
GetHostName
();
}
catch
{}
if
(
hostName
!=
null
)
{
CompareProxy
(
webProxy
,
resolver
,
"http://"
+
hostName
);
CompareProxy
(
webProxy
,
resolver
,
"https://"
+
hostName
);
}
CompareProxy
(
webProxy
,
resolver
,
"http://google.com"
);
CompareProxy
(
webProxy
,
resolver
,
"https://google.com"
);
CompareProxy
(
webProxy
,
resolver
,
"http://bing.com"
);
CompareProxy
(
webProxy
,
resolver
,
"https://bing.com"
);
CompareProxy
(
webProxy
,
resolver
,
"http://yahoo.com"
);
CompareProxy
(
webProxy
,
resolver
,
"https://yahoo.com"
);
CompareProxy
(
webProxy
,
resolver
,
"http://test.local"
);
CompareProxy
(
webProxy
,
resolver
,
"https://test.local"
);
}
private
void
CompareProxy
(
IWebProxy
webProxy
,
WinHttpWebProxyFinder
resolver
,
string
url
)
{
var
uri
=
new
Uri
(
url
);
var
expectedProxyUri
=
webProxy
.
GetProxy
(
uri
);
var
proxy
=
resolver
.
GetProxy
(
uri
);
if
(
expectedProxyUri
==
uri
)
{
// no proxy
Assert
.
AreEqual
(
proxy
,
null
);
return
;
}
Assert
.
AreEqual
(
expectedProxyUri
.
ToString
(),
$"http://
{
proxy
.
HostName
}
:
{
proxy
.
Port
}
/"
);
}
}
}
Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
View file @
e1543300
...
@@ -60,6 +60,7 @@
...
@@ -60,6 +60,7 @@
<Compile
Include=
"CertificateManagerTests.cs"
/>
<Compile
Include=
"CertificateManagerTests.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"ProxyServerTests.cs"
/>
<Compile
Include=
"ProxyServerTests.cs"
/>
<Compile
Include=
"SystemProxyTest.cs"
/>
<Compile
Include=
"WinAuthTests.cs"
/>
<Compile
Include=
"WinAuthTests.cs"
/>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ItemGroup>
...
...
Titanium.Web.Proxy/Helpers/ProxyInfo.cs
0 → 100644
View file @
e1543300
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Text.RegularExpressions
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Helpers
{
internal
class
ProxyInfo
{
public
bool
?
AutoDetect
{
get
;
}
public
string
AutoConfigUrl
{
get
;
}
public
int
?
ProxyEnable
{
get
;
}
public
string
ProxyServer
{
get
;
}
public
string
ProxyOverride
{
get
;
}
public
bool
BypassLoopback
{
get
;
}
public
bool
BypassOnLocal
{
get
;
}
public
Dictionary
<
ProxyProtocolType
,
HttpSystemProxyValue
>
Proxies
{
get
;
}
public
string
[]
BypassList
{
get
;
}
public
ProxyInfo
(
bool
?
autoDetect
,
string
autoConfigUrl
,
int
?
proxyEnable
,
string
proxyServer
,
string
proxyOverride
)
{
AutoDetect
=
autoDetect
;
AutoConfigUrl
=
autoConfigUrl
;
ProxyEnable
=
proxyEnable
;
ProxyServer
=
proxyServer
;
ProxyOverride
=
proxyOverride
;
if
(
proxyServer
!=
null
)
{
Proxies
=
GetSystemProxyValues
(
proxyServer
).
ToDictionary
(
x
=>
x
.
ProtocolType
);
}
if
(
proxyOverride
!=
null
)
{
var
overrides
=
proxyOverride
.
Split
(
';'
);
var
overrides2
=
new
List
<
string
>();
foreach
(
var
overrideHost
in
overrides
)
{
if
(
overrideHost
==
"<-loopback>"
)
{
BypassLoopback
=
true
;
}
else
if
(
overrideHost
==
"<local>"
)
{
BypassOnLocal
=
true
;
}
else
{
overrides2
.
Add
(
BypassStringEscape
(
overrideHost
));
}
}
if
(
overrides2
.
Count
>
0
)
{
BypassList
=
overrides2
.
ToArray
();
}
Proxies
=
GetSystemProxyValues
(
proxyServer
).
ToDictionary
(
x
=>
x
.
ProtocolType
);
}
}
private
static
string
BypassStringEscape
(
string
rawString
)
{
Match
match
=
new
Regex
(
"^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$"
,
RegexOptions
.
IgnoreCase
|
RegexOptions
.
CultureInvariant
).
Match
(
rawString
);
string
empty1
;
string
rawString1
;
string
empty2
;
if
(
match
.
Success
)
{
empty1
=
match
.
Groups
[
"scheme"
].
Value
;
rawString1
=
match
.
Groups
[
"host"
].
Value
;
empty2
=
match
.
Groups
[
"port"
].
Value
;
}
else
{
empty1
=
string
.
Empty
;
rawString1
=
rawString
;
empty2
=
string
.
Empty
;
}
string
str1
=
ConvertRegexReservedChars
(
empty1
);
string
str2
=
ConvertRegexReservedChars
(
rawString1
);
string
str3
=
ConvertRegexReservedChars
(
empty2
);
if
(
str1
==
string
.
Empty
)
str1
=
"(?:.*://)?"
;
if
(
str3
==
string
.
Empty
)
str3
=
"(?::[0-9]{1,5})?"
;
return
"^"
+
str1
+
str2
+
str3
+
"$"
;
}
private
static
string
ConvertRegexReservedChars
(
string
rawString
)
{
if
(
rawString
.
Length
==
0
)
return
rawString
;
var
stringBuilder
=
new
StringBuilder
();
foreach
(
char
ch
in
rawString
)
{
if
(
"#$()+.?[\\^{|"
.
IndexOf
(
ch
)
!=
-
1
)
stringBuilder
.
Append
(
'\\'
);
else
if
(
ch
==
42
)
stringBuilder
.
Append
(
'.'
);
stringBuilder
.
Append
(
ch
);
}
return
stringBuilder
.
ToString
();
}
public
static
ProxyProtocolType
?
ParseProtocolType
(
string
protocolTypeStr
)
{
if
(
protocolTypeStr
==
null
)
{
return
null
;
}
ProxyProtocolType
?
protocolType
=
null
;
if
(
protocolTypeStr
.
Equals
(
"http"
,
StringComparison
.
InvariantCultureIgnoreCase
))
{
protocolType
=
ProxyProtocolType
.
Http
;
}
else
if
(
protocolTypeStr
.
Equals
(
"https"
,
StringComparison
.
InvariantCultureIgnoreCase
))
{
protocolType
=
ProxyProtocolType
.
Https
;
}
return
protocolType
;
}
/// <summary>
/// Parse the system proxy setting values
/// </summary>
/// <param name="proxyServerValues"></param>
/// <returns></returns>
public
static
List
<
HttpSystemProxyValue
>
GetSystemProxyValues
(
string
proxyServerValues
)
{
var
result
=
new
List
<
HttpSystemProxyValue
>();
if
(
string
.
IsNullOrWhiteSpace
(
proxyServerValues
))
return
result
;
var
proxyValues
=
proxyServerValues
.
Split
(
';'
);
if
(
proxyValues
.
Length
>
0
)
{
result
.
AddRange
(
proxyValues
.
Select
(
ParseProxyValue
).
Where
(
parsedValue
=>
parsedValue
!=
null
));
}
else
{
var
parsedValue
=
ParseProxyValue
(
proxyServerValues
);
if
(
parsedValue
!=
null
)
result
.
Add
(
parsedValue
);
}
return
result
;
}
/// <summary>
/// Parses the system proxy setting string
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private
static
HttpSystemProxyValue
ParseProxyValue
(
string
value
)
{
var
tmp
=
Regex
.
Replace
(
value
,
@"\s+"
,
" "
).
Trim
();
int
equalsIndex
=
tmp
.
IndexOf
(
"="
,
StringComparison
.
InvariantCulture
);
if
(
equalsIndex
>=
0
)
{
string
protocolTypeStr
=
tmp
.
Substring
(
0
,
equalsIndex
);
var
protocolType
=
ParseProtocolType
(
protocolTypeStr
);
if
(
protocolType
.
HasValue
)
{
var
endPointParts
=
tmp
.
Substring
(
equalsIndex
+
1
).
Split
(
':'
);
return
new
HttpSystemProxyValue
{
HostName
=
endPointParts
[
0
],
Port
=
int
.
Parse
(
endPointParts
[
1
]),
ProtocolType
=
protocolType
.
Value
,
};
}
}
return
null
;
}
}
}
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
e1543300
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs
0 → 100644
View file @
e1543300
using
System
;
using
System.Runtime.InteropServices
;
// Helper classes for setting system proxy settings
namespace
Titanium.Web.Proxy.Helpers.WinHttp
{
internal
partial
class
NativeMethods
{
internal
static
class
WinHttp
{
[
DllImport
(
"winhttp.dll"
,
SetLastError
=
true
)]
internal
static
extern
bool
WinHttpGetIEProxyConfigForCurrentUser
(
ref
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
proxyConfig
);
[
DllImport
(
"winhttp.dll"
,
CharSet
=
CharSet
.
Unicode
,
SetLastError
=
true
)]
internal
static
extern
WinHttpHandle
WinHttpOpen
(
string
userAgent
,
AccessType
accessType
,
string
proxyName
,
string
proxyBypass
,
int
dwFlags
);
[
DllImport
(
"winhttp.dll"
,
CharSet
=
CharSet
.
Unicode
,
SetLastError
=
true
)]
internal
static
extern
bool
WinHttpSetTimeouts
(
WinHttpHandle
session
,
int
resolveTimeout
,
int
connectTimeout
,
int
sendTimeout
,
int
receiveTimeout
);
[
DllImport
(
"winhttp.dll"
,
CharSet
=
CharSet
.
Unicode
,
SetLastError
=
true
)]
internal
static
extern
bool
WinHttpGetProxyForUrl
(
WinHttpHandle
session
,
string
url
,
[
In
]
ref
WINHTTP_AUTOPROXY_OPTIONS
autoProxyOptions
,
out
WINHTTP_PROXY_INFO
proxyInfo
);
[
DllImport
(
"winhttp.dll"
,
CharSet
=
CharSet
.
Unicode
,
SetLastError
=
true
)]
internal
static
extern
bool
WinHttpCloseHandle
(
IntPtr
httpSession
);
[
StructLayout
(
LayoutKind
.
Sequential
,
CharSet
=
CharSet
.
Unicode
)]
internal
struct
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
{
public
bool
AutoDetect
;
public
IntPtr
AutoConfigUrl
;
public
IntPtr
Proxy
;
public
IntPtr
ProxyBypass
;
}
[
Flags
]
internal
enum
AutoProxyFlags
{
AutoDetect
=
1
,
AutoProxyConfigUrl
=
2
,
RunInProcess
=
65536
,
RunOutProcessOnly
=
131072
}
internal
enum
AccessType
{
DefaultProxy
=
0
,
NoProxy
=
1
,
NamedProxy
=
3
}
[
Flags
]
internal
enum
AutoDetectType
{
None
=
0
,
Dhcp
=
1
,
DnsA
=
2
}
[
StructLayout
(
LayoutKind
.
Sequential
,
CharSet
=
CharSet
.
Unicode
)]
internal
struct
WINHTTP_AUTOPROXY_OPTIONS
{
public
AutoProxyFlags
Flags
;
public
AutoDetectType
AutoDetectFlags
;
[
MarshalAs
(
UnmanagedType
.
LPWStr
)]
public
string
AutoConfigUrl
;
private
IntPtr
lpvReserved
;
private
int
dwReserved
;
public
bool
AutoLogonIfChallenged
;
}
[
StructLayout
(
LayoutKind
.
Sequential
,
CharSet
=
CharSet
.
Unicode
)]
internal
struct
WINHTTP_PROXY_INFO
{
public
AccessType
AccessType
;
public
IntPtr
Proxy
;
public
IntPtr
ProxyBypass
;
}
internal
enum
ErrorCodes
{
Success
=
0
,
OutOfHandles
=
12001
,
Timeout
=
12002
,
InternalError
=
12004
,
InvalidUrl
=
12005
,
UnrecognizedScheme
=
12006
,
NameNotResolved
=
12007
,
InvalidOption
=
12009
,
OptionNotSettable
=
12011
,
Shutdown
=
12012
,
LoginFailure
=
12015
,
OperationCancelled
=
12017
,
IncorrectHandleType
=
12018
,
IncorrectHandleState
=
12019
,
CannotConnect
=
12029
,
ConnectionError
=
12030
,
ResendRequest
=
12032
,
SecureCertDateInvalid
=
12037
,
SecureCertCNInvalid
=
12038
,
AuthCertNeeded
=
12044
,
SecureInvalidCA
=
12045
,
SecureCertRevFailed
=
12057
,
CannotCallBeforeOpen
=
12100
,
CannotCallBeforeSend
=
12101
,
CannotCallAfterSend
=
12102
,
CannotCallAfterOpen
=
12103
,
HeaderNotFound
=
12150
,
InvalidServerResponse
=
12152
,
InvalidHeader
=
12153
,
InvalidQueryRequest
=
12154
,
HeaderAlreadyExists
=
12155
,
RedirectFailed
=
12156
,
SecureChannelError
=
12157
,
BadAutoProxyScript
=
12166
,
UnableToDownloadScript
=
12167
,
SecureInvalidCert
=
12169
,
SecureCertRevoked
=
12170
,
NotInitialized
=
12172
,
SecureFailure
=
12175
,
AutoProxyServiceError
=
12178
,
SecureCertWrongUsage
=
12179
,
AudodetectionFailed
=
12180
,
HeaderCountExceeded
=
12181
,
HeaderSizeOverflow
=
12182
,
ChunkedEncodingHeaderSizeOverflow
=
12183
,
ResponseDrainOverflow
=
12184
,
ClientCertNoPrivateKey
=
12185
,
ClientCertNoAccessPrivateKey
=
12186
}
}
}
}
Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs
0 → 100644
View file @
e1543300
using
System
;
using
System.Runtime.InteropServices
;
namespace
Titanium.Web.Proxy.Helpers.WinHttp
{
internal
class
WinHttpHandle
:
SafeHandle
{
public
WinHttpHandle
()
:
base
(
IntPtr
.
Zero
,
true
)
{
}
protected
override
bool
ReleaseHandle
()
{
return
NativeMethods
.
WinHttp
.
WinHttpCloseHandle
(
handle
);
}
public
override
bool
IsInvalid
=>
handle
==
IntPtr
.
Zero
;
}
}
\ No newline at end of file
Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs
0 → 100644
View file @
e1543300
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
e1543300
...
@@ -80,17 +80,14 @@ namespace Titanium.Web.Proxy.Http
...
@@ -80,17 +80,14 @@ namespace Titanium.Web.Proxy.Http
var
requestLines
=
new
StringBuilder
();
var
requestLines
=
new
StringBuilder
();
//prepare the request & headers
//prepare the request & headers
if
(
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
||
ServerConnection
.
UpStreamHttpsProxy
!=
null
&&
ServerConnection
.
IsHttps
)
requestLines
.
AppendLine
(
$"
{
Request
.
Method
}
{
Request
.
RequestUri
.
PathAndQuery
}
HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
);
{
requestLines
.
AppendLine
(
$"
{
Request
.
Method
}
{
Request
.
RequestUri
.
AbsoluteUri
}
HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
);
}
else
{
requestLines
.
AppendLine
(
$"
{
Request
.
Method
}
{
Request
.
RequestUri
.
PathAndQuery
}
HTTP/
{
Request
.
HttpVersion
.
Major
}
.
{
Request
.
HttpVersion
.
Minor
}
"
);
}
//Send Authentication to Upstream proxy if needed
//Send Authentication to Upstream proxy if needed
if
(
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
&&
!
string
.
IsNullOrEmpty
(
ServerConnection
.
UpStreamHttpProxy
.
UserName
)
&&
ServerConnection
.
UpStreamHttpProxy
.
Password
!=
null
)
if
(
ServerConnection
.
UpStreamHttpProxy
!=
null
&&
ServerConnection
.
IsHttps
==
false
&&
!
string
.
IsNullOrEmpty
(
ServerConnection
.
UpStreamHttpProxy
.
UserName
)
&&
ServerConnection
.
UpStreamHttpProxy
.
Password
!=
null
)
{
{
requestLines
.
AppendLine
(
"Proxy-Connection: keep-alive"
);
requestLines
.
AppendLine
(
"Proxy-Connection: keep-alive"
);
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
requestLines
.
AppendLine
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
e1543300
...
@@ -33,9 +33,11 @@ namespace Titanium.Web.Proxy.Http
...
@@ -33,9 +33,11 @@ namespace Titanium.Web.Proxy.Http
public
bool
HasBody
=>
Method
==
"POST"
||
Method
==
"PUT"
||
Method
==
"PATCH"
;
public
bool
HasBody
=>
Method
==
"POST"
||
Method
==
"PUT"
||
Method
==
"PATCH"
;
/// <summary>
/// <summary>
/// Request Http hostanem
/// Http hostname header value if exists
/// Note: Changing this does NOT change host in RequestUri
/// Users can set new RequestUri separately
/// </summary>
/// </summary>
internal
string
Host
public
string
Host
{
{
get
get
{
{
...
@@ -57,9 +59,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -57,9 +59,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// <summary>
///
Request content encoding
///
Content encoding header value
/// </summary>
/// </summary>
internal
string
ContentEncoding
public
string
ContentEncoding
{
{
get
get
{
{
...
@@ -231,7 +233,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -231,7 +233,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Encoding for this request
/// Encoding for this request
/// </summary>
/// </summary>
internal
Encoding
Encoding
=>
this
.
GetEncoding
();
public
Encoding
Encoding
=>
this
.
GetEncoding
();
/// <summary>
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request
/// Terminates the underlying Tcp Connection to client after current request
...
@@ -261,7 +263,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -261,7 +263,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Does this request has an upgrade to websocket header?
/// Does this request has an upgrade to websocket header?
/// </summary>
/// </summary>
internal
bool
UpgradeToWebSocket
public
bool
UpgradeToWebSocket
{
{
get
get
{
{
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
e1543300
...
@@ -23,12 +23,15 @@ namespace Titanium.Web.Proxy.Http
...
@@ -23,12 +23,15 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
string
ResponseStatusDescription
{
get
;
set
;
}
public
string
ResponseStatusDescription
{
get
;
set
;
}
internal
Encoding
Encoding
=>
this
.
GetResponseCharacterEncoding
();
/// <summary>
/// Encoding used in response
/// </summary>
public
Encoding
Encoding
=>
this
.
GetResponseCharacterEncoding
();
/// <summary>
/// <summary>
/// Content encoding for this response
/// Content encoding for this response
/// </summary>
/// </summary>
internal
string
ContentEncoding
public
string
ContentEncoding
{
{
get
get
{
{
...
@@ -41,12 +44,15 @@ namespace Titanium.Web.Proxy.Http
...
@@ -41,12 +44,15 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
internal
Version
HttpVersion
{
get
;
set
;
}
/// <summary>
/// Http version
/// </summary>
public
Version
HttpVersion
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Keep the connection alive?
/// Keep the connection alive?
/// </summary>
/// </summary>
internal
bool
ResponseKeepAlive
public
bool
ResponseKeepAlive
{
{
get
get
{
{
...
@@ -89,7 +95,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -89,7 +95,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Length of response body
/// Length of response body
/// </summary>
/// </summary>
internal
long
ContentLength
public
long
ContentLength
{
{
get
get
{
{
...
@@ -142,7 +148,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -142,7 +148,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Response transfer-encoding is chunked?
/// Response transfer-encoding is chunked?
/// </summary>
/// </summary>
internal
bool
IsChunked
public
bool
IsChunked
{
{
get
get
{
{
...
@@ -198,14 +204,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -198,14 +204,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
Dictionary
<
string
,
List
<
HttpHeader
>>
NonUniqueResponseHeaders
{
get
;
set
;
}
public
Dictionary
<
string
,
List
<
HttpHeader
>>
NonUniqueResponseHeaders
{
get
;
set
;
}
/// <summary>
/// Response network stream
/// </summary>
public
Stream
ResponseStream
{
get
;
set
;
}
/// <summary>
/// <summary>
/// response body conten
s
t as byte array
/// response body content as byte array
/// </summary>
/// </summary>
internal
byte
[]
ResponseBody
{
get
;
set
;
}
internal
byte
[]
ResponseBody
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
e1543300
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/RequestHandler.cs
View file @
e1543300
...
@@ -6,6 +6,7 @@ using System.Net;
...
@@ -6,6 +6,7 @@ using System.Net;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Security.Authentication
;
using
System.Security.Authentication
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
...
@@ -236,12 +237,12 @@ namespace Titanium.Web.Proxy
...
@@ -236,12 +237,12 @@ namespace Titanium.Web.Proxy
/// <param name="clientStream"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="https
HostN
ame"></param>
/// <param name="https
ConnectHostn
ame"></param>
/// <param name="endPoint"></param>
/// <param name="endPoint"></param>
/// <param name="connectHeaders"></param>
/// <param name="connectHeaders"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
<
bool
>
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
private
async
Task
<
bool
>
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
https
HostN
ame
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
https
ConnectHostn
ame
,
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
)
ProxyEndPoint
endPoint
,
List
<
HttpHeader
>
connectHeaders
)
{
{
bool
disposed
=
false
;
bool
disposed
=
false
;
...
@@ -299,9 +300,9 @@ namespace Titanium.Web.Proxy
...
@@ -299,9 +300,9 @@ namespace Titanium.Web.Proxy
//Read the request headers in to unique and non-unique header collections
//Read the request headers in to unique and non-unique header collections
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
,
args
.
WebSession
.
Request
.
RequestHeaders
);
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
NonUniqueRequestHeaders
,
args
.
WebSession
.
Request
.
RequestHeaders
);
var
httpRemoteUri
=
new
Uri
(
https
HostN
ame
==
null
var
httpRemoteUri
=
new
Uri
(
https
ConnectHostn
ame
==
null
?
httpCmdSplit
[
1
]
?
httpCmdSplit
[
1
]
:
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
??
https
HostN
ame
,
httpCmdSplit
[
1
]));
:
string
.
Concat
(
"https://"
,
args
.
WebSession
.
Request
.
Host
??
https
ConnectHostn
ame
,
httpCmdSplit
[
1
]));
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
...
@@ -311,7 +312,8 @@ namespace Titanium.Web.Proxy
...
@@ -311,7 +312,8 @@ namespace Titanium.Web.Proxy
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
if
(
httpsHostName
==
null
&&
//proxy authorization check
if
(
httpsConnectHostname
==
null
&&
await
CheckAuthorization
(
clientStreamWriter
,
await
CheckAuthorization
(
clientStreamWriter
,
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
)
args
.
WebSession
.
Request
.
RequestHeaders
.
Values
)
==
false
)
{
{
...
@@ -338,6 +340,12 @@ namespace Titanium.Web.Proxy
...
@@ -338,6 +340,12 @@ namespace Titanium.Web.Proxy
await
BeforeRequest
.
InvokeParallelAsync
(
this
,
args
);
await
BeforeRequest
.
InvokeParallelAsync
(
this
,
args
);
}
}
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
args
.
Dispose
();
break
;
}
//if upgrading to websocket then relay the requet without reading the contents
//if upgrading to websocket then relay the requet without reading the contents
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
{
...
@@ -354,6 +362,14 @@ namespace Titanium.Web.Proxy
...
@@ -354,6 +362,14 @@ namespace Titanium.Web.Proxy
{
{
connection
=
await
GetServerConnection
(
args
);
connection
=
await
GetServerConnection
(
args
);
}
}
//create a new connection if hostname changes
else
if
(!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
))
{
connection
.
Dispose
();
Interlocked
.
Decrement
(
ref
serverConnectionCount
);
connection
=
await
GetServerConnection
(
args
);
}
//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.
disposed
=
await
HandleHttpSessionRequestInternal
(
connection
,
args
,
false
);
disposed
=
await
HandleHttpSessionRequestInternal
(
connection
,
args
,
false
);
...
@@ -364,13 +380,7 @@ namespace Titanium.Web.Proxy
...
@@ -364,13 +380,7 @@ namespace Titanium.Web.Proxy
args
.
Dispose
();
args
.
Dispose
();
break
;
break
;
}
}
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
args
.
Dispose
();
break
;
}
//if connection is closing exit
//if connection is closing exit
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
==
false
)
{
{
...
@@ -415,12 +425,6 @@ namespace Titanium.Web.Proxy
...
@@ -415,12 +425,6 @@ namespace Titanium.Web.Proxy
{
{
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
args
.
WebSession
.
Request
.
RequestLocked
=
true
;
//If request was cancelled by user then dispose the client
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
{
return
true
;
}
//if expect continue is enabled then send the headers first
//if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue
//and see if server would return 100 conitinue
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
if
(
args
.
WebSession
.
Request
.
ExpectContinue
)
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e1543300
...
@@ -31,11 +31,6 @@ namespace Titanium.Web.Proxy
...
@@ -31,11 +31,6 @@ namespace Titanium.Web.Proxy
//read response & headers from server
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
await
args
.
WebSession
.
ReceiveResponse
();
if
(!
args
.
WebSession
.
Response
.
ResponseBodyRead
)
{
args
.
WebSession
.
Response
.
ResponseStream
=
args
.
WebSession
.
ServerConnection
.
Stream
;
}
//check for windows authentication
//check for windows authentication
if
(
EnableWinAuth
if
(
EnableWinAuth
&&
!
RunTime
.
IsRunningOnMono
&&
!
RunTime
.
IsRunningOnMono
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
e1543300
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
</Reference>
</Reference>
<Reference
Include=
"System"
/>
<Reference
Include=
"System"
/>
<Reference
Include=
"System.Net"
/>
<Reference
Include=
"System.Net"
/>
<Reference
Include=
"System.
c
onfiguration"
/>
<Reference
Include=
"System.
C
onfiguration"
/>
<Reference
Include=
"System.Core"
/>
<Reference
Include=
"System.Core"
/>
<Reference
Include=
"System.Xml.Linq"
/>
<Reference
Include=
"System.Xml.Linq"
/>
<Reference
Include=
"System.Data.DataSetExtensions"
/>
<Reference
Include=
"System.Data.DataSetExtensions"
/>
...
@@ -79,8 +79,12 @@
...
@@ -79,8 +79,12 @@
<Compile
Include=
"Extensions\StringExtensions.cs"
/>
<Compile
Include=
"Extensions\StringExtensions.cs"
/>
<Compile
Include=
"Helpers\BufferPool.cs"
/>
<Compile
Include=
"Helpers\BufferPool.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\ProxyInfo.cs"
/>
<Compile
Include=
"Helpers\WinHttp\NativeMethods.WinHttp.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
<Compile
Include=
"Helpers\Network.cs"
/>
<Compile
Include=
"Helpers\RunTime.cs"
/>
<Compile
Include=
"Helpers\RunTime.cs"
/>
<Compile
Include=
"Helpers\WinHttp\WinHttpHandle.cs"
/>
<Compile
Include=
"Helpers\WinHttp\WinHttpWebProxyFinder.cs"
/>
<Compile
Include=
"Http\HeaderParser.cs"
/>
<Compile
Include=
"Http\HeaderParser.cs"
/>
<Compile
Include=
"Http\Responses\GenericResponse.cs"
/>
<Compile
Include=
"Http\Responses\GenericResponse.cs"
/>
<Compile
Include=
"Network\CachedCertificate.cs"
/>
<Compile
Include=
"Network\CachedCertificate.cs"
/>
...
@@ -129,7 +133,7 @@
...
@@ -129,7 +133,7 @@
<Compile
Include=
"WinAuthHandler.cs"
/>
<Compile
Include=
"WinAuthHandler.cs"
/>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ItemGroup>
<COMReference
Include=
"CERTENROLLLib"
>
<COMReference
Include=
"CERTENROLLLib"
Condition=
"'$(OS)' != 'Unix'"
>
<Guid>
{728AB348-217D-11DA-B2A4-000E7BBB2B09}
</Guid>
<Guid>
{728AB348-217D-11DA-B2A4-000E7BBB2B09}
</Guid>
<VersionMajor>
1
</VersionMajor>
<VersionMajor>
1
</VersionMajor>
<VersionMinor>
0
</VersionMinor>
<VersionMinor>
0
</VersionMinor>
...
@@ -159,4 +163,4 @@
...
@@ -159,4 +163,4 @@
<Target Name="AfterBuild">
<Target Name="AfterBuild">
</Target>
</Target>
-->
-->
</Project>
</Project>
\ No newline at end of file
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
View file @
e1543300
...
@@ -6,8 +6,8 @@
...
@@ -6,8 +6,8 @@
<title>
Titanium web proxy
</title>
<title>
Titanium web proxy
</title>
<authors>
Titanium
</authors>
<authors>
Titanium
</authors>
<owners>
Titanium
</owners>
<owners>
Titanium
</owners>
<licenseUrl>
https://github.com/
titanium007/Titanium/blob/master
/LICENSE
</licenseUrl>
<licenseUrl>
https://github.com/
justcoding121/Titanium-Web-Proxy/blob/develop
/LICENSE
</licenseUrl>
<projectUrl>
https://github.com/
titanium007/Titanium/
</projectUrl>
<projectUrl>
https://github.com/
justcoding121/Titanium-Web-Proxy
</projectUrl>
<requireLicenseAcceptance>
false
</requireLicenseAcceptance>
<requireLicenseAcceptance>
false
</requireLicenseAcceptance>
<description>
Titanium is a light weight web proxy.
</description>
<description>
Titanium is a light weight web proxy.
</description>
<releaseNotes></releaseNotes>
<releaseNotes></releaseNotes>
...
@@ -20,4 +20,4 @@
...
@@ -20,4 +20,4 @@
<files>
<files>
<file
src=
"bin\$configuration$\Titanium.Web.Proxy.dll"
target=
"lib\net45"
/>
<file
src=
"bin\$configuration$\Titanium.Web.Proxy.dll"
target=
"lib\net45"
/>
</files>
</files>
</package>
</package>
\ 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