Commit 0dd28233 authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #282 from honfika/develop

Websocket fix in GUI demo + handle user exceptions in TWP
parents 9eb2546f dd8d719e
...@@ -119,7 +119,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -119,7 +119,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf
if (item != null) if (item != null)
{ {
item.ResponseBody = await e.GetResponseBody(); if (e.WebSession.Response.HasBody)
{
item.ResponseBody = await e.GetResponseBody();
}
} }
} }
...@@ -195,18 +198,30 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -195,18 +198,30 @@ namespace Titanium.Web.Proxy.Examples.Wpf
return; return;
} }
const int truncateLimit = 1024;
var session = SelectedSession; var session = SelectedSession;
var data = session.RequestBody ?? new byte[0]; var data = session.RequestBody ?? new byte[0];
data = data.Take(1024).ToArray(); bool truncated = data.Length > truncateLimit;
if (truncated)
{
data = data.Take(truncateLimit).ToArray();
}
string dataStr = string.Join(" ", data.Select(x => x.ToString("X2"))); //string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxRequest.Text = session.Request.HeaderText + dataStr; TextBoxRequest.Text = session.Request.HeaderText + session.Request.Encoding.GetString(data) +
(truncated ? Environment.NewLine + $"Data is truncated after {truncateLimit} bytes" : null);
data = session.ResponseBody ?? new byte[0]; data = session.ResponseBody ?? new byte[0];
data = data.Take(1024).ToArray(); truncated = data.Length > truncateLimit;
if (truncated)
{
data = data.Take(truncateLimit).ToArray();
}
dataStr = string.Join(" ", data.Select(x => x.ToString("X2"))); //hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxResponse.Text = session.Response.HeaderText + dataStr; TextBoxResponse.Text = session.Response.HeaderText + session.Response.Encoding.GetString(data) +
(truncated ? Environment.NewLine + $"Data is truncated after {truncateLimit} bytes" : null);
} }
} }
} }
using System;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
public class DataEventArgs public class DataEventArgs : EventArgs
{ {
public byte[] Buffer { get; } public byte[] Buffer { get; }
......
...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Does this session uses SSL /// Does this session uses SSL
/// </summary> /// </summary>
public bool IsHttps => WebSession.Request.RequestUri.Scheme == Uri.UriSchemeHttps; public bool IsHttps => WebSession.Request.RequestUri.Scheme == ProxyServer.UriSchemeHttps;
/// <summary> /// <summary>
/// Client End Point. /// Client End Point.
...@@ -109,6 +109,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -109,6 +109,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.ProcessId = new Lazy<int>(() => WebSession.ProcessId = new Lazy<int>(() =>
{ {
#if NET45
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id //If client is localhost get the process id
...@@ -119,6 +120,9 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -119,6 +120,9 @@ namespace Titanium.Web.Proxy.EventArguments
//can't access process Id of remote request from remote machine //can't access process Id of remote request from remote machine
return -1; return -1;
#else
throw new PlatformNotSupportedException();
#endif
}); });
} }
...@@ -198,28 +202,35 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -198,28 +202,35 @@ namespace Titanium.Web.Proxy.EventArguments
//If not already read (not cached yet) //If not already read (not cached yet)
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
{ {
using (var responseBodyStream = new MemoryStream()) if (WebSession.Response.HasBody)
{ {
//If chuncked the read chunk by chunk until we hit chunk end symbol using (var responseBodyStream = new MemoryStream())
if (WebSession.Response.IsChunked)
{ {
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream); //If chuncked the read chunk by chunk until we hit chunk end symbol
} if (WebSession.Response.IsChunked)
else
{
if (WebSession.Response.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream);
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength);
} }
else if (WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0 || else
WebSession.Response.ContentLength == -1)
{ {
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue); if (WebSession.Response.ContentLength > 0)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength);
}
else if (WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0 ||
WebSession.Response.ContentLength == -1)
{
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue);
}
} }
}
WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()); WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray());
}
}
else
{
WebSession.Response.ResponseBody = new byte[0];
} }
//set this to true for caching //set this to true for caching
......
...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class TunnelConnectSessionEventArgs : SessionEventArgs public class TunnelConnectSessionEventArgs : SessionEventArgs
{ {
public bool IsHttps { get; set; } public bool IsHttpsConnect { get; set; }
public TunnelConnectSessionEventArgs(ProxyEndPoint endPoint) : base(0, endPoint, null) public TunnelConnectSessionEventArgs(ProxyEndPoint endPoint) : base(0, endPoint, null)
{ {
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Extensions
{
internal static class DotNetStandardExtensions
{
#if NET45
/// <summary>
/// Disposes the specified client.
/// Int .NET framework 4.5 the TcpClient class has no Dispose method,
/// it is available from .NET 4.6, see
/// https://msdn.microsoft.com/en-us/library/dn823304(v=vs.110).aspx
/// </summary>
/// <param name="client">The client.</param>
internal static void Dispose(this TcpClient client)
{
client.Close();
}
/// <summary>
/// Disposes the specified store.
/// Int .NET framework 4.5 the X509Store class has no Dispose method,
/// it is available from .NET 4.6, see
/// https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509store.dispose(v=vs.110).aspx
/// </summary>
/// <param name="store">The store.</param>
internal static void Dispose(this X509Store store)
{
store.Close();
}
#endif
}
}
...@@ -18,17 +18,30 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -18,17 +18,30 @@ namespace Titanium.Web.Proxy.Extensions
Task.WhenAll(handlerTasks).Wait(); Task.WhenAll(handlerTasks).Wait();
} }
public static async Task InvokeParallelAsync<T>(this Func<object, T, Task> callback, object sender, T args) public static async Task InvokeParallelAsync<T>(this Func<object, T, Task> callback, object sender, T args, Action<Exception> exceptionFunc)
{ {
var invocationList = callback.GetInvocationList(); var invocationList = callback.GetInvocationList();
var handlerTasks = new Task[invocationList.Length]; var handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++) for (int i = 0; i < invocationList.Length; i++)
{ {
handlerTasks[i] = ((Func<object, T, Task>)invocationList[i])(sender, args); handlerTasks[i] = InvokeAsync((Func<object, T, Task>)invocationList[i], sender, args, exceptionFunc);
} }
await Task.WhenAll(handlerTasks); await Task.WhenAll(handlerTasks);
} }
private static async Task InvokeAsync<T>(Func<object, T, Task> callback, object sender, T args, Action<Exception> exceptionFunc)
{
try
{
await callback(sender, args);
}
catch (Exception ex)
{
var ex2 = new Exception("Exception thrown in user event", ex);
exceptionFunc(ex2);
}
}
} }
} }
...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Extensions
catch (SocketException e) catch (SocketException e)
{ {
// 10035 == WSAEWOULDBLOCK // 10035 == WSAEWOULDBLOCK
return e.NativeErrorCode.Equals(10035); return e.SocketErrorCode == SocketError.WouldBlock;
} }
finally finally
{ {
...@@ -34,6 +34,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -34,6 +34,7 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
#if NET45
/// <summary> /// <summary>
/// Gets the local port from a native TCP row object. /// Gets the local port from a native TCP row object.
/// </summary> /// </summary>
...@@ -53,5 +54,6 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -53,5 +54,6 @@ namespace Titanium.Web.Proxy.Extensions
{ {
return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16); return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
} }
#endif
} }
} }
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.Remoting;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -14,7 +13,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -14,7 +13,9 @@ namespace Titanium.Web.Proxy.Helpers
/// <seealso cref="System.IO.Stream" /> /// <seealso cref="System.IO.Stream" />
internal class CustomBufferedStream : Stream internal class CustomBufferedStream : Stream
{ {
#if NET45
private AsyncCallback readCallback; private AsyncCallback readCallback;
#endif
private readonly Stream baseStream; private readonly Stream baseStream;
...@@ -35,7 +36,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -35,7 +36,9 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="bufferSize">Size of the buffer.</param> /// <param name="bufferSize">Size of the buffer.</param>
public CustomBufferedStream(Stream baseStream, int bufferSize) public CustomBufferedStream(Stream baseStream, int bufferSize)
{ {
#if NET45
readCallback = ReadCallback; readCallback = ReadCallback;
#endif
this.baseStream = baseStream; this.baseStream = baseStream;
streamBuffer = BufferPool.GetBuffer(bufferSize); streamBuffer = BufferPool.GetBuffer(bufferSize);
} }
...@@ -111,6 +114,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -111,6 +114,7 @@ namespace Titanium.Web.Proxy.Helpers
baseStream.Write(buffer, offset, count); baseStream.Write(buffer, offset, count);
} }
#if NET45
/// <summary> /// <summary>
/// Begins an asynchronous read operation. (Consider using <see cref="M:System.IO.Stream.ReadAsync(System.Byte[],System.Int32,System.Int32)" /> instead; see the Remarks section.) /// Begins an asynchronous read operation. (Consider using <see cref="M:System.IO.Stream.ReadAsync(System.Byte[],System.Int32,System.Int32)" /> instead; see the Remarks section.)
/// </summary> /// </summary>
...@@ -163,6 +167,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -163,6 +167,7 @@ namespace Titanium.Web.Proxy.Helpers
OnDataSent(buffer, offset, count); OnDataSent(buffer, offset, count);
return baseStream.BeginWrite(buffer, offset, count, callback, state); return baseStream.BeginWrite(buffer, offset, count, callback, state);
} }
#endif
/// <summary> /// <summary>
/// Asynchronously reads the bytes from the current stream and writes them to another stream, using a specified buffer size and cancellation token. /// Asynchronously reads the bytes from the current stream and writes them to another stream, using a specified buffer size and cancellation token.
...@@ -184,18 +189,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -184,18 +189,7 @@ namespace Titanium.Web.Proxy.Helpers
await base.CopyToAsync(destination, bufferSize, cancellationToken); await base.CopyToAsync(destination, bufferSize, cancellationToken);
} }
/// <summary> #if NET45
/// Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object.
/// </summary>
/// <param name="requestedType">The <see cref="T:System.Type" /> of the object that the new <see cref="T:System.Runtime.Remoting.ObjRef" /> will reference.</param>
/// <returns>
/// Information required to generate a proxy.
/// </returns>
public override ObjRef CreateObjRef(Type requestedType)
{
return baseStream.CreateObjRef(requestedType);
}
/// <summary> /// <summary>
/// Waits for the pending asynchronous read to complete. (Consider using <see cref="M:System.IO.Stream.ReadAsync(System.Byte[],System.Int32,System.Int32)" /> instead; see the Remarks section.) /// Waits for the pending asynchronous read to complete. (Consider using <see cref="M:System.IO.Stream.ReadAsync(System.Byte[],System.Int32,System.Int32)" /> instead; see the Remarks section.)
/// </summary> /// </summary>
...@@ -222,6 +216,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -222,6 +216,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
baseStream.EndWrite(asyncResult); baseStream.EndWrite(asyncResult);
} }
#endif
/// <summary> /// <summary>
/// Asynchronously clears all buffers for this stream, causes any buffered data to be written to the underlying device, and monitors cancellation requests. /// Asynchronously clears all buffers for this stream, causes any buffered data to be written to the underlying device, and monitors cancellation requests.
...@@ -235,17 +230,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -235,17 +230,6 @@ namespace Titanium.Web.Proxy.Helpers
return baseStream.FlushAsync(cancellationToken); return baseStream.FlushAsync(cancellationToken);
} }
/// <summary>
/// Obtains a lifetime service object to control the lifetime policy for this instance.
/// </summary>
/// <returns>
/// An object of type <see cref="T:System.Runtime.Remoting.Lifetime.ILease" /> used to control the lifetime policy for this instance. This is the current lifetime service object for this instance if one exists; otherwise, a new lifetime service object initialized to the value of the <see cref="P:System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseManagerPollTime" /> property.
/// </returns>
public override object InitializeLifetimeService()
{
return baseStream.InitializeLifetimeService();
}
/// <summary> /// <summary>
/// Asynchronously reads a sequence of bytes from the current stream, /// Asynchronously reads a sequence of bytes from the current stream,
/// advances the position within the stream by the number of bytes read, /// advances the position within the stream by the number of bytes read,
...@@ -380,7 +364,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -380,7 +364,9 @@ namespace Titanium.Web.Proxy.Helpers
baseStream.Dispose(); baseStream.Dispose();
BufferPool.ReturnBuffer(streamBuffer); BufferPool.ReturnBuffer(streamBuffer);
streamBuffer = null; streamBuffer = null;
#if NET45
readCallback = null; readCallback = null;
#endif
} }
} }
......
using System;
using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Helpers
{
internal partial class NativeMethods
{
[DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow();
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
// Pinvoke
internal delegate bool ConsoleEventDelegate(int eventType);
}
}
\ No newline at end of file
using System;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Helpers
{
internal partial class NativeMethods
{
internal const int AfInet = 2;
internal const int AfInet6 = 23;
internal enum TcpTableType
{
BasicListener,
BasicConnections,
BasicAll,
OwnerPidListener,
OwnerPidConnections,
OwnerPidAll,
OwnerModuleListener,
OwnerModuleConnections,
OwnerModuleAll,
}
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct TcpTable
{
public uint length;
public TcpRow row;
}
/// <summary>
/// <see href="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 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);
}
}
\ No newline at end of file
...@@ -6,6 +6,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -6,6 +6,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class NetworkHelper internal class NetworkHelper
{ {
#if NET45
private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion) private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion)
{ {
var tcpRow = TcpHelper.GetTcpRowByLocalPort(ipVersion, port); var tcpRow = TcpHelper.GetTcpRowByLocalPort(ipVersion, port);
...@@ -74,5 +75,56 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -74,5 +75,56 @@ namespace Titanium.Web.Proxy.Helpers
return isLocalhost; return isLocalhost;
} }
#else
/// <summary>
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
internal static bool IsLocalIpAddress(IPAddress address)
{
// get local IP addresses
var localIPs = Dns.GetHostAddressesAsync(Dns.GetHostName()).Result;
// test if any host IP equals to any local IP or to localhost
return IPAddress.IsLoopback(address) || localIPs.Contains(address);
}
internal static bool IsLocalIpAddress(string hostName)
{
bool isLocalhost = false;
var localhost = Dns.GetHostEntryAsync("127.0.0.1").Result;
if (hostName == localhost.HostName)
{
var hostEntry = Dns.GetHostEntryAsync(hostName).Result;
isLocalhost = hostEntry.AddressList.Any(IPAddress.IsLoopback);
}
if (!isLocalhost)
{
localhost = Dns.GetHostEntryAsync(Dns.GetHostName()).Result;
IPAddress ipAddress;
if (IPAddress.TryParse(hostName, out ipAddress))
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
if (!isLocalhost)
{
try
{
var hostEntry = Dns.GetHostEntryAsync(hostName).Result;
isLocalhost = localhost.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals));
}
catch (SocketException)
{
}
}
}
return isLocalhost;
}
#endif
} }
} }
...@@ -127,11 +127,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -127,11 +127,11 @@ namespace Titanium.Web.Proxy.Helpers
} }
ProxyProtocolType? protocolType = null; ProxyProtocolType? protocolType = null;
if (protocolTypeStr.Equals("http", StringComparison.InvariantCultureIgnoreCase)) if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttp, StringComparison.InvariantCultureIgnoreCase))
{ {
protocolType = ProxyProtocolType.Http; protocolType = ProxyProtocolType.Http;
} }
else if (protocolTypeStr.Equals("https", StringComparison.InvariantCultureIgnoreCase)) else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps, StringComparison.InvariantCultureIgnoreCase))
{ {
protocolType = ProxyProtocolType.Https; protocolType = ProxyProtocolType.Https;
} }
......
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32; using Microsoft.Win32;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
...@@ -30,24 +29,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -30,24 +29,6 @@ namespace Titanium.Web.Proxy.Helpers
AllHttp = Http | Https, AllHttp = Http | Https,
} }
internal partial class NativeMethods
{
[DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow();
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
// Pinvoke
internal delegate bool ConsoleEventDelegate(int eventType);
}
internal class HttpSystemProxyValue internal class HttpSystemProxyValue
{ {
internal string HostName { get; set; } internal string HostName { get; set; }
...@@ -62,10 +43,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -62,10 +43,10 @@ namespace Titanium.Web.Proxy.Helpers
switch (ProtocolType) switch (ProtocolType)
{ {
case ProxyProtocolType.Http: case ProxyProtocolType.Http:
protocol = "http"; protocol = ProxyServer.UriSchemeHttp;
break; break;
case ProxyProtocolType.Https: case ProxyProtocolType.Https:
protocol = "https"; protocol = Proxy.ProxyServer.UriSchemeHttps;
break; break;
default: default:
throw new Exception("Unsupported protocol type"); throw new Exception("Unsupported protocol type");
......
using System; using System;
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.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading;
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;
...@@ -20,63 +18,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -20,63 +18,9 @@ namespace Titanium.Web.Proxy.Helpers
Ipv6 = 2, Ipv6 = 2,
} }
internal partial class NativeMethods
{
internal const int AfInet = 2;
internal const int AfInet6 = 23;
internal enum TcpTableType
{
BasicListener,
BasicConnections,
BasicAll,
OwnerPidListener,
OwnerPidConnections,
OwnerPidAll,
OwnerModuleListener,
OwnerModuleConnections,
OwnerModuleAll,
}
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct TcpTable
{
public uint length;
public TcpRow row;
}
/// <summary>
/// <see href="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 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 class TcpHelper internal class TcpHelper
{ {
#if NET45
/// <summary> /// <summary>
/// Gets the extended TCP table. /// Gets the extended TCP table.
/// </summary> /// </summary>
...@@ -165,6 +109,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -165,6 +109,7 @@ namespace Titanium.Web.Proxy.Helpers
return null; return null;
} }
#endif
/// <summary> /// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix /// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
...@@ -202,7 +147,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -202,7 +147,7 @@ namespace Titanium.Web.Proxy.Helpers
writer.Flush(); writer.Flush();
var data = ms.ToArray(); var data = ms.ToArray();
await ms.WriteAsync(data, 0, data.Length); await clientStream.WriteAsync(data, 0, data.Length);
onDataSend?.Invoke(data, 0, data.Length); onDataSend?.Invoke(data, 0, data.Length);
} }
} }
...@@ -217,4 +162,4 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -217,4 +162,4 @@ namespace Titanium.Web.Proxy.Helpers
await Task.WhenAll(sendRelay, receiveRelay); await Task.WhenAll(sendRelay, receiveRelay);
} }
} }
} }
\ No newline at end of file
...@@ -48,7 +48,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -48,7 +48,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Is Https? /// Is Https?
/// </summary> /// </summary>
public bool IsHttps => Request.RequestUri.Scheme == Uri.UriSchemeHttps; public bool IsHttps => Request.RequestUri.Scheme == ProxyServer.UriSchemeHttps;
internal HttpWebClient() internal HttpWebClient()
......
...@@ -37,6 +37,31 @@ namespace Titanium.Web.Proxy.Http ...@@ -37,6 +37,31 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public Version HttpVersion { get; set; } public Version HttpVersion { get; set; }
/// <summary>
/// Has response body?
/// </summary>
public bool HasBody
{
get
{
//Has body only if response is chunked or content length >0
//If none are true then check if connection:close header exist, if so write response until server or client terminates the connection
if (IsChunked || ContentLength > 0 || !ResponseKeepAlive)
{
return true;
}
//has response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
if (ResponseKeepAlive && HttpVersion.Minor == 0)
{
return true;
}
return false;
}
}
/// <summary> /// <summary>
/// Keep the connection alive? /// Keep the connection alive?
/// </summary> /// </summary>
......
using System; #if NET45
using System;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1;
...@@ -189,3 +190,4 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -189,3 +190,4 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
} }
} }
#endif
\ No newline at end of file
...@@ -7,6 +7,7 @@ using System.Linq; ...@@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Certificate; using Titanium.Web.Proxy.Network.Certificate;
...@@ -38,11 +39,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -38,11 +39,13 @@ namespace Titanium.Web.Proxy.Network
get { return engine; } get { return engine; }
set set
{ {
#if NET45
//For Mono only Bouncy Castle is supported //For Mono only Bouncy Castle is supported
if (RunTime.IsRunningOnMono) if (RunTime.IsRunningOnMono)
{ {
value = CertificateEngine.BouncyCastle; value = CertificateEngine.BouncyCastle;
} }
#endif
if (value != engine) if (value != engine)
{ {
...@@ -52,7 +55,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -52,7 +55,11 @@ namespace Titanium.Web.Proxy.Network
if (certEngine == null) if (certEngine == null)
{ {
#if NET45
certEngine = engine == CertificateEngine.BouncyCastle ? (ICertificateMaker)new BCCertificateMaker() : new WinCertificateMaker(); certEngine = engine == CertificateEngine.BouncyCastle ? (ICertificateMaker)new BCCertificateMaker() : new WinCertificateMaker();
#else
certEngine = new BCCertificateMaker();
#endif
} }
} }
} }
...@@ -132,7 +139,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -132,7 +139,11 @@ namespace Titanium.Web.Proxy.Network
private string GetRootCertificatePath() private string GetRootCertificatePath()
{ {
#if NET45
string assemblyLocation = Assembly.GetExecutingAssembly().Location; string assemblyLocation = Assembly.GetExecutingAssembly().Location;
#else
string assemblyLocation = string.Empty;
#endif
// dynamically loaded assemblies returns string.Empty location // dynamically loaded assemblies returns string.Empty location
if (assemblyLocation == string.Empty) if (assemblyLocation == string.Empty)
...@@ -219,6 +230,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -219,6 +230,7 @@ namespace Titanium.Web.Proxy.Network
TrustRootCertificate(StoreLocation.LocalMachine); TrustRootCertificate(StoreLocation.LocalMachine);
} }
#if NET45
/// <summary> /// <summary>
/// Puts the certificate to the local machine's certificate store. /// Puts the certificate to the local machine's certificate store.
/// Needs elevated permission. Works only on Windows. /// Needs elevated permission. Works only on Windows.
...@@ -263,6 +275,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -263,6 +275,7 @@ namespace Titanium.Web.Proxy.Network
return true; return true;
} }
#endif
/// <summary> /// <summary>
/// Removes the trusted certificates. /// Removes the trusted certificates.
...@@ -276,6 +289,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -276,6 +289,7 @@ namespace Titanium.Web.Proxy.Network
RemoveTrustedRootCertificates(StoreLocation.LocalMachine); RemoveTrustedRootCertificates(StoreLocation.LocalMachine);
} }
#if NET45
/// <summary> /// <summary>
/// Removes the trusted certificates from the local machine's certificate store. /// Removes the trusted certificates from the local machine's certificate store.
/// Needs elevated permission. Works only on Windows. /// Needs elevated permission. Works only on Windows.
...@@ -315,6 +329,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -315,6 +329,7 @@ namespace Titanium.Web.Proxy.Network
return true; return true;
} }
#endif
/// <summary> /// <summary>
/// Determines whether the root certificate is trusted. /// Determines whether the root certificate is trusted.
...@@ -348,7 +363,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -348,7 +363,7 @@ namespace Titanium.Web.Proxy.Network
} }
finally finally
{ {
x509Store.Close(); x509Store.Dispose();
} }
} }
...@@ -368,8 +383,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -368,8 +383,11 @@ namespace Titanium.Web.Proxy.Network
} }
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
// todo: lock in netstandard, too
#if NET45
lock (string.Intern(certificateName)) lock (string.Intern(certificateName))
{ {
#endif
if (certificateCache.ContainsKey(certificateName) == false) if (certificateCache.ContainsKey(certificateName) == false)
{ {
try try
...@@ -402,7 +420,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -402,7 +420,9 @@ namespace Titanium.Web.Proxy.Network
return cached.Certificate; return cached.Certificate;
} }
} }
} #if NET45
}
#endif
return certificate; return certificate;
} }
...@@ -470,8 +490,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -470,8 +490,8 @@ namespace Titanium.Web.Proxy.Network
} }
finally finally
{ {
x509RootStore.Close(); x509RootStore.Dispose();
x509PersonalStore.Close(); x509PersonalStore.Dispose();
} }
} }
...@@ -510,8 +530,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -510,8 +530,8 @@ namespace Titanium.Web.Proxy.Network
} }
finally finally
{ {
x509RootStore.Close(); x509RootStore.Dispose();
x509PersonalStore.Close(); x509PersonalStore.Dispose();
} }
} }
......
using System; using System;
using System.IO; using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
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;
...@@ -57,7 +58,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -57,7 +58,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
Stream?.Close(); Stream?.Dispose();
StreamReader?.Dispose(); StreamReader?.Dispose();
...@@ -70,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -70,7 +71,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion //It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes //due to default TCP CLOSE_WAIT timeout for 4 minutes
TcpClient.LingerState = new LingerOption(true, 0); TcpClient.LingerState = new LingerOption(true, 0);
TcpClient.Close(); TcpClient.Dispose();
} }
} }
catch catch
......
...@@ -55,7 +55,11 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -55,7 +55,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
//If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections //If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
if (useProxy) if (useProxy)
{ {
#if NET45
client = new TcpClient(server.UpStreamEndPoint); client = new TcpClient(server.UpStreamEndPoint);
#else
client = new TcpClient(server.UpStreamEndPoint.AddressFamily);
#endif
await client.ConnectAsync(externalProxy.HostName, externalProxy.Port); await client.ConnectAsync(externalProxy.HostName, externalProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize); stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
...@@ -77,7 +81,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -77,7 +81,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
await writer.WriteLineAsync(); await writer.WriteLineAsync();
await writer.FlushAsync(); await writer.FlushAsync();
writer.Close();
} }
using (var reader = new CustomBinaryReader(stream, server.BufferSize)) using (var reader = new CustomBinaryReader(stream, server.BufferSize))
...@@ -94,7 +97,11 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -94,7 +97,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
else else
{ {
#if NET45
client = new TcpClient(server.UpStreamEndPoint); client = new TcpClient(server.UpStreamEndPoint);
#else
client = new TcpClient(server.UpStreamEndPoint.AddressFamily);
#endif
await client.ConnectAsync(remoteHostName, remotePort); await client.ConnectAsync(remoteHostName, remotePort);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize); stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
} }
...@@ -113,7 +120,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -113,7 +120,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
catch (Exception) catch (Exception)
{ {
stream?.Dispose(); stream?.Dispose();
client?.Close(); client?.Dispose();
throw; throw;
} }
......
This diff is collapsed.
...@@ -111,14 +111,14 @@ namespace Titanium.Web.Proxy ...@@ -111,14 +111,14 @@ namespace Titanium.Web.Proxy
if (TunnelConnectRequest != null) if (TunnelConnectRequest != null)
{ {
await TunnelConnectRequest.InvokeParallelAsync(this, connectArgs); await TunnelConnectRequest.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
} }
if (!excluded && await CheckAuthorization(clientStreamWriter, connectArgs) == false) if (!excluded && await CheckAuthorization(clientStreamWriter, connectArgs) == false)
{ {
if (TunnelConnectResponse != null) if (TunnelConnectResponse != null)
{ {
await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs); await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
} }
return; return;
...@@ -132,8 +132,8 @@ namespace Titanium.Web.Proxy ...@@ -132,8 +132,8 @@ namespace Titanium.Web.Proxy
if (TunnelConnectResponse != null) if (TunnelConnectResponse != null)
{ {
connectArgs.IsHttps = isClientHello; connectArgs.IsHttpsConnect = isClientHello;
await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs); await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
} }
if (!excluded && isClientHello) if (!excluded && isClientHello)
...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy ...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy
//Now create the request //Now create the request
disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequest); httpRemoteUri.Scheme == UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequest);
} }
catch (Exception e) catch (Exception e)
{ {
...@@ -338,6 +338,7 @@ namespace Titanium.Web.Proxy ...@@ -338,6 +338,7 @@ namespace Titanium.Web.Proxy
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders); PrepareRequestHeaders(args.WebSession.Request.RequestHeaders);
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
#if NET45
//if win auth is enabled //if win auth is enabled
//we need a cache of request body //we need a cache of request body
//so that we can send it after authentication in WinAuthHandler.cs //so that we can send it after authentication in WinAuthHandler.cs
...@@ -345,11 +346,12 @@ namespace Titanium.Web.Proxy ...@@ -345,11 +346,12 @@ namespace Titanium.Web.Proxy
{ {
await args.GetRequestBody(); await args.GetRequestBody();
} }
#endif
//If user requested interception do it //If user requested interception do it
if (BeforeRequest != null) if (BeforeRequest != null)
{ {
await BeforeRequest.InvokeParallelAsync(this, args); await BeforeRequest.InvokeParallelAsync(this, args, ExceptionFunc);
} }
if (args.WebSession.Request.CancelRequest) if (args.WebSession.Request.CancelRequest)
...@@ -546,7 +548,7 @@ namespace Titanium.Web.Proxy ...@@ -546,7 +548,7 @@ namespace Titanium.Web.Proxy
ExternalProxy customUpStreamHttpProxy = null; ExternalProxy customUpStreamHttpProxy = null;
ExternalProxy customUpStreamHttpsProxy = null; ExternalProxy customUpStreamHttpsProxy = null;
if (args.WebSession.Request.RequestUri.Scheme == "http") if (args.WebSession.Request.RequestUri.Scheme == UriSchemeHttp)
{ {
if (GetCustomUpStreamHttpProxyFunc != null) if (GetCustomUpStreamHttpProxyFunc != null)
{ {
......
...@@ -31,10 +31,13 @@ namespace Titanium.Web.Proxy ...@@ -31,10 +31,13 @@ namespace Titanium.Web.Proxy
//read response & headers from server //read response & headers from server
await args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse();
var response = args.WebSession.Response;
#if NET45
//check for windows authentication //check for windows authentication
if (EnableWinAuth if (EnableWinAuth
&& !RunTime.IsRunningOnMono && !RunTime.IsRunningOnMono
&& args.WebSession.Response.ResponseStatusCode == "401") && response.ResponseStatusCode == "401")
{ {
bool disposed = await Handle401UnAuthorized(args); bool disposed = await Handle401UnAuthorized(args);
...@@ -43,13 +46,14 @@ namespace Titanium.Web.Proxy ...@@ -43,13 +46,14 @@ namespace Titanium.Web.Proxy
return true; return true;
} }
} }
#endif
args.ReRequest = false; args.ReRequest = false;
//If user requested call back then do it //If user requested call back then do it
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) if (BeforeResponse != null && !response.ResponseLocked)
{ {
await BeforeResponse.InvokeParallelAsync(this, args); await BeforeResponse.InvokeParallelAsync(this, args, ExceptionFunc);
} }
//if user requested to send request again //if user requested to send request again
...@@ -62,63 +66,55 @@ namespace Titanium.Web.Proxy ...@@ -62,63 +66,55 @@ namespace Titanium.Web.Proxy
return disposed; return disposed;
} }
args.WebSession.Response.ResponseLocked = true; response.ResponseLocked = true;
//Write back to client 100-conitinue response if that's what server returned //Write back to client 100-conitinue response if that's what server returned
if (args.WebSession.Response.Is100Continue) if (response.Is100Continue)
{ {
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100", "Continue", args.ProxyClient.ClientStreamWriter); await WriteResponseStatus(response.HttpVersion, "100", "Continue", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync(); await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
} }
else if (args.WebSession.Response.ExpectationFailed) else if (response.ExpectationFailed)
{ {
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417", "Expectation Failed", args.ProxyClient.ClientStreamWriter); await WriteResponseStatus(response.HttpVersion, "417", "Expectation Failed", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync(); await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
} }
//Write back response status to client //Write back response status to client
await WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode, await WriteResponseStatus(response.HttpVersion, response.ResponseStatusCode,
args.WebSession.Response.ResponseStatusDescription, args.ProxyClient.ClientStreamWriter); response.ResponseStatusDescription, args.ProxyClient.ClientStreamWriter);
if (args.WebSession.Response.ResponseBodyRead) if (response.ResponseBodyRead)
{ {
bool isChunked = args.WebSession.Response.IsChunked; bool isChunked = response.IsChunked;
string contentEncoding = args.WebSession.Response.ContentEncoding; string contentEncoding = response.ContentEncoding;
if (contentEncoding != null) if (contentEncoding != null)
{ {
args.WebSession.Response.ResponseBody = await GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody); response.ResponseBody = await GetCompressedResponseBody(contentEncoding, response.ResponseBody);
if (isChunked == false) if (isChunked == false)
{ {
args.WebSession.Response.ContentLength = args.WebSession.Response.ResponseBody.Length; response.ContentLength = response.ResponseBody.Length;
} }
else else
{ {
args.WebSession.Response.ContentLength = -1; response.ContentLength = -1;
} }
} }
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response); await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, response);
await args.ProxyClient.ClientStream.WriteResponseBody(args.WebSession.Response.ResponseBody, isChunked); await args.ProxyClient.ClientStream.WriteResponseBody(response.ResponseBody, isChunked);
} }
else else
{ {
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response); await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, response);
//Write body only if response is chunked or content length >0 //Write body if exists
//Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection if (response.HasBody)
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || !args.WebSession.Response.ResponseKeepAlive)
{
await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(BufferSize, args.ProxyClient.ClientStream,
args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength);
}
//write response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0)
{ {
await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(BufferSize, args.ProxyClient.ClientStream, await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(BufferSize, args.ProxyClient.ClientStream,
args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength); response.IsChunked, response.ContentLength);
} }
} }
...@@ -223,7 +219,6 @@ namespace Titanium.Web.Proxy ...@@ -223,7 +219,6 @@ namespace Titanium.Web.Proxy
/// <param name="serverConnection"></param> /// <param name="serverConnection"></param>
private void Dispose(Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, TcpConnection serverConnection) private void Dispose(Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, TcpConnection serverConnection)
{ {
clientStream?.Close();
clientStream?.Dispose(); clientStream?.Dispose();
clientStreamReader?.Dispose(); clientStreamReader?.Dispose();
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.5</TargetFramework>
<RootNamespace>Titanium.Web.Proxy</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Properties\AssemblyInfo.cs" />
<Compile Remove="Helpers\WinHttp\NativeMethods.WinHttp.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Remove="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
<Compile Remove="Helpers\NativeMethods.SystemProxy.cs" />
<Compile Remove="Helpers\NativeMethods.Tcp.cs" />
<Compile Remove="Helpers\Firefox.cs" />
<Compile Remove="Helpers\ProxyInfo.cs" />
<Compile Remove="Helpers\RunTime.cs" />
<Compile Remove="Helpers\SystemProxy.cs" />
<Compile Remove="Network\Certificate\WinCertificateMaker.cs" />
<Compile Remove="Network\Tcp\TcpRow.cs" />
<Compile Remove="Network\Tcp\TcpTable.cs" />
<Compile Remove="Network\WinAuth\Security\Common.cs" />
<Compile Remove="Network\WinAuth\Security\LittleEndian.cs" />
<Compile Remove="Network\WinAuth\Security\Message.cs" />
<Compile Remove="Network\WinAuth\Security\State.cs" />
<Compile Remove="Network\WinAuth\Security\WinAuthEndPoint.cs" />
<Compile Remove="Network\WinAuth\WinAuthHandler.cs" />
<Compile Remove="WinAuthHandler.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.2" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.1" />
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
<PackageReference Include="System.Security.SecureString" Version="4.3.0" />
</ItemGroup>
</Project>
\ No newline at end of file
...@@ -51,17 +51,16 @@ ...@@ -51,17 +51,16 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CertificateHandler.cs" />
<Compile Include="Compression\CompressionFactory.cs" /> <Compile Include="Compression\CompressionFactory.cs" />
<Compile Include="Compression\DeflateCompression.cs" /> <Compile Include="Compression\DeflateCompression.cs" />
<Compile Include="Compression\GZipCompression.cs" /> <Compile Include="Compression\GZipCompression.cs" />
...@@ -74,69 +73,75 @@ ...@@ -74,69 +73,75 @@
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="EventArguments\DataEventArgs.cs" /> <Compile Include="EventArguments\DataEventArgs.cs" />
<Compile Include="EventArguments\SessionEventArgs.cs" />
<Compile Include="EventArguments\TunnelConnectEventArgs.cs" /> <Compile Include="EventArguments\TunnelConnectEventArgs.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Exceptions\ProxyAuthorizationException.cs" />
<Compile Include="Exceptions\ProxyException.cs" />
<Compile Include="Exceptions\ProxyHttpException.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" /> <Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Extensions\DotNetStandardExtensions.cs" />
<Compile Include="Extensions\FuncExtensions.cs" /> <Compile Include="Extensions\FuncExtensions.cs" />
<Compile Include="Helpers\HttpHelper.cs" /> <Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Extensions\TcpExtensions.cs" />
<Compile Include="Helpers\BufferPool.cs" /> <Compile Include="Helpers\BufferPool.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" />
<Compile Include="Helpers\CustomBufferedStream.cs" /> <Compile Include="Helpers\CustomBufferedStream.cs" />
<Compile Include="Helpers\ProxyInfo.cs" /> <Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\WinHttp\NativeMethods.WinHttp.cs" /> <Compile Include="Helpers\HttpHelper.cs" />
<Compile Include="Helpers\Network.cs" /> <Compile Include="Helpers\Network.cs" />
<Compile Include="Helpers\RunTime.cs" /> <Compile Include="Helpers\Tcp.cs" />
<Compile Include="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Include="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
<Compile Include="Http\ConnectRequest.cs" /> <Compile Include="Http\ConnectRequest.cs" />
<Compile Include="Http\ConnectResponse.cs" /> <Compile Include="Http\ConnectResponse.cs" />
<Compile Include="Http\HeaderCollection.cs" /> <Compile Include="Http\HeaderCollection.cs" />
<Compile Include="Http\HeaderParser.cs" /> <Compile Include="Http\HeaderParser.cs" />
<Compile Include="Http\HttpsTools.cs" /> <Compile Include="Http\HttpsTools.cs" />
<Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Http\Request.cs" />
<Compile Include="Http\Response.cs" />
<Compile Include="Http\Responses\GenericResponse.cs" /> <Compile Include="Http\Responses\GenericResponse.cs" />
<Compile Include="Http\Responses\OkResponse.cs" />
<Compile Include="Http\Responses\RedirectResponse.cs" />
<Compile Include="Models\EndPoint.cs" />
<Compile Include="Models\ExternalProxy.cs" />
<Compile Include="Models\HttpHeader.cs" />
<Compile Include="Network\CachedCertificate.cs" /> <Compile Include="Network\CachedCertificate.cs" />
<Compile Include="Network\Certificate\WinCertificateMaker.cs" />
<Compile Include="Network\Certificate\BCCertificateMaker.cs" /> <Compile Include="Network\Certificate\BCCertificateMaker.cs" />
<Compile Include="Network\Certificate\ICertificateMaker.cs" /> <Compile Include="Network\Certificate\ICertificateMaker.cs" />
<Compile Include="Network\ProxyClient.cs" /> <Compile Include="Network\Certificate\WinCertificateMaker.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Exceptions\ProxyAuthorizationException.cs" />
<Compile Include="Exceptions\ProxyException.cs" />
<Compile Include="Exceptions\ProxyHttpException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Network\CertificateManager.cs" /> <Compile Include="Network\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" /> <Compile Include="Network\ProxyClient.cs" />
<Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Models\EndPoint.cs" />
<Compile Include="Extensions\TcpExtensions.cs" />
<Compile Include="Http\Request.cs" />
<Compile Include="Http\Response.cs" />
<Compile Include="Models\ExternalProxy.cs" />
<Compile Include="Network\Tcp\TcpConnection.cs" /> <Compile Include="Network\Tcp\TcpConnection.cs" />
<Compile Include="Network\Tcp\TcpConnectionFactory.cs" /> <Compile Include="Network\Tcp\TcpConnectionFactory.cs" />
<Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Network\WinAuth\Security\Common.cs" /> <Compile Include="Network\WinAuth\Security\Common.cs" />
<Compile Include="Network\WinAuth\Security\WinAuthEndPoint.cs" />
<Compile Include="Network\WinAuth\Security\LittleEndian.cs" /> <Compile Include="Network\WinAuth\Security\LittleEndian.cs" />
<Compile Include="Network\WinAuth\Security\Message.cs" /> <Compile Include="Network\WinAuth\Security\Message.cs" />
<Compile Include="Network\WinAuth\Security\State.cs" /> <Compile Include="Network\WinAuth\Security\State.cs" />
<Compile Include="Network\WinAuth\Security\WinAuthEndPoint.cs" />
<Compile Include="Network\WinAuth\WinAuthHandler.cs" /> <Compile Include="Network\WinAuth\WinAuthHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shared\ProxyConstants.cs" />
<Compile Include="WinAuthHandler.cs" />
<Compile Include="CertificateHandler.cs" />
<Compile Include="ProxyAuthorizationHandler.cs" /> <Compile Include="ProxyAuthorizationHandler.cs" />
<Compile Include="ProxyServer.cs" />
<Compile Include="RequestHandler.cs" /> <Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" /> <Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" /> </ItemGroup>
<Compile Include="ProxyServer.cs" /> <ItemGroup>
<Compile Include="EventArguments\SessionEventArgs.cs" /> <Compile Include="Helpers\WinHttp\NativeMethods.WinHttp.cs" />
<Compile Include="Helpers\Tcp.cs" /> <Compile Include="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Include="Extensions\StreamExtensions.cs" /> <Compile Include="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
<Compile Include="Http\Responses\OkResponse.cs" /> <Compile Include="Helpers\NativeMethods.SystemProxy.cs" />
<Compile Include="Http\Responses\RedirectResponse.cs" /> <Compile Include="Helpers\NativeMethods.Tcp.cs" />
<Compile Include="Shared\ProxyConstants.cs" /> <Compile Include="Helpers\ProxyInfo.cs" />
<Compile Include="Helpers\RunTime.cs" />
<Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Network\Tcp\TcpRow.cs" /> <Compile Include="Network\Tcp\TcpRow.cs" />
<Compile Include="Network\Tcp\TcpTable.cs" /> <Compile Include="Network\Tcp\TcpTable.cs" />
<Compile Include="WinAuthHandler.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<COMReference Include="CERTENROLLLib" Condition="'$(OS)' != 'Unix'"> <COMReference Include="CERTENROLLLib" Condition="'$(OS)' != 'Unix'">
......
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