Commit 2316ea2d authored by Jehonathan's avatar Jehonathan Committed by GitHub

Merge pull request #142 from justcoding121/release

Merge Beta with Stable branch
parents 14016520 fa9a02c4
...@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
public ProxyTestController() public ProxyTestController()
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
proxyServer.TrustRootCertificate = true;
} }
public void StartProxy() public void StartProxy()
...@@ -115,6 +116,9 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -115,6 +116,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
//read response headers //read response headers
var responseHeaders = e.WebSession.Response.ResponseHeaders; var responseHeaders = e.WebSession.Response.ResponseHeaders;
// print out process id of current session
Console.WriteLine($"PID: {e.WebSession.ProcessId.Value}");
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return; //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST") if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
{ {
......
Doneness:
- [ ] Build is okay - I made sure that this change is building successfully.
- [ ] No Bugs - I made sure that this change is working properly as expected. It does'nt have any bugs that you are aware of.
- [ ] Branching - If this is not a hotfix, I am making this request against release branch (aka beta branch)
...@@ -17,6 +17,8 @@ Features ...@@ -17,6 +17,8 @@ Features
* Safely relays WebSocket requests over Http * Safely relays WebSocket requests over Http
* Support mutual SSL authentication * Support mutual SSL authentication
* Fully asynchronous proxy * Fully asynchronous proxy
* Supports proxy authentication
Usage Usage
===== =====
...@@ -25,18 +27,22 @@ Refer the HTTP Proxy Server library in your project, look up Test project to lea ...@@ -25,18 +27,22 @@ Refer the HTTP Proxy Server library in your project, look up Test project to lea
Install by nuget: Install by nuget:
Install-Package Titanium.Web.Proxy For beta releases on [release branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/release)
After installing nuget package mark following files to be copied to app directory Install-Package Titanium.Web.Proxy -Pre
* makecert.exe For stable releases on [master branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/master)
Install-Package Titanium.Web.Proxy
Setup HTTP proxy: Setup HTTP proxy:
```csharp ```csharp
var proxyServer = new ProxyServer(); var proxyServer = new ProxyServer();
//locally trust root certificate used by this proxy
proxyServer.TrustRootCertificate = true;
proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse; proxyServer.BeforeResponse += OnResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
...@@ -69,8 +75,8 @@ Setup HTTP proxy: ...@@ -69,8 +75,8 @@ Setup HTTP proxy:
}; };
proxyServer.AddEndPoint(transparentEndPoint); proxyServer.AddEndPoint(transparentEndPoint);
//proxyServer.ExternalHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//proxyServer.ExternalHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
foreach (var endPoint in proxyServer.ProxyEndPoints) foreach (var endPoint in proxyServer.ProxyEndPoints)
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
...@@ -176,7 +182,10 @@ Sample request and response event handlers ...@@ -176,7 +182,10 @@ Sample request and response event handlers
``` ```
Future roadmap Future roadmap
============ ============
* Implement Kerberos/NTLM authentication over HTTP protocols for windows domain
* Support Server Name Indication (SNI) for transparent endpoints * Support Server Name Indication (SNI) for transparent endpoints
* Support HTTP 2.0 * Support HTTP 2.0
* Support upstream AutoProxy detection
* Support SOCKS protocol
* Implement Kerberos/NTLM authentication over HTTP protocols for windows domain
...@@ -20,7 +20,8 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -20,7 +20,8 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
var tasks = new List<Task>(); var tasks = new List<Task>();
var mgr = new CertificateManager("Titanium","Titanium Root Certificate Authority"); var mgr = new CertificateManager("Titanium", "Titanium Root Certificate Authority",
new Lazy<Action<Exception>>(() => (e => { })).Value);
mgr.ClearIdleCertificates(1); mgr.ClearIdleCertificates(1);
...@@ -33,9 +34,9 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -33,9 +34,9 @@ namespace Titanium.Web.Proxy.UnitTests
await Task.Delay(random.Next(0, 10) * 1000); await Task.Delay(random.Next(0, 10) * 1000);
//get the connection //get the connection
var certificate = await mgr.CreateCertificate(host, false); var certificate = mgr.CreateCertificate(host, false);
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
})); }));
......
using System;
using System.Net;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.UnitTests
{
[TestClass]
public class ProxyServerTests
{
[TestMethod]
public void GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenExceptionIsThrown()
{
// Arrange
var proxy = new ProxyServer();
const int port = 9999;
var firstIpAddress = IPAddress.Parse("127.0.0.1");
var secondIpAddress = IPAddress.Parse("127.0.0.1");
proxy.AddEndPoint(new ExplicitProxyEndPoint(firstIpAddress, port, false));
// Act
try
{
proxy.AddEndPoint(new ExplicitProxyEndPoint(secondIpAddress, port, false));
}
catch (Exception exc)
{
// Assert
StringAssert.Contains(exc.Message, "Cannot add another endpoint to same port");
return;
}
Assert.Fail("An exception should be thrown by now");
}
[TestMethod]
public void GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenTwoEndpointsExists()
{
// Arrange
var proxy = new ProxyServer();
const int port = 9999;
var firstIpAddress = IPAddress.Parse("127.0.0.1");
var secondIpAddress = IPAddress.Parse("192.168.1.1");
proxy.AddEndPoint(new ExplicitProxyEndPoint(firstIpAddress, port, false));
// Act
proxy.AddEndPoint(new ExplicitProxyEndPoint(secondIpAddress, port, false));
// Assert
Assert.AreEqual(2, proxy.ProxyEndPoints.Count);
}
[TestMethod]
public void GivenOneEndpointIsAlreadyAddedToPort_WhenAddingNewEndpointToExistingPort_ThenExceptionIsThrown()
{
// Arrange
var proxy = new ProxyServer();
const int port = 9999;
proxy.AddEndPoint(new ExplicitProxyEndPoint(IPAddress.Loopback, port, false));
// Act
try
{
proxy.AddEndPoint(new ExplicitProxyEndPoint(IPAddress.Loopback, port, false));
}
catch (Exception exc)
{
// Assert
StringAssert.Contains(exc.Message, "Cannot add another endpoint to same port");
return;
}
Assert.Fail("An exception should be thrown by now");
}
[TestMethod]
public void GivenOneEndpointIsAlreadyAddedToZeroPort_WhenAddingNewEndpointToExistingPort_ThenTwoEndpointsExists()
{
// Arrange
var proxy = new ProxyServer();
const int port = 0;
proxy.AddEndPoint(new ExplicitProxyEndPoint(IPAddress.Loopback, port, false));
// Act
proxy.AddEndPoint(new ExplicitProxyEndPoint(IPAddress.Loopback, port, false));
// Assert
Assert.AreEqual(2, proxy.ProxyEndPoints.Count);
}
}
}
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="CertificateManagerTests.cs" /> <Compile Include="CertificateManagerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyServerTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj"> <ProjectReference Include="..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj">
......
...@@ -60,11 +60,12 @@ namespace Titanium.Web.Proxy ...@@ -60,11 +60,12 @@ namespace Titanium.Web.Proxy
/// Call back to select client certificate used for mutual authentication /// Call back to select client certificate used for mutual authentication
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="certificate"></param> /// <param name="targetHost"></param>
/// <param name="chain"></param> /// <param name="localCertificates"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate( internal X509Certificate SelectClientCertificate(
object sender, object sender,
string targetHost, string targetHost,
X509CertificateCollection localCertificates, X509CertificateCollection localCertificates,
...@@ -101,11 +102,11 @@ namespace Titanium.Web.Proxy ...@@ -101,11 +102,11 @@ namespace Titanium.Web.Proxy
{ {
var args = new CertificateSelectionEventArgs(); var args = new CertificateSelectionEventArgs();
args.targetHost = targetHost; args.TargetHost = targetHost;
args.localCertificates = localCertificates; args.LocalCertificates = localCertificates;
args.remoteCertificate = remoteCertificate; args.RemoteCertificate = remoteCertificate;
args.acceptableIssuers = acceptableIssuers; args.AcceptableIssuers = acceptableIssuers;
args.clientCertificate = clientCertificate; args.ClientCertificate = clientCertificate;
Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList(); Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length]; Task[] handlerTasks = new Task[invocationList.Length];
...@@ -117,7 +118,7 @@ namespace Titanium.Web.Proxy ...@@ -117,7 +118,7 @@ namespace Titanium.Web.Proxy
Task.WhenAll(handlerTasks).Wait(); Task.WhenAll(handlerTasks).Wait();
return args.clientCertificate; return args.ClientCertificate;
} }
return clientCertificate; return clientCertificate;
......
...@@ -6,19 +6,15 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -6,19 +6,15 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// An argument passed on to user for client certificate selection during mutual SSL authentication /// An argument passed on to user for client certificate selection during mutual SSL authentication
/// </summary> /// </summary>
public class CertificateSelectionEventArgs : EventArgs, IDisposable public class CertificateSelectionEventArgs : EventArgs
{ {
public object sender { get; internal set; } public object Sender { get; internal set; }
public string targetHost { get; internal set; } public string TargetHost { get; internal set; }
public X509CertificateCollection localCertificates { get; internal set; } public X509CertificateCollection LocalCertificates { get; internal set; }
public X509Certificate remoteCertificate { get; internal set; } public X509Certificate RemoteCertificate { get; internal set; }
public string[] acceptableIssuers { get; internal set; } public string[] AcceptableIssuers { get; internal set; }
public X509Certificate clientCertificate { get; set; } public X509Certificate ClientCertificate { get; set; }
public void Dispose()
{
throw new NotImplementedException();
}
} }
} }
...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Exceptions
/// <summary> /// <summary>
/// An expception thrown when body is unexpectedly empty /// An expception thrown when body is unexpectedly empty
/// </summary> /// </summary>
public class BodyNotFoundException : Exception public class BodyNotFoundException : ProxyException
{ {
public BodyNotFoundException(string message) public BodyNotFoundException(string message)
: base(message) : base(message)
......
using System;
using System.Collections.Generic;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Exceptions
{
/// <summary>
/// Proxy authorization exception
/// </summary>
public class ProxyAuthorizationException : ProxyException
{
/// <summary>
/// Instantiate new instance
/// </summary>
/// <param name="message">Exception message</param>
/// <param name="innerException">Inner exception associated to upstream proxy authorization</param>
/// <param name="headers">Http's headers associated</param>
public ProxyAuthorizationException(string message, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException)
{
Headers = headers;
}
/// <summary>
/// Headers associated with the authorization exception
/// </summary>
public IEnumerable<HttpHeader> Headers { get; }
}
}
\ No newline at end of file
using System;
namespace Titanium.Web.Proxy.Exceptions
{
/// <summary>
/// Base class exception associated with this proxy implementation
/// </summary>
public abstract class ProxyException : Exception
{
/// <summary>
/// Instantiate a new instance of this exception - must be invoked by derived classes' constructors
/// </summary>
/// <param name="message">Exception message</param>
protected ProxyException(string message) : base(message)
{
}
/// <summary>
/// Instantiate this exception - must be invoked by derived classes' constructors
/// </summary>
/// <param name="message">Excception message</param>
/// <param name="innerException">Inner exception associated</param>
protected ProxyException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
\ No newline at end of file
using System;
using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Exceptions
{
/// <summary>
/// Proxy HTTP exception
/// </summary>
public class ProxyHttpException : ProxyException
{
/// <summary>
/// Instantiate new instance
/// </summary>
/// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param>
/// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs"/> associated to the exception</param>
public ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(message, innerException)
{
SessionEventArgs = sessionEventArgs;
}
/// <summary>
/// Gets session info associated to the exception
/// </summary>
/// <remarks>
/// This object should not be edited
/// </remarks>
public SessionEventArgs SessionEventArgs { get; }
}
}
\ No newline at end of file
...@@ -29,27 +29,20 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -29,27 +29,20 @@ namespace Titanium.Web.Proxy.Extensions
await input.CopyToAsync(output); await input.CopyToAsync(output);
} }
/// <summary>
/// copies the specified bytes to the stream from the input stream /// <summary>
/// </summary> /// copies the specified bytes to the stream from the input stream
/// <param name="streamReader"></param> /// </summary>
/// <param name="stream"></param> /// <param name="streamReader"></param>
/// <param name="totalBytesToRead"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="stream"></param>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, int bufferSize, Stream stream, long totalBytesToRead) /// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, int bufferSize, Stream stream, long totalBytesToRead)
{ {
var totalbytesRead = 0; var totalbytesRead = 0;
long bytesToRead; long bytesToRead = totalBytesToRead < bufferSize ? totalBytesToRead : bufferSize;
if (totalBytesToRead < bufferSize)
{
bytesToRead = totalBytesToRead;
}
else
{
bytesToRead = bufferSize;
}
while (totalbytesRead < totalBytesToRead) while (totalbytesRead < totalBytesToRead)
{ {
...@@ -72,13 +65,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -72,13 +65,14 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
/// <summary> /// <summary>
/// Copies the stream chunked /// Copies the stream chunked
/// </summary> /// </summary>
/// <param name="clientStreamReader"></param> /// <param name="clientStreamReader"></param>
/// <param name="stream"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="stream"></param>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, int bufferSize, Stream stream) /// <returns></returns>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, int bufferSize, Stream stream)
{ {
while (true) while (true)
{ {
...@@ -117,30 +111,32 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -117,30 +111,32 @@ namespace Titanium.Web.Proxy.Extensions
await WriteResponseBodyChunked(data, clientStream); await WriteResponseBodyChunked(data, clientStream);
} }
} }
/// <summary>
/// Copies the specified content length number of bytes to the output stream from the given inputs stream /// <summary>
/// optionally chunked /// Copies the specified content length number of bytes to the output stream from the given inputs stream
/// </summary> /// optionally chunked
/// <param name="inStreamReader"></param> /// </summary>
/// <param name="outStream"></param> /// <param name="inStreamReader"></param>
/// <param name="isChunked"></param> /// <param name="bufferSize"></param>
/// <param name="ContentLength"></param> /// <param name="outStream"></param>
/// <returns></returns> /// <param name="isChunked"></param>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream, bool isChunked, long ContentLength) /// <param name="contentLength"></param>
/// <returns></returns>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream, bool isChunked, long contentLength)
{ {
if (!isChunked) if (!isChunked)
{ {
//http 1.0 //http 1.0
if (ContentLength == -1) if (contentLength == -1)
{ {
ContentLength = long.MaxValue; contentLength = long.MaxValue;
} }
int bytesToRead = bufferSize; int bytesToRead = bufferSize;
if (ContentLength < bufferSize) if (contentLength < bufferSize)
{ {
bytesToRead = (int)ContentLength; bytesToRead = (int)contentLength;
} }
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
...@@ -153,11 +149,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -153,11 +149,11 @@ namespace Titanium.Web.Proxy.Extensions
await outStream.WriteAsync(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
if (totalBytesRead == ContentLength) if (totalBytesRead == contentLength)
break; break;
bytesRead = 0; bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead); var remainingBytes = (contentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes; bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes;
} }
} }
...@@ -167,13 +163,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -167,13 +163,14 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
/// <summary> /// <summary>
/// Copies the streams chunked /// Copies the streams chunked
/// </summary> /// </summary>
/// <param name="inStreamReader"></param> /// <param name="inStreamReader"></param>
/// <param name="outStream"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="outStream"></param>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream) /// <returns></returns>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream)
{ {
while (true) while (true)
{ {
......
...@@ -37,37 +37,30 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -37,37 +37,30 @@ namespace Titanium.Web.Proxy.Helpers
{ {
using (var readBuffer = new MemoryStream()) using (var readBuffer = new MemoryStream())
{ {
try var lastChar = default(char);
{ var buffer = new byte[1];
var lastChar = default(char);
var buffer = new byte[1]; while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0)
{
while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0) //if new line
{ if (lastChar == '\r' && buffer[0] == '\n')
//if new line {
if (lastChar == '\r' && buffer[0] == '\n') var result = readBuffer.ToArray();
{ return encoding.GetString(result.SubArray(0, result.Length - 1));
var result = readBuffer.ToArray(); }
return encoding.GetString(result.SubArray(0, result.Length - 1)); //end of stream
} if (buffer[0] == '\0')
//end of stream {
if (buffer[0] == '\0') return encoding.GetString(readBuffer.ToArray());
{ }
return encoding.GetString(readBuffer.ToArray());
} await readBuffer.WriteAsync(buffer,0,1);
await readBuffer.WriteAsync(buffer,0,1); //store last char for new line comparison
lastChar = (char)buffer[0];
//store last char for new line comparison }
lastChar = (char)buffer[0];
} return encoding.GetString(readBuffer.ToArray());
return encoding.GetString(readBuffer.ToArray());
}
catch (IOException)
{
throw;
}
} }
} }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Helpers
{
internal class NetworkHelper
{
private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion)
{
var tcpRow = TcpHelper.GetExtendedTcpTable(ipVersion).FirstOrDefault(
row => row.LocalEndPoint.Port == port);
return tcpRow?.ProcessId ?? 0;
}
internal static int GetProcessIdFromPort(int port, bool ipV6Enabled)
{
var processId = FindProcessIdFromLocalPort(port, IpVersion.Ipv4);
if (processId > 0 && !ipV6Enabled)
{
return processId;
}
return FindProcessIdFromLocalPort(port, IpVersion.Ipv6);
}
/// <summary>
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address></param>
/// <returns></returns>
internal static bool IsLocalIpAddress(IPAddress address)
{
try
{
// get local IP addresses
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
// test if any host IP equals to any local IP or to localhost
// is localhost
if (IPAddress.IsLoopback(address)) return true;
// is local address
foreach (IPAddress localIP in localIPs)
{
if (address.Equals(localIP)) return true;
}
}
catch { }
return false;
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -234,13 +233,14 @@ namespace Titanium.Web.Proxy.Http ...@@ -234,13 +233,14 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Request Url /// Request Url
/// </summary> /// </summary>
public string Url { get { return RequestUri.OriginalString; } } public string Url => RequestUri.OriginalString;
/// <summary> /// <summary>
/// Encoding for this request /// Encoding for this request
/// </summary> /// </summary>
internal Encoding Encoding { get { return this.GetEncoding(); } } internal 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
/// </summary> /// </summary>
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
......
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -16,9 +15,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -16,9 +15,9 @@ namespace Titanium.Web.Proxy.Http
public string ResponseStatusCode { get; set; } public string ResponseStatusCode { get; set; }
public string ResponseStatusDescription { get; set; } public string ResponseStatusDescription { get; set; }
internal Encoding Encoding { get { return this.GetResponseCharacterEncoding(); } } internal Encoding Encoding => this.GetResponseCharacterEncoding();
/// <summary> /// <summary>
/// Content encoding for this response /// Content encoding for this response
/// </summary> /// </summary>
internal string ContentEncoding internal string ContentEncoding
...@@ -205,7 +204,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -205,7 +204,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Response network stream /// Response network stream
/// </summary> /// </summary>
internal Stream ResponseStream { get; set; } public Stream ResponseStream { get; set; }
/// <summary> /// <summary>
/// response body contenst as byte array /// response body contenst as byte array
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// 200 Ok response /// 200 Ok response
/// </summary> /// </summary>
public class OkResponse : Response public sealed class OkResponse : Response
{ {
public OkResponse() public OkResponse()
{ {
......
using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.Http.Responses
namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary> /// <summary>
/// Redirect response /// Redirect response
/// </summary> /// </summary>
public class RedirectResponse : Response public sealed class RedirectResponse : Response
{ {
public RedirectResponse() public RedirectResponse()
{ {
......
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// An abstract endpoint where the proxy listens /// An abstract endpoint where the proxy listens
/// </summary> /// </summary>
public abstract class ProxyEndPoint public abstract class ProxyEndPoint
{ {
public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
{ {
this.IpAddress = IpAddress; this.IpAddress = IpAddress;
this.Port = Port; this.Port = Port;
this.EnableSsl = EnableSsl; this.EnableSsl = EnableSsl;
} }
public IPAddress IpAddress { get; internal set; } public IPAddress IpAddress { get; internal set; }
public int Port { get; internal set; } public int Port { get; internal set; }
public bool EnableSsl { get; internal set; } public bool EnableSsl { get; internal set; }
internal TcpListener listener { get; set; } public bool IpV6Enabled => IpAddress == IPAddress.IPv6Any
} || IpAddress == IPAddress.IPv6Loopback
|| IpAddress == IPAddress.IPv6None;
/// <summary>
/// A proxy endpoint that the client is aware of internal TcpListener listener { get; set; }
/// So client application know that it is communicating with a proxy server }
/// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint /// <summary>
{ /// A proxy endpoint that the client is aware of
internal bool IsSystemHttpProxy { get; set; } /// So client application know that it is communicating with a proxy server
internal bool IsSystemHttpsProxy { get; set; } /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint
public List<string> ExcludedHttpsHostNameRegex { get; set; } {
internal bool IsSystemHttpProxy { get; set; }
public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) internal bool IsSystemHttpsProxy { get; set; }
: base(IpAddress, Port, EnableSsl)
{ public List<string> ExcludedHttpsHostNameRegex { get; set; }
} public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
} : base(IpAddress, Port, EnableSsl)
{
/// <summary>
/// A proxy end point client is not aware of }
/// Usefull when requests are redirected to this proxy end point through port forwarding }
/// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint /// <summary>
{ /// A proxy end point client is not aware of
//Name of the Certificate need to be sent (same as the hostname we want to proxy) /// Usefull when requests are redirected to this proxy end point through port forwarding
//This is valid only when UseServerNameIndication is set to false /// </summary>
public string GenericCertificateName { get; set; } public class TransparentProxyEndPoint : ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
// public bool UseServerNameIndication { get; set; } //This is valid only when UseServerNameIndication is set to false
public string GenericCertificateName { get; set; }
public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
: base(IpAddress, Port, EnableSsl)
{ // public bool UseServerNameIndication { get; set; }
this.GenericCertificateName = "localhost";
} public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
} : base(IpAddress, Port, EnableSsl)
{
} this.GenericCertificateName = "localhost";
}
}
}
namespace Titanium.Web.Proxy.Models using System;
{ using System.Net;
/// <summary>
/// An upstream proxy this proxy uses if any namespace Titanium.Web.Proxy.Models
/// </summary> {
public class ExternalProxy /// <summary>
{ /// An upstream proxy this proxy uses if any
public string HostName { get; set; } /// </summary>
public int Port { get; set; } public class ExternalProxy
} {
} private static readonly Lazy<NetworkCredential> DefaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials);
private string userName;
private string password;
public bool UseDefaultCredentials { get; set; }
public string UserName {
get { return UseDefaultCredentials ? DefaultCredentials.Value.UserName : userName; }
set
{
userName = value;
if (DefaultCredentials.Value.UserName != userName)
{
UseDefaultCredentials = false;
}
}
}
public string Password
{
get { return UseDefaultCredentials ? DefaultCredentials.Value.Password : password; }
set
{
password = value;
if (DefaultCredentials.Value.Password != password)
{
UseDefaultCredentials = false;
}
}
}
public string HostName { get; set; }
public int Port { get; set; }
}
}
This diff is collapsed.
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.IO; using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
...@@ -10,11 +11,20 @@ namespace Titanium.Web.Proxy.Network ...@@ -10,11 +11,20 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
public class TcpConnection : IDisposable public class TcpConnection : IDisposable
{ {
internal ExternalProxy UpStreamHttpProxy { get; set; }
internal ExternalProxy UpStreamHttpsProxy { get; set; }
internal string HostName { get; set; } internal string HostName { get; set; }
internal int port { get; set; } internal int Port { get; set; }
internal bool IsHttps { get; set; } internal bool IsHttps { get; set; }
/// <summary>
/// Http version
/// </summary>
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; } internal TcpClient TcpClient { get; set; }
/// <summary> /// <summary>
...@@ -27,6 +37,16 @@ namespace Titanium.Web.Proxy.Network ...@@ -27,6 +37,16 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal Stream Stream { get; set; } internal Stream Stream { get; set; }
/// <summary>
/// Last time this connection was used
/// </summary>
internal DateTime LastAccess { get; set; }
internal TcpConnection()
{
LastAccess = DateTime.Now;
}
public void Dispose() public void Dispose()
{ {
Stream.Close(); Stream.Close();
......
...@@ -7,6 +7,7 @@ using System.Net.Security; ...@@ -7,6 +7,7 @@ using System.Net.Security;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Security.Authentication; using System.Security.Authentication;
using System.Linq;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
...@@ -34,7 +35,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -34,7 +35,7 @@ namespace Titanium.Web.Proxy.Network
/// <param name="clientStream"></param> /// <param name="clientStream"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpConnection> CreateClient(int bufferSize, int connectionTimeOutSeconds, internal async Task<TcpConnection> CreateClient(int bufferSize, int connectionTimeOutSeconds,
string remoteHostName, int remotePort, Version httpVersion, string remoteHostName, int remotePort, Version httpVersion,
bool isHttps, SslProtocols supportedSslProtocols, bool isHttps, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallback, LocalCertificateSelectionCallback localCertificateSelectionCallback, RemoteCertificateValidationCallback remoteCertificateValidationCallback, LocalCertificateSelectionCallback localCertificateSelectionCallback,
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy, ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy,
...@@ -48,16 +49,22 @@ namespace Titanium.Web.Proxy.Network ...@@ -48,16 +49,22 @@ namespace Titanium.Web.Proxy.Network
SslStream sslStream = null; SslStream sslStream = null;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections //If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (externalHttpsProxy != null) if (externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName)
{ {
client = new TcpClient(externalHttpsProxy.HostName, externalHttpsProxy.Port); client = new TcpClient(externalHttpsProxy.HostName, externalHttpsProxy.Port);
stream = client.GetStream(); stream = client.GetStream();
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true))
{ {
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", remoteHostName, remotePort, httpVersion)); await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", remoteHostName, remotePort)); await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
await writer.WriteLineAsync("Connection: Keep-Alive"); await writer.WriteLineAsync("Connection: Keep-Alive");
if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null)
{
await writer.WriteLineAsync("Proxy-Connection: keep-alive");
await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password)));
}
await writer.WriteLineAsync(); await writer.WriteLineAsync();
await writer.FlushAsync(); await writer.FlushAsync();
writer.Close(); writer.Close();
...@@ -67,7 +74,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -67,7 +74,8 @@ namespace Titanium.Web.Proxy.Network
{ {
var result = await reader.ReadLineAsync(); var result = await reader.ReadLineAsync();
if (!result.ToLower().Contains("200 connection established"))
if (!new string[] { "200 OK", "connection established" }.Any(s=> result.ToLower().Contains(s.ToLower())))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
...@@ -92,17 +100,14 @@ namespace Titanium.Web.Proxy.Network ...@@ -92,17 +100,14 @@ namespace Titanium.Web.Proxy.Network
} }
catch catch
{ {
if (sslStream != null) sslStream?.Dispose();
{
sslStream.Dispose();
}
throw; throw;
} }
} }
else else
{ {
if (externalHttpProxy != null) if (externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName)
{ {
client = new TcpClient(externalHttpProxy.HostName, externalHttpProxy.Port); client = new TcpClient(externalHttpProxy.HostName, externalHttpProxy.Port);
stream = client.GetStream(); stream = client.GetStream();
...@@ -119,15 +124,18 @@ namespace Titanium.Web.Proxy.Network ...@@ -119,15 +124,18 @@ namespace Titanium.Web.Proxy.Network
stream.ReadTimeout = connectionTimeOutSeconds * 1000; stream.ReadTimeout = connectionTimeOutSeconds * 1000;
stream.WriteTimeout = connectionTimeOutSeconds * 1000; stream.WriteTimeout = connectionTimeOutSeconds * 1000;
return new TcpConnection() return new TcpConnection()
{ {
UpStreamHttpProxy = externalHttpProxy,
UpStreamHttpsProxy = externalHttpsProxy,
HostName = remoteHostName, HostName = remoteHostName,
port = remotePort, Port = remotePort,
IsHttps = isHttps, IsHttps = isHttps,
TcpClient = client, TcpClient = client,
StreamReader = new CustomBinaryReader(stream), StreamReader = new CustomBinaryReader(stream),
Stream = stream Stream = stream,
Version = httpVersion
}; };
} }
} }
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy
{
public partial class ProxyServer
{
private async Task<bool> CheckAuthorization(StreamWriter clientStreamWriter, IEnumerable<HttpHeader> Headers)
{
if (AuthenticateUserFunc == null)
{
return true;
}
var httpHeaders = Headers as HttpHeader[] ?? Headers.ToArray();
try
{
if (!httpHeaders.Where(t => t.Name == "Proxy-Authorization").Any())
{
await WriteResponseStatus(new Version(1, 1), "407",
"Proxy Authentication Required", clientStreamWriter);
var response = new Response();
response.ResponseHeaders = new Dictionary<string, HttpHeader>();
response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\""));
response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close"));
await WriteResponseHeaders(clientStreamWriter, response);
await clientStreamWriter.WriteLineAsync();
return false;
}
else
{
var headerValue = httpHeaders.Where(t => t.Name == "Proxy-Authorization").FirstOrDefault().Value.Trim();
if (!headerValue.ToLower().StartsWith("basic"))
{
//Return not authorized
await WriteResponseStatus(new Version(1, 1), "407",
"Proxy Authentication Invalid", clientStreamWriter);
var response = new Response();
response.ResponseHeaders = new Dictionary<string, HttpHeader>();
response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\""));
response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close"));
await WriteResponseHeaders(clientStreamWriter, response);
await clientStreamWriter.WriteLineAsync();
return false;
}
headerValue = headerValue.Substring(5).Trim();
var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValue));
if (decoded.Contains(":") == false)
{
//Return not authorized
await WriteResponseStatus(new Version(1, 1), "407",
"Proxy Authentication Invalid", clientStreamWriter);
var response = new Response();
response.ResponseHeaders = new Dictionary<string, HttpHeader>();
response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\""));
response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close"));
await WriteResponseHeaders(clientStreamWriter, response);
await clientStreamWriter.WriteLineAsync();
return false;
}
var username = decoded.Substring(0, decoded.IndexOf(':'));
var password = decoded.Substring(decoded.IndexOf(':') + 1);
return await AuthenticateUserFunc(username, password).ConfigureAwait(false);
}
}
catch (Exception e)
{
ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", e, httpHeaders));
//Return not authorized
await WriteResponseStatus(new Version(1, 1), "407",
"Proxy Authentication Invalid", clientStreamWriter);
var response = new Response();
response.ResponseHeaders = new Dictionary<string, HttpHeader>();
response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\""));
response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close"));
await WriteResponseHeaders(clientStreamWriter, response);
await clientStreamWriter.WriteLineAsync();
return false;
}
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
using System.Net;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Tcp
{
/// <summary>
/// Represents a managed interface of IP Helper API TcpRow struct
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
/// </summary>
internal class TcpRow
{
/// <summary>
/// Initializes a new instance of the <see cref="TcpRow"/> class.
/// </summary>
/// <param name="tcpRow">TcpRow struct.</param>
public TcpRow(NativeMethods.TcpRow tcpRow)
{
ProcessId = tcpRow.owningPid;
int localPort = (tcpRow.localPort1 << 8) + (tcpRow.localPort2) + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
long localAddress = tcpRow.localAddr;
LocalEndPoint = new IPEndPoint(localAddress, localPort);
int remotePort = (tcpRow.remotePort1 << 8) + (tcpRow.remotePort2) + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
long remoteAddress = tcpRow.remoteAddr;
RemoteEndPoint = new IPEndPoint(remoteAddress, remotePort);
}
/// <summary>
/// Gets the local end point.
/// </summary>
public IPEndPoint LocalEndPoint { get; private set; }
/// <summary>
/// Gets the remote end point.
/// </summary>
public IPEndPoint RemoteEndPoint { get; private set; }
/// <summary>
/// Gets the process identifier.
/// </summary>
public int ProcessId { get; private set; }
}
}
\ No newline at end of file
using System.Collections;
using System.Collections.Generic;
namespace Titanium.Web.Proxy.Tcp
{
/// <summary>
/// Represents collection of TcpRows
/// </summary>
/// <seealso cref="System.Collections.Generic.IEnumerable{Titanium.Web.Proxy.Tcp.TcpRow}" />
internal class TcpTable : IEnumerable<TcpRow>
{
private readonly IEnumerable<TcpRow> tcpRows;
/// <summary>
/// Initializes a new instance of the <see cref="TcpTable"/> class.
/// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param>
public TcpTable(IEnumerable<TcpRow> tcpRows)
{
this.tcpRows = tcpRows;
}
/// <summary>
/// Gets the TCP rows.
/// </summary>
public IEnumerable<TcpRow> TcpRows => tcpRows;
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator<TcpRow> GetEnumerator()
{
return tcpRows.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
\ No newline at end of file
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>bin\Debug\Titanium.Web.Proxy.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DefineConstants>NET45</DefineConstants> <DefineConstants>NET45</DefineConstants>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>bin\Release\Titanium.Web.Proxy.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Ionic.Zip, Version=1.9.8.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL"> <Reference Include="Ionic.Zip, Version=1.9.8.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
...@@ -64,9 +66,14 @@ ...@@ -64,9 +66,14 @@
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" /> <Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Helpers\Network.cs" />
<Compile Include="Network\CachedCertificate.cs" /> <Compile Include="Network\CachedCertificate.cs" />
<Compile Include="Network\CertificateMaker.cs" />
<Compile Include="Network\ProxyClient.cs" /> <Compile Include="Network\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" /> <Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Exceptions\ProxyAuthorizationException.cs" />
<Compile Include="Exceptions\ProxyException.cs" />
<Compile Include="Exceptions\ProxyHttpException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" /> <Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" /> <Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Network\CertificateManager.cs" /> <Compile Include="Network\CertificateManager.cs" />
...@@ -82,6 +89,7 @@ ...@@ -82,6 +89,7 @@
<Compile Include="Models\HttpHeader.cs" /> <Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" /> <Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyAuthorizationHandler.cs" />
<Compile Include="RequestHandler.cs" /> <Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" /> <Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" /> <Compile Include="Helpers\CustomBinaryReader.cs" />
...@@ -92,16 +100,23 @@ ...@@ -92,16 +100,23 @@
<Compile Include="Http\Responses\OkResponse.cs" /> <Compile Include="Http\Responses\OkResponse.cs" />
<Compile Include="Http\Responses\RedirectResponse.cs" /> <Compile Include="Http\Responses\RedirectResponse.cs" />
<Compile Include="Shared\ProxyConstants.cs" /> <Compile Include="Shared\ProxyConstants.cs" />
<Compile Include="Tcp\TcpRow.cs" />
<Compile Include="Tcp\TcpTable.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <COMReference Include="CERTENROLLLib">
<None Include="packages.config" /> <Guid>{728AB348-217D-11DA-B2A4-000E7BBB2B09}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="makecert.exe"> <None Include="app.config" />
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <None Include="packages.config" />
</None>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment