Skip to content

Commit ae0025c

Browse files
committed
Fixes, upgrades
Upgrades core deps. Enables HTTP/2 on the proxy front-end, but backend fulfillment is still HTTP/1.x. Strips all compression methods from the front end. Configures Kestrel for optimal throughput. Ensures that headers are replaced if they exist. This ensures that client changes always apply. Removes arbitrary limits, such as max length on request strings. Fixes an issue where ASP.NET Core incorrectly decodes some URL's, which causes some things to randomly fail as bad requests. Google maps is an example of what suffered in previous versions. Now builds out the full URL based on the raw values sent by the browser. This applies to websockets as well. Adds the ability to inspect individual websocket messages. Fixes an issue where the whole body inspection callback was invoked on websockets even if not requested. Exempts well-defined windows-exclusive ports from packet interception. Everything is now extremely fast, and stable. No more public changes or additions will be made.
1 parent ee34d47 commit ae0025c

8 files changed

+234
-37
lines changed

CitadelCore/CitadelCore.csproj

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,23 @@
1212
<PackageIconUrl />
1313
<RepositoryUrl>https://github.com/TechnikEmpire/CitadelCore</RepositoryUrl>
1414
<PackageTags>proxy filtering content-filtering transparent-proxy</PackageTags>
15-
<PackageReleaseNotes>Includes originating message info in replay callback. This is a breaking API change, so version is bumped to 4.x.
16-
Fixes an issue where websockets were malfunctioning as a result of the new websocket fork work.</PackageReleaseNotes>
15+
<PackageReleaseNotes>Upgrades core deps.
16+
Enables HTTP/2 on the proxy front-end, but backend fulfillment is still HTTP/1.x.
17+
Strips all compression methods from the front end.
18+
Configures Kestrel for optimal throughput.
19+
Ensures that headers are replaced if they exist. This ensures that client changes always apply.
20+
Removes arbitrary limits, such as max length on request strings.
21+
Fixes an issue where ASP.NET Core incorrectly decodes some URL's, which causes some things to randomly fail as bad requests. Google maps is an example of what suffered in previous versions.
22+
Now builds out the full URL based on the raw values sent by the browser. This applies to websockets as well.
23+
Adds the ability to inspect individual websocket messages.
24+
Fixes an issue where the whole body inspection callback was invoked on websockets even if not requested.
25+
Everything is now extremely fast, and stable. No more public changes or additions will be made.</PackageReleaseNotes>
1726
<Title>CitadelCore</Title>
1827
<Summary>Transparent filtering HTTP/S and Websocket/WebsocketSecure proxy.</Summary>
1928
<Description>Transparent filtering HTTP/S and Websocket/WebsocketSecure proxy.</Description>
20-
<Version>4.0.1</Version>
21-
<AssemblyVersion>4.0.1.0</AssemblyVersion>
22-
<FileVersion>4.0.1.0</FileVersion>
29+
<Version>4.2.3</Version>
30+
<AssemblyVersion>4.2.3.0</AssemblyVersion>
31+
<FileVersion>4.2.3.0</FileVersion>
2332
</PropertyGroup>
2433

2534
<ItemGroup Label="dotnet pack instructions">
@@ -62,9 +71,8 @@ Fixes an issue where websockets were malfunctioning as a result of the new webso
6271

6372
<ItemGroup>
6473
<PackageReference Include="CitadelCore.Websockets.Client.Managed" Version="1.1.1" />
65-
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.1.1" />
66-
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.1.1" />
67-
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.3" />
74+
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
75+
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
6876
<PackageReference Include="Microsoft.AspNetCore.WebSockets.Server" Version="0.1.0" />
6977
<PackageReference Include="Portable.BouncyCastle" Version="1.8.4" />
7078
<PackageReference Include="StreamExtended" Version="[1.0.81]" />

