Skip to content

Commit 955f05e

Browse files
authored
Allow retaining the original casing for known header values (#80754)
1 parent 4827704 commit 955f05e

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ namespace System.Net.Http
88
/// </summary>
99
internal static class GlobalHttpSettings
1010
{
11+
// Switch to disable ignore-case matching for known header values. Enabled by default.
12+
public static bool IgnoreCaseForKnownHeaderValues { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(
13+
"System.Net.Http.IgnoreCaseForKnownHeaderValues",
14+
"DOTNET_SYSTEM_NET_HTTP_IGNORECASEFORKNOWNHEADERVALUES",
15+
true);
16+
1117
internal static class DiagnosticsHandler
1218
{
1319
public static bool EnableActivityPropagation { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(

src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public string GetHeaderValue(ReadOnlySpan<byte> headerValue, Encoding? valueEnco
132132
{
133133
for (int i = 0; i < knownValues.Length; i++)
134134
{
135-
if (ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(knownValues[i], headerValue))
135+
if (GlobalHttpSettings.IgnoreCaseForKnownHeaderValues
136+
? ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(knownValues[i], headerValue)
137+
: ByteArrayHelpers.EqualsOrdinalAscii(knownValues[i], headerValue))
136138
{
137139
return knownValues[i];
138140
}
@@ -239,9 +241,17 @@ public string GetHeaderValue(ReadOnlySpan<byte> headerValue, Encoding? valueEnco
239241

240242
Debug.Assert(candidate is null || candidate.Length == contentTypeValue.Length);
241243

242-
return candidate != null && ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(candidate, contentTypeValue) ?
243-
candidate :
244-
null;
244+
if (candidate is not null)
245+
{
246+
if (GlobalHttpSettings.IgnoreCaseForKnownHeaderValues
247+
? ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(candidate, contentTypeValue)
248+
: ByteArrayHelpers.EqualsOrdinalAscii(candidate, contentTypeValue))
249+
{
250+
return candidate;
251+
}
252+
}
253+
254+
return null;
245255
}
246256

247257
private static bool TryDecodeUtf8(ReadOnlySpan<byte> input, [NotNullWhen(true)] out string? decoded)

src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using System.Linq;
55
using System.Net.Http.Headers;
6+
using System.Text;
7+
using Microsoft.DotNet.RemoteExecutor;
68
using Xunit;
79

810
namespace System.Net.Http.Tests
@@ -245,5 +247,28 @@ public void GetKnownHeaderValue_Unknown_NotFound(string name, string value)
245247
Assert.Equal(value, v2);
246248
Assert.NotSame(v1, v2);
247249
}
250+
251+
[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
252+
[InlineData("Access-Control-Allow-Credentials", "true")]
253+
[InlineData("Cache-Control", "no-cache")]
254+
[InlineData("Content-Type", "text/plain")]
255+
public void GetKnownHeaderValue_RespectsAppContextIgnoreCaseSwitch(string name, string value)
256+
{
257+
RemoteExecutor.Invoke(static (name, value) =>
258+
{
259+
AppContext.SetSwitch("System.Net.Http.IgnoreCaseForKnownHeaderValues", false);
260+
261+
KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(name);
262+
Assert.NotNull(knownHeader);
263+
264+
string sameCase = knownHeader.Descriptor.GetHeaderValue(Encoding.ASCII.GetBytes(value), valueEncoding: null);
265+
Assert.NotNull(sameCase);
266+
Assert.Equal(value, sameCase);
267+
268+
string differentCase = knownHeader.Descriptor.GetHeaderValue(Encoding.ASCII.GetBytes(value.ToUpperInvariant()), valueEncoding: null);
269+
Assert.NotNull(differentCase);
270+
Assert.NotEqual(value, differentCase);
271+
}, name, value).Dispose();
272+
}
248273
}
249274
}

src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<StringResourcesPath>../../src/Resources/Strings.resx</StringResourcesPath>
44
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -78,6 +78,8 @@
7878
Link="ProductionCode\System\Net\Http\EmptyReadStream.cs" />
7979
<Compile Include="..\..\src\System\Net\Http\FormUrlEncodedContent.cs"
8080
Link="ProductionCode\System\Net\Http\FormUrlEncodedContent.cs" />
81+
<Compile Include="..\..\src\System\Net\Http\GlobalHttpSettings.cs"
82+
Link="ProductionCode\System\Net\Http\GlobalHttpSettings.cs" />
8183
<Compile Include="..\..\src\System\Net\Http\HeaderEncodingSelector.cs"
8284
Link="ProductionCode\System\Net\Http\HeaderEncodingSelector.cs" />
8385
<Compile Include="..\..\src\System\Net\Http\Headers\AltSvcHeaderParser.cs"

0 commit comments

Comments
 (0)