Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

stable #688

Merged
merged 17 commits into from
Nov 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public ProxyTestController()
proxyServer.ForwardToUpstreamGateway = true;
proxyServer.CertificateManager.SaveFakeCertificates = true;

// this is just to show the functionality, provided implementations use junk value
//proxyServer.GetCustomUpStreamProxyFunc = onGetCustomUpStreamProxyFunc;
//proxyServer.CustomUpStreamProxyFailureFunc = onCustomUpStreamProxyFailureFunc;

// optionally set the Certificate Engine
// Under Mono or Non-Windows runtimes only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
Expand Down Expand Up @@ -116,6 +120,18 @@ public void Stop()
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
}

private async Task<IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.9", Port = 9090, Password = "fake", UserName = "fake", UseDefaultCredentials = false };
}

private async Task<IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "fake2", UserName = "fake2", UseDefaultCredentials = false };
}

private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
Expand All @@ -135,7 +151,7 @@ private Task onBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEv
return Task.FromResult(false);
}

// intecept & cancel redirect or update requests
// intercept & cancel redirect or update requests
private async Task onRequest(object sender, SessionEventArgs e)
{
await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
Expand Down
2 changes: 2 additions & 0 deletions examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
<GridViewColumn Header="SentBytes" DisplayMemberBinding="{Binding SentDataCount}" />
<GridViewColumn Header="ReceivedBytes" DisplayMemberBinding="{Binding ReceivedDataCount}" />
<GridViewColumn Header="ClientEndPoint" DisplayMemberBinding="{Binding ClientEndPoint}" />
<GridViewColumn Header="ClientConnectionId" DisplayMemberBinding="{Binding ClientConnectionId}" />
<GridViewColumn Header="ServerConnectionId" DisplayMemberBinding="{Binding ServerConnectionId}" />
</GridView>
</ListView.View>
</ListView>
Expand Down
41 changes: 32 additions & 9 deletions examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,15 @@ await Dispatcher.InvokeAsync(() =>
{
if (sessionDictionary.TryGetValue(e.HttpClient, out var item))
{
item.Update();
item.Update(e);
}
});
}

