diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs index 229490b5432dd9..b58132c2b081db 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs @@ -132,7 +132,7 @@ public string GetHeaderValue(ReadOnlySpan headerValue, Encoding? valueEnco { for (int i = 0; i < knownValues.Length; i++) { - if (ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(knownValues[i], headerValue)) + if (ByteArrayHelpers.EqualsOrdinalAscii(knownValues[i], headerValue)) { return knownValues[i]; } @@ -166,45 +166,45 @@ public string GetHeaderValue(ReadOnlySpan headerValue, Encoding? valueEnco switch (contentTypeValue.Length) { case 8: - switch (contentTypeValue[7] | 0x20) + switch (contentTypeValue[7]) { - case 'l': candidate = "text/xml"; break; // text/xm[l] - case 's': candidate = "text/css"; break; // text/cs[s] - case 'v': candidate = "text/csv"; break; // text/cs[v] + case (byte)'l': candidate = "text/xml"; break; // text/xm[l] + case (byte)'s': candidate = "text/css"; break; // text/cs[s] + case (byte)'v': candidate = "text/csv"; break; // text/cs[v] } break; case 9: - switch (contentTypeValue[6] | 0x20) + switch (contentTypeValue[6]) { - case 'g': candidate = "image/gif"; break; // image/[g]if - case 'p': candidate = "image/png"; break; // image/[p]ng - case 't': candidate = "text/html"; break; // text/h[t]ml + case (byte)'g': candidate = "image/gif"; break; // image/[g]if + case (byte)'p': candidate = "image/png"; break; // image/[p]ng + case (byte)'t': candidate = "text/html"; break; // text/h[t]ml } break; case 10: - switch (contentTypeValue[0] | 0x20) + switch (contentTypeValue[0]) { - case 't': candidate = "text/plain"; break; // [t]ext/plain - case 'i': candidate = "image/jpeg"; break; // [i]mage/jpeg + case (byte)'t': candidate = "text/plain"; break; // [t]ext/plain + case (byte)'i': candidate = "image/jpeg"; break; // [i]mage/jpeg } break; case 15: - switch (contentTypeValue[12] | 0x20) + switch (contentTypeValue[12]) { - case 'p': candidate = "application/pdf"; break; // application/[p]df - case 'x': candidate = "application/xml"; break; // application/[x]ml - case 'z': candidate = "application/zip"; break; // application/[z]ip + case (byte)'p': candidate = "application/pdf"; break; // application/[p]df + case (byte)'x': candidate = "application/xml"; break; // application/[x]ml + case (byte)'z': candidate = "application/zip"; break; // application/[z]ip } break; case 16: - switch (contentTypeValue[12] | 0x20) + switch (contentTypeValue[12]) { - case 'g': candidate = "application/grpc"; break; // application/[g]rpc - case 'j': candidate = "application/json"; break; // application/[j]son + case (byte)'g': candidate = "application/grpc"; break; // application/[g]rpc + case (byte)'j': candidate = "application/json"; break; // application/[j]son } break; @@ -217,10 +217,11 @@ public string GetHeaderValue(ReadOnlySpan headerValue, Encoding? valueEnco break; case 24: - switch (contentTypeValue[0] | 0x20) + switch (contentTypeValue[19]) { - case 'a': candidate = "application/octet-stream"; break; // application/octet-stream - case 't': candidate = "text/html; charset=utf-8"; break; // text/html; charset=utf-8 + case (byte)'t': candidate = "application/octet-stream"; break; // application/octet-s[t]ream + case (byte)'u': candidate = "text/html; charset=utf-8"; break; // text/html; charset=[u]tf-8 + case (byte)'U': candidate = "text/html; charset=UTF-8"; break; // text/html; charset=[U]TF-8 } break; @@ -239,7 +240,7 @@ public string GetHeaderValue(ReadOnlySpan headerValue, Encoding? valueEnco Debug.Assert(candidate is null || candidate.Length == contentTypeValue.Length); - return candidate != null && ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(candidate, contentTypeValue) ? + return candidate != null && ByteArrayHelpers.EqualsOrdinalAscii(candidate, contentTypeValue) ? candidate : null; } diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs index 78fada7218b4ac..aac0f0fec5d1c3 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs @@ -177,6 +177,7 @@ public void TryGetKnownHeader_Unknown_NotFound(string name) [InlineData("Content-Type", "application/javascript")] [InlineData("Content-Type", "application/octet-stream")] [InlineData("Content-Type", "text/html; charset=utf-8")] + [InlineData("Content-Type", "text/html; charset=UTF-8")] [InlineData("Content-Type", "text/plain; charset=utf-8")] [InlineData("Content-Type", "application/json; charset=utf-8")] [InlineData("Content-Type", "application/x-www-form-urlencoded")] @@ -213,27 +214,46 @@ public void TryGetKnownHeader_Unknown_NotFound(string name) [InlineData("X-XSS-Protection", "1; mode=block")] public void GetKnownHeaderValue_Known_Found(string name, string value) { - foreach (string casedValue in new[] { value, value.ToUpperInvariant(), value.ToLowerInvariant() }) + KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(name); + Assert.NotNull(knownHeader); + + string v1 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray(), valueEncoding: null); + Assert.NotNull(v1); + Assert.Equal(value, v1); + + string v2 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray(), valueEncoding: null); + Assert.Same(v1, v2); + + if (TryChangeCasing(value, out string newValue)) // Doesn't make sense for values that are just numbers { - Validate(KnownHeaders.TryGetKnownHeader(name), casedValue); + GetKnownHeaderValue_Unknown_NotFound(name, newValue); } - static void Validate(KnownHeader knownHeader, string value) + static bool TryChangeCasing(string value, out string newValue) { - Assert.NotNull(knownHeader); + string upper = value.ToUpperInvariant(); + if (upper != value) + { + newValue = upper; + return true; + } - string v1 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray(), valueEncoding: null); - Assert.NotNull(v1); - Assert.Equal(value, v1, StringComparer.OrdinalIgnoreCase); + string lower = value.ToLowerInvariant(); + if (lower != value) + { + newValue = lower; + return true; + } - string v2 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray(), valueEncoding: null); - Assert.Same(v1, v2); + newValue = null; + return false; } } [Theory] [InlineData("Content-Type", "application/jsot")] [InlineData("Content-Type", "application/jsons")] + [InlineData("Transfer-Encoding", "foo")] public void GetKnownHeaderValue_Unknown_NotFound(string name, string value) { KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(name);