Commit 000f3715 authored by justcoding121's avatar justcoding121

enforce max line length; enforce one line braces

parent f870fad5
...@@ -9,14 +9,15 @@ namespace Titanium.Web.Proxy ...@@ -9,14 +9,15 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer public partial class ProxyServer
{ {
/// <summary> /// <summary>
/// Call back to override server certificate validation /// Call back to override server certificate validation
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="certificate"></param> /// <param name="certificate"></param>
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{ {
//if user callback is registered then do it //if user callback is registered then do it
if (ServerCertificateValidationCallback != null) if (ServerCertificateValidationCallback != null)
...@@ -44,7 +45,7 @@ namespace Titanium.Web.Proxy ...@@ -44,7 +45,7 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// 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="targetHost"></param> /// <param name="targetHost"></param>
...@@ -52,14 +53,15 @@ namespace Titanium.Web.Proxy ...@@ -52,14 +53,15 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param> /// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param> /// <param name="acceptableIssuers"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, internal X509Certificate SelectClientCertificate(object sender, string targetHost,
X509CertificateCollection localCertificates,
X509Certificate remoteCertificate, string[] acceptableIssuers) X509Certificate remoteCertificate, string[] acceptableIssuers)
{ {
X509Certificate clientCertificate = null; X509Certificate clientCertificate = null;
if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null && localCertificates.Count > 0) if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null &&
localCertificates.Count > 0)
{ {
// Use the first certificate that is from an acceptable issuer.
foreach (var certificate in localCertificates) foreach (var certificate in localCertificates)
{ {
string issuer = certificate.Issuer; string issuer = certificate.Issuer;
......
...@@ -4,7 +4,7 @@ using Titanium.Web.Proxy.Http; ...@@ -4,7 +4,7 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// A factory to generate the compression methods based on the type of compression /// A factory to generate the compression methods based on the type of compression
/// </summary> /// </summary>
internal static class CompressionFactory internal static class CompressionFactory
{ {
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// Concrete implementation of deflate compression /// Concrete implementation of deflate compression
/// </summary> /// </summary>
internal class DeflateCompression : ICompression internal class DeflateCompression : ICompression
{ {
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// concreate implementation of gzip compression /// concreate implementation of gzip compression
/// </summary> /// </summary>
internal class GZipCompression : ICompression internal class GZipCompression : ICompression
{ {
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// An inteface for http compression /// An inteface for http compression
/// </summary> /// </summary>
interface ICompression internal interface ICompression
{ {
Stream GetStream(Stream stream); Stream GetStream(Stream stream);
} }
......
...@@ -4,13 +4,15 @@ using Titanium.Web.Proxy.Http; ...@@ -4,13 +4,15 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// A factory to generate the de-compression methods based on the type of compression /// A factory to generate the de-compression methods based on the type of compression
/// </summary> /// </summary>
internal class DecompressionFactory internal class DecompressionFactory
{ {
//cache //cache
private static readonly Lazy<IDecompression> gzip = new Lazy<IDecompression>(() => new GZipDecompression()); private static readonly Lazy<IDecompression> gzip = new Lazy<IDecompression>(() => new GZipDecompression());
private static readonly Lazy<IDecompression> deflate = new Lazy<IDecompression>(() => new DeflateDecompression());
private static readonly Lazy<IDecompression> deflate =
new Lazy<IDecompression>(() => new DeflateDecompression());
public static IDecompression Create(string type) public static IDecompression Create(string type)
{ {
......
using StreamExtended.Helpers; using System.IO;
using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// concrete implementation of deflate de-compression /// concrete implementation of deflate de-compression
/// </summary> /// </summary>
internal class DeflateDecompression : IDecompression internal class DeflateDecompression : IDecompression
{ {
......
using StreamExtended.Helpers; using System.IO;
using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// concrete implementation of gzip de-compression /// concrete implementation of gzip de-compression
/// </summary> /// </summary>
internal class GZipDecompression : IDecompression internal class GZipDecompression : IDecompression
{ {
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// An interface for decompression /// An interface for decompression
/// </summary> /// </summary>
internal interface IDecompression internal interface IDecompression
{ {
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e); public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e);
} }
\ No newline at end of file
...@@ -4,37 +4,37 @@ using System.Security.Cryptography.X509Certificates; ...@@ -4,37 +4,37 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments 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 public class CertificateSelectionEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Sender object. /// Sender object.
/// </summary> /// </summary>
public object Sender { get; internal set; } public object Sender { get; internal set; }
/// <summary> /// <summary>
/// Target host. /// Target host.
/// </summary> /// </summary>
public string TargetHost { get; internal set; } public string TargetHost { get; internal set; }
/// <summary> /// <summary>
/// Local certificates. /// Local certificates.
/// </summary> /// </summary>
public X509CertificateCollection LocalCertificates { get; internal set; } public X509CertificateCollection LocalCertificates { get; internal set; }
/// <summary> /// <summary>
/// Remote certificate. /// Remote certificate.
/// </summary> /// </summary>
public X509Certificate RemoteCertificate { get; internal set; } public X509Certificate RemoteCertificate { get; internal set; }
/// <summary> /// <summary>
/// Acceptable issuers. /// Acceptable issuers.
/// </summary> /// </summary>
public string[] AcceptableIssuers { get; internal set; } public string[] AcceptableIssuers { get; internal set; }
/// <summary> /// <summary>
/// Client Certificate. /// Client Certificate.
/// </summary> /// </summary>
public X509Certificate ClientCertificate { get; set; } public X509Certificate ClientCertificate { get; set; }
} }
......
...@@ -5,27 +5,27 @@ using System.Security.Cryptography.X509Certificates; ...@@ -5,27 +5,27 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// An argument passed on to the user for validating the server certificate during SSL authentication /// An argument passed on to the user for validating the server certificate during SSL authentication
/// </summary> /// </summary>
public class CertificateValidationEventArgs : EventArgs public class CertificateValidationEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Certificate /// Certificate
/// </summary> /// </summary>
public X509Certificate Certificate { get; internal set; } public X509Certificate Certificate { get; internal set; }
/// <summary> /// <summary>
/// Certificate chain /// Certificate chain
/// </summary> /// </summary>
public X509Chain Chain { get; internal set; } public X509Chain Chain { get; internal set; }
/// <summary> /// <summary>
/// SSL policy errors. /// SSL policy errors.
/// </summary> /// </summary>
public SslPolicyErrors SslPolicyErrors { get; internal set; } public SslPolicyErrors SslPolicyErrors { get; internal set; }
/// <summary> /// <summary>
/// is a valid certificate? /// is a valid certificate?
/// </summary> /// </summary>
public bool IsValid { get; set; } public bool IsValid { get; set; }
} }
......
...@@ -4,17 +4,17 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -4,17 +4,17 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class DataEventArgs : EventArgs public class DataEventArgs : EventArgs
{ {
public byte[] Buffer { get; }
public int Offset { get; }
public int Count { get; }
internal DataEventArgs(byte[] buffer, int offset, int count) internal DataEventArgs(byte[] buffer, int offset, int count)
{ {
Buffer = buffer; Buffer = buffer;
Offset = offset; Offset = offset;
Count = count; Count = count;
} }
public byte[] Buffer { get; }
public int Offset { get; }
public int Count { get; }
} }
} }
\ No newline at end of file
...@@ -9,25 +9,40 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -9,25 +9,40 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
internal class LimitedStream : Stream internal class LimitedStream : Stream
{ {
private readonly CustomBufferedStream baseStream;
private readonly CustomBinaryReader baseReader; private readonly CustomBinaryReader baseReader;
private readonly CustomBufferedStream baseStream;
private readonly bool isChunked; private readonly bool isChunked;
private long bytesRemaining;
private bool readChunkTrail; private bool readChunkTrail;
private long bytesRemaining;
internal LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked, long contentLength) internal LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked,
long contentLength)
{ {
this.baseStream = baseStream; this.baseStream = baseStream;
this.baseReader = baseReader; this.baseReader = baseReader;
this.isChunked = isChunked; this.isChunked = isChunked;
bytesRemaining = isChunked bytesRemaining = isChunked
? 0 ? 0
: contentLength == -1 : contentLength == -1
? long.MaxValue ? long.MaxValue
: contentLength; : contentLength;
} }
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
private void GetNextChunk() private void GetNextChunk()
{ {
if (readChunkTrail) if (readChunkTrail)
...@@ -42,7 +57,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -42,7 +57,6 @@ namespace Titanium.Web.Proxy.EventArguments
int idx = chunkHead.IndexOf(";"); int idx = chunkHead.IndexOf(";");
if (idx >= 0) if (idx >= 0)
{ {
// remove chunk extension
chunkHead = chunkHead.Substring(0, idx); chunkHead = chunkHead.Substring(0, idx);
} }
...@@ -133,19 +147,5 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -133,19 +147,5 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
} }
} }
...@@ -5,14 +5,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -5,14 +5,14 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class MultipartRequestPartSentEventArgs : EventArgs public class MultipartRequestPartSentEventArgs : EventArgs
{ {
public string Boundary { get; }
public HeaderCollection Headers { get; }
public MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers) public MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers)
{ {
Boundary = boundary; Boundary = boundary;
Headers = headers; Headers = headers;
} }
public string Boundary { get; }
public HeaderCollection Headers { get; }
} }
} }
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Helpers; using StreamExtended.Helpers;
using StreamExtended.Network; using StreamExtended.Network;
...@@ -10,8 +11,6 @@ using Titanium.Web.Proxy.Helpers; ...@@ -10,8 +11,6 @@ using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses; using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using System.Threading;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
...@@ -30,6 +29,21 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -30,6 +29,21 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
private bool reRequest; private bool reRequest;
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
{
}
protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, Request request, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, request, exceptionFunc)
{
}
private bool hasMulipartEventSubscribers => MultipartRequestPartSent != null; private bool hasMulipartEventSubscribers => MultipartRequestPartSent != null;
/// <summary> /// <summary>
...@@ -54,21 +68,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -54,21 +68,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent; public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
{
}
protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, Request request, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, request, exceptionFunc)
{
}
private CustomBufferedStream GetStream(bool isRequest) private CustomBufferedStream GetStream(bool isRequest)
{ {
return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream; return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream;
...@@ -476,7 +475,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -476,7 +475,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
response.Headers.AddHeaders(headers); response.Headers.AddHeaders(headers);
} }
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.Body = response.Encoding.GetBytes(html ?? string.Empty); response.Body = response.Encoding.GetBytes(html ?? string.Empty);
......
...@@ -9,15 +9,15 @@ using Titanium.Web.Proxy.Network; ...@@ -9,15 +9,15 @@ using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// Holds info related to a single proxy session (single request/response sequence) /// Holds info related to a single proxy session (single request/response sequence)
/// A proxy session is bounded to a single connection from client /// A proxy session is bounded to a single connection from client
/// A proxy session ends when client terminates connection to proxy /// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy /// or when server terminates connection from proxy
/// </summary> /// </summary>
public class SessionEventArgsBase : EventArgs, IDisposable public class SessionEventArgsBase : EventArgs, IDisposable
{ {
/// <summary> /// <summary>
/// Size of Buffers used by this object /// Size of Buffers used by this object
/// </summary> /// </summary>
protected readonly int BufferSize; protected readonly int BufferSize;
...@@ -26,41 +26,78 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -26,41 +26,78 @@ namespace Titanium.Web.Proxy.EventArguments
internal CancellationTokenSource cancellationTokenSource; internal CancellationTokenSource cancellationTokenSource;
/// <summary> /// <summary>
/// Holds a reference to client /// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
{
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource,
Request request, ExceptionHandler exceptionFunc)
{
BufferSize = bufferSize;
ExceptionFunc = exceptionFunc;
this.cancellationTokenSource = cancellationTokenSource;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() =>
{
if (RunTime.IsWindows)
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
return NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled);
}
//can't access process Id of remote request from remote machine
return -1;
}
throw new PlatformNotSupportedException();
});
}
/// <summary>
/// Holds a reference to client
/// </summary> /// </summary>
internal ProxyClient ProxyClient { get; } internal ProxyClient ProxyClient { get; }
/// <summary> /// <summary>
/// Returns a unique Id for this request/response session /// Returns a unique Id for this request/response session
/// same as RequestId of WebSession /// same as RequestId of WebSession
/// </summary> /// </summary>
public Guid Id => WebSession.RequestId; public Guid Id => WebSession.RequestId;
/// <summary> /// <summary>
/// Does this session uses SSL /// Does this session uses SSL
/// </summary> /// </summary>
public bool IsHttps => WebSession.Request.IsHttps; public bool IsHttps => WebSession.Request.IsHttps;
/// <summary> /// <summary>
/// Client End Point. /// Client End Point.
/// </summary> /// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
/// <summary> /// <summary>
/// A web session corresponding to a single request/response sequence /// A web session corresponding to a single request/response sequence
/// within a proxy connection /// within a proxy connection
/// </summary> /// </summary>
public HttpWebClient WebSession { get; } public HttpWebClient WebSession { get; }
/// <summary> /// <summary>
/// Are we using a custom upstream HTTP(S) proxy? /// Are we using a custom upstream HTTP(S) proxy?
/// </summary> /// </summary>
public ExternalProxy CustomUpStreamProxyUsed { get; internal set; } public ExternalProxy CustomUpStreamProxyUsed { get; internal set; }
public event EventHandler<DataEventArgs> DataSent;
public event EventHandler<DataEventArgs> DataReceived;
public ProxyEndPoint LocalEndPoint { get; } public ProxyEndPoint LocalEndPoint { get; }
public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint; public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint;
...@@ -68,45 +105,22 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -68,45 +105,22 @@ namespace Titanium.Web.Proxy.EventArguments
public Exception Exception { get; internal set; } public Exception Exception { get; internal set; }
/// <summary> /// <summary>
/// Constructor to initialize the proxy /// implement any cleanup here
/// </summary> /// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, public virtual void Dispose()
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
{
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource,
Request request, ExceptionHandler exceptionFunc)
{ {
this.BufferSize = bufferSize; CustomUpStreamProxyUsed = null;
this.ExceptionFunc = exceptionFunc;
this.cancellationTokenSource = cancellationTokenSource;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() => DataSent = null;
{ DataReceived = null;
if (RunTime.IsWindows) Exception = null;
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id WebSession.FinishSession();
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) }
{
return NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled);
}
//can't access process Id of remote request from remote machine public event EventHandler<DataEventArgs> DataSent;
return -1;
}
throw new PlatformNotSupportedException(); public event EventHandler<DataEventArgs> DataReceived;
});
}
internal void OnDataSent(byte[] buffer, int offset, int count) internal void OnDataSent(byte[] buffer, int offset, int count)
{ {
...@@ -133,24 +147,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -133,24 +147,11 @@ namespace Titanium.Web.Proxy.EventArguments
} }
/// <summary> /// <summary>
/// Terminates the session abruptly by terminating client/server connections /// Terminates the session abruptly by terminating client/server connections
/// </summary> /// </summary>
public void TerminateSession() public void TerminateSession()
{ {
cancellationTokenSource.Cancel(); cancellationTokenSource.Cancel();
} }
/// <summary>
/// implement any cleanup here
/// </summary>
public virtual void Dispose()
{
CustomUpStreamProxyUsed = null;
DataSent = null;
DataReceived = null;
Exception = null;
WebSession.FinishSession();
}
} }
} }
using System; namespace Titanium.Web.Proxy.EventArguments
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.EventArguments
{ {
internal enum TransformationMode internal enum TransformationMode
{ {
None, None,
/// <summary> /// <summary>
/// Removes the chunked encoding /// Removes the chunked encoding
/// </summary> /// </summary>
RemoveChunked, RemoveChunked,
/// <summary> /// <summary>
/// Uncompress the body (this also removes the chunked encoding if exists) /// Uncompress the body (this also removes the chunked encoding if exists)
/// </summary> /// </summary>
Uncompress, Uncompress
} }
} }
using System; using System.Threading;
using System.Threading;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -7,18 +6,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -7,18 +6,19 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class TunnelConnectSessionEventArgs : SessionEventArgsBase public class TunnelConnectSessionEventArgs : SessionEventArgsBase
{ {
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest,
ExceptionHandler exceptionFunc, CancellationTokenSource cancellationTokenSource)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
{
}
public bool DecryptSsl { get; set; } = true; public bool DecryptSsl { get; set; } = true;
/// <summary> /// <summary>
/// Denies the connect request with a Forbidden status /// Denies the connect request with a Forbidden status
/// </summary> /// </summary>
public bool DenyConnect { get; set; } public bool DenyConnect { get; set; }
public bool IsHttpsConnect { get; internal set; } public bool IsHttpsConnect { get; internal set; }
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, ExceptionHandler exceptionFunc, CancellationTokenSource cancellationTokenSource)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
{
}
} }
} }
...@@ -3,4 +3,4 @@ using System; ...@@ -3,4 +3,4 @@ using System;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
public delegate void ExceptionHandler(Exception exception); public delegate void ExceptionHandler(Exception exception);
} }
\ No newline at end of file
namespace Titanium.Web.Proxy.Exceptions 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 : ProxyException public class BodyNotFoundException : ProxyException
{ {
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
internal BodyNotFoundException(string message) : base(message) internal BodyNotFoundException(string message) : base(message)
......
...@@ -6,18 +6,19 @@ using Titanium.Web.Proxy.Models; ...@@ -6,18 +6,19 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Proxy authorization exception /// Proxy authorization exception
/// </summary> /// </summary>
public class ProxyAuthorizationException : ProxyException public class ProxyAuthorizationException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance /// Instantiate new instance
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
/// <param name="session">The <see cref="SessionEventArgs"/> instance containing the event data.</param> /// <param name="session">The <see cref="SessionEventArgs" /> instance containing the event data.</param>
/// <param name="innerException">Inner exception associated to upstream proxy authorization</param> /// <param name="innerException">Inner exception associated to upstream proxy authorization</param>
/// <param name="headers">Http's headers associated</param> /// <param name="headers">Http's headers associated</param>
internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException) internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException,
IEnumerable<HttpHeader> headers) : base(message, innerException)
{ {
Session = session; Session = session;
Headers = headers; Headers = headers;
...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.Exceptions
public SessionEventArgsBase Session { get; } public SessionEventArgsBase Session { get; }
/// <summary> /// <summary>
/// Headers associated with the authorization exception /// Headers associated with the authorization exception
/// </summary> /// </summary>
public IEnumerable<HttpHeader> Headers { get; } public IEnumerable<HttpHeader> Headers { get; }
} }
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Base class exception associated with this proxy implementation /// Base class exception associated with this proxy implementation
/// </summary> /// </summary>
public abstract class ProxyException : Exception public abstract class ProxyException : Exception
{ {
/// <summary> /// <summary>
/// Instantiate a new instance of this exception - must be invoked by derived classes' constructors /// Instantiate a new instance of this exception - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
protected ProxyException(string message) : base(message) protected ProxyException(string message) : base(message)
...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.Exceptions
} }
/// <summary> /// <summary>
/// Instantiate this exception - must be invoked by derived classes' constructors /// Instantiate this exception - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Excception message</param> /// <param name="message">Excception message</param>
/// <param name="innerException">Inner exception associated</param> /// <param name="innerException">Inner exception associated</param>
......
...@@ -4,26 +4,27 @@ using Titanium.Web.Proxy.EventArguments; ...@@ -4,26 +4,27 @@ using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Proxy HTTP exception /// Proxy HTTP exception
/// </summary> /// </summary>
public class ProxyHttpException : ProxyException public class ProxyHttpException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance /// Instantiate new instance
/// </summary> /// </summary>
/// <param name="message">Message for this exception</param> /// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param> /// <param name="innerException">Associated inner exception</param>
/// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs"/> associated to the exception</param> /// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs" /> associated to the exception</param>
internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(message, innerException) internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(
message, innerException)
{ {
SessionEventArgs = sessionEventArgs; SessionEventArgs = sessionEventArgs;
} }
/// <summary> /// <summary>
/// Gets session info associated to the exception /// Gets session info associated to the exception
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This object should not be edited /// This object should not be edited
/// </remarks> /// </remarks>
public SessionEventArgs SessionEventArgs { get; } public SessionEventArgs SessionEventArgs { get; }
} }
......
...@@ -3,6 +3,7 @@ using System.IO; ...@@ -3,6 +3,7 @@ using System.IO;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended; using StreamExtended;
using StreamExtended.Helpers; using StreamExtended.Helpers;
...@@ -12,15 +13,14 @@ using Titanium.Web.Proxy.Exceptions; ...@@ -12,15 +13,14 @@ using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Threading;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer partial class ProxyServer
{ {
/// <summary> /// <summary>
/// This is called when client is aware of proxy /// This is called when client is aware of proxy
/// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
/// </summary> /// </summary>
/// <param name="endPoint"></param> /// <param name="endPoint"></param>
/// <param name="tcpClient"></param> /// <param name="tcpClient"></param>
...@@ -57,12 +57,13 @@ namespace Titanium.Web.Proxy ...@@ -57,12 +57,13 @@ namespace Titanium.Web.Proxy
{ {
RequestUri = httpRemoteUri, RequestUri = httpRemoteUri,
OriginalUrl = httpUrl, OriginalUrl = httpUrl,
HttpVersion = version, HttpVersion = version
}; };
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers); await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers);
var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, ExceptionFunc, cancellationTokenSource); var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
ExceptionFunc, cancellationTokenSource);
connectArgs.ProxyClient.TcpClient = tcpClient; connectArgs.ProxyClient.TcpClient = tcpClient;
connectArgs.ProxyClient.ClientStream = clientStream; connectArgs.ProxyClient.ClientStream = clientStream;
...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy ...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy
{ {
HttpVersion = HttpHeader.Version11, HttpVersion = HttpHeader.Version11,
StatusCode = (int)HttpStatusCode.Forbidden, StatusCode = (int)HttpStatusCode.Forbidden,
StatusDescription = "Forbidden", StatusDescription = "Forbidden"
}; };
} }
...@@ -128,7 +129,8 @@ namespace Titanium.Web.Proxy ...@@ -128,7 +129,8 @@ namespace Titanium.Web.Proxy
string certName = HttpHelper.GetWildCardDomainName(connectHostname); string certName = HttpHelper.GetWildCardDomainName(connectHostname);
var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName); var certificate = endPoint.GenericCertificate ??
await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);
...@@ -142,14 +144,14 @@ namespace Titanium.Web.Proxy ...@@ -142,14 +144,14 @@ namespace Titanium.Web.Proxy
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new Exception($"Could'nt authenticate client '{connectHostname}' with fake certificate.", e)); ExceptionFunc(new Exception(
$"Could'nt authenticate client '{connectHostname}' with fake certificate.", e));
sslStream?.Dispose(); sslStream?.Dispose();
return; return;
} }
if (await HttpHelper.IsConnectMethod(clientStream) == -1) if (await HttpHelper.IsConnectMethod(clientStream) == -1)
{ {
// It can be for example some Google (Cloude Messaging for Chrome) magic
decryptSsl = false; decryptSsl = false;
} }
} }
...@@ -200,7 +202,8 @@ namespace Titanium.Web.Proxy ...@@ -200,7 +202,8 @@ namespace Titanium.Web.Proxy
} }
//Now create the request //Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, clientStreamWriter, cancellationTokenSource, connectHostname, connectRequest); await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader,
clientStreamWriter, cancellationTokenSource, connectHostname, connectRequest);
} }
catch (ProxyHttpException e) catch (ProxyHttpException e)
{ {
...@@ -228,7 +231,5 @@ namespace Titanium.Web.Proxy ...@@ -228,7 +231,5 @@ namespace Titanium.Web.Proxy
} }
} }
} }
} }
} }
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
/// <summary> /// <summary>
/// Extension methods for Byte Arrays. /// Extension methods for Byte Arrays.
/// </summary> /// </summary>
internal static class ByteArrayExtensions internal static class ByteArrayExtensions
{ {
/// <summary> /// <summary>
/// Get the sub array from byte of data /// Get the sub array from byte of data
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="data"></param> /// <param name="data"></param>
......
...@@ -6,8 +6,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -6,8 +6,8 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal static class FuncExtensions internal static class FuncExtensions
{ {
public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args,
public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
var invocationList = callback.GetInvocationList(); var invocationList = callback.GetInvocationList();
...@@ -17,7 +17,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -17,7 +17,8 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc) private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args,
ExceptionHandler exceptionFunc)
{ {
try try
{ {
......
using System; using StreamExtended;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StreamExtended;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
static class SslExtensions internal static class SslExtensions
{ {
public static string GetServerName(this ClientHelloInfo clientHelloInfo) public static string GetServerName(this ClientHelloInfo clientHelloInfo)
{ {
if (clientHelloInfo.Extensions != null && clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension)) if (clientHelloInfo.Extensions != null &&
clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension))
{ {
return serverNameExtension.Data; return serverNameExtension.Data;
} }
......
...@@ -7,40 +7,43 @@ using StreamExtended.Helpers; ...@@ -7,40 +7,43 @@ using StreamExtended.Helpers;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
/// <summary> /// <summary>
/// Extensions used for Stream and CustomBinaryReader objects /// Extensions used for Stream and CustomBinaryReader objects
/// </summary> /// </summary>
internal static class StreamExtensions internal static class StreamExtensions
{ {
/// <summary> /// <summary>
/// Copy streams asynchronously /// Copy streams asynchronously
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="bufferSize"></param> /// <param name="bufferSize"></param>
internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy, int bufferSize) internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize)
{ {
return CopyToAsync(input, output, onCopy, bufferSize, CancellationToken.None); return CopyToAsync(input, output, onCopy, bufferSize, CancellationToken.None);
} }
/// <summary> /// <summary>
/// Copy streams asynchronously /// Copy streams asynchronously
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="bufferSize"></param> /// <param name="bufferSize"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy, int bufferSize, CancellationToken cancellationToken) internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, CancellationToken cancellationToken)
{ {
byte[] buffer = BufferPool.GetBuffer(bufferSize); var buffer = BufferPool.GetBuffer(bufferSize);
try try
{ {
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
// cancellation is not working on Socket ReadAsync // cancellation is not working on Socket ReadAsync
// https://github.com/dotnet/corefx/issues/15033 // https://github.com/dotnet/corefx/issues/15033
int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None).WithCancellation(cancellationToken); int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None)
.WithCancellation(cancellationToken);
int bytesRead; int bytesRead;
if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested) if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested)
{ {
...@@ -66,7 +69,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -66,7 +69,7 @@ namespace Titanium.Web.Proxy.Extensions
{ {
if (task != await Task.WhenAny(task, tcs.Task)) if (task != await Task.WhenAny(task, tcs.Task))
{ {
return default(T); return default;
} }
} }
......
...@@ -17,13 +17,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -17,13 +17,14 @@ namespace Titanium.Web.Proxy.Extensions
var method = property.GetMethod; var method = property.GetMethod;
if (method != null && method.ReturnType == typeof(bool)) if (method != null && method.ReturnType == typeof(bool))
{ {
socketCleanedUpGetter = (Func<Socket, bool>)Delegate.CreateDelegate(typeof(Func<Socket, bool>), method); socketCleanedUpGetter =
(Func<Socket, bool>)Delegate.CreateDelegate(typeof(Func<Socket, bool>), method);
} }
} }
} }
/// <summary> /// <summary>
/// Gets the local port from a native TCP row object. /// Gets the local port from a native TCP row object.
/// </summary> /// </summary>
/// <param name="tcpRow">The TCP row.</param> /// <param name="tcpRow">The TCP row.</param>
/// <returns>The local port</returns> /// <returns>The local port</returns>
...@@ -33,13 +34,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -33,13 +34,14 @@ namespace Titanium.Web.Proxy.Extensions
} }
/// <summary> /// <summary>
/// Gets the remote port from a native TCP row object. /// Gets the remote port from a native TCP row object.
/// </summary> /// </summary>
/// <param name="tcpRow">The TCP row.</param> /// <param name="tcpRow">The TCP row.</param>
/// <returns>The remote port</returns> /// <returns>The remote port</returns>
internal static int GetRemotePort(this NativeMethods.TcpRow tcpRow) internal static int GetRemotePort(this NativeMethods.TcpRow tcpRow)
{ {
return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16); return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) +
(tcpRow.remotePort4 << 16);
} }
internal static void CloseSocket(this TcpClient tcpClient) internal static void CloseSocket(this TcpClient tcpClient)
......
using StreamExtended.Network; using System;
using System;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Helpers
private static readonly Encoding defaultEncoding = Encoding.GetEncoding("ISO-8859-1"); private static readonly Encoding defaultEncoding = Encoding.GetEncoding("ISO-8859-1");
/// <summary> /// <summary>
/// Gets the character encoding of request/response from content-type header /// Gets the character encoding of request/response from content-type header
/// </summary> /// </summary>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <returns></returns> /// <returns></returns>
...@@ -37,7 +37,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -37,7 +37,6 @@ namespace Titanium.Web.Proxy.Helpers
string value = split[1]; string value = split[1];
if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase)) if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase))
{ {
//todo: what is this?
continue; continue;
} }
...@@ -87,9 +86,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -87,9 +86,9 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Tries to get root domain from a given hostname /// Tries to get root domain from a given hostname
/// Adapted from below answer /// Adapted from below answer
/// https://stackoverflow.com/questions/16473838/get-domain-name-of-a-url-in-c-sharp-net /// https://stackoverflow.com/questions/16473838/get-domain-name-of-a-url-in-c-sharp-net
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <returns></returns> /// <returns></returns>
...@@ -103,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -103,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers
int idx = hostname.IndexOf(ProxyConstants.DotSplit); int idx = hostname.IndexOf(ProxyConstants.DotSplit);
//issue #352 //issue #352
if(hostname.Substring(0, idx).Contains("-")) if (hostname.Substring(0, idx).Contains("-"))
{ {
return hostname; return hostname;
} }
...@@ -117,7 +116,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -117,7 +116,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Determines whether is connect method. /// Determines whether is connect method.
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStream">The client stream.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns> /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
...@@ -135,14 +134,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -135,14 +134,12 @@ namespace Titanium.Web.Proxy.Helpers
if (b == ' ' && i > 2) if (b == ' ' && i > 2)
{ {
// at least 3 letters and a space
return isConnect ? 1 : 0; return isConnect ? 1 : 0;
} }
char ch = (char)b; char ch = (char)b;
if (!char.IsLetter(ch)) if (!char.IsLetter(ch))
{ {
// non letter or too short
return -1; return -1;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
sealed class HttpRequestWriter : HttpWriter internal sealed class HttpRequestWriter : HttpWriter
{ {
public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize) public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
{ {
......
...@@ -5,14 +5,14 @@ using Titanium.Web.Proxy.Http; ...@@ -5,14 +5,14 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
sealed class HttpResponseWriter : HttpWriter internal sealed class HttpResponseWriter : HttpWriter
{ {
public HttpResponseWriter(Stream stream, int bufferSize) : base(stream, bufferSize) public HttpResponseWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
{ {
} }
/// <summary> /// <summary>
/// Writes the response. /// Writes the response.
/// </summary> /// </summary>
/// <param name="response"></param> /// <param name="response"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
...@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Write response status /// Write response status
/// </summary> /// </summary>
/// <param name="version"></param> /// <param name="version"></param>
/// <param name="code"></param> /// <param name="code"></param>
......
...@@ -5,7 +5,6 @@ using System.Text; ...@@ -5,7 +5,6 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Helpers; using StreamExtended.Helpers;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -13,14 +12,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -13,14 +12,12 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class HttpWriter : CustomBinaryWriter internal class HttpWriter : CustomBinaryWriter
{ {
public int BufferSize { get; }
private readonly char[] charBuffer;
private static readonly byte[] newLine = ProxyConstants.NewLine; private static readonly byte[] newLine = ProxyConstants.NewLine;
private static readonly Encoder encoder = Encoding.ASCII.GetEncoder(); private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();
private readonly char[] charBuffer;
internal HttpWriter(Stream stream, int bufferSize) : base(stream) internal HttpWriter(Stream stream, int bufferSize) : base(stream)
{ {
BufferSize = bufferSize; BufferSize = bufferSize;
...@@ -29,6 +26,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,6 +26,8 @@ namespace Titanium.Web.Proxy.Helpers
charBuffer = new char[BufferSize - 1]; charBuffer = new char[BufferSize - 1];
} }
public int BufferSize { get; }
public Task WriteLineAsync() public Task WriteLineAsync()
{ {
return WriteAsync(newLine); return WriteAsync(newLine);
...@@ -87,7 +86,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -87,7 +86,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Write the headers to client /// Write the headers to client
/// </summary> /// </summary>
/// <param name="headers"></param> /// <param name="headers"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
...@@ -102,7 +101,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -102,7 +101,6 @@ namespace Titanium.Web.Proxy.Helpers
await WriteLineAsync(); await WriteLineAsync();
if (flush) if (flush)
{ {
// flush the stream
await FlushAsync(); await FlushAsync();
} }
} }
...@@ -112,7 +110,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -112,7 +110,6 @@ namespace Titanium.Web.Proxy.Helpers
await WriteAsync(data, 0, data.Length); await WriteAsync(data, 0, data.Length);
if (flush) if (flush)
{ {
// flush the stream
await FlushAsync(); await FlushAsync();
} }
} }
...@@ -122,13 +119,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -122,13 +119,12 @@ namespace Titanium.Web.Proxy.Helpers
await WriteAsync(data, offset, count); await WriteAsync(data, offset, count);
if (flush) if (flush)
{ {
// flush the stream
await FlushAsync(); await FlushAsync();
} }
} }
/// <summary> /// <summary>
/// Writes the byte array body to the stream; optionally chunked /// Writes the byte array body to the stream; optionally chunked
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="isChunked"></param> /// <param name="isChunked"></param>
...@@ -144,24 +140,23 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -144,24 +140,23 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Copies the specified content length number of bytes to the output stream from the given inputs stream /// Copies the specified content length number of bytes to the output stream from the given inputs stream
/// optionally chunked /// optionally chunked
/// </summary> /// </summary>
/// <param name="streamReader"></param> /// <param name="streamReader"></param>
/// <param name="isChunked"></param> /// <param name="isChunked"></param>
/// <param name="contentLength"></param> /// <param name="contentLength"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <returns></returns> /// <returns></returns>
internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength, Action<byte[], int, int> onCopy) internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength,
Action<byte[], int, int> onCopy)
{ {
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (isChunked) if (isChunked)
{ {
//Need to revist, find any potential bugs
//send the body bytes to server in chunks
return CopyBodyChunkedAsync(streamReader, onCopy); return CopyBodyChunkedAsync(streamReader, onCopy);
} }
//http 1.0 or the stream reader limits the stream //http 1.0 or the stream reader limits the stream
if (contentLength == -1) if (contentLength == -1)
{ {
...@@ -173,7 +168,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -173,7 +168,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Copies the given input bytes to output stream chunked /// Copies the given input bytes to output stream chunked
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
...@@ -191,7 +186,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -191,7 +186,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Copies the streams chunked /// Copies the streams chunked
/// </summary> /// </summary>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
...@@ -204,7 +199,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -204,7 +199,6 @@ namespace Titanium.Web.Proxy.Helpers
int idx = chunkHead.IndexOf(";"); int idx = chunkHead.IndexOf(";");
if (idx >= 0) if (idx >= 0)
{ {
// remove chunk extension
chunkHead = chunkHead.Substring(0, idx); chunkHead = chunkHead.Substring(0, idx);
} }
...@@ -230,7 +224,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -230,7 +224,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Copies the specified bytes to the stream from the input stream /// Copies the specified bytes to the stream from the input stream
/// </summary> /// </summary>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <param name="count"></param> /// <param name="count"></param>
...@@ -264,7 +258,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -264,7 +258,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Writes the request/response headers and body. /// Writes the request/response headers and body.
/// </summary> /// </summary>
/// <param name="requestResponse"></param> /// <param name="requestResponse"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
......
...@@ -5,15 +5,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -5,15 +5,16 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal partial class NativeMethods internal partial class NativeMethods
{ {
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
int dwBufferLength);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow(); internal static extern IntPtr GetConsoleWindow();
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add); internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
......
...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Helpers
internal const int AfInet = 2; internal const int AfInet = 2;
internal const int AfInet6 = 23; internal const int AfInet6 = 23;
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa365928.aspx" />
/// </summary>
[DllImport("iphlpapi.dll", SetLastError = true)]
internal static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int size, bool sort, int ipVersion,
int tableClass, int reserved);
internal enum TcpTableType internal enum TcpTableType
{ {
BasicListener, BasicListener,
...@@ -19,11 +26,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -19,11 +26,11 @@ namespace Titanium.Web.Proxy.Helpers
OwnerPidAll, OwnerPidAll,
OwnerModuleListener, OwnerModuleListener,
OwnerModuleConnections, OwnerModuleConnections,
OwnerModuleAll, OwnerModuleAll
} }
/// <summary> /// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/> /// <see href="http://msdn2.microsoft.com/en-us/library/aa366921.aspx" />
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct TcpTable internal struct TcpTable
...@@ -33,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -33,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/> /// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx" />
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct TcpRow internal struct TcpRow
...@@ -51,11 +58,5 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -51,11 +58,5 @@ namespace Titanium.Web.Proxy.Helpers
public byte remotePort4; public byte remotePort4;
public int owningPid; public int owningPid;
} }
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa365928.aspx"/>
/// </summary>
[DllImport("iphlpapi.dll", SetLastError = true)]
internal static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int size, bool sort, int ipVersion, int tableClass, int reserved);
} }
} }
...@@ -26,8 +26,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -26,8 +26,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Adapated from below link /// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary> /// </summary>
/// <param name="address"></param> /// <param name="address"></param>
/// <returns></returns> /// <returns></returns>
...@@ -55,7 +55,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -55,7 +55,9 @@ namespace Titanium.Web.Proxy.Helpers
localhost = Dns.GetHostEntry(Dns.GetHostName()); localhost = Dns.GetHostEntry(Dns.GetHostName());
if (IPAddress.TryParse(hostName, out var ipAddress)) if (IPAddress.TryParse(hostName, out var ipAddress))
{
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress)); isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
}
if (!isLocalhost) if (!isLocalhost)
{ {
......
...@@ -8,25 +8,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -8,25 +8,8 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class ProxyInfo internal class ProxyInfo
{ {
public bool? AutoDetect { get; } public ProxyInfo(bool? autoDetect, string autoConfigUrl, int? proxyEnable, string proxyServer,
string proxyOverride)
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; AutoDetect = autoDetect;
AutoConfigUrl = autoConfigUrl; AutoConfigUrl = autoConfigUrl;
...@@ -68,10 +51,29 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -68,10 +51,29 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
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; }
private static string BypassStringEscape(string rawString) private static string BypassStringEscape(string rawString)
{ {
var match = var match =
new Regex("^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Match(rawString); new Regex("^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Match(rawString);
string empty1; string empty1;
string rawString1; string rawString1;
string empty2; string empty2;
...@@ -92,10 +94,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -92,10 +94,14 @@ namespace Titanium.Web.Proxy.Helpers
string str2 = ConvertRegexReservedChars(rawString1); string str2 = ConvertRegexReservedChars(rawString1);
string str3 = ConvertRegexReservedChars(empty2); string str3 = ConvertRegexReservedChars(empty2);
if (str1 == string.Empty) if (str1 == string.Empty)
{
str1 = "(?:.*://)?"; str1 = "(?:.*://)?";
}
if (str3 == string.Empty) if (str3 == string.Empty)
{
str3 = "(?::[0-9]{1,5})?"; str3 = "(?::[0-9]{1,5})?";
}
return "^" + str1 + str2 + str3 + "$"; return "^" + str1 + str2 + str3 + "$";
} }
...@@ -103,15 +109,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -103,15 +109,21 @@ namespace Titanium.Web.Proxy.Helpers
private static string ConvertRegexReservedChars(string rawString) private static string ConvertRegexReservedChars(string rawString)
{ {
if (rawString.Length == 0) if (rawString.Length == 0)
{
return rawString; return rawString;
}
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
foreach (char ch in rawString) foreach (char ch in rawString)
{ {
if ("#$()+.?[\\^{|".IndexOf(ch) != -1) if ("#$()+.?[\\^{|".IndexOf(ch) != -1)
{
stringBuilder.Append('\\'); stringBuilder.Append('\\');
}
else if (ch == 42) else if (ch == 42)
{
stringBuilder.Append('.'); stringBuilder.Append('.');
}
stringBuilder.Append(ch); stringBuilder.Append(ch);
} }
...@@ -131,7 +143,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -131,7 +143,8 @@ namespace Titanium.Web.Proxy.Helpers
{ {
protocolType = ProxyProtocolType.Http; protocolType = ProxyProtocolType.Http;
} }
else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps, StringComparison.InvariantCultureIgnoreCase)) else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps,
StringComparison.InvariantCultureIgnoreCase))
{ {
protocolType = ProxyProtocolType.Https; protocolType = ProxyProtocolType.Https;
} }
...@@ -140,7 +153,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -140,7 +153,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Parse the system proxy setting values /// Parse the system proxy setting values
/// </summary> /// </summary>
/// <param name="proxyServerValues"></param> /// <param name="proxyServerValues"></param>
/// <returns></returns> /// <returns></returns>
...@@ -149,7 +162,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -149,7 +162,9 @@ namespace Titanium.Web.Proxy.Helpers
var result = new List<HttpSystemProxyValue>(); var result = new List<HttpSystemProxyValue>();
if (string.IsNullOrWhiteSpace(proxyServerValues)) if (string.IsNullOrWhiteSpace(proxyServerValues))
{
return result; return result;
}
var proxyValues = proxyServerValues.Split(';'); var proxyValues = proxyServerValues.Split(';');
...@@ -161,14 +176,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -161,14 +176,16 @@ namespace Titanium.Web.Proxy.Helpers
{ {
var parsedValue = ParseProxyValue(proxyServerValues); var parsedValue = ParseProxyValue(proxyServerValues);
if (parsedValue != null) if (parsedValue != null)
{
result.Add(parsedValue); result.Add(parsedValue);
}
} }
return result; return result;
} }
/// <summary> /// <summary>
/// Parses the system proxy setting string /// Parses the system proxy setting string
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
...@@ -189,7 +206,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -189,7 +206,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
HostName = endPointParts[0], HostName = endPointParts[0],
Port = int.Parse(endPointParts[1]), Port = int.Parse(endPointParts[1]),
ProtocolType = protocolType.Value, ProtocolType = protocolType.Value
}; };
} }
} }
......
...@@ -4,26 +4,27 @@ using System.Runtime.InteropServices; ...@@ -4,26 +4,27 @@ using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
/// <summary> /// <summary>
/// Run time helpers /// Run time helpers
/// </summary> /// </summary>
internal class RunTime internal class RunTime
{ {
/// <summary> /// <summary>
/// cache for mono runtime check /// cache for mono runtime check
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static readonly Lazy<bool> isRunningOnMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null); private static readonly Lazy<bool> isRunningOnMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null);
#if NETSTANDARD2_0 #if NETSTANDARD2_0
/// <summary> /// <summary>
/// cache for Windows platform check /// cache for Windows platform check
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static readonly Lazy<bool> isRunningOnWindows = new Lazy<bool>(() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); private static readonly Lazy<bool> isRunningOnWindows = new Lazy<bool>(() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
#endif #endif
/// <summary> /// <summary>
/// Is running on Mono? /// Is running on Mono?
/// </summary> /// </summary>
internal static bool IsRunningOnMono => isRunningOnMono.Value; internal static bool IsRunningOnMono => isRunningOnMono.Value;
......
...@@ -9,24 +9,24 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -9,24 +9,24 @@ namespace Titanium.Web.Proxy.Helpers
public enum ProxyProtocolType public enum ProxyProtocolType
{ {
/// <summary> /// <summary>
/// The none /// The none
/// </summary> /// </summary>
None = 0, None = 0,
/// <summary> /// <summary>
/// HTTP /// HTTP
/// </summary> /// </summary>
Http = 1, Http = 1,
/// <summary> /// <summary>
/// HTTPS /// HTTPS
/// </summary> /// </summary>
Https = 2, Https = 2,
/// <summary> /// <summary>
/// Both HTTP and HTTPS /// Both HTTP and HTTPS
/// </summary> /// </summary>
AllHttp = Http | Https, AllHttp = Http | Https
} }
internal class HttpSystemProxyValue internal class HttpSystemProxyValue
...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Manage system proxy settings /// Manage system proxy settings
/// </summary> /// </summary>
internal class SystemProxyManager internal class SystemProxyManager
{ {
...@@ -94,7 +94,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -94,7 +94,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Set the HTTP and/or HTTPS proxy server for current machine /// Set the HTTP and/or HTTPS proxy server for current machine
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <param name="port"></param> /// <param name="port"></param>
...@@ -133,14 +133,15 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -133,14 +133,15 @@ namespace Titanium.Web.Proxy.Helpers
reg.DeleteValue(regAutoConfigUrl, false); reg.DeleteValue(regAutoConfigUrl, false);
reg.SetValue(regProxyEnable, 1); reg.SetValue(regProxyEnable, 1);
reg.SetValue(regProxyServer, string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray())); reg.SetValue(regProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
Refresh(); Refresh();
} }
} }
/// <summary> /// <summary>
/// Remove the HTTP and/or HTTPS proxy setting from current machine /// Remove the HTTP and/or HTTPS proxy setting from current machine
/// </summary> /// </summary>
internal void RemoveProxy(ProxyProtocolType protocolType, bool saveOriginalConfig = true) internal void RemoveProxy(ProxyProtocolType protocolType, bool saveOriginalConfig = true)
{ {
...@@ -162,7 +163,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -162,7 +163,8 @@ namespace Titanium.Web.Proxy.Helpers
if (existingSystemProxyValues.Count != 0) if (existingSystemProxyValues.Count != 0)
{ {
reg.SetValue(regProxyEnable, 1); reg.SetValue(regProxyEnable, 1);
reg.SetValue(regProxyServer, string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray())); reg.SetValue(regProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
} }
else else
{ {
...@@ -176,7 +178,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -176,7 +178,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Removes all types of proxy settings (both http and https) /// Removes all types of proxy settings (both http and https)
/// </summary> /// </summary>
internal void DisableAllProxy() internal void DisableAllProxy()
{ {
...@@ -284,7 +286,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -284,7 +286,8 @@ namespace Titanium.Web.Proxy.Helpers
private ProxyInfo GetProxyInfoFromRegistry(RegistryKey reg) private ProxyInfo GetProxyInfoFromRegistry(RegistryKey reg)
{ {
var pi = new ProxyInfo(null, reg.GetValue(regAutoConfigUrl) as string, reg.GetValue(regProxyEnable) as int?, reg.GetValue(regProxyServer) as string, var pi = new ProxyInfo(null, reg.GetValue(regAutoConfigUrl) as string, reg.GetValue(regProxyEnable) as int?,
reg.GetValue(regProxyServer) as string,
reg.GetValue(regProxyOverride) as string); reg.GetValue(regProxyOverride) as string);
return pi; return pi;
...@@ -301,7 +304,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -301,7 +304,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Prepares the proxy server registry (create empty values if they don't exist) /// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary> /// </summary>
/// <param name="reg"></param> /// <param name="reg"></param>
private static void PrepareRegistry(RegistryKey reg) private static void PrepareRegistry(RegistryKey reg)
...@@ -318,7 +321,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -318,7 +321,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Refresh the settings so that the system know about a change in proxy setting /// Refresh the settings so that the system know about a change in proxy setting
/// </summary> /// </summary>
private void Refresh() private void Refresh()
{ {
......
This diff is collapsed.
...@@ -4,21 +4,25 @@ using System.Runtime.InteropServices; ...@@ -4,21 +4,25 @@ using System.Runtime.InteropServices;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
namespace Titanium.Web.Proxy.Helpers.WinHttp namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
internal partial class NativeMethods internal class NativeMethods
{ {
internal static class WinHttp internal static class WinHttp
{ {
[DllImport("winhttp.dll", SetLastError = true)] [DllImport("winhttp.dll", SetLastError = true)]
internal static extern bool WinHttpGetIEProxyConfigForCurrentUser(ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig); internal static extern bool WinHttpGetIEProxyConfigForCurrentUser(
ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern WinHttpHandle WinHttpOpen(string userAgent, AccessType accessType, string proxyName, string proxyBypass, int dwFlags); internal static extern WinHttpHandle WinHttpOpen(string userAgent, AccessType accessType, string proxyName,
string proxyBypass, int dwFlags);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout, int connectTimeout, int sendTimeout, int receiveTimeout); internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout,
int connectTimeout, int sendTimeout, int receiveTimeout);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool WinHttpGetProxyForUrl(WinHttpHandle session, string url, [In] ref WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, internal static extern bool WinHttpGetProxyForUrl(WinHttpHandle session, string url,
[In] ref WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions,
out WINHTTP_PROXY_INFO proxyInfo); out WINHTTP_PROXY_INFO proxyInfo);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
......
...@@ -9,11 +9,11 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -9,11 +9,11 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
} }
public override bool IsInvalid => handle == IntPtr.Zero;
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
return NativeMethods.WinHttp.WinHttpCloseHandle(handle); return NativeMethods.WinHttp.WinHttpCloseHandle(handle);
} }
public override bool IsInvalid => handle == IntPtr.Zero;
} }
} }
...@@ -14,6 +14,26 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -14,6 +14,26 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private bool autoDetectFailed; private bool autoDetectFailed;
private AutoWebProxyState state; private AutoWebProxyState state;
public WinHttpWebProxyFinder()
{
session = NativeMethods.WinHttp.WinHttpOpen(null, NativeMethods.WinHttp.AccessType.NoProxy, null, null, 0);
if (session == null || session.IsInvalid)
{
int lastWin32Error = GetLastWin32Error();
}
else
{
int downloadTimeout = 60 * 1000;
if (NativeMethods.WinHttp.WinHttpSetTimeouts(session, downloadTimeout, downloadTimeout, downloadTimeout,
downloadTimeout))
{
return;
}
int lastWin32Error = GetLastWin32Error();
}
}
public ICredentials Credentials { get; set; } public ICredentials Credentials { get; set; }
public ProxyInfo ProxyInfo { get; internal set; } public ProxyInfo ProxyInfo { get; internal set; }
...@@ -28,27 +48,18 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -28,27 +48,18 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private WebProxy proxy { get; set; } private WebProxy proxy { get; set; }
public WinHttpWebProxyFinder() public void Dispose()
{ {
session = NativeMethods.WinHttp.WinHttpOpen(null, NativeMethods.WinHttp.AccessType.NoProxy, null, null, 0); Dispose(true);
if (session == null || session.IsInvalid)
{
int lastWin32Error = GetLastWin32Error();
}
else
{
int downloadTimeout = 60 * 1000;
if (NativeMethods.WinHttp.WinHttpSetTimeouts(session, downloadTimeout, downloadTimeout, downloadTimeout, downloadTimeout))
return;
int lastWin32Error = GetLastWin32Error();
}
} }
public bool GetAutoProxies(Uri destination, out IList<string> proxyList) public bool GetAutoProxies(Uri destination, out IList<string> proxyList)
{ {
proxyList = null; proxyList = null;
if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme) if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme)
{
return false; return false;
}
string proxyListString = null; string proxyListString = null;
var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed; var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed;
...@@ -64,11 +75,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -64,11 +75,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
} }
if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode)) if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode))
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, AutomaticConfigurationScript, out proxyListString); {
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, AutomaticConfigurationScript,
out proxyListString);
}
state = GetStateFromErrorCode(errorCode); state = GetStateFromErrorCode(errorCode);
if (state != AutoWebProxyState.Completed) if (state != AutoWebProxyState.Completed)
{
return false; return false;
}
if (!string.IsNullOrEmpty(proxyListString)) if (!string.IsNullOrEmpty(proxyListString))
{ {
...@@ -101,14 +117,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -101,14 +117,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var systemProxy = new ExternalProxy var systemProxy = new ExternalProxy
{ {
HostName = proxyStr, HostName = proxyStr,
Port = port, Port = port
}; };
return systemProxy; return systemProxy;
} }
if (proxy?.IsBypassed(destination) == true) if (proxy?.IsBypassed(destination) == true)
{
return null; return null;
}
var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme); var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme);
if (protocolType.HasValue) if (protocolType.HasValue)
...@@ -119,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -119,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var systemProxy = new ExternalProxy var systemProxy = new ExternalProxy
{ {
HostName = value.HostName, HostName = value.HostName,
Port = value.Port, Port = value.Port
}; };
return systemProxy; return systemProxy;
...@@ -159,7 +177,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -159,7 +177,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
else else
{ {
if (Marshal.GetLastWin32Error() == 8) if (Marshal.GetLastWin32Error() == 8)
{
throw new OutOfMemoryException(); throw new OutOfMemoryException();
}
result = new ProxyInfo(true, null, null, null, null); result = new ProxyInfo(true, null, null, null, null);
} }
...@@ -180,15 +200,13 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -180,15 +200,13 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
autoDetectFailed = false; autoDetectFailed = false;
} }
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (!disposing || session == null || session.IsInvalid) if (!disposing || session == null || session.IsInvalid)
{
return; return;
}
session.Close(); session.Close();
} }
...@@ -201,7 +219,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -201,7 +219,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
autoProxyOptions.Flags = NativeMethods.WinHttp.AutoProxyFlags.AutoDetect; autoProxyOptions.Flags = NativeMethods.WinHttp.AutoProxyFlags.AutoDetect;
autoProxyOptions.AutoConfigUrl = null; autoProxyOptions.AutoConfigUrl = null;
autoProxyOptions.AutoDetectFlags = NativeMethods.WinHttp.AutoDetectType.Dhcp | NativeMethods.WinHttp.AutoDetectType.DnsA; autoProxyOptions.AutoDetectFlags =
NativeMethods.WinHttp.AutoDetectType.Dhcp | NativeMethods.WinHttp.AutoDetectType.DnsA;
} }
else else
{ {
...@@ -218,14 +237,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -218,14 +237,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
autoProxyOptions.AutoLogonIfChallenged = true; autoProxyOptions.AutoLogonIfChallenged = true;
if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString)) if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
{
num = GetLastWin32Error(); num = GetLastWin32Error();
}
} }
} }
return num; return num;
} }
private bool WinHttpGetProxyForUrl(string destination, ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString) private bool WinHttpGetProxyForUrl(string destination,
ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString)
{ {
proxyListString = null; proxyListString = null;
bool flag; bool flag;
...@@ -233,15 +255,19 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -233,15 +255,19 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
flag = NativeMethods.WinHttp.WinHttpGetProxyForUrl(session, destination, ref autoProxyOptions, out proxyInfo); flag = NativeMethods.WinHttp.WinHttpGetProxyForUrl(session, destination, ref autoProxyOptions,
out proxyInfo);
if (flag) if (flag)
{
proxyListString = Marshal.PtrToStringUni(proxyInfo.Proxy); proxyListString = Marshal.PtrToStringUni(proxyInfo.Proxy);
}
} }
finally finally
{ {
Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.Proxy);
Marshal.FreeHGlobal(proxyInfo.ProxyBypass); Marshal.FreeHGlobal(proxyInfo.ProxyBypass);
} }
return flag; return flag;
} }
...@@ -249,7 +275,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -249,7 +275,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
int lastWin32Error = Marshal.GetLastWin32Error(); int lastWin32Error = Marshal.GetLastWin32Error();
if (lastWin32Error == 8) if (lastWin32Error == 8)
{
throw new OutOfMemoryException(); throw new OutOfMemoryException();
}
return lastWin32Error; return lastWin32Error;
} }
...@@ -274,7 +303,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -274,7 +303,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private static AutoWebProxyState GetStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode) private static AutoWebProxyState GetStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode)
{ {
if (errorCode == 0L) if (errorCode == 0L)
{
return AutoWebProxyState.Completed; return AutoWebProxyState.Completed;
}
switch (errorCode) switch (errorCode)
{ {
case NativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript: case NativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript:
...@@ -298,7 +330,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -298,7 +330,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
foreach (char c in value) foreach (char c in value)
{ {
if (!char.IsWhiteSpace(c)) if (!char.IsWhiteSpace(c))
{
stringBuilder.Append(c); stringBuilder.Append(c);
}
} }
return stringBuilder.ToString(); return stringBuilder.ToString();
...@@ -325,7 +359,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -325,7 +359,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
DownloadFailure, DownloadFailure,
CompilationFailure, CompilationFailure,
UnrecognizedScheme, UnrecognizedScheme,
Completed, Completed
} }
} }
} }
...@@ -4,11 +4,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -4,11 +4,11 @@ namespace Titanium.Web.Proxy.Http
{ {
public class ConnectRequest : Request public class ConnectRequest : Request
{ {
public ClientHelloInfo ClientHelloInfo { get; set; }
public ConnectRequest() public ConnectRequest()
{ {
Method = "CONNECT"; Method = "CONNECT";
} }
public ClientHelloInfo ClientHelloInfo { get; set; }
} }
} }
using StreamExtended; using System;
using System;
using System.Net; using System.Net;
using StreamExtended;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
public ServerHelloInfo ServerHelloInfo { get; set; } public ServerHelloInfo ServerHelloInfo { get; set; }
/// <summary> /// <summary>
/// Creates a successfull CONNECT response /// Creates a successfull CONNECT response
/// </summary> /// </summary>
/// <param name="httpVersion"></param> /// <param name="httpVersion"></param>
/// <returns></returns> /// <returns></returns>
......
...@@ -16,28 +16,44 @@ namespace Titanium.Web.Proxy.Http ...@@ -16,28 +16,44 @@ namespace Titanium.Web.Proxy.Http
private readonly Dictionary<string, List<HttpHeader>> nonUniqueHeaders; private readonly Dictionary<string, List<HttpHeader>> nonUniqueHeaders;
/// <summary> /// <summary>
/// Unique Request header collection /// Initializes a new instance of the <see cref="HeaderCollection" /> class.
/// </summary>
public HeaderCollection()
{
headers = new Dictionary<string, HttpHeader>(StringComparer.OrdinalIgnoreCase);
nonUniqueHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase);
Headers = new ReadOnlyDictionary<string, HttpHeader>(headers);
NonUniqueHeaders = new ReadOnlyDictionary<string, List<HttpHeader>>(nonUniqueHeaders);
}
/// <summary>
/// Unique Request header collection
/// </summary> /// </summary>
public ReadOnlyDictionary<string, HttpHeader> Headers { get; } public ReadOnlyDictionary<string, HttpHeader> Headers { get; }
/// <summary> /// <summary>
/// Non Unique headers /// Non Unique headers
/// </summary> /// </summary>
public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; } public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HeaderCollection"/> class. /// Returns an enumerator that iterates through the collection.
/// </summary> /// </summary>
public HeaderCollection() /// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<HttpHeader> GetEnumerator()
{ {
headers = new Dictionary<string, HttpHeader>(StringComparer.OrdinalIgnoreCase); return headers.Values.Concat(nonUniqueHeaders.Values.SelectMany(x => x)).GetEnumerator();
nonUniqueHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase); }
Headers = new ReadOnlyDictionary<string, HttpHeader>(headers);
NonUniqueHeaders = new ReadOnlyDictionary<string, List<HttpHeader>>(nonUniqueHeaders); IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
} }
/// <summary> /// <summary>
/// True if header exists /// True if header exists
/// </summary> /// </summary>
/// <param name="name"></param> /// <param name="name"></param>
/// <returns></returns> /// <returns></returns>
...@@ -47,8 +63,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -47,8 +63,8 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Returns all headers with given name if exists /// Returns all headers with given name if exists
/// Returns null if does'nt exist /// Returns null if does'nt exist
/// </summary> /// </summary>
/// <param name="name"></param> /// <param name="name"></param>
/// <returns></returns> /// <returns></returns>
...@@ -86,7 +102,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -86,7 +102,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Returns all headers /// Returns all headers
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public List<HttpHeader> GetAllHeaders() public List<HttpHeader> GetAllHeaders()
...@@ -100,7 +116,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -100,7 +116,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Add a new header with given name and value /// Add a new header with given name and value
/// </summary> /// </summary>
/// <param name="name"></param> /// <param name="name"></param>
/// <param name="value"></param> /// <param name="value"></param>
...@@ -110,7 +126,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -110,7 +126,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Adds the given header object to Request /// Adds the given header object to Request
/// </summary> /// </summary>
/// <param name="newHeader"></param> /// <param name="newHeader"></param>
public void AddHeader(HttpHeader newHeader) public void AddHeader(HttpHeader newHeader)
...@@ -142,7 +158,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -142,7 +158,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Adds the given header objects to Request /// Adds the given header objects to Request
/// </summary> /// </summary>
/// <param name="newHeaders"></param> /// <param name="newHeaders"></param>
public void AddHeaders(IEnumerable<HttpHeader> newHeaders) public void AddHeaders(IEnumerable<HttpHeader> newHeaders)
...@@ -159,7 +175,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -159,7 +175,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Adds the given header objects to Request /// Adds the given header objects to Request
/// </summary> /// </summary>
/// <param name="newHeaders"></param> /// <param name="newHeaders"></param>
public void AddHeaders(IEnumerable<KeyValuePair<string, string>> newHeaders) public void AddHeaders(IEnumerable<KeyValuePair<string, string>> newHeaders)
...@@ -176,7 +192,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -176,7 +192,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Adds the given header objects to Request /// Adds the given header objects to Request
/// </summary> /// </summary>
/// <param name="newHeaders"></param> /// <param name="newHeaders"></param>
public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>> newHeaders) public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>> newHeaders)
...@@ -190,7 +206,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -190,7 +206,8 @@ namespace Titanium.Web.Proxy.Http
{ {
if (header.Key != header.Value.Name) if (header.Key != header.Value.Name)
{ {
throw new Exception("Header name mismatch. Key and the name of the HttpHeader object should be the same."); throw new Exception(
"Header name mismatch. Key and the name of the HttpHeader object should be the same.");
} }
AddHeader(header.Value); AddHeader(header.Value);
...@@ -198,11 +215,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -198,11 +215,13 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// removes all headers with given name /// removes all headers with given name
/// </summary> /// </summary>
/// <param name="headerName"></param> /// <param name="headerName"></param>
/// <returns>True if header was removed /// <returns>
/// False if no header exists with given name</returns> /// True if header was removed
/// False if no header exists with given name
/// </returns>
public bool RemoveHeader(string headerName) public bool RemoveHeader(string headerName)
{ {
bool result = headers.Remove(headerName); bool result = headers.Remove(headerName);
...@@ -217,7 +236,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -217,7 +236,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Removes given header object if it exist /// Removes given header object if it exist
/// </summary> /// </summary>
/// <param name="header">Returns true if header exists and was removed </param> /// <param name="header">Returns true if header exists and was removed </param>
public bool RemoveHeader(HttpHeader header) public bool RemoveHeader(HttpHeader header)
...@@ -242,7 +261,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -242,7 +261,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Removes all the headers. /// Removes all the headers.
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
...@@ -273,7 +292,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -273,7 +292,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Fix proxy specific headers /// Fix proxy specific headers
/// </summary> /// </summary>
internal void FixProxyHeaders() internal void FixProxyHeaders()
{ {
...@@ -286,21 +305,5 @@ namespace Titanium.Web.Proxy.Http ...@@ -286,21 +305,5 @@ namespace Titanium.Web.Proxy.Http
SetOrAddHeaderValue(KnownHeaders.Connection, proxyHeader); SetOrAddHeaderValue(KnownHeaders.Connection, proxyHeader);
} }
} }
/// <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<HttpHeader> GetEnumerator()
{
return headers.Values.Concat(nonUniqueHeaders.Values.SelectMany(x => x)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} }
} }
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
...@@ -20,7 +18,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -20,7 +18,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Increase size of buffer and copy existing content to new buffer /// Increase size of buffer and copy existing content to new buffer
/// </summary> /// </summary>
/// <param name="buffer"></param> /// <param name="buffer"></param>
/// <param name="size"></param> /// <param name="size"></param>
......
...@@ -9,66 +9,66 @@ using Titanium.Web.Proxy.Network.Tcp; ...@@ -9,66 +9,66 @@ using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary> /// <summary>
/// Used to communicate with the server over HTTP(S) /// Used to communicate with the server over HTTP(S)
/// </summary> /// </summary>
public class HttpWebClient public class HttpWebClient
{ {
private readonly int bufferSize; private readonly int bufferSize;
internal HttpWebClient(int bufferSize, Request request = null, Response response = null)
{
this.bufferSize = bufferSize;
RequestId = Guid.NewGuid();
Request = request ?? new Request();
Response = response ?? new Response();
}
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
internal TcpConnection ServerConnection { get; set; } internal TcpConnection ServerConnection { get; set; }
/// <summary> /// <summary>
/// Request ID. /// Request ID.
/// </summary> /// </summary>
public Guid RequestId { get; } public Guid RequestId { get; }
/// <summary> /// <summary>
/// Override UpStreamEndPoint for this request; Local NIC via request is made /// Override UpStreamEndPoint for this request; Local NIC via request is made
/// </summary> /// </summary>
public IPEndPoint UpStreamEndPoint { get; set; } public IPEndPoint UpStreamEndPoint { get; set; }
/// <summary> /// <summary>
/// Headers passed with Connect. /// Headers passed with Connect.
/// </summary> /// </summary>
public ConnectRequest ConnectRequest { get; internal set; } public ConnectRequest ConnectRequest { get; internal set; }
/// <summary> /// <summary>
/// Web Request. /// Web Request.
/// </summary> /// </summary>
public Request Request { get; } public Request Request { get; }
/// <summary> /// <summary>
/// Web Response. /// Web Response.
/// </summary> /// </summary>
public Response Response { get; internal set; } public Response Response { get; internal set; }
/// <summary> /// <summary>
/// PID of the process that is created the current session when client is running in this machine /// PID of the process that is created the current session when client is running in this machine
/// If client is remote then this will return /// If client is remote then this will return
/// </summary> /// </summary>
public Lazy<int> ProcessId { get; internal set; } public Lazy<int> ProcessId { get; internal set; }
/// <summary> /// <summary>
/// Is Https? /// Is Https?
/// </summary> /// </summary>
public bool IsHttps => Request.IsHttps; public bool IsHttps => Request.IsHttps;
internal HttpWebClient(int bufferSize, Request request = null, Response response = null)
{
this.bufferSize = bufferSize;
RequestId = Guid.NewGuid();
Request = request ?? new Request();
Response = response ?? new Response();
}
/// <summary> /// <summary>
/// Set the tcp connection to server used by this webclient /// Set the tcp connection to server used by this webclient
/// </summary> /// </summary>
/// <param name="connection">Instance of <see cref="TcpConnection"/></param> /// <param name="connection">Instance of <see cref="TcpConnection" /></param>
internal void SetConnection(TcpConnection connection) internal void SetConnection(TcpConnection connection)
{ {
connection.LastAccess = DateTime.Now; connection.LastAccess = DateTime.Now;
...@@ -76,7 +76,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -76,7 +76,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Prepare and send the http(s) request /// Prepare and send the http(s) request
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent) internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent)
...@@ -95,12 +95,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -95,12 +95,13 @@ namespace Titanium.Web.Proxy.Http
//Send Authentication to Upstream proxy if needed //Send Authentication to Upstream proxy if needed
if (!isTransparent && upstreamProxy != null if (!isTransparent && upstreamProxy != null
&& ServerConnection.IsHttps == false && ServerConnection.IsHttps == false
&& !string.IsNullOrEmpty(upstreamProxy.UserName) && !string.IsNullOrEmpty(upstreamProxy.UserName)
&& upstreamProxy.Password != null) && upstreamProxy.Password != null)
{ {
await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer); await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer);
await HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password).WriteToStreamAsync(writer); await HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)
.WriteToStreamAsync(writer);
} }
//write request headers //write request headers
...@@ -120,7 +121,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -120,7 +121,8 @@ namespace Titanium.Web.Proxy.Http
{ {
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, out string responseStatusDescription); Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription);
//find if server is willing for expect continue //find if server is willing for expect continue
if (responseStatusCode == (int)HttpStatusCode.Continue if (responseStatusCode == (int)HttpStatusCode.Continue
...@@ -140,14 +142,16 @@ namespace Titanium.Web.Proxy.Http ...@@ -140,14 +142,16 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Receive and parse the http response from server /// Receive and parse the http response from server
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task ReceiveResponse() internal async Task ReceiveResponse()
{ {
//return if this is already read //return if this is already read
if (Response.StatusCode != 0) if (Response.StatusCode != 0)
{
return; return;
}
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
if (httpStatus == null) if (httpStatus == null)
...@@ -157,7 +161,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -157,7 +161,6 @@ namespace Titanium.Web.Proxy.Http
if (httpStatus == string.Empty) if (httpStatus == string.Empty)
{ {
//Empty content in first-line, try again
httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
} }
...@@ -199,7 +202,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -199,7 +202,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary> /// </summary>
internal void FinishSession() internal void FinishSession()
{ {
......
using System; namespace Titanium.Web.Proxy.Http
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Http
{ {
public static class KnownHeaders public static class KnownHeaders
{ {
......
...@@ -9,33 +9,33 @@ using Titanium.Web.Proxy.Shared; ...@@ -9,33 +9,33 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary> /// <summary>
/// Http(s) request object /// Http(s) request object
/// </summary> /// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))] [TypeConverter(typeof(ExpandableObjectConverter))]
public class Request : RequestResponseBase public class Request : RequestResponseBase
{ {
/// <summary> /// <summary>
/// Request Method /// Request Method
/// </summary> /// </summary>
public string Method { get; set; } public string Method { get; set; }
/// <summary> /// <summary>
/// Request HTTP Uri /// Request HTTP Uri
/// </summary> /// </summary>
public Uri RequestUri { get; set; } public Uri RequestUri { get; set; }
/// <summary> /// <summary>
/// Is Https? /// Is Https?
/// </summary> /// </summary>
public bool IsHttps => RequestUri.Scheme == ProxyServer.UriSchemeHttps; public bool IsHttps => RequestUri.Scheme == ProxyServer.UriSchemeHttps;
/// <summary> /// <summary>
/// The original request Url. /// The original request Url.
/// </summary> /// </summary>
public string OriginalUrl { get; set; } public string OriginalUrl { get; set; }
/// <summary> /// <summary>
/// Has request body? /// Has request body?
/// </summary> /// </summary>
public override bool HasBody public override bool HasBody
{ {
...@@ -66,9 +66,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -66,9 +66,9 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Http hostname header value if exists /// Http hostname header value if exists
/// Note: Changing this does NOT change host in RequestUri /// Note: Changing this does NOT change host in RequestUri
/// Users can set new RequestUri separately /// Users can set new RequestUri separately
/// </summary> /// </summary>
public string Host public string Host
{ {
...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Does this request has a 100-continue header? /// Does this request has a 100-continue header?
/// </summary> /// </summary>
public bool ExpectContinue public bool ExpectContinue
{ {
...@@ -91,47 +91,17 @@ namespace Titanium.Web.Proxy.Http ...@@ -91,47 +91,17 @@ namespace Titanium.Web.Proxy.Http
public bool IsMultipartFormData => ContentType?.StartsWith("multipart/form-data") == true; public bool IsMultipartFormData => ContentType?.StartsWith("multipart/form-data") == true;
/// <summary> /// <summary>
/// Request Url /// Request Url
/// </summary> /// </summary>
public string Url => RequestUri.OriginalString; public string Url => RequestUri.OriginalString;
/// <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; }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
//GET request don't have a request body to read
if (!HasBody)
{
throw new BodyNotFoundException("Request don't have a body. " + "Please verify that this request is a Http POST/PUT/PATCH and request " +
"content length is greater than zero before accessing the body.");
}
if (!IsBodyRead)
{
if (Locked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
if (throwWhenNotReadYet)
{
throw new Exception("Request body is not read yet. " +
"Use SessionEventArgs.GetRequestBody() or SessionEventArgs.GetRequestBodyAsString() " +
"method to read the request body.");
}
}
}
/// <summary> /// <summary>
/// Does this request has an upgrade to websocket header? /// Does this request has an upgrade to websocket header?
/// </summary> /// </summary>
public bool UpgradeToWebSocket public bool UpgradeToWebSocket
{ {
...@@ -149,17 +119,17 @@ namespace Titanium.Web.Proxy.Http ...@@ -149,17 +119,17 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Does server responsed positively for 100 continue request /// Does server responsed positively for 100 continue request
/// </summary> /// </summary>
public bool Is100Continue { get; internal set; } public bool Is100Continue { get; internal set; }
/// <summary> /// <summary>
/// Server responsed negatively for the request for 100 continue /// Server responsed negatively for the request for 100 continue
/// </summary> /// </summary>
public bool ExpectationFailed { get; internal set; } public bool ExpectationFailed { get; internal set; }
/// <summary> /// <summary>
/// Gets the header text. /// Gets the header text.
/// </summary> /// </summary>
public override string HeaderText public override string HeaderText
{ {
...@@ -177,12 +147,44 @@ namespace Titanium.Web.Proxy.Http ...@@ -177,12 +147,44 @@ namespace Titanium.Web.Proxy.Http
} }
} }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
//GET request don't have a request body to read
if (!HasBody)
{
throw new BodyNotFoundException("Request don't have a body. " +
"Please verify that this request is a Http POST/PUT/PATCH and request " +
"content length is greater than zero before accessing the body.");
}
if (!IsBodyRead)
{
if (Locked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
if (throwWhenNotReadYet)
{
throw new Exception("Request body is not read yet. " +
"Use SessionEventArgs.GetRequestBody() or SessionEventArgs.GetRequestBodyAsString() " +
"method to read the request body.");
}
}
}
internal static string CreateRequestLine(string httpMethod, string httpUrl, Version version) internal static string CreateRequestLine(string httpMethod, string httpUrl, Version version)
{ {
return $"{httpMethod} {httpUrl} HTTP/{version.Major}.{version.Minor}"; return $"{httpMethod} {httpUrl} HTTP/{version.Major}.{version.Minor}";
} }
internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl, out Version version) internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl,
out Version version)
{ {
//break up the line into three components (method, remote URL & Http Version) //break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
...@@ -196,11 +198,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -196,11 +198,6 @@ namespace Titanium.Web.Proxy.Http
httpMethod = httpCmdSplit[0]; httpMethod = httpCmdSplit[0];
if (!IsAllUpper(httpMethod)) if (!IsAllUpper(httpMethod))
{ {
//method should be upper cased: https://tools.ietf.org/html/rfc7231#section-4
//todo: create protocol violation message
//fix it
httpMethod = httpMethod.ToUpper(); httpMethod = httpMethod.ToUpper();
} }
......
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -14,32 +12,37 @@ namespace Titanium.Web.Proxy.Http ...@@ -14,32 +12,37 @@ namespace Titanium.Web.Proxy.Http
public abstract class RequestResponseBase public abstract class RequestResponseBase
{ {
/// <summary> /// <summary>
/// Cached body content as byte array /// Cached body content as byte array
/// </summary> /// </summary>
protected byte[] BodyInternal; protected byte[] BodyInternal;
/// <summary> /// <summary>
/// Cached body as string /// Cached body as string
/// </summary> /// </summary>
private string bodyString; private string bodyString;
/// <summary> /// <summary>
/// Keeps the body data after the session is finished /// Store weather the original request/response has body or not, since the user may change the parameters
/// </summary>
internal bool OriginalHasBody;
/// <summary>
/// Keeps the body data after the session is finished
/// </summary> /// </summary>
public bool KeepBody { get; set; } public bool KeepBody { get; set; }
/// <summary> /// <summary>
/// Http Version /// Http Version
/// </summary> /// </summary>
public Version HttpVersion { get; set; } = HttpHeader.VersionUnknown; public Version HttpVersion { get; set; } = HttpHeader.VersionUnknown;
/// <summary> /// <summary>
/// Collection of all headers /// Collection of all headers
/// </summary> /// </summary>
public HeaderCollection Headers { get; } = new HeaderCollection(); public HeaderCollection Headers { get; } = new HeaderCollection();
/// <summary> /// <summary>
/// Length of the body /// Length of the body
/// </summary> /// </summary>
public long ContentLength public long ContentLength
{ {
...@@ -74,17 +77,17 @@ namespace Titanium.Web.Proxy.Http ...@@ -74,17 +77,17 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Content encoding for this request/response /// Content encoding for this request/response
/// </summary> /// </summary>
public string ContentEncoding => Headers.GetHeaderValueOrNull(KnownHeaders.ContentEncoding)?.Trim(); public string ContentEncoding => Headers.GetHeaderValueOrNull(KnownHeaders.ContentEncoding)?.Trim();
/// <summary> /// <summary>
/// Encoding for this request/response /// Encoding for this request/response
/// </summary> /// </summary>
public Encoding Encoding => HttpHelper.GetEncodingFromContentType(ContentType); public Encoding Encoding => HttpHelper.GetEncodingFromContentType(ContentType);
/// <summary> /// <summary>
/// Content-type of the request/response /// Content-type of the request/response
/// </summary> /// </summary>
public string ContentType public string ContentType
{ {
...@@ -93,7 +96,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -93,7 +96,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Is body send as chunked bytes /// Is body send as chunked bytes
/// </summary> /// </summary>
public bool IsChunked public bool IsChunked
{ {
...@@ -119,7 +122,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -119,7 +122,7 @@ namespace Titanium.Web.Proxy.Http
public abstract string HeaderText { get; } public abstract string HeaderText { get; }
/// <summary> /// <summary>
/// Body as byte array /// Body as byte array
/// </summary> /// </summary>
[Browsable(false)] [Browsable(false)]
public byte[] Body public byte[] Body
...@@ -140,19 +143,31 @@ namespace Titanium.Web.Proxy.Http ...@@ -140,19 +143,31 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Has the request/response body? /// Has the request/response body?
/// </summary> /// </summary>
public abstract bool HasBody { get; } public abstract bool HasBody { get; }
/// <summary> /// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters /// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// </summary> /// </summary>
internal bool OriginalHasBody; [Browsable(false)]
public string BodyString => bodyString ?? (bodyString = Encoding.GetString(Body));
/// <summary>
/// Was the body read by user?
/// </summary>
public bool IsBodyRead { get; internal set; }
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// </summary>
internal bool Locked { get; set; }
internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true); internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true);
/// <summary> /// <summary>
/// get the compressed body from given bytes /// get the compressed body from given bytes
/// </summary> /// </summary>
/// <param name="encodingType"></param> /// <param name="encodingType"></param>
/// <param name="body"></param> /// <param name="body"></param>
...@@ -205,30 +220,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -205,30 +220,13 @@ namespace Titanium.Web.Proxy.Http
return null; return null;
} }
/// <summary>
/// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// </summary>
[Browsable(false)]
public string BodyString => bodyString ?? (bodyString = Encoding.GetString(Body));
/// <summary>
/// Was the body read by user?
/// </summary>
public bool IsBodyRead { get; internal set; }
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// </summary>
internal bool Locked { get; set; }
internal void UpdateContentLength() internal void UpdateContentLength()
{ {
ContentLength = IsChunked ? -1 : BodyInternal?.Length ?? 0; ContentLength = IsChunked ? -1 : BodyInternal?.Length ?? 0;
} }
/// <summary> /// <summary>
/// Finish the session /// Finish the session
/// </summary> /// </summary>
internal void FinishSession() internal void FinishSession()
{ {
......
...@@ -8,23 +8,38 @@ using Titanium.Web.Proxy.Shared; ...@@ -8,23 +8,38 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary> /// <summary>
/// Http(s) response object /// Http(s) response object
/// </summary> /// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))] [TypeConverter(typeof(ExpandableObjectConverter))]
public class Response : RequestResponseBase public class Response : RequestResponseBase
{ {
/// <summary> /// <summary>
/// Response Status Code. /// Constructor.
/// </summary>
public Response()
{
}
/// <summary>
/// Constructor.
/// </summary>
public Response(byte[] body)
{
Body = body;
}
/// <summary>
/// Response Status Code.
/// </summary> /// </summary>
public int StatusCode { get; set; } public int StatusCode { get; set; }
/// <summary> /// <summary>
/// Response Status description. /// Response Status description.
/// </summary> /// </summary>
public string StatusDescription { get; set; } public string StatusDescription { get; set; }
/// <summary> /// <summary>
/// Has response body? /// Has response body?
/// </summary> /// </summary>
public override bool HasBody public override bool HasBody
{ {
...@@ -57,7 +72,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -57,7 +72,7 @@ namespace Titanium.Web.Proxy.Http
} }
/// <summary> /// <summary>
/// Keep the connection alive? /// Keep the connection alive?
/// </summary> /// </summary>
public bool KeepAlive public bool KeepAlive
{ {
...@@ -79,38 +94,23 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,38 +94,23 @@ namespace Titanium.Web.Proxy.Http
internal bool TerminateResponse { get; set; } internal bool TerminateResponse { get; set; }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
if (!IsBodyRead && throwWhenNotReadYet)
{
throw new Exception("Response body is not read yet. " +
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() " +
"method to read the response body.");
}
}
/// <summary> /// <summary>
/// Is response 100-continue /// Is response 100-continue
/// </summary> /// </summary>
public bool Is100Continue { get; internal set; } public bool Is100Continue { get; internal set; }
/// <summary> /// <summary>
/// expectation failed returned by server? /// expectation failed returned by server?
/// </summary> /// </summary>
public bool ExpectationFailed { get; internal set; } public bool ExpectationFailed { get; internal set; }
/// <summary> /// <summary>
/// Gets the resposne status. /// Gets the resposne status.
/// </summary> /// </summary>
public string Status => CreateResponseLine(HttpVersion, StatusCode, StatusDescription); public string Status => CreateResponseLine(HttpVersion, StatusCode, StatusDescription);
/// <summary> /// <summary>
/// Gets the header text. /// Gets the header text.
/// </summary> /// </summary>
public override string HeaderText public override string HeaderText
{ {
...@@ -128,19 +128,19 @@ namespace Titanium.Web.Proxy.Http ...@@ -128,19 +128,19 @@ namespace Titanium.Web.Proxy.Http
} }
} }
/// <summary> internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
/// Constructor.
/// </summary>
public Response()
{ {
} if (BodyInternal != null)
{
return;
}
/// <summary> if (!IsBodyRead && throwWhenNotReadYet)
/// Constructor. {
/// </summary> throw new Exception("Response body is not read yet. " +
public Response(byte[] body) "Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() " +
{ "method to read the response body.");
Body = body; }
} }
internal static string CreateResponseLine(Version version, int statusCode, string statusDescription) internal static string CreateResponseLine(Version version, int statusCode, string statusDescription)
...@@ -148,7 +148,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -148,7 +148,8 @@ namespace Titanium.Web.Proxy.Http
return $"HTTP/{version.Major}.{version.Minor} {statusCode} {statusDescription}"; return $"HTTP/{version.Major}.{version.Minor} {statusCode} {statusDescription}";
} }
internal static void ParseResponseLine(string httpStatus, out Version version, out int statusCode, out string statusDescription) internal static void ParseResponseLine(string httpStatus, out Version version, out int statusCode,
out string statusDescription)
{ {
var httpResult = httpStatus.Split(ProxyConstants.SpaceSplit, 3); var httpResult = httpStatus.Split(ProxyConstants.SpaceSplit, 3);
if (httpResult.Length != 3) if (httpResult.Length != 3)
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary> /// <summary>
/// 200 Ok response /// 200 Ok response
/// </summary> /// </summary>
public sealed class OkResponse : Response public sealed class OkResponse : Response
{ {
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
public OkResponse() public OkResponse()
{ {
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http.Responses
} }
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
public OkResponse(byte[] body) : this() public OkResponse(byte[] body) : this()
{ {
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary> /// <summary>
/// Redirect response /// Redirect response
/// </summary> /// </summary>
public sealed class RedirectResponse : Response public sealed class RedirectResponse : Response
{ {
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
public RedirectResponse() public RedirectResponse()
{ {
......
...@@ -7,44 +7,47 @@ using Titanium.Web.Proxy.Extensions; ...@@ -7,44 +7,47 @@ using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// A proxy endpoint that the client is aware of /// A proxy endpoint that the client is aware of
/// So client application know that it is communicating with a proxy server /// So client application know that it is communicating with a proxy server
/// </summary> /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint public class ExplicitProxyEndPoint : ProxyEndPoint
{ {
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port,
decryptSsl)
{
}
internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpProxy { get; set; }
internal bool IsSystemHttpsProxy { get; set; } internal bool IsSystemHttpsProxy { get; set; }
/// <summary> /// <summary>
/// Generic certificate to use for SSL decryption. /// Generic certificate to use for SSL decryption.
/// </summary> /// </summary>
public X509Certificate2 GenericCertificate { get; set; } public X509Certificate2 GenericCertificate { get; set; }
/// <summary> /// <summary>
/// Intercept tunnel connect request /// Intercept tunnel connect request
/// Valid only for explicit endpoints /// Valid only for explicit endpoints
/// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl"/> property to false if this HTTP connect request should'nt be decrypted and instead be relayed /// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl" /> property to false if this HTTP connect request
/// should'nt be decrypted and instead be relayed
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest; public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest;
/// <summary> /// <summary>
/// Intercept tunnel connect response /// Intercept tunnel connect response
/// Valid only for explicit endpoints /// Valid only for explicit endpoints
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse; public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse;
/// <summary> internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
/// Constructor. TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port, decryptSsl)
{
}
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
{ {
if (BeforeTunnelConnectRequest != null) if (BeforeTunnelConnectRequest != null)
{ {
...@@ -52,7 +55,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -52,7 +55,8 @@ namespace Titanium.Web.Proxy.Models
} }
} }
internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false) internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer,
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
{ {
if (BeforeTunnelConnectResponse != null) if (BeforeTunnelConnectResponse != null)
{ {
...@@ -61,4 +65,4 @@ namespace Titanium.Web.Proxy.Models ...@@ -61,4 +65,4 @@ namespace Titanium.Web.Proxy.Models
} }
} }
} }
} }
\ No newline at end of file
...@@ -4,27 +4,29 @@ using System.Net; ...@@ -4,27 +4,29 @@ using System.Net;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// An upstream proxy this proxy uses if any /// An upstream proxy this proxy uses if any
/// </summary> /// </summary>
public class ExternalProxy public class ExternalProxy
{ {
private static readonly Lazy<NetworkCredential> defaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials); private static readonly Lazy<NetworkCredential> defaultCredentials =
new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials);
private string userName;
private string password; private string password;
private string userName;
/// <summary> /// <summary>
/// Use default windows credentials? /// Use default windows credentials?
/// </summary> /// </summary>
public bool UseDefaultCredentials { get; set; } public bool UseDefaultCredentials { get; set; }
/// <summary> /// <summary>
/// Bypass this proxy for connections to localhost? /// Bypass this proxy for connections to localhost?
/// </summary> /// </summary>
public bool BypassLocalhost { get; set; } public bool BypassLocalhost { get; set; }
/// <summary> /// <summary>
/// Username. /// Username.
/// </summary> /// </summary>
public string UserName public string UserName
{ {
...@@ -41,7 +43,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -41,7 +43,7 @@ namespace Titanium.Web.Proxy.Models
} }
/// <summary> /// <summary>
/// Password. /// Password.
/// </summary> /// </summary>
public string Password public string Password
{ {
...@@ -58,12 +60,12 @@ namespace Titanium.Web.Proxy.Models ...@@ -58,12 +60,12 @@ namespace Titanium.Web.Proxy.Models
} }
/// <summary> /// <summary>
/// Host name. /// Host name.
/// </summary> /// </summary>
public string HostName { get; set; } public string HostName { get; set; }
/// <summary> /// <summary>
/// Port. /// Port.
/// </summary> /// </summary>
public int Port { get; set; } public int Port { get; set; }
......
...@@ -7,7 +7,7 @@ using Titanium.Web.Proxy.Http; ...@@ -7,7 +7,7 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// Http Header object used by proxy /// Http Header object used by proxy
/// </summary> /// </summary>
public class HttpHeader public class HttpHeader
{ {
...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Models
internal static HttpHeader ProxyConnectionKeepAlive = new HttpHeader("Proxy-Connection", "keep-alive"); internal static HttpHeader ProxyConnectionKeepAlive = new HttpHeader("Proxy-Connection", "keep-alive");
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="name"></param> /// <param name="name"></param>
/// <param name="value"></param> /// <param name="value"></param>
...@@ -37,17 +37,17 @@ namespace Titanium.Web.Proxy.Models ...@@ -37,17 +37,17 @@ namespace Titanium.Web.Proxy.Models
} }
/// <summary> /// <summary>
/// Header Name. /// Header Name.
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// Header Value. /// Header Value.
/// </summary> /// </summary>
public string Value { get; set; } public string Value { get; set; }
/// <summary> /// <summary>
/// Returns header as a valid header string /// Returns header as a valid header string
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public override string ToString() public override string ToString()
......
using System.Collections.Generic; using System.Net;
using System.Linq;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text.RegularExpressions;
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
{ {
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
...@@ -25,27 +22,27 @@ namespace Titanium.Web.Proxy.Models ...@@ -25,27 +22,27 @@ namespace Titanium.Web.Proxy.Models
} }
/// <summary> /// <summary>
/// underlying TCP Listener object /// underlying TCP Listener object
/// </summary> /// </summary>
internal TcpListener Listener { get; set; } internal TcpListener Listener { get; set; }
/// <summary> /// <summary>
/// Ip Address we are listening. /// Ip Address we are listening.
/// </summary> /// </summary>
public IPAddress IpAddress { get; } public IPAddress IpAddress { get; }
/// <summary> /// <summary>
/// Port we are listening. /// Port we are listening.
/// </summary> /// </summary>
public int Port { get; internal set; } public int Port { get; internal set; }
/// <summary> /// <summary>
/// Enable SSL? /// Enable SSL?
/// </summary> /// </summary>
public bool DecryptSsl { get; } public bool DecryptSsl { get; }
/// <summary> /// <summary>
/// Is IPv6 enabled? /// Is IPv6 enabled?
/// </summary> /// </summary>
public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any) public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any)
|| Equals(IpAddress, IPAddress.IPv6Loopback) || Equals(IpAddress, IPAddress.IPv6Loopback)
......
...@@ -6,34 +6,36 @@ using Titanium.Web.Proxy.Extensions; ...@@ -6,34 +6,36 @@ using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// A proxy end point client is not aware of /// A proxy end point client is not aware of
/// Usefull when requests are redirected to this proxy end point through port forwarding /// Usefull when requests are redirected to this proxy end point through port forwarding
/// </summary> /// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint public class TransparentProxyEndPoint : ProxyEndPoint
{ {
/// <summary> /// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy) /// Constructor.
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public string GenericCertificateName { get; set; }
/// <summary>
/// Before Ssl authentication
/// </summary>
public event AsyncEventHandler<BeforeSslAuthenticateEventArgs> BeforeSslAuthenticate;
/// <summary>
/// Constructor.
/// </summary> /// </summary>
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="decryptSsl"></param> /// <param name="decryptSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port, decryptSsl) public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port,
decryptSsl)
{ {
GenericCertificateName = "localhost"; GenericCertificateName = "localhost";
} }
internal async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer, BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc) /// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public string GenericCertificateName { get; set; }
/// <summary>
/// Before Ssl authentication
/// </summary>
public event AsyncEventHandler<BeforeSslAuthenticateEventArgs> BeforeSslAuthenticate;
internal async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer,
BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc)
{ {
if (BeforeSslAuthenticate != null) if (BeforeSslAuthenticate != null)
{ {
...@@ -41,4 +43,4 @@ namespace Titanium.Web.Proxy.Models ...@@ -41,4 +43,4 @@ namespace Titanium.Web.Proxy.Models
} }
} }
} }
} }
\ No newline at end of file
...@@ -4,21 +4,21 @@ using System.Security.Cryptography.X509Certificates; ...@@ -4,21 +4,21 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
/// <summary> /// <summary>
/// An object that holds the cached certificate /// An object that holds the cached certificate
/// </summary> /// </summary>
internal class CachedCertificate internal class CachedCertificate
{ {
internal CachedCertificate()
{
LastAccess = DateTime.Now;
}
internal X509Certificate2 Certificate { get; set; } internal X509Certificate2 Certificate { get; set; }
/// <summary> /// <summary>
/// last time this certificate was used /// last time this certificate was used
/// Usefull in determining its cache lifetime /// Usefull in determining its cache lifetime
/// </summary> /// </summary>
internal DateTime LastAccess { get; set; } internal DateTime LastAccess { get; set; }
internal CachedCertificate()
{
LastAccess = DateTime.Now;
}
} }
} }
...@@ -17,11 +17,12 @@ using Org.BouncyCastle.Security; ...@@ -17,11 +17,12 @@ using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509; using Org.BouncyCastle.X509;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace Titanium.Web.Proxy.Network.Certificate namespace Titanium.Web.Proxy.Network.Certificate
{ {
/// <summary> /// <summary>
/// Implements certificate generation operations. /// Implements certificate generation operations.
/// </summary> /// </summary>
internal class BCCertificateMaker : ICertificateMaker internal class BCCertificateMaker : ICertificateMaker
{ {
...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
/// <summary> /// <summary>
/// Makes the certificate. /// Makes the certificate.
/// </summary> /// </summary>
/// <param name="sSubjectCn">The s subject cn.</param> /// <param name="sSubjectCn">The s subject cn.</param>
/// <param name="isRoot">if set to <c>true</c> [is root].</param> /// <param name="isRoot">if set to <c>true</c> [is root].</param>
...@@ -52,7 +53,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -52,7 +53,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
/// <summary> /// <summary>
/// Generates the certificate. /// Generates the certificate.
/// </summary> /// </summary>
/// <param name="subjectName">Name of the subject.</param> /// <param name="subjectName">Name of the subject.</param>
/// <param name="issuerName">Name of the issuer.</param> /// <param name="issuerName">Name of the issuer.</param>
...@@ -79,7 +80,8 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -79,7 +80,8 @@ namespace Titanium.Web.Proxy.Network.Certificate
var certificateGenerator = new X509V3CertificateGenerator(); var certificateGenerator = new X509V3CertificateGenerator();
// Serial Number // Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), secureRandom); var serialNumber =
BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), secureRandom);
certificateGenerator.SetSerialNumber(serialNumber); certificateGenerator.SetSerialNumber(serialNumber);
// Issuer and Subject Name // Issuer and Subject Name
...@@ -94,12 +96,13 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -94,12 +96,13 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (hostName != null) if (hostName != null)
{ {
//add subject alternative names //add subject alternative names
var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName), }; var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName) };
var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames); var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension); certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false,
subjectAlternativeNamesExtension);
} }
// Subject Public Key // Subject Public Key
var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength); var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator(); var keyPairGenerator = new RsaKeyPairGenerator();
...@@ -109,13 +112,15 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -109,13 +112,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
certificateGenerator.SetPublicKey(subjectKeyPair.Public); certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Set certificate intended purposes to only Server Authentication // Set certificate intended purposes to only Server Authentication
certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth)); certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false,
new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));
if (issuerPrivateKey == null) if (issuerPrivateKey == null)
{ {
certificateGenerator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(true)); certificateGenerator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(true));
} }
var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerPrivateKey ?? subjectKeyPair.Private, secureRandom); var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm,
issuerPrivateKey ?? subjectKeyPair.Private, secureRandom);
// Self-sign the certificate // Self-sign the certificate
var certificate = certificateGenerator.Generate(signatureFactory); var certificate = certificateGenerator.Generate(signatureFactory);
...@@ -131,7 +136,8 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -131,7 +136,8 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
var rsa = RsaPrivateKeyStructure.GetInstance(seq); var rsa = RsaPrivateKeyStructure.GetInstance(seq);
var rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, var rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent,
rsa.Prime1, rsa.Prime2, rsa.Exponent1,
rsa.Exponent2, rsa.Coefficient); rsa.Exponent2, rsa.Coefficient);
#if NET45 #if NET45
...@@ -158,7 +164,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -158,7 +164,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return x509Certificate; return x509Certificate;
} }
private static X509Certificate2 WithPrivateKey(Org.BouncyCastle.X509.X509Certificate certificate, AsymmetricKeyParameter privateKey) private static X509Certificate2 WithPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey)
{ {
const string password = "password"; const string password = "password";
var store = new Pkcs12Store(); var store = new Pkcs12Store();
...@@ -173,9 +179,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -173,9 +179,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable); return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
} }
} }
/// <summary> /// <summary>
/// Makes the certificate internal. /// Makes the certificate internal.
/// </summary> /// </summary>
/// <param name="isRoot">if set to <c>true</c> [is root].</param> /// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="hostName">hostname for certificate</param> /// <param name="hostName">hostname for certificate</param>
...@@ -184,29 +190,33 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -184,29 +190,33 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="validTo">The valid to.</param> /// <param name="validTo">The valid to.</param>
/// <param name="signingCertificate">The signing certificate.</param> /// <param name="signingCertificate">The signing certificate.</param>
/// <returns>X509Certificate2 instance.</returns> /// <returns>X509Certificate2 instance.</returns>
/// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception> /// <exception cref="System.ArgumentException">
/// You must specify a Signing Certificate if and only if you are not creating a
/// root.
/// </exception>
private X509Certificate2 MakeCertificateInternal(bool isRoot, private X509Certificate2 MakeCertificateInternal(bool isRoot,
string hostName, string subjectName, string hostName, string subjectName,
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate) DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{ {
if (isRoot != (null == signingCertificate)) if (isRoot != (null == signingCertificate))
{ {
throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(signingCertificate)); throw new ArgumentException(
"You must specify a Signing Certificate if and only if you are not creating a root.",
nameof(signingCertificate));
} }
if (isRoot) if (isRoot)
{ {
return GenerateCertificate(null, subjectName, subjectName, validFrom, validTo); return GenerateCertificate(null, subjectName, subjectName, validFrom, validTo);
} }
else
{ var kp = DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey);
var kp = DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey); return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo,
return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo, issuerPrivateKey: kp.Private); issuerPrivateKey: kp.Private);
}
} }
/// <summary> /// <summary>
/// Makes the certificate internal. /// Makes the certificate internal.
/// </summary> /// </summary>
/// <param name="subject">The s subject cn.</param> /// <param name="subject">The s subject cn.</param>
/// <param name="isRoot">if set to <c>true</c> [is root].</param> /// <param name="isRoot">if set to <c>true</c> [is root].</param>
...@@ -216,7 +226,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -216,7 +226,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <returns>X509Certificate2.</returns> /// <returns>X509Certificate2.</returns>
private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot, private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot,
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null, bool switchToMtaIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default(CancellationToken)) CancellationToken cancellationToken = default)
{ {
#if NET45 #if NET45
if (switchToMtaIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) if (switchToMtaIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
...@@ -248,7 +258,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -248,7 +258,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
#endif #endif
return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert); return MakeCertificateInternal(isRoot, subject, $"CN={subject}",
DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays),
isRoot ? null : signingCert);
} }
} }
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Titanium.Web.Proxy.Network.Certificate namespace Titanium.Web.Proxy.Network.Certificate
{ {
/// <summary> /// <summary>
/// Abstract interface for different Certificate Maker Engines /// Abstract interface for different Certificate Maker Engines
/// </summary> /// </summary>
internal interface ICertificateMaker internal interface ICertificateMaker
{ {
......
#if DEBUG #if DEBUG
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network; using StreamExtended.Network;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
class DebugCustomBufferedStream : CustomBufferedStream internal class DebugCustomBufferedStream : CustomBufferedStream
{ {
private const string basePath = @"."; private const string basePath = @".";
private static int counter; private static int counter;
public int Counter { get; } private readonly FileStream fileStreamReceived;
private readonly FileStream fileStreamSent; private readonly FileStream fileStreamSent;
private readonly FileStream fileStreamReceived;
public DebugCustomBufferedStream(Stream baseStream, int bufferSize) : base(baseStream, bufferSize) public DebugCustomBufferedStream(Stream baseStream, int bufferSize) : base(baseStream, bufferSize)
{ {
Counter = Interlocked.Increment(ref counter); Counter = Interlocked.Increment(ref counter);
...@@ -29,6 +22,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -29,6 +22,8 @@ namespace Titanium.Web.Proxy.Network
fileStreamReceived = new FileStream(Path.Combine(basePath, $"{Counter}_received.dat"), FileMode.Create); fileStreamReceived = new FileStream(Path.Combine(basePath, $"{Counter}_received.dat"), FileMode.Create);
} }
public int Counter { get; }
protected override void OnDataSent(byte[] buffer, int offset, int count) protected override void OnDataSent(byte[] buffer, int offset, int count)
{ {
fileStreamSent.Write(buffer, offset, count); fileStreamSent.Write(buffer, offset, count);
...@@ -47,4 +42,4 @@ namespace Titanium.Web.Proxy.Network ...@@ -47,4 +42,4 @@ namespace Titanium.Web.Proxy.Network
} }
} }
} }
#endif #endif
\ No newline at end of file
using StreamExtended.Network; using System.Net.Sockets;
using System.Net.Sockets; using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
/// <summary> /// <summary>
/// This class wraps Tcp connection to client /// This class wraps Tcp connection to client
/// </summary> /// </summary>
internal class ProxyClient internal class ProxyClient
{ {
/// <summary> /// <summary>
/// TcpClient used to communicate with client /// TcpClient used to communicate with client
/// </summary> /// </summary>
internal TcpClient TcpClient { get; set; } internal TcpClient TcpClient { get; set; }
/// <summary> /// <summary>
/// Holds the stream to client /// Holds the stream to client
/// </summary> /// </summary>
internal CustomBufferedStream ClientStream { get; set; } internal CustomBufferedStream ClientStream { get; set; }
/// <summary> /// <summary>
/// Used to read line by line from client /// Used to read line by line from client
/// </summary> /// </summary>
internal CustomBinaryReader ClientStreamReader { get; set; } internal CustomBinaryReader ClientStreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write line by line to client /// Used to write line by line to client
/// </summary> /// </summary>
internal HttpResponseWriter ClientStreamWriter { get; set; } internal HttpResponseWriter ClientStreamWriter { get; set; }
} }
......
using StreamExtended.Network; using System;
using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -9,10 +9,17 @@ using Titanium.Web.Proxy.Models; ...@@ -9,10 +9,17 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network.Tcp namespace Titanium.Web.Proxy.Network.Tcp
{ {
/// <summary> /// <summary>
/// An object that holds TcpConnection to a particular server and port /// An object that holds TcpConnection to a particular server and port
/// </summary> /// </summary>
internal class TcpConnection : IDisposable internal class TcpConnection : IDisposable
{ {
internal TcpConnection(ProxyServer proxyServer)
{
LastAccess = DateTime.Now;
this.proxyServer = proxyServer;
this.proxyServer.UpdateServerConnectionCount(true);
}
private ProxyServer proxyServer { get; } private ProxyServer proxyServer { get; }
internal ExternalProxy UpStreamProxy { get; set; } internal ExternalProxy UpStreamProxy { get; set; }
...@@ -26,46 +33,39 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -26,46 +33,39 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal bool UseUpstreamProxy { get; set; } internal bool UseUpstreamProxy { get; set; }
/// <summary> /// <summary>
/// Local NIC via connection is made /// Local NIC via connection is made
/// </summary> /// </summary>
internal IPEndPoint UpStreamEndPoint { get; set; } internal IPEndPoint UpStreamEndPoint { get; set; }
/// <summary> /// <summary>
/// Http version /// Http version
/// </summary> /// </summary>
internal Version Version { get; set; } internal Version Version { get; set; }
internal TcpClient TcpClient { private get; set; } internal TcpClient TcpClient { private get; set; }
/// <summary> /// <summary>
/// Used to read lines from server /// Used to read lines from server
/// </summary> /// </summary>
internal CustomBinaryReader StreamReader { get; set; } internal CustomBinaryReader StreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write lines to server /// Used to write lines to server
/// </summary> /// </summary>
internal HttpRequestWriter StreamWriter { get; set; } internal HttpRequestWriter StreamWriter { get; set; }
/// <summary> /// <summary>
/// Server stream /// Server stream
/// </summary> /// </summary>
internal CustomBufferedStream Stream { get; set; } internal CustomBufferedStream Stream { get; set; }
/// <summary> /// <summary>
/// Last time this connection was used /// Last time this connection was used
/// </summary> /// </summary>
internal DateTime LastAccess { get; set; } internal DateTime LastAccess { get; set; }
internal TcpConnection(ProxyServer proxyServer)
{
LastAccess = DateTime.Now;
this.proxyServer = proxyServer;
this.proxyServer.UpdateServerConnectionCount(true);
}
/// <summary> /// <summary>
/// Dispose. /// Dispose.
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
......
using StreamExtended.Network; using System;
using System;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
...@@ -14,12 +13,12 @@ using Titanium.Web.Proxy.Models; ...@@ -14,12 +13,12 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network.Tcp namespace Titanium.Web.Proxy.Network.Tcp
{ {
/// <summary> /// <summary>
/// A class that manages Tcp Connection to server used by this proxy server /// A class that manages Tcp Connection to server used by this proxy server
/// </summary> /// </summary>
internal class TcpConnectionFactory internal class TcpConnectionFactory
{ {
/// <summary> /// <summary>
/// Creates a TCP connection to server /// Creates a TCP connection to server
/// </summary> /// </summary>
/// <param name="remoteHostName"></param> /// <param name="remoteHostName"></param>
/// <param name="remotePort"></param> /// <param name="remotePort"></param>
...@@ -37,7 +36,8 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -37,7 +36,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
bool useUpstreamProxy = false; bool useUpstreamProxy = false;
//check if external proxy is set for HTTP/HTTPS //check if external proxy is set for HTTP/HTTPS
if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort)) if (externalProxy != null &&
!(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
{ {
useUpstreamProxy = true; useUpstreamProxy = true;
...@@ -90,8 +90,8 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -90,8 +90,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);
if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK")
&& !statusDescription.EqualsIgnoreCase("Connection Established")) && !statusDescription.EqualsIgnoreCase("Connection Established"))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
...@@ -102,10 +102,12 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -102,10 +102,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
if (isHttps) if (isHttps)
{ {
var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate, proxyServer.SelectClientCertificate); var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate,
proxyServer.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, proxyServer.BufferSize); stream = new CustomBufferedStream(sslStream, proxyServer.BufferSize);
await sslStream.AuthenticateAsClientAsync(remoteHostName, null, proxyServer.SupportedSslProtocols, proxyServer.CheckCertificateRevocation); await sslStream.AuthenticateAsClientAsync(remoteHostName, null, proxyServer.SupportedSslProtocols,
proxyServer.CheckCertificateRevocation);
} }
client.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000; client.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
......
...@@ -5,13 +5,13 @@ using Titanium.Web.Proxy.Helpers; ...@@ -5,13 +5,13 @@ using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Network.Tcp namespace Titanium.Web.Proxy.Network.Tcp
{ {
/// <summary> /// <summary>
/// Represents a managed interface of IP Helper API TcpRow struct /// Represents a managed interface of IP Helper API TcpRow struct
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/> /// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx" />
/// </summary> /// </summary>
internal class TcpRow internal class TcpRow
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TcpRow"/> class. /// Initializes a new instance of the <see cref="TcpRow" /> class.
/// </summary> /// </summary>
/// <param name="tcpRow">TcpRow struct.</param> /// <param name="tcpRow">TcpRow struct.</param>
internal TcpRow(NativeMethods.TcpRow tcpRow) internal TcpRow(NativeMethods.TcpRow tcpRow)
...@@ -26,37 +26,37 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -26,37 +26,37 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
/// <summary> /// <summary>
/// Gets the local end point address. /// Gets the local end point address.
/// </summary> /// </summary>
internal long LocalAddress { get; } internal long LocalAddress { get; }
/// <summary> /// <summary>
/// Gets the local end point port. /// Gets the local end point port.
/// </summary> /// </summary>
internal int LocalPort { get; } internal int LocalPort { get; }
/// <summary> /// <summary>
/// Gets the local end point. /// Gets the local end point.
/// </summary> /// </summary>
internal IPEndPoint LocalEndPoint => new IPEndPoint(LocalAddress, LocalPort); internal IPEndPoint LocalEndPoint => new IPEndPoint(LocalAddress, LocalPort);
/// <summary> /// <summary>
/// Gets the remote end point address. /// Gets the remote end point address.
/// </summary> /// </summary>
internal long RemoteAddress { get; } internal long RemoteAddress { get; }
/// <summary> /// <summary>
/// Gets the remote end point port. /// Gets the remote end point port.
/// </summary> /// </summary>
internal int RemotePort { get; } internal int RemotePort { get; }
/// <summary> /// <summary>
/// Gets the remote end point. /// Gets the remote end point.
/// </summary> /// </summary>
internal IPEndPoint RemoteEndPoint => new IPEndPoint(RemoteAddress, RemotePort); internal IPEndPoint RemoteEndPoint => new IPEndPoint(RemoteAddress, RemotePort);
/// <summary> /// <summary>
/// Gets the process identifier. /// Gets the process identifier.
/// </summary> /// </summary>
internal int ProcessId { get; } internal int ProcessId { get; }
} }
......
...@@ -4,7 +4,7 @@ using System.Collections.Generic; ...@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace Titanium.Web.Proxy.Network.Tcp namespace Titanium.Web.Proxy.Network.Tcp
{ {
/// <summary> /// <summary>
/// Represents collection of TcpRows /// Represents collection of TcpRows
/// </summary> /// </summary>
/// <seealso> /// <seealso>
/// <cref>System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}</cref> /// <cref>System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow}</cref>
...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal class TcpTable : IEnumerable<TcpRow> internal class TcpTable : IEnumerable<TcpRow>
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TcpTable"/> class. /// Initializes a new instance of the <see cref="TcpTable" /> class.
/// </summary> /// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param> /// <param name="tcpRows">TcpRow collection to initialize with.</param>
internal TcpTable(IEnumerable<TcpRow> tcpRows) internal TcpTable(IEnumerable<TcpRow> tcpRows)
...@@ -21,12 +21,12 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -21,12 +21,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
/// <summary> /// <summary>
/// Gets the TCP rows. /// Gets the TCP rows.
/// </summary> /// </summary>
internal IEnumerable<TcpRow> TcpRows { get; } internal IEnumerable<TcpRow> TcpRows { get; }
/// <summary> /// <summary>
/// Returns an enumerator that iterates through the collection. /// Returns an enumerator that iterates through the collection.
/// </summary> /// </summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns> /// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator<TcpRow> GetEnumerator() public IEnumerator<TcpRow> GetEnumerator()
...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
/// <summary> /// <summary>
/// Returns an enumerator that iterates through a collection. /// Returns an enumerator that iterates through a collection.
/// </summary> /// </summary>
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns> /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()
......
...@@ -5,6 +5,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -5,6 +5,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
internal class Common internal class Common
{ {
internal static uint NewContextAttributes = 0;
internal static SecurityInteger NewLifeTime = new SecurityInteger(0);
#region Private constants #region Private constants
private const int ISC_REQ_REPLAY_DETECT = 0x00000004; private const int ISC_REQ_REPLAY_DETECT = 0x00000004;
...@@ -14,12 +17,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -14,12 +17,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
#endregion #endregion
internal static uint NewContextAttributes = 0;
internal static SecurityInteger NewLifeTime = new SecurityInteger(0);
#region internal constants #region internal constants
internal const int StandardContextAttributes = ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONNECTION; internal const int StandardContextAttributes =
ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONNECTION;
internal const int SecurityNativeDataRepresentation = 0x10; internal const int SecurityNativeDataRepresentation = 0x10;
internal const int MaximumTokenSize = 12288; internal const int MaximumTokenSize = 12288;
internal const int SecurityCredentialsOutbound = 2; internal const int SecurityCredentialsOutbound = 2;
...@@ -69,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -69,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
Negotiate128 = 0x20000000, Negotiate128 = 0x20000000,
// Indicates that this client supports medium (56-bit) encryption. // Indicates that this client supports medium (56-bit) encryption.
Negotiate56 = (unchecked((int)0x80000000)) Negotiate56 = unchecked((int)0x80000000)
} }
internal enum NtlmAuthLevel internal enum NtlmAuthLevel
...@@ -86,7 +88,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -86,7 +88,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
NTLM_only, NTLM_only,
/* Use NTLMv2 only. */ /* Use NTLMv2 only. */
NTLMv2_only, NTLMv2_only
} }
#endregion #endregion
...@@ -105,7 +107,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -105,7 +107,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
} }
/// <summary> /// <summary>
/// Resets all internal pointers to default value /// Resets all internal pointers to default value
/// </summary> /// </summary>
internal void Reset() internal void Reset()
{ {
...@@ -211,7 +213,8 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -211,7 +213,8 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
//What we need to do here is to grab a hold of the pvBuffer allocate by the individual //What we need to do here is to grab a hold of the pvBuffer allocate by the individual
//SecBuffer and release it... //SecBuffer and release it...
int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); int currentOffset = index * Marshal.SizeOf(typeof(Buffer));
var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int))); var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,
currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)));
Marshal.FreeHGlobal(secBufferpvBuffer); Marshal.FreeHGlobal(secBufferpvBuffer);
} }
} }
...@@ -267,13 +270,14 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -267,13 +270,14 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
//byte array... //byte array...
int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); int currentOffset = index * Marshal.SizeOf(typeof(Buffer));
int bytesToCopy = Marshal.ReadInt32(pBuffers, currentOffset); int bytesToCopy = Marshal.ReadInt32(pBuffers, currentOffset);
var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int))); var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,
currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)));
Marshal.Copy(secBufferpvBuffer, buffer, bufferIndex, bytesToCopy); Marshal.Copy(secBufferpvBuffer, buffer, bufferIndex, bytesToCopy);
bufferIndex += bytesToCopy; bufferIndex += bytesToCopy;
} }
} }
return (buffer); return buffer;
} }
} }
......
...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
} }
private static unsafe byte[] GetUShortBytes(byte*bytes) private static unsafe byte[] GetUShortBytes(byte* bytes)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -47,7 +47,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return new[] { bytes[1], bytes[0] }; return new[] { bytes[1], bytes[0] };
} }
private static unsafe byte[] GetUIntBytes(byte*bytes) private static unsafe byte[] GetUIntBytes(byte* bytes)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return new[] { bytes[3], bytes[2], bytes[1], bytes[0] }; return new[] { bytes[3], bytes[2], bytes[1], bytes[0] };
} }
private static unsafe byte[] GetULongBytes(byte*bytes) private static unsafe byte[] GetULongBytes(byte* bytes)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -117,7 +117,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -117,7 +117,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return GetULongBytes((byte*)&value); return GetULongBytes((byte*)&value);
} }
private static unsafe void UShortFromBytes(byte*dst, byte[] src, int startIndex) private static unsafe void UShortFromBytes(byte* dst, byte[] src, int startIndex)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -131,7 +131,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -131,7 +131,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
} }
} }
private static unsafe void UIntFromBytes(byte*dst, byte[] src, int startIndex) private static unsafe void UIntFromBytes(byte* dst, byte[] src, int startIndex)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -149,17 +149,21 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -149,17 +149,21 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
} }
} }
private static unsafe void ULongFromBytes(byte*dst, byte[] src, int startIndex) private static unsafe void ULongFromBytes(byte* dst, byte[] src, int startIndex)
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{
dst[i] = src[startIndex + i]; dst[i] = src[startIndex + i];
}
} }
else else
{ {
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{
dst[i] = src[startIndex + (7 - i)]; dst[i] = src[startIndex + (7 - i)];
}
} }
} }
......
...@@ -42,6 +42,8 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -42,6 +42,8 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
private static readonly byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 }; private static readonly byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 };
private readonly int type;
internal Message(byte[] message) internal Message(byte[] message)
{ {
type = 3; type = 3;
...@@ -49,17 +51,15 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -49,17 +51,15 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
} }
/// <summary> /// <summary>
/// Domain name /// Domain name
/// </summary> /// </summary>
internal string Domain { get; private set; } internal string Domain { get; private set; }
/// <summary> /// <summary>
/// Username /// Username
/// </summary> /// </summary>
internal string Username { get; private set; } internal string Username { get; private set; }
private readonly int type;
internal Common.NtlmFlags Flags { get; set; } internal Common.NtlmFlags Flags { get; set; }
// methods // methods
...@@ -68,7 +68,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -68,7 +68,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
//base.Decode (message); //base.Decode (message);
if (message == null) if (message == null)
{
throw new ArgumentNullException("message"); throw new ArgumentNullException("message");
}
if (message.Length < 12) if (message.Length < 12)
{ {
...@@ -108,12 +110,13 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -108,12 +110,13 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
Username = DecodeString(message, userOff, userLen); Username = DecodeString(message, userOff, userLen);
} }
string DecodeString(byte[] buffer, int offset, int len) private string DecodeString(byte[] buffer, int offset, int len)
{ {
if ((Flags & Common.NtlmFlags.NegotiateUnicode) != 0) if ((Flags & Common.NtlmFlags.NegotiateUnicode) != 0)
{ {
return Encoding.Unicode.GetString(buffer, offset, len); return Encoding.Unicode.GetString(buffer, offset, len);
} }
return Encoding.ASCII.GetString(buffer, offset, len); return Encoding.ASCII.GetString(buffer, offset, len);
} }
...@@ -122,9 +125,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -122,9 +125,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
for (int i = 0; i < header.Length; i++) for (int i = 0; i < header.Length; i++)
{ {
if (message[i] != header[i]) if (message[i] != header[i])
{
return false; return false;
}
} }
return (LittleEndian.ToUInt32(message, 8) == type);
return LittleEndian.ToUInt32(message, 8) == type;
} }
} }
} }
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Network.WinAuth.Security namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
/// <summary> /// <summary>
/// Status of authenticated session /// Status of authenticated session
/// </summary> /// </summary>
internal class State internal class State
{ {
/// <summary> /// <summary>
/// States during Windows Authentication /// States during Windows Authentication
/// </summary> /// </summary>
public enum WinAuthState public enum WinAuthState
{ {
...@@ -16,36 +16,36 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -16,36 +16,36 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
INITIAL_TOKEN, INITIAL_TOKEN,
FINAL_TOKEN, FINAL_TOKEN,
AUTHORIZED AUTHORIZED
};
internal State()
{
Credentials = new Common.SecurityHandle(0);
Context = new Common.SecurityHandle(0);
LastSeen = DateTime.Now;
AuthState = WinAuthState.UNAUTHORIZED;
} }
/// <summary> /// <summary>
/// Credentials used to validate NTLM hashes /// Current state of the authentication process
/// </summary> /// </summary>
internal Common.SecurityHandle Credentials; internal WinAuthState AuthState;
/// <summary> /// <summary>
/// Context will be used to validate HTLM hashes /// Context will be used to validate HTLM hashes
/// </summary> /// </summary>
internal Common.SecurityHandle Context; internal Common.SecurityHandle Context;
/// <summary> /// <summary>
/// Timestamp needed to calculate validity of the authenticated session /// Credentials used to validate NTLM hashes
/// </summary> /// </summary>
internal DateTime LastSeen; internal Common.SecurityHandle Credentials;
/// <summary> /// <summary>
/// Current state of the authentication process /// Timestamp needed to calculate validity of the authenticated session
/// </summary> /// </summary>
internal WinAuthState AuthState; internal DateTime LastSeen;
internal State()
{
Credentials = new Common.SecurityHandle(0);
Context = new Common.SecurityHandle(0);
LastSeen = DateTime.Now;
AuthState = WinAuthState.UNAUTHORIZED;
}
internal void ResetHandles() internal void ResetHandles()
{ {
......
...@@ -4,15 +4,15 @@ using Titanium.Web.Proxy.Network.WinAuth.Security; ...@@ -4,15 +4,15 @@ using Titanium.Web.Proxy.Network.WinAuth.Security;
namespace Titanium.Web.Proxy.Network.WinAuth namespace Titanium.Web.Proxy.Network.WinAuth
{ {
/// <summary> /// <summary>
/// A handler for NTLM/Kerberos windows authentication challenge from server /// A handler for NTLM/Kerberos windows authentication challenge from server
/// NTLM process details below /// NTLM process details below
/// https://blogs.msdn.microsoft.com/chiranth/2013/09/20/ntlm-want-to-know-how-it-works/ /// https://blogs.msdn.microsoft.com/chiranth/2013/09/20/ntlm-want-to-know-how-it-works/
/// </summary> /// </summary>
public static class WinAuthHandler public static class WinAuthHandler
{ {
/// <summary> /// <summary>
/// Get the initial client token for server /// Get the initial client token for server
/// using credentials of user running the proxy server process /// using credentials of user running the proxy server process
/// </summary> /// </summary>
/// <param name="serverHostname"></param> /// <param name="serverHostname"></param>
/// <param name="authScheme"></param> /// <param name="authScheme"></param>
...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth ...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth
/// <summary> /// <summary>
/// Get the final token given the server challenge token /// Get the final token given the server challenge token
/// </summary> /// </summary>
/// <param name="serverHostname"></param> /// <param name="serverHostname"></param>
/// <param name="serverToken"></param> /// <param name="serverToken"></param>
...@@ -34,7 +34,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth ...@@ -34,7 +34,9 @@ namespace Titanium.Web.Proxy.Network.WinAuth
/// <returns></returns> /// <returns></returns>
public static string GetFinalAuthToken(string serverHostname, string serverToken, Guid requestId) public static string GetFinalAuthToken(string serverHostname, string serverToken, Guid requestId)
{ {
var tokenBytes = WinAuthEndPoint.AcquireFinalSecurityToken(serverHostname, Convert.FromBase64String(serverToken), requestId); var tokenBytes =
WinAuthEndPoint.AcquireFinalSecurityToken(serverHostname, Convert.FromBase64String(serverToken),
requestId);
return string.Concat(" ", Convert.ToBase64String(tokenBytes)); return string.Concat(" ", Convert.ToBase64String(tokenBytes));
} }
......
...@@ -32,7 +32,8 @@ namespace Titanium.Web.Proxy ...@@ -32,7 +32,8 @@ namespace Titanium.Web.Proxy
} }
var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit);
if (headerValueParts.Length != 2 || !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) if (headerValueParts.Length != 2 ||
!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
{ {
//Return not authorized //Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
...@@ -53,7 +54,6 @@ namespace Titanium.Web.Proxy ...@@ -53,7 +54,6 @@ namespace Titanium.Web.Proxy
bool authenticated = await AuthenticateUserFunc(username, password); bool authenticated = await AuthenticateUserFunc(username, password);
if (!authenticated) if (!authenticated)
{ {
//Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
} }
...@@ -61,7 +61,8 @@ namespace Titanium.Web.Proxy ...@@ -61,7 +61,8 @@ namespace Titanium.Web.Proxy
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, httpHeaders)); ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e,
httpHeaders));
//Return not authorized //Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.1.4" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.1.4" targetFramework="net45" />
<package id="StreamExtended" version="1.0.141-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.141-beta" targetFramework="net45" />
......
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