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

Small HTTP/2 and other improvements #585

Merged
merged 8 commits into from
Apr 26, 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
11 changes: 9 additions & 2 deletions examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,20 @@
</ListView>
<TabControl Grid.Column="2" Grid.Row="0">
<TabItem Header="Session">
<Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox x:Name="TextBoxRequest" Grid.Row="0" />
<TextBox x:Name="TextBoxResponse" Grid.Row="1" />
<TabControl Grid.Row="1">
<TabItem Header="Text">
<TextBox x:Name="TextBoxResponse" />
</TabItem>
<TabItem Header="Image">
<Image x:Name="ImageResponse" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" />
</TabItem>
</TabControl>
</Grid>
</TabItem>
</TabControl>
Expand Down
26 changes: 23 additions & 3 deletions examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
Expand Down Expand Up @@ -99,7 +101,7 @@ public MainWindow()
InitializeComponent();
}

public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public ObservableCollectionEx<SessionListItem> Sessions { get; } = new ObservableCollectionEx<SessionListItem>();

public SessionListItem SelectedSession
{
Expand Down Expand Up @@ -278,11 +280,14 @@ private void ListViewSessions_OnKeyDown(object sender, KeyEventArgs e)
if (e.Key == Key.Delete)
{
var selectedItems = ((ListView)sender).SelectedItems;
Sessions.SuppressNotification = true;
foreach (var item in selectedItems.Cast<SessionListItem>().ToArray())
{
Sessions.Remove(item);
sessionDictionary.Remove(item.HttpClient);
}

Sessions.SuppressNotification = false;
}
}

Expand All @@ -297,7 +302,8 @@ private void selectedSessionChanged()

var session = SelectedSession.HttpClient;
var request = session.Request;
var data = (request.IsBodyRead ? request.Body : null) ?? new byte[0];
var fullData = (request.IsBodyRead ? request.Body : null) ?? new byte[0];
var data = fullData;
bool truncated = data.Length > truncateLimit;
if (truncated)
{
Expand All @@ -313,7 +319,8 @@ private void selectedSessionChanged()
TextBoxRequest.Text = sb.ToString();

var response = session.Response;
data = (response.IsBodyRead ? response.Body : null) ?? new byte[0];
fullData = (response.IsBodyRead ? response.Body : null) ?? new byte[0];
data = fullData;
truncated = data.Length > truncateLimit;
if (truncated)
{
Expand All @@ -333,6 +340,19 @@ private void selectedSessionChanged()
}

TextBoxResponse.Text = sb.ToString();

try
{
using (MemoryStream stream = new MemoryStream(fullData))
{
ImageResponse.Source =
BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
catch
{
ImageResponse.Source = null;
}
}
}
}
36 changes: 36 additions & 0 deletions examples/Titanium.Web.Proxy.Examples.Wpf/ObservableCollectionEx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace Titanium.Web.Proxy.Examples.Wpf
{
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
private bool notificationSuppressed;
private bool suppressNotification;

public bool SuppressNotification
{
get => suppressNotification;
set
{
suppressNotification = value;
if (suppressNotification == false && notificationSuppressed)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
notificationSuppressed = false;
}
}
}

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SuppressNotification)
{
notificationSuppressed = true;
return;
}

base.OnCollectionChanged(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ObservableCollectionEx.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="SessionListItem.cs" />
<Page Include="MainWindow.xaml">
Expand Down
6 changes: 2 additions & 4 deletions src/StreamExtended/Network/CustomBufferedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ public override int ReadByte()
{
return -1;
}



return streamBuffer[bufferPos + index];
}

Expand Down Expand Up @@ -491,7 +490,7 @@ public bool FillBuffer()
if (bufferLength > 0)
{
//normally we fill the buffer only when it is empty, but sometimes we need more data
//move the remanining data to the beginning of the buffer
//move the remaining data to the beginning of the buffer
Buffer.BlockCopy(streamBuffer, bufferPos, streamBuffer, 0, bufferLength);
}

Expand All @@ -516,7 +515,6 @@ public bool FillBuffer()
}

return result;

}

/// <summary>
Expand Down
7 changes: 6 additions & 1 deletion src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Exceptions;

namespace Titanium.Web.Proxy.EventArguments
{
Expand Down Expand Up @@ -60,7 +61,11 @@ private void getNextChunk()
chunkHead = chunkHead.Substring(0, idx);
}

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

bytesRemaining = chunkSize;

if (chunkSize == 0)
Expand Down
28 changes: 17 additions & 11 deletions src/Titanium.Web.Proxy/ExplicitClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
{
string connectHostname = null;
TunnelConnectSessionEventArgs connectArgs = null;



// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream) == 1)
{
Expand Down Expand Up @@ -142,15 +141,22 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2))
{
// test server HTTP/2 support
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: SslExtensions.Http2ProtocolAsList,
noCache: true, cancellationToken: cancellationToken);

http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2;

//release connection back to pool instead of closing when connection pool is enabled.
await tcpConnectionFactory.Release(connection, true);
try
{
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: SslExtensions.Http2ProtocolAsList,
noCache: true, cancellationToken: cancellationToken);

http2Supported = connection.NegotiatedApplicationProtocol ==
SslApplicationProtocol.Http2;
//release connection back to pool instead of closing when connection pool is enabled.
await tcpConnectionFactory.Release(connection, true);
}
catch (Exception)
{
// ignore
}
}

if (EnableTcpServerConnectionPrefetch)
Expand Down
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal HttpRequestWriter(Stream stream, IBufferPool bufferPool, int bufferSize
internal async Task WriteRequestAsync(Request request, bool flush = true,
CancellationToken cancellationToken = default)
{
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.OriginalUrl, request.HttpVersion),
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.RequestUriString, request.HttpVersion),
cancellationToken);
await WriteAsync(request, flush, cancellationToken);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Http/HttpWebClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTranspar

// prepare the request & headers
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
useUpstreamProxy || isTransparent ? Request.RequestUriString : Request.RequestUri.PathAndQuery,
Request.HttpVersion), cancellationToken);

var headerBuilder = new StringBuilder();
Expand Down
19 changes: 17 additions & 2 deletions src/Titanium.Web.Proxy/Http/Request.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Titanium.Web.Proxy.Http
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Request : RequestResponseBase
{
private string originalUrl;

/// <summary>
/// Request Method.
/// </summary>
Expand All @@ -32,7 +34,20 @@ public class Request : RequestResponseBase
/// <summary>
/// The original request Url.
/// </summary>
public string OriginalUrl { get; set; }
public string OriginalUrl
{
get => originalUrl;
internal set
{
originalUrl = value;
RequestUriString = value;
}
}

/// <summary>
/// The request uri as it is in the HTTP header
/// </summary>
public string RequestUriString { get; set; }

/// <summary>
/// Has request body?
Expand Down Expand Up @@ -140,7 +155,7 @@ public override string HeaderText
get
{
var sb = new StringBuilder();
sb.Append($"{CreateRequestLine(Method, OriginalUrl, HttpVersion)}{ProxyConstants.NewLine}");
sb.Append($"{CreateRequestLine(Method, RequestUriString, HttpVersion)}{ProxyConstants.NewLine}");
foreach (var header in Headers)
{
sb.Append($"{header.ToString()}{ProxyConstants.NewLine}");
Expand Down
Loading