CitadelCore/Extensions/HttpRequestExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public static NameValueCollection PopulateHeaders(this HttpRequest message, Name
5454

5555
try
5656
{
57+
if (message.Headers.ContainsKey(key))
58+
{
59+
message.Headers.Remove(key);
60+
}
61+
5762
message.Headers.Add(key, headers.GetValues(key));
5863
clonedCollection.Remove(key);
5964
}

CitadelCore/Extensions/HttpRequestMessageExtensions.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ public static NameValueCollection PopulateHeaders(this HttpRequestMessage messag
5050
{
5151
continue;
5252
}
53-
53+
54+
if (message.Headers.Contains(key))
55+
{
56+
message.Headers.Remove(key);
57+
}
58+
5459
if (message.Headers.TryAddWithoutValidation(key, headers.GetValues(key)))
5560
{
5661
clonedCollection.Remove(key);
@@ -59,6 +64,11 @@ public static NameValueCollection PopulateHeaders(this HttpRequestMessage messag
5964
{
6065
if (message.Content != null)
6166
{
67+
if (message.Content.Headers.Contains(key))
68+
{
69+
message.Content.Headers.Remove(key);
70+
}
71+
6272
if (message.Content.Headers.TryAddWithoutValidation(key, headers.GetValues(key)))
6373
{
6474
clonedCollection.Remove(key);

CitadelCore/Extensions/HttpResponseExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public static NameValueCollection PopulateHeaders(this HttpResponse message, Nam
5454

5555
try
5656
{
57+
if (message.Headers.ContainsKey(key))
58+
{
59+
message.Headers.Remove(key);
60+
}
61+
5762
message.Headers.Add(key, new Microsoft.Extensions.Primitives.StringValues(headers.GetValues(key)));
5863
clonedCollection.Remove(key);
5964
}

CitadelCore/Extensions/HttpResponseMessageExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public static NameValueCollection PopulateHeaders(this HttpResponseMessage messa
5151
continue;
5252
}
5353

54+
if (message.Headers.Contains(key))
55+
{
56+
message.Headers.Remove(key);
57+
}
58+
5459
if (message.Headers.TryAddWithoutValidation(key, headers.GetValues(key)))
5560
{
5661
clonedCollection.Remove(key);
@@ -59,6 +64,11 @@ public static NameValueCollection PopulateHeaders(this HttpResponseMessage messa
5964
{
6065
if (message.Content != null)
6166
{
67+
if (message.Content.Headers.Contains(key))
68+
{
69+
message.Content.Headers.Remove(key);
70+
}
71+
6272
if (message.Content.Headers.TryAddWithoutValidation(key, headers.GetValues(key)))
6373
{
6474
clonedCollection.Remove(key);

CitadelCore/Net/Handlers/FilterHttpResponseHandler.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
using CitadelCore.Net.Handlers.Replay;
1212
using CitadelCore.Net.Http;
1313
using CitadelCore.Net.Proxy;
14+
using CitadelCore.Util;
1415
using Microsoft.AspNetCore.Http;
16+
using Microsoft.AspNetCore.Http.Features;
1517
using System;
1618
using System.Collections.Generic;
1719
using System.IO;
1820
using System.Net;
1921
using System.Net.Http;
22+
using System.Text;
2023
using System.Text.RegularExpressions;
2124
using System.Threading.Tasks;
25+
using System.Web;
2226

2327
namespace CitadelCore.Net.Handlers
2428
{
@@ -114,15 +118,27 @@ public override async Task Handle(HttpContext context)
114118
HttpRequestMessage requestMsg = null;
115119

116120
HttpClient upstreamClient = _client;
117-
121+
118122
try
119123
{
120124
// Use helper to get the full, proper URL for the request. var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request);
121-
var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request);
125+
//var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request);
126+
127+
var connFeature = context.Features.Get<IHttpRequestFeature>();
128+
129+
string fullUrl = string.Empty;
130+
131+
if (connFeature != null && connFeature.RawTarget != null && !string.IsNullOrEmpty(connFeature.RawTarget) && !(string.IsNullOrWhiteSpace(connFeature.RawTarget)))
132+
{
133+
fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{connFeature.RawTarget}";
134+
}
135+
else
136+
{
137+
fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}";
138+
}
122139

123140
// Next we need to try and parse the URL as a URI, because the web client requires
124141
// this for connecting upstream.
125-
126142
if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri reqUrl))
127143
{
128144
LoggerProxy.Default.Error("Failed to parse HTTP URL.");
@@ -197,12 +213,17 @@ public override async Task Handle(HttpContext context)
197213

198214
// Create the message AFTER we give the user a chance to alter things.
199215
requestMsg = new HttpRequestMessage(requestMessageNfo.Method, requestMessageNfo.Url);
216+
200217
var initialFailedHeaders = requestMsg.PopulateHeaders(requestMessageNfo.Headers, requestMessageNfo.ExemptedHeaders);
201218

202219
// Ensure that we match the protocol of the client!
203220
if (upstreamReqVersionMatch != null)
204221
{
205-
requestMsg.Version = upstreamReqVersionMatch;
222+
// Upstream won't have HTTP/2 support on all OS versions!
223+
if (upstreamReqVersionMatch.Major <= 1)
224+
{
225+
requestMsg.Version = upstreamReqVersionMatch;
226+
}
206227
}
207228

208229
// Check if we have a request body.
@@ -356,7 +377,7 @@ public override async Task Handle(HttpContext context)
356377
try
357378
{
358379
try
359-
{
380+
{
360381
response = await upstreamClient.SendAsync(requestMsg, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted);
361382
}
362383
catch (Exception e)

0 commit comments

Comments
 (0)