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

Commit 05ed651

Browse files
Merge pull request #583 from honfika/master
Basic HTTP/2 support. Disabled by default. Warning added to the enabl…
2 parents a8a822a + 2d4dc4e commit 05ed651

File tree

16 files changed

+342
-163
lines changed

16 files changed

+342
-163
lines changed

examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)
150150
SessionListItem item = null;
151151
await Dispatcher.InvokeAsync(() => { item = addSession(e); });
152152

153+
if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
154+
{
155+
// GetRequestBody for HTTP/2 currently not supported
156+
return;
157+
}
158+
153159
if (e.HttpClient.Request.HasBody)
154160
{
155161
e.HttpClient.Request.KeepBody = true;
@@ -168,6 +174,12 @@ await Dispatcher.InvokeAsync(() =>
168174
}
169175
});
170176

177+
if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
178+
{
179+
// GetRequestBody for HTTP/2 currently not supported
180+
return;
181+
}
182+
171183
if (item != null)
172184
{
173185
if (e.HttpClient.Response.HasBody)
@@ -217,6 +229,12 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
217229
var session = (SessionEventArgsBase)sender;
218230
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
219231
{
232+
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
233+
if (tunnelType != TunnelType.Unknown)
234+
{
235+
li.Protocol = TunnelTypeToString(tunnelType);
236+
}
237+
220238
li.ReceivedDataCount += args.Count;
221239
}
222240
};
@@ -226,6 +244,12 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
226244
var session = (SessionEventArgsBase)sender;
227245
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
228246
{
247+
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
248+
if (tunnelType != TunnelType.Unknown)
249+
{
250+
li.Protocol = TunnelTypeToString(tunnelType);
251+
}
252+
229253
li.SentDataCount += args.Count;
230254
}
231255
};
@@ -235,6 +259,21 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e)
235259
return item;
236260
}
237261

262+
private string TunnelTypeToString(TunnelType tunnelType)
263+
{
264+
switch (tunnelType)
265+
{
266+
case TunnelType.Https:
267+
return "https";
268+
case TunnelType.Websocket:
269+
return "websocket";
270+
case TunnelType.Http2:
271+
return "http2";
272+
}
273+
274+
return null;
275+
}
276+
238277
private void ListViewSessions_OnKeyDown(object sender, KeyEventArgs e)
239278
{
240279
if (e.Key == Key.Delete)

examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class SessionListItem : INotifyPropertyChanged
1111
private long? bodySize;
1212
private Exception exception;
1313
private string host;
14-
private string process;
14+
private int processId;
1515
private string protocol;
1616
private long receivedDataCount;
1717
private long sentDataCount;
@@ -54,10 +54,32 @@ public long? BodySize
5454
set => SetField(ref bodySize, value);
5555
}
5656

57+
public int ProcessId
58+
{
59+
get => processId;
60+
set
61+
{
62+
if (SetField(ref processId, value))
63+
{
64+
OnPropertyChanged(nameof(Process));
65+
}
66+
}
67+
}
68+
5769
public string Process
5870
{
59-
get => process;
60-
set => SetField(ref process, value);
71+
get
72+
{
73+
try
74+
{
75+
var process = System.Diagnostics.Process.GetProcessById(processId);
76+
return process.ProcessName + ":" + processId;
77+
}
78+
catch (Exception)
79+
{
80+
return string.Empty;
81+
}
82+
}
6183
}
6284

6385
public long ReceivedDataCount
@@ -80,13 +102,16 @@ public Exception Exception
80102

81103
public event PropertyChangedEventHandler PropertyChanged;
82104

83-
protected void SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
105+
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
84106
{
85107
if (!Equals(field, value))
86108
{
87109
field = value;
88110
OnPropertyChanged(propertyName);
111+
return true;
89112
}
113+
114+
return false;
90115
}
91116

92117
[NotifyPropertyChangedInvocator]
@@ -132,20 +157,7 @@ public void Update()
132157
BodySize = responseSize;
133158
}
134159

135-
Process = GetProcessDescription(HttpClient.ProcessId.Value);
136-
}
137-
138-
private string GetProcessDescription(int processId)
139-
{
140-
try
141-
{
142-
var process = System.Diagnostics.Process.GetProcessById(processId);
143-
return process.ProcessName + ":" + processId;
144-
}
145-
catch (Exception)
146-
{
147-
return string.Empty;
148-
}
160+
ProcessId = HttpClient.ProcessId.Value;
149161
}
150162
}
151163
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
2+
3+
<PropertyGroup>
4+
<OutputType>WinExe</OutputType>
5+
<TargetFramework>netcoreapp3.0</TargetFramework>
6+
<UseWPF>true</UseWPF>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Compile Remove="Properties\AssemblyInfo.cs" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\..\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj" />
15+
</ItemGroup>
16+
17+
</Project>

src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public abstract class SessionEventArgsBase : EventArgs, IDisposable
3131
/// <summary>
3232
/// Relative milliseconds for various events.
3333
/// </summary>
34-
public Dictionary<string, DateTime> TimeLine { get; set; } = new Dictionary<string, DateTime>();
34+
public Dictionary<string, DateTime> TimeLine { get; } = new Dictionary<string, DateTime>();
3535

3636
/// <summary>
3737
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.

