diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 680de6066..015aa518f 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-sonarscanner": {
- "version": "11.0.0",
+ "version": "11.2.1",
"commands": [
"dotnet-sonarscanner"
]
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 111af2d01..58395fdea 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -36,7 +36,7 @@ jobs:
sudo apt-get install -y libmsquic
- name: Download .NET SDK
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0
@@ -110,24 +110,33 @@ jobs:
- os:
name: 🍎
- runs-on: macos-15-intel
+ runs-on: macos-26-intel
arch: x64
runtime: osx-x64
platform: macos/amd64
- os:
name: 🍎
- runs-on: macos-15
+ runs-on: macos-26
arch: arm64
runtime: osx-arm64
platform: macos/arm64
steps:
- name: Checkout source
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
+
+ - name: Harden macOS x64 environment
+
+ if: matrix.os.runs-on == 'macos-26-intel'
+ run: |
+ sudo rm -rf /opt/homebrew || true
+ export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+ export DYLD_LIBRARY_PATH=""
+ export DYLD_FALLBACK_LIBRARY_PATH=""
- name: Setup .NET SDK
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
if: matrix.os.runs-on != 'linux-arm32'
with:
dotnet-version: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c07984002..199c3c423 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -20,17 +20,17 @@ jobs:
steps:
- name: Checkout source
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET SDK
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0
- name: Setup NuGet CLI
- uses: NuGet/setup-nuget@v2
+ uses: NuGet/setup-nuget@v4
- name: Restore dependencies
run: dotnet restore
diff --git a/Adapters/AspNetCore/GenHTTP.Adapters.AspNetCore.csproj b/Adapters/AspNetCore/GenHTTP.Adapters.AspNetCore.csproj
index d6f0cac36..13482f227 100644
--- a/Adapters/AspNetCore/GenHTTP.Adapters.AspNetCore.csproj
+++ b/Adapters/AspNetCore/GenHTTP.Adapters.AspNetCore.csproj
@@ -35,7 +35,7 @@
-
+
diff --git a/Directory.Build.props b/Directory.Build.props
index 9c27b106d..f53dfb2a4 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -40,7 +40,7 @@
-
+
diff --git a/Engine/Internal/GenHTTP.Engine.Internal.csproj b/Engine/Internal/GenHTTP.Engine.Internal.csproj
index bdb1a4719..98bb93d50 100644
--- a/Engine/Internal/GenHTTP.Engine.Internal.csproj
+++ b/Engine/Internal/GenHTTP.Engine.Internal.csproj
@@ -19,9 +19,9 @@
-
+
-
+
diff --git a/Modules/Archives/GenHTTP.Modules.Archives.csproj b/Modules/Archives/GenHTTP.Modules.Archives.csproj
index 08b9ed305..95232adb1 100644
--- a/Modules/Archives/GenHTTP.Modules.Archives.csproj
+++ b/Modules/Archives/GenHTTP.Modules.Archives.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/Modules/Caching/GenHTTP.Modules.Caching.csproj b/Modules/Caching/GenHTTP.Modules.Caching.csproj
index 1e2a159f2..5ca1f3436 100644
--- a/Modules/Caching/GenHTTP.Modules.Caching.csproj
+++ b/Modules/Caching/GenHTTP.Modules.Caching.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/Modules/Compression/Providers/CompressionConcern.cs b/Modules/Compression/Providers/CompressionConcern.cs
index 963f2e919..63ec00850 100644
--- a/Modules/Compression/Providers/CompressionConcern.cs
+++ b/Modules/Compression/Providers/CompressionConcern.cs
@@ -1,4 +1,5 @@
-using System.IO.Compression;
+using System.Buffers;
+using System.IO.Compression;
using GenHTTP.Api.Content;
using GenHTTP.Api.Content.IO;
@@ -131,31 +132,39 @@ private bool ShouldCompressBySize(IResponse response)
return MinimumSize is null || contentLength is null || contentLength >= MinimumSize;
}
+
+ private static readonly SearchValues Delimiters = SearchValues.Create([',', ';']);
private static HashSet ParseSupported(ReadOnlySpan acceptHeader)
{
var result = new HashSet(StringComparer.OrdinalIgnoreCase);
- var start = 0;
-
- while (start <= acceptHeader.Length)
+ while (!acceptHeader.IsEmpty)
{
- var comma = acceptHeader[start..].IndexOf(',');
- var end = comma >= 0 ? start + comma : acceptHeader.Length;
-
- var part = acceptHeader.Slice(start, end - start).Trim();
+ var delimIdx = acceptHeader.IndexOfAny(Delimiters);
- if (!part.IsEmpty)
+ ReadOnlySpan token;
+ if (delimIdx < 0)
{
- result.Add(part.ToString());
+ token = acceptHeader.Trim();
+ acceptHeader = default;
}
-
- if (comma < 0)
+ else if (acceptHeader[delimIdx] == ',')
+ {
+ token = acceptHeader[..delimIdx].Trim();
+ acceptHeader = acceptHeader[(delimIdx + 1)..];
+ }
+ else
{
- break;
+ token = acceptHeader[..delimIdx].TrimEnd();
+ var commaIdx = acceptHeader[delimIdx..].IndexOf(',');
+ acceptHeader = commaIdx >= 0
+ ? acceptHeader[(delimIdx + commaIdx + 1)..]
+ : default;
}
- start = end + 1;
+ if (!token.IsEmpty)
+ result.Add(token.ToString());
}
return result;
diff --git a/Modules/Conversion/GenHTTP.Modules.Conversion.csproj b/Modules/Conversion/GenHTTP.Modules.Conversion.csproj
index d85fee0eb..e4e02ad89 100644
--- a/Modules/Conversion/GenHTTP.Modules.Conversion.csproj
+++ b/Modules/Conversion/GenHTTP.Modules.Conversion.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/Modules/DependencyInjection/GenHTTP.Modules.DependencyInjection.csproj b/Modules/DependencyInjection/GenHTTP.Modules.DependencyInjection.csproj
index f36480a5e..695a2ea30 100644
--- a/Modules/DependencyInjection/GenHTTP.Modules.DependencyInjection.csproj
+++ b/Modules/DependencyInjection/GenHTTP.Modules.DependencyInjection.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/Modules/OpenApi/GenHTTP.Modules.OpenApi.csproj b/Modules/OpenApi/GenHTTP.Modules.OpenApi.csproj
index 03e73e535..f482e33eb 100644
--- a/Modules/OpenApi/GenHTTP.Modules.OpenApi.csproj
+++ b/Modules/OpenApi/GenHTTP.Modules.OpenApi.csproj
@@ -16,11 +16,11 @@
-
+
-
+
-
+
diff --git a/Modules/ReverseProxy/GenHTTP.Modules.ReverseProxy.csproj b/Modules/ReverseProxy/GenHTTP.Modules.ReverseProxy.csproj
index acfdab81b..96995d620 100644
--- a/Modules/ReverseProxy/GenHTTP.Modules.ReverseProxy.csproj
+++ b/Modules/ReverseProxy/GenHTTP.Modules.ReverseProxy.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/Modules/Websockets/GenHTTP.Modules.Websockets.csproj b/Modules/Websockets/GenHTTP.Modules.Websockets.csproj
index 84d40cf24..da8868ef2 100644
--- a/Modules/Websockets/GenHTTP.Modules.Websockets.csproj
+++ b/Modules/Websockets/GenHTTP.Modules.Websockets.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj b/Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj
index 2fdcdb2f6..23dba0324 100644
--- a/Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj
+++ b/Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj
@@ -43,16 +43,16 @@
-
+
-
-
+
+
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Testing/Acceptance/Modules/Compression/CompressionTests.cs b/Testing/Acceptance/Modules/Compression/CompressionTests.cs
index 12e40c5a9..097e06ff1 100644
--- a/Testing/Acceptance/Modules/Compression/CompressionTests.cs
+++ b/Testing/Acceptance/Modules/Compression/CompressionTests.cs
@@ -35,7 +35,7 @@ public async Task TestCompression(TestEngine engine)
Assert.AreEqual("zstd", response.Content.Headers.ContentEncoding.First());
}
-
+
///
/// As a browser, I expect only supported compression algorithms to be used
/// to generate my response.
@@ -378,6 +378,20 @@ public async Task TestCompressionThreshold_Disabled_AllContentCompressed(TestEng
await runner.DisposeAsync();
}
+
+ [TestMethod]
+ [MultiEngineTest]
+ public async Task TestWeights(TestEngine engine)
+ {
+ await using var runner = await TestHost.RunAsync(CreateLargeContentHandler().Build(), engine: engine);
+
+ var request = runner.GetRequest();
+ request.Headers.Add("Accept-Encoding", "br;q=1, gzip;q=0.8");
+
+ using var response = await runner.GetResponseAsync(request);
+
+ Assert.AreEqual("br", response.Content.Headers.ContentEncoding.First());
+ }
///
/// Helper class to create content with unknown length (null)