Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,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];
}
Expand Down Expand Up @@ -166,45 +166,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;

Expand All @@ -217,10 +217,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;

Expand All @@ -239,7 +240,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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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);
Expand Down