Commit 9250384d authored by Jehonathan's avatar Jehonathan Committed by GitHub

Merge pull request #129 from aricih/release

IP Helper API wrapped to associate port with process id
parents 13aa2a63 c02c9f3a
...@@ -115,6 +115,9 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -115,6 +115,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
//read response headers //read response headers
var responseHeaders = e.WebSession.Response.ResponseHeaders; var responseHeaders = e.WebSession.Response.ResponseHeaders;
// print out process id of current session
Console.WriteLine($"PID: {e.WebSession.ProcessId}");
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return; //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST") if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
{ {
......
...@@ -29,27 +29,20 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -29,27 +29,20 @@ namespace Titanium.Web.Proxy.Extensions
await input.CopyToAsync(output); await input.CopyToAsync(output);
} }
/// <summary>
/// copies the specified bytes to the stream from the input stream /// <summary>
/// </summary> /// copies the specified bytes to the stream from the input stream
/// <param name="streamReader"></param> /// </summary>
/// <param name="stream"></param> /// <param name="streamReader"></param>
/// <param name="totalBytesToRead"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="stream"></param>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, int bufferSize, Stream stream, long totalBytesToRead) /// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, int bufferSize, Stream stream, long totalBytesToRead)
{ {
var totalbytesRead = 0; var totalbytesRead = 0;
long bytesToRead; long bytesToRead = totalBytesToRead < bufferSize ? totalBytesToRead : bufferSize;
if (totalBytesToRead < bufferSize)
{
bytesToRead = totalBytesToRead;
}
else
{
bytesToRead = bufferSize;
}
while (totalbytesRead < totalBytesToRead) while (totalbytesRead < totalBytesToRead)
{ {
...@@ -72,13 +65,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -72,13 +65,14 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
/// <summary> /// <summary>
/// Copies the stream chunked /// Copies the stream chunked
/// </summary> /// </summary>
/// <param name="clientStreamReader"></param> /// <param name="clientStreamReader"></param>
/// <param name="stream"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="stream"></param>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, int bufferSize, Stream stream) /// <returns></returns>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, int bufferSize, Stream stream)
{ {
while (true) while (true)
{ {
...@@ -117,30 +111,32 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -117,30 +111,32 @@ namespace Titanium.Web.Proxy.Extensions
await WriteResponseBodyChunked(data, clientStream); await WriteResponseBodyChunked(data, clientStream);
} }
} }
/// <summary>
/// Copies the specified content length number of bytes to the output stream from the given inputs stream /// <summary>
/// optionally chunked /// Copies the specified content length number of bytes to the output stream from the given inputs stream
/// </summary> /// optionally chunked
/// <param name="inStreamReader"></param> /// </summary>
/// <param name="outStream"></param> /// <param name="inStreamReader"></param>
/// <param name="isChunked"></param> /// <param name="bufferSize"></param>
/// <param name="ContentLength"></param> /// <param name="outStream"></param>
/// <returns></returns> /// <param name="isChunked"></param>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream, bool isChunked, long ContentLength) /// <param name="contentLength"></param>
/// <returns></returns>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream, bool isChunked, long contentLength)
{ {
if (!isChunked) if (!isChunked)
{ {
//http 1.0 //http 1.0
if (ContentLength == -1) if (contentLength == -1)
{ {
ContentLength = long.MaxValue; contentLength = long.MaxValue;
} }
int bytesToRead = bufferSize; int bytesToRead = bufferSize;
if (ContentLength < bufferSize) if (contentLength < bufferSize)
{ {
bytesToRead = (int)ContentLength; bytesToRead = (int)contentLength;
} }
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
...@@ -153,11 +149,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -153,11 +149,11 @@ namespace Titanium.Web.Proxy.Extensions
await outStream.WriteAsync(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
if (totalBytesRead == ContentLength) if (totalBytesRead == contentLength)
break; break;
bytesRead = 0; bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead); var remainingBytes = (contentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes; bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes;
} }
} }
...@@ -167,13 +163,14 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -167,13 +163,14 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
/// <summary> /// <summary>
/// Copies the streams chunked /// Copies the streams chunked
/// </summary> /// </summary>
/// <param name="inStreamReader"></param> /// <param name="inStreamReader"></param>
/// <param name="outStream"></param> /// <param name="bufferSize"></param>
/// <returns></returns> /// <param name="outStream"></param>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream) /// <returns></returns>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream)
{ {
while (true) while (true)
{ {
......
...@@ -37,37 +37,30 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -37,37 +37,30 @@ namespace Titanium.Web.Proxy.Helpers
{ {
using (var readBuffer = new MemoryStream()) using (var readBuffer = new MemoryStream())
{ {
try var lastChar = default(char);
{ var buffer = new byte[1];
var lastChar = default(char);
var buffer = new byte[1]; while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0)
{
while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0) //if new line
{ if (lastChar == '\r' && buffer[0] == '\n')
//if new line {
if (lastChar == '\r' && buffer[0] == '\n') var result = readBuffer.ToArray();
{ return encoding.GetString(result.SubArray(0, result.Length - 1));
var result = readBuffer.ToArray(); }
return encoding.GetString(result.SubArray(0, result.Length - 1)); //end of stream
} if (buffer[0] == '\0')
//end of stream {
if (buffer[0] == '\0') return encoding.GetString(readBuffer.ToArray());
{ }
return encoding.GetString(readBuffer.ToArray());
} await readBuffer.WriteAsync(buffer,0,1);
await readBuffer.WriteAsync(buffer,0,1); //store last char for new line comparison
lastChar = (char)buffer[0];
//store last char for new line comparison }
lastChar = (char)buffer[0];
} return encoding.GetString(readBuffer.ToArray());
return encoding.GetString(readBuffer.ToArray());
}
catch (IOException)
{
throw;
}
} }
} }
......
...@@ -4,14 +4,20 @@ using Microsoft.Win32; ...@@ -4,14 +4,20 @@ using Microsoft.Win32;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Sockets;
/// <summary> /// <summary>
/// Helper classes for setting system proxy settings /// Helper classes for setting system proxy settings
/// </summary> /// </summary>
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal enum ProxyProtocolType
internal class NativeMethods {
Http,
Https,
}
internal partial class NativeMethods
{ {
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
...@@ -26,16 +32,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -26,16 +32,10 @@ namespace Titanium.Web.Proxy.Helpers
public override string ToString() public override string ToString()
{ {
if (!IsHttps) return $"{(IsHttps ? "https" : "http")}={HostName}:{Port}";
{
return "http=" + HostName + ":" + Port;
}
else
{
return "https=" + HostName + ":" + Port;
}
} }
} }
/// <summary> /// <summary>
/// Manage system proxy settings /// Manage system proxy settings
/// </summary> /// </summary>
...@@ -44,62 +44,17 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -44,62 +44,17 @@ namespace Titanium.Web.Proxy.Helpers
internal const int InternetOptionSettingsChanged = 39; internal const int InternetOptionSettingsChanged = 39;
internal const int InternetOptionRefresh = 37; internal const int InternetOptionRefresh = 37;
internal void SetHttpProxy(string hostname, int port) internal void SetHttpProxy(string hostname, int port)
{ {
var reg = Registry.CurrentUser.OpenSubKey( SetProxy(hostname, port, ProxyProtocolType.Http);
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null)
{
prepareRegistry(reg);
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => !x.IsHttps);
existingSystemProxyValues.Add(new HttpSystemProxyValue()
{
HostName = hostname,
IsHttps = false,
Port = port
});
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", String.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
}
Refresh();
} }
/// <summary> /// <summary>
/// Remove the http proxy setting from current machine /// Remove the http proxy setting from current machine
/// </summary> /// </summary>
internal void RemoveHttpProxy() internal void RemoveHttpProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( RemoveProxy(ProxyProtocolType.Http);
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null)
{
if (reg.GetValue("ProxyServer") != null)
{
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => !x.IsHttps);
if (!(existingSystemProxyValues.Count() == 0))
{
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", String.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
}
else
{
reg.SetValue("ProxyEnable", 0);
reg.SetValue("ProxyServer", string.Empty);
}
}
}
Refresh();
} }
/// <summary> /// <summary>
...@@ -107,60 +62,65 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -107,60 +62,65 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <param name="port"></param> /// <param name="port"></param>
internal void SetHttpsProxy(string hostname, int port) internal void SetHttpsProxy(string hostname, int port)
{
SetProxy(hostname, port, ProxyProtocolType.Https);
}
/// <summary>
/// Removes the https proxy setting to nothing
/// </summary>
internal void RemoveHttpsProxy()
{
RemoveProxy(ProxyProtocolType.Https);
}
private void SetProxy(string hostname, int port, ProxyProtocolType protocolType)
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null) if (reg != null)
{ {
prepareRegistry(reg); PrepareRegistry(reg);
var exisitingContent = reg.GetValue("ProxyServer") as string; var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent); var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => x.IsHttps); existingSystemProxyValues.RemoveAll(x => protocolType == ProxyProtocolType.Https ? x.IsHttps : !x.IsHttps);
existingSystemProxyValues.Add(new HttpSystemProxyValue() existingSystemProxyValues.Add(new HttpSystemProxyValue()
{ {
HostName = hostname, HostName = hostname,
IsHttps = true, IsHttps = protocolType == ProxyProtocolType.Https,
Port = port Port = port
}); });
reg.SetValue("ProxyEnable", 1); reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", String.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray())); reg.SetValue("ProxyServer", string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
} }
Refresh(); Refresh();
} }
/// <summary> private void RemoveProxy(ProxyProtocolType protocolType)
/// Removes the https proxy setting to nothing
/// </summary>
internal void RemoveHttpsProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null) if (reg?.GetValue("ProxyServer") != null)
{ {
if (reg.GetValue("ProxyServer") != null) var exisitingContent = reg.GetValue("ProxyServer") as string;
{
var exisitingContent = reg.GetValue("ProxyServer") as string; var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => protocolType == ProxyProtocolType.Https ? x.IsHttps : !x.IsHttps);
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => x.IsHttps);
if (!(existingSystemProxyValues.Count() == 0))
{
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", String.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
}
else
{
reg.SetValue("ProxyEnable", 0);
reg.SetValue("ProxyServer", string.Empty);
}
if (existingSystemProxyValues.Count != 0)
{
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
}
else
{
reg.SetValue("ProxyEnable", 0);
reg.SetValue("ProxyServer", string.Empty);
} }
} }
...@@ -170,7 +130,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -170,7 +130,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Removes all types of proxy settings (both http & https) /// Removes all types of proxy settings (both http & https)
/// </summary> /// </summary>
internal void DisableAllProxy() internal void DisableAllProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -189,7 +149,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -189,7 +149,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="prevServerValue"></param> /// <param name="prevServerValue"></param>
/// <returns></returns> /// <returns></returns>
private List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue) private List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue)
{ {
var result = new List<HttpSystemProxyValue>(); var result = new List<HttpSystemProxyValue>();
...@@ -200,16 +160,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -200,16 +160,11 @@ namespace Titanium.Web.Proxy.Helpers
if (proxyValues.Length > 0) if (proxyValues.Length > 0)
{ {
foreach (var value in proxyValues) result.AddRange(proxyValues.Select(ParseProxyValue).Where(parsedValue => parsedValue != null));
{
var parsedValue = parseProxyValue(value);
if (parsedValue != null)
result.Add(parsedValue);
}
} }
else else
{ {
var parsedValue = parseProxyValue(prevServerValue); var parsedValue = ParseProxyValue(prevServerValue);
if (parsedValue != null) if (parsedValue != null)
result.Add(parsedValue); result.Add(parsedValue);
} }
...@@ -222,29 +177,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -222,29 +177,21 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
private HttpSystemProxyValue parseProxyValue(string value) private HttpSystemProxyValue ParseProxyValue(string value)
{ {
var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower(); var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower();
if (tmp.StartsWith("http="))
{ if (tmp.StartsWith("http=") || tmp.StartsWith("https="))
var endPoint = tmp.Substring(5);
return new HttpSystemProxyValue()
{
HostName = endPoint.Split(':')[0],
Port = int.Parse(endPoint.Split(':')[1]),
IsHttps = false
};
}
else if (tmp.StartsWith("https="))
{ {
var endPoint = tmp.Substring(5); var endPoint = tmp.Substring(5);
return new HttpSystemProxyValue() return new HttpSystemProxyValue()
{ {
HostName = endPoint.Split(':')[0], HostName = endPoint.Split(':')[0],
Port = int.Parse(endPoint.Split(':')[1]), Port = int.Parse(endPoint.Split(':')[1]),
IsHttps = true IsHttps = tmp.StartsWith("https=")
}; };
} }
return null; return null;
} }
...@@ -252,7 +199,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -252,7 +199,7 @@ namespace Titanium.Web.Proxy.Helpers
/// 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 void prepareRegistry(RegistryKey reg) private static void PrepareRegistry(RegistryKey reg)
{ {
if (reg.GetValue("ProxyEnable") == null) if (reg.GetValue("ProxyEnable") == null)
{ {
...@@ -269,7 +216,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -269,7 +216,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()
{ {
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0);
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0);
......
...@@ -2,20 +2,115 @@ ...@@ -2,20 +2,115 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Runtime.InteropServices;
using System.Security.Authentication; using System.Security.Authentication;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Tcp;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal partial class NativeMethods
{
internal const int AfInet = 2;
internal enum TcpTableType
{
BasicListener,
BasicConnections,
BasicAll,
OwnerPidListener,
OwnerPidConnections,
OwnerPidAll,
OwnerModuleListener,
OwnerModuleConnections,
OwnerModuleAll,
}
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct TcpTable
{
public uint length;
public TcpRow row;
}
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct TcpRow
{
public TcpState state;
public uint localAddr;
public byte localPort1;
public byte localPort2;
public byte localPort3;
public byte localPort4;
public uint remoteAddr;
public byte remotePort1;
public byte remotePort2;
public byte remotePort3;
public byte remotePort4;
public int owningPid;
}
/// <summary>
/// <see cref="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 class TcpHelper internal class TcpHelper
{ {
/// <summary>
/// Gets the extended TCP table.
/// </summary>
/// <returns>Collection of <see cref="TcpRow"/>.</returns>
internal static TcpTable GetExtendedTcpTable()
{
List<TcpRow> tcpRows = new List<TcpRow>();
IntPtr tcpTable = IntPtr.Zero;
int tcpTableLength = 0;
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, NativeMethods.AfInet, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) != 0)
{
try
{
tcpTable = Marshal.AllocHGlobal(tcpTableLength);
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, NativeMethods.AfInet, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) == 0)
{
NativeMethods.TcpTable table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable));
IntPtr rowPtr = (IntPtr)((long)tcpTable + Marshal.SizeOf(table.length));
for (int i = 0; i < table.length; ++i)
{
tcpRows.Add(new TcpRow((NativeMethods.TcpRow)Marshal.PtrToStructure(rowPtr, typeof(NativeMethods.TcpRow))));
rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(NativeMethods.TcpRow)));
}
}
}
finally
{
if (tcpTable != IntPtr.Zero)
{
Marshal.FreeHGlobal(tcpTable);
}
}
}
return new TcpTable(tcpRows);
}
/// <summary> /// <summary>
/// relays the input clientStream to the server at the specified host name & port with the given httpCmd & headers as prefix /// relays the input clientStream to the server at the specified host name & port with the given httpCmd & headers as prefix
...@@ -73,36 +168,22 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -73,36 +168,22 @@ namespace Titanium.Web.Proxy.Helpers
try try
{ {
TcpClient tunnelClient = tcpConnection.TcpClient;
Stream tunnelStream = tcpConnection.Stream; Stream tunnelStream = tcpConnection.Stream;
Task sendRelay; Task sendRelay;
//Now async relay all server=>client & client=>server data //Now async relay all server=>client & client=>server data
if (sb != null) sendRelay = clientStream.CopyToAsync(sb?.ToString() ?? string.Empty, tunnelStream);
{
sendRelay = clientStream.CopyToAsync(sb.ToString(), tunnelStream);
}
else
{
sendRelay = clientStream.CopyToAsync(string.Empty, tunnelStream);
}
var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream); var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream);
await Task.WhenAll(sendRelay, receiveRelay); await Task.WhenAll(sendRelay, receiveRelay);
} }
catch
{
throw;
}
finally finally
{ {
tcpConnection.Dispose(); tcpConnection.Dispose();
} }
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.Tcp;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
...@@ -14,6 +17,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -14,6 +17,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public class HttpWebClient public class HttpWebClient
{ {
private int processId;
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
...@@ -25,24 +30,36 @@ namespace Titanium.Web.Proxy.Http ...@@ -25,24 +30,36 @@ namespace Titanium.Web.Proxy.Http
public Response Response { get; set; } public Response Response { get; set; }
/// <summary> /// <summary>
/// Is Https? /// PID of the process that is created the current session
/// </summary> /// </summary>
public bool IsHttps public int ProcessId
{ {
get get
{ {
return this.Request.RequestUri.Scheme == Uri.UriSchemeHttps; if (processId == 0)
{
TcpRow tcpRow = TcpHelper.GetExtendedTcpTable().TcpRows.FirstOrDefault(row => row.LocalEndPoint.Port == ServerConnection.port);
processId = tcpRow?.ProcessId ?? -1;
}
return processId;
} }
} }
/// <summary> /// <summary>
/// Is Https?
/// </summary>
public bool IsHttps => this.Request.RequestUri.Scheme == Uri.UriSchemeHttps;
/// <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"></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;
ServerConnection = Connection; ServerConnection = connection;
} }
internal HttpWebClient() internal HttpWebClient()
...@@ -64,28 +81,18 @@ namespace Titanium.Web.Proxy.Http ...@@ -64,28 +81,18 @@ namespace Titanium.Web.Proxy.Http
//prepare the request & headers //prepare the request & headers
if ((ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false) || (ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps == true)) if ((ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false) || (ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps == true))
{ {
requestLines.AppendLine(string.Join(" ", new string[3] requestLines.AppendLine(string.Join(" ", this.Request.Method, this.Request.RequestUri.AbsoluteUri, $"HTTP/{this.Request.HttpVersion.Major}.{this.Request.HttpVersion.Minor}"));
{
this.Request.Method,
this.Request.RequestUri.AbsoluteUri,
string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor)
}));
} }
else else
{ {
requestLines.AppendLine(string.Join(" ", new string[3] requestLines.AppendLine(string.Join(" ", this.Request.Method, this.Request.RequestUri.PathAndQuery, $"HTTP/{this.Request.HttpVersion.Major}.{this.Request.HttpVersion.Minor}"));
{
this.Request.Method,
this.Request.RequestUri.PathAndQuery,
string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor)
}));
} }
//Send Authentication to Upstream proxy if needed //Send Authentication to Upstream proxy if needed
if (ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false && ServerConnection.UpStreamHttpProxy.UserName != null && ServerConnection.UpStreamHttpProxy.UserName != "" && ServerConnection.UpStreamHttpProxy.Password != null) if (ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false && !string.IsNullOrEmpty(ServerConnection.UpStreamHttpProxy.UserName) && ServerConnection.UpStreamHttpProxy.Password != null)
{ {
requestLines.AppendLine("Proxy-Connection: keep-alive"); requestLines.AppendLine("Proxy-Connection: keep-alive");
requestLines.AppendLine("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(ServerConnection.UpStreamHttpProxy.UserName + ":" + ServerConnection.UpStreamHttpProxy.Password))); requestLines.AppendLine("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ServerConnection.UpStreamHttpProxy.UserName + ":" + ServerConnection.UpStreamHttpProxy.Password)));
} }
//write request headers //write request headers
foreach (var headerItem in this.Request.RequestHeaders) foreach (var headerItem in this.Request.RequestHeaders)
...@@ -115,8 +122,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -115,8 +122,6 @@ namespace Titanium.Web.Proxy.Http
string request = requestLines.ToString(); string request = requestLines.ToString();
byte[] requestBytes = Encoding.ASCII.GetBytes(request); byte[] requestBytes = Encoding.ASCII.GetBytes(request);
var test = Encoding.UTF8.GetString(requestBytes);
await stream.WriteAsync(requestBytes, 0, requestBytes.Length); await stream.WriteAsync(requestBytes, 0, requestBytes.Length);
await stream.FlushAsync(); await stream.FlushAsync();
...@@ -217,12 +222,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -217,12 +222,9 @@ namespace Titanium.Web.Proxy.Http
{ {
var existing = Response.ResponseHeaders[newHeader.Name]; var existing = Response.ResponseHeaders[newHeader.Name];
var nonUniqueHeaders = new List<HttpHeader>(); var nonUniqueHeaders = new List<HttpHeader> {existing, newHeader};
nonUniqueHeaders.Add(existing);
nonUniqueHeaders.Add(newHeader);
Response.NonUniqueResponseHeaders.Add(newHeader.Name, nonUniqueHeaders); Response.NonUniqueResponseHeaders.Add(newHeader.Name, nonUniqueHeaders);
Response.ResponseHeaders.Remove(newHeader.Name); Response.ResponseHeaders.Remove(newHeader.Name);
} }
//add to unique header collection //add to unique header collection
...@@ -233,5 +235,4 @@ namespace Titanium.Web.Proxy.Http ...@@ -233,5 +235,4 @@ namespace Titanium.Web.Proxy.Http
} }
} }
} }
}
} \ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -234,13 +233,14 @@ namespace Titanium.Web.Proxy.Http ...@@ -234,13 +233,14 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Request Url /// Request Url
/// </summary> /// </summary>
public string Url { get { return RequestUri.OriginalString; } } public string Url => RequestUri.OriginalString;
/// <summary> /// <summary>
/// Encoding for this request /// Encoding for this request
/// </summary> /// </summary>
internal Encoding Encoding { get { return this.GetEncoding(); } } internal Encoding Encoding => this.GetEncoding();
/// <summary>
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request /// Terminates the underlying Tcp Connection to client after current request
/// </summary> /// </summary>
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
......
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -16,9 +15,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -16,9 +15,9 @@ namespace Titanium.Web.Proxy.Http
public string ResponseStatusCode { get; set; } public string ResponseStatusCode { get; set; }
public string ResponseStatusDescription { get; set; } public string ResponseStatusDescription { get; set; }
internal Encoding Encoding { get { return this.GetResponseCharacterEncoding(); } } internal Encoding Encoding => this.GetResponseCharacterEncoding();
/// <summary> /// <summary>
/// Content encoding for this response /// Content encoding for this response
/// </summary> /// </summary>
internal string ContentEncoding internal string ContentEncoding
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// 200 Ok response /// 200 Ok response
/// </summary> /// </summary>
public class OkResponse : Response public sealed class OkResponse : Response
{ {
public OkResponse() public OkResponse()
{ {
......
using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.Http.Responses
namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary> /// <summary>
/// Redirect response /// Redirect response
/// </summary> /// </summary>
public class RedirectResponse : Response public sealed class RedirectResponse : Response
{ {
public RedirectResponse() public RedirectResponse()
{ {
......
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading;
using System.Linq; using System.Linq;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Diagnostics;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
......
...@@ -56,11 +56,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -56,11 +56,11 @@ namespace Titanium.Web.Proxy.Network
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true))
{ {
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} HTTP/{2}", remoteHostName, remotePort,httpVersion)); await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", remoteHostName, remotePort)); await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
await writer.WriteLineAsync("Connection: Keep-Alive"); await writer.WriteLineAsync("Connection: Keep-Alive");
if (externalHttpsProxy.UserName != null && externalHttpsProxy.UserName != "" && externalHttpsProxy.Password != null) if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null)
{ {
await writer.WriteLineAsync("Proxy-Connection: keep-alive"); await writer.WriteLineAsync("Proxy-Connection: keep-alive");
await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password))); await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password)));
......
...@@ -9,7 +9,6 @@ using Titanium.Web.Proxy.Models; ...@@ -9,7 +9,6 @@ using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using System.Linq; using System.Linq;
using System.Security.Authentication; using System.Security.Authentication;
using System.Collections.Concurrent;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -18,22 +17,13 @@ namespace Titanium.Web.Proxy ...@@ -18,22 +17,13 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public partial class ProxyServer : IDisposable public partial class ProxyServer : IDisposable
{ {
private static Action<Exception> _exceptionFunc=null; private static readonly Lazy<Action<Exception>> _defaultExceptionFunc = new Lazy<Action<Exception>>(() => (e => { }));
private static Action<Exception> _exceptionFunc;
public static Action<Exception> ExceptionFunc public static Action<Exception> ExceptionFunc
{ {
get get
{ {
if(_exceptionFunc!=null) return _exceptionFunc ?? _defaultExceptionFunc.Value;
{
return _exceptionFunc;
}
else
{
return (e)=>
{
};
}
} }
set set
{ {
...@@ -157,6 +147,11 @@ namespace Titanium.Web.Proxy ...@@ -157,6 +147,11 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3; public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3;
/// <summary>
/// Is the proxy currently running
/// </summary>
public bool ProxyRunning => proxyRunning;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
......
using System.Net;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Tcp
{
/// <summary>
/// Represents a managed interface of IP Helper API TcpRow struct
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
/// </summary>
internal class TcpRow
{
/// <summary>
/// Initializes a new instance of the <see cref="TcpRow"/> class.
/// </summary>
/// <param name="tcpRow">TcpRow struct.</param>
public TcpRow(NativeMethods.TcpRow tcpRow)
{
ProcessId = tcpRow.owningPid;
int localPort = (tcpRow.localPort1 << 8) + (tcpRow.localPort2) + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
long localAddress = tcpRow.localAddr;
LocalEndPoint = new IPEndPoint(localAddress, localPort);
}
/// <summary>
/// Gets the local end point.
/// </summary>
public IPEndPoint LocalEndPoint { get; private set; }
/// <summary>
/// Gets the process identifier.
/// </summary>
public int ProcessId { get; private set; }
}
}
\ No newline at end of file
using System.Collections;
using System.Collections.Generic;
namespace Titanium.Web.Proxy.Tcp
{
/// <summary>
/// Represents collection of TcpRows
/// </summary>
/// <seealso cref="System.Collections.Generic.IEnumerable{Titanium.Web.Proxy.Tcp.TcpRow}" />
internal class TcpTable : IEnumerable<TcpRow>
{
private readonly IEnumerable<TcpRow> tcpRows;
/// <summary>
/// Initializes a new instance of the <see cref="TcpTable"/> class.
/// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param>
public TcpTable(IEnumerable<TcpRow> tcpRows)
{
this.tcpRows = tcpRows;
}
/// <summary>
/// Gets the TCP rows.
/// </summary>
public IEnumerable<TcpRow> TcpRows => tcpRows;
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator<TcpRow> GetEnumerator()
{
return tcpRows.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
\ No newline at end of file
...@@ -93,6 +93,8 @@ ...@@ -93,6 +93,8 @@
<Compile Include="Http\Responses\OkResponse.cs" /> <Compile Include="Http\Responses\OkResponse.cs" />
<Compile Include="Http\Responses\RedirectResponse.cs" /> <Compile Include="Http\Responses\RedirectResponse.cs" />
<Compile Include="Shared\ProxyConstants.cs" /> <Compile Include="Shared\ProxyConstants.cs" />
<Compile Include="Tcp\TcpRow.cs" />
<Compile Include="Tcp\TcpTable.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<COMReference Include="CERTENROLLLib"> <COMReference Include="CERTENROLLLib">
......
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