private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)
{
//if (e.HttpClient.Request.HttpVersion.Major != 2) return;

SessionListItem item = null;
await Dispatcher.InvokeAsync(() => { item = addSession(e); });

Expand All @@ -175,7 +177,7 @@ await Dispatcher.InvokeAsync(() =>
{
if (sessionDictionary.TryGetValue(e.HttpClient, out item))
{
item.Update();
item.Update(e);
}
});

Expand All @@ -190,7 +192,7 @@ await Dispatcher.InvokeAsync(() =>
e.HttpClient.Response.KeepBody = true;
await e.GetResponseBody();

await Dispatcher.InvokeAsync(() => { item.Update(); });
await Dispatcher.InvokeAsync(() => { item.Update(e); });
if (item == SelectedSession)
{
await Dispatcher.InvokeAsync(selectedSessionChanged);
Expand Down Expand Up @@ -225,6 +227,8 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
var item = new SessionListItem
{
Number = lastSessionNumber,
ClientConnectionId = e.ClientConnectionId,
ServerConnectionId = e.ServerConnectionId,
HttpClient = e.HttpClient,
ClientEndPoint = e.ClientEndPoint,
IsTunnelConnect = isTunnelConnect
Expand All @@ -236,14 +240,16 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
var session = (SessionEventArgsBase)sender;
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
{
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
var connectRequest = session.HttpClient.ConnectRequest;
var tunnelType = connectRequest?.TunnelType ?? TunnelType.Unknown;
if (tunnelType != TunnelType.Unknown)
{
li.Protocol = TunnelTypeToString(tunnelType);
}

li.ReceivedDataCount += args.Count;

//if (tunnelType == TunnelType.Http2)
AppendTransferLog(session.GetHashCode() + (isTunnelConnect ? "_tunnel" : "") + "_received",
args.Buffer, args.Offset, args.Count);
}
Expand All @@ -254,15 +260,17 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
var session = (SessionEventArgsBase)sender;
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
{
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
var connectRequest = session.HttpClient.ConnectRequest;
var tunnelType = connectRequest?.TunnelType ?? TunnelType.Unknown;
if (tunnelType != TunnelType.Unknown)
{
li.Protocol = TunnelTypeToString(tunnelType);
}

li.SentDataCount += args.Count;

AppendTransferLog(session.GetHashCode() + (isTunnelConnect ? "_tunnel" : "") + "_sent",
//if (tunnelType == TunnelType.Http2)
AppendTransferLog( session.GetHashCode() + (isTunnelConnect ? "_tunnel" : "") + "_sent",
args.Buffer, args.Offset, args.Count);
}
};
Expand All @@ -272,18 +280,22 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
te.DecryptedDataReceived += (sender, args) =>
{
var session = (SessionEventArgsBase)sender;
//var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
//if (tunnelType == TunnelType.Http2)
AppendTransferLog(session.GetHashCode() + "_decrypted_received", args.Buffer, args.Offset,
args.Count);
};

te.DecryptedDataSent += (sender, args) =>
{
var session = (SessionEventArgsBase)sender;
//var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
//if (tunnelType == TunnelType.Http2)
AppendTransferLog(session.GetHashCode() + "_decrypted_sent", args.Buffer, args.Offset, args.Count);
};
}

item.Update();
item.Update(e);
return item;
}

Expand Down Expand Up @@ -362,9 +374,15 @@ private void selectedSessionChanged()

//string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
var sb = new StringBuilder();
sb.AppendLine("URI: " + request.RequestUri);
sb.Append(request.HeaderText);
sb.Append(request.Encoding.GetString(data));
sb.Append(truncated ? Environment.NewLine + $"Data is truncated after {truncateLimit} bytes" : null);
if (truncated)
{
sb.AppendLine();
sb.Append($"Data is truncated after {truncateLimit} bytes");
}

sb.Append((request as ConnectRequest)?.ClientHelloInfo);
TextBoxRequest.Text = sb.ToString();

Expand All @@ -381,7 +399,12 @@ private void selectedSessionChanged()
sb = new StringBuilder();
sb.Append(response.HeaderText);
sb.Append(response.Encoding.GetString(data));
sb.Append(truncated ? Environment.NewLine + $"Data is truncated after {truncateLimit} bytes" : null);
if (truncated)
{
sb.AppendLine();
sb.Append($"Data is truncated after {truncateLimit} bytes");
}

sb.Append((response as ConnectResponse)?.ServerHelloInfo);
if (SelectedSession.Exception != null)
{
Expand Down
19 changes: 18 additions & 1 deletion examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Net;
using System.Runtime.CompilerServices;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Examples.Wpf.Annotations;
using Titanium.Web.Proxy.Http;

Expand All @@ -18,9 +19,23 @@ public class SessionListItem : INotifyPropertyChanged
private long sentDataCount;
private string statusCode;
private string url;
private Guid clientConnectionId;
private Guid serverConnectionId;

public int Number { get; set; }

public Guid ClientConnectionId
{
get => clientConnectionId;
set => SetField(ref clientConnectionId, value);
}

public Guid ServerConnectionId
{
get => serverConnectionId;
set => SetField(ref serverConnectionId, value);
}

public HttpWebClient HttpClient { get; set; }

public IPEndPoint ClientEndPoint { get; set; }
Expand Down Expand Up @@ -123,13 +138,15 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public void Update()
public void Update(SessionEventArgsBase args)
{
var request = HttpClient.Request;
var response = HttpClient.Response;
int statusCode = response?.StatusCode ?? 0;
StatusCode = statusCode == 0 ? "-" : statusCode.ToString();
Protocol = request.RequestUri.Scheme;
ClientConnectionId = args.ClientConnectionId;
ServerConnectionId = args.ServerConnectionId;

if (IsTunnelConnect)
{
Expand Down
95 changes: 93 additions & 2 deletions src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;

Expand Down Expand Up @@ -51,11 +51,22 @@ private void getNextChunk()
{
// read the chunk trail of the previous chunk
string? s = baseReader.ReadLineAsync().Result;
if (s == null)
{
bytesRemaining = -1;
return;
}
}

readChunkTrail = true;

string? chunkHead = baseReader.ReadLineAsync().Result!;
string? chunkHead = baseReader.ReadLineAsync().Result;
if (chunkHead == null)
{
bytesRemaining = -1;
return;
}

int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
if (idx >= 0)
{
Expand All @@ -80,6 +91,50 @@ private void getNextChunk()
}
}

private async Task getNextChunkAsync()
{
if (readChunkTrail)
{
// read the chunk trail of the previous chunk
string? s = await baseReader.ReadLineAsync();
if (s == null)
{
bytesRemaining = -1;
return;
}
}

readChunkTrail = true;

string? chunkHead = await baseReader.ReadLineAsync();
if (chunkHead == null)
{
bytesRemaining = -1;
return;
}

int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
if (idx >= 0)
{
chunkHead = chunkHead.Substring(0, idx);
}

if (!int.TryParse(chunkHead, NumberStyles.HexNumber, null, out int chunkSize))
{
throw new ProxyHttpException($"Invalid chunk length: '{chunkHead}'", null, null);
}

bytesRemaining = chunkSize;

if (chunkSize == 0)
{
bytesRemaining = -1;

// chunk trail
await baseReader.ReadLineAsync();
}
}

public override void Flush()
{
throw new NotSupportedException();
Expand Down Expand Up @@ -131,6 +186,42 @@ public override int Read(byte[] buffer, int offset, int count)
return res;
}

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (bytesRemaining == -1)
{
return 0;
}

if (bytesRemaining == 0)
{
if (isChunked)
{
await getNextChunkAsync();
}
else
{
bytesRemaining = -1;
}
}

if (bytesRemaining == -1)
{
return 0;
}

int toRead = (int)Math.Min(count, bytesRemaining);
int res = await baseReader.ReadAsync(buffer, offset, toRead, cancellationToken);
bytesRemaining -= res;

if (res == 0)
{
bytesRemaining = -1;
}

return res;
}

public async Task Finish()
{
if (bytesRemaining != -1)
Expand Down
Loading