src/Titanium.Web.Proxy/ExplicitClientHandler.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
126126
bool isClientHello = clientHelloInfo != null;
127127
if (isClientHello)
128128
{
129+
connectRequest.TunnelType = TunnelType.Https;
129130
connectRequest.ClientHelloInfo = clientHelloInfo;
130131
}
131132

@@ -208,9 +209,9 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
208209
}
209210
catch (Exception e)
210211
{
211-
var certname = certificate?.GetNameInfo(X509NameType.SimpleName, false);
212+
var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
212213
throw new ProxyConnectException(
213-
$"Couldn't authenticate host '{connectHostname}' with certificate '{certname}'.", e, connectArgs);
214+
$"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs);
214215
}
215216

216217
if (await HttpHelper.IsConnectMethod(clientStream) == -1)
@@ -233,6 +234,11 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
233234
// Hostname is excluded or it is not an HTTPS connect
234235
if (!decryptSsl || !isClientHello)
235236
{
237+
if (!isClientHello)
238+
{
239+
connectRequest.TunnelType = TunnelType.Websocket;
240+
}
241+
236242
// create new connection to server.
237243
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
238244
// this connection should not be HTTPS.
@@ -286,6 +292,8 @@ await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize,
286292
string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
287293
if (httpCmd == "PRI * HTTP/2.0")
288294
{
295+
connectArgs.HttpClient.ConnectRequest.TunnelType = TunnelType.Http2;
296+
289297
// HTTP/2 Connection Preface
290298
string line = await clientStream.ReadLineAsync(cancellationToken);
291299
if (line != string.Empty)
@@ -318,9 +326,16 @@ await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize,
318326
await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize,
319327
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
320328
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
329+
() => new SessionEventArgs(this, endPoint, cancellationTokenSource)
330+
{
331+
ProxyClient = { Connection = clientConnection },
332+
HttpClient = { ConnectRequest = connectArgs?.HttpClient.ConnectRequest },
333+
UserData = connectArgs?.UserData
334+
},
335+
async args => { await invokeBeforeRequest(args); },
336+
async args => { await invokeBeforeResponse(args); },
321337
connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc);
322338
#endif
323-
324339
}
325340
finally
326341
{

src/Titanium.Web.Proxy/Helpers/HttpHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader)
146146
private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, string expectedStart)
147147
{
148148
bool isExpected = true;
149-
int legthToCheck = 10;
150-
for (int i = 0; i < legthToCheck; i++)
149+
int lengthToCheck = 10;
150+
for (int i = 0; i < lengthToCheck; i++)
151151
{
152152
int b = await clientStreamReader.PeekByteAsync(i);
153153
if (b == -1)

src/Titanium.Web.Proxy/Helpers/Ref.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/Titanium.Web.Proxy/Http/ConnectRequest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public ConnectRequest()
1212
Method = "CONNECT";
1313
}
1414

15+
public TunnelType TunnelType { get; internal set; }
16+
1517
public ClientHelloInfo ClientHelloInfo { get; set; }
1618
}
1719
}

src/Titanium.Web.Proxy/Http/KnownHeaders.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,28 @@
66
public static class KnownHeaders
77
{
88
// Both
9-
public const string Connection = "connection";
9+
public const string Connection = "Connection";
1010
public const string ConnectionClose = "close";
1111
public const string ConnectionKeepAlive = "keep-alive";
1212

13-
public const string ContentLength = "content-length";
13+
public const string ContentLength = "Content-Length";
1414

15-
public const string ContentType = "content-type";
15+
public const string ContentType = "Content-Type";
1616
public const string ContentTypeCharset = "charset";
1717
public const string ContentTypeBoundary = "boundary";
1818

19-
public const string Upgrade = "upgrade";
19+
public const string Upgrade = "Upgrade";
2020
public const string UpgradeWebsocket = "websocket";
2121

2222
// Request headers
23-
public const string AcceptEncoding = "accept-encoding";
23+
public const string AcceptEncoding = "Accept-Encoding";
2424

2525
public const string Authorization = "Authorization";
2626

27-
public const string Expect = "expect";
27+
public const string Expect = "Expect";
2828
public const string Expect100Continue = "100-continue";
2929

30-
public const string Host = "host";
30+
public const string Host = "Host";
3131

3232
public const string ProxyAuthorization = "Proxy-Authorization";
3333
public const string ProxyAuthorizationBasic = "basic";
@@ -36,7 +36,7 @@ public static class KnownHeaders
3636
public const string ProxyConnectionClose = "close";
3737

3838
// Response headers
39-
public const string ContentEncoding = "content-encoding";
39+
public const string ContentEncoding = "Content-Encoding";
4040
public const string ContentEncodingDeflate = "deflate";
4141
public const string ContentEncodingGzip = "gzip";
4242
public const string ContentEncodingBrotli = "br";
@@ -45,7 +45,7 @@ public static class KnownHeaders
4545

4646
public const string ProxyAuthenticate = "Proxy-Authenticate";
4747

48-
public const string TransferEncoding = "transfer-encoding";
48+
public const string TransferEncoding = "Transfer-Encoding";
4949
public const string TransferEncodingChunked = "chunked";
5050
}
5151
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Titanium.Web.Proxy.Http
2+
{
3+
public enum TunnelType
4+
{
5+
Unknown,
6+
Https,
7+
Websocket,
8+
Http2,
9+
}
10+
}

0 commit comments

Comments
 (0)