未验证 提交 0b260608 编写于 作者: M Miha Zupan 提交者: GitHub

Use ordinal comparison for known header values (#64702)

* Use ordinal comparison for known header values

* Match 'text/html; charset=UTF-8' again
上级 54404d70
......@@ -143,7 +143,7 @@ public string GetHeaderValue(ReadOnlySpan<byte> 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];
}
......@@ -177,45 +177,45 @@ public string GetHeaderValue(ReadOnlySpan<byte> 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;
......@@ -228,10 +228,11 @@ public string GetHeaderValue(ReadOnlySpan<byte> 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;
......@@ -250,7 +251,7 @@ public string GetHeaderValue(ReadOnlySpan<byte> 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;
}
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册