Using the optimized method for converting header name to ASCII

This commit is contained in:
moozzyk 2016-05-27 11:03:05 -07:00
parent de022b6051
commit 0342754c57
5 changed files with 499 additions and 451 deletions

View File

@ -172,6 +172,23 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
} }
} }
[Fact]
public async Task BadRequestWhenNameHeaderNamesContainsNonASCIICharacters()
{
using (var server = new TestServer(context => { return Task.FromResult(0); }))
{
using (var connection = server.CreateConnection())
{
await connection.SendEnd(
"GET / HTTP/1.1",
"Hëädër: value",
"",
"");
await ReceiveBadRequestResponse(connection);
}
}
}
private async Task ReceiveBadRequestResponse(TestConnection connection) private async Task ReceiveBadRequestResponse(TestConnection connection)
{ {
await connection.Receive( await connection.Receive(

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Xunit; using Xunit;
@ -233,5 +235,16 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
Assert.Null(entries[3].Key); Assert.Null(entries[3].Key);
Assert.Equal(new StringValues(), entries[0].Value); Assert.Equal(new StringValues(), entries[0].Value);
} }
[Fact]
public void AppendThrowsWhenHeaderValueContainsNonASCIICharacters()
{
var headers = new FrameRequestHeaders();
const string key = "\u00141ód\017c";
var encoding = Encoding.GetEncoding("iso-8859-1");
Assert.Throws<BadHttpRequestException>(
() => headers.Append(encoding.GetBytes(key), 0, encoding.GetByteCount(key), key));
}
} }
} }

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task Send(params string[] lines) public async Task Send(params string[] lines)
{ {
var text = String.Join("\r\n", lines); var text = String.Join("\r\n", lines);
var writer = new StreamWriter(_stream, Encoding.ASCII); var writer = new StreamWriter(_stream, Encoding.GetEncoding("iso-8859-1"));
for (var index = 0; index < text.Length; index++) for (var index = 0; index < text.Length; index++)
{ {
var ch = text[index]; var ch = text[index];

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.GeneratedCode
return $"(({array}[{offset / count}] & {mask}{suffix}) == {comp}{suffix})"; return $"(({array}[{offset / count}] & {mask}{suffix}) == {comp}{suffix})";
} }
} }
public static string GeneratedFile() public static string GeneratedFile()
{ {
var commonHeaders = new[] var commonHeaders = new[]
@ -199,11 +199,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.GeneratedCode
return $@" return $@"
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using Microsoft.AspNetCore.Server.Kestrel.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Server.Kestrel.Http namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{ {{
{Each(loops, loop => $@" {Each(loops, loop => $@"
public partial class {loop.ClassName} public partial class {loop.ClassName}
@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{Each(loop.Bytes, b => $"{b},")} {Each(loop.Bytes, b => $"{b},")}
}};" }};"
: "")} : "")}
private long _bits = 0; private long _bits = 0;
private HeaderReferences _headers; private HeaderReferences _headers;
{Each(loop.Headers, header => $@" {Each(loop.Headers, header => $@"
@ -239,7 +239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
public void SetRaw{header.Identifier}(StringValues value, byte[] raw) public void SetRaw{header.Identifier}(StringValues value, byte[] raw)
{{ {{
{header.SetBit()}; {header.SetBit()};
_headers._{header.Identifier} = value; _headers._{header.Identifier} = value;
_headers._raw{header.Identifier} = raw; _headers._raw{header.Identifier} = raw;
}}")} }}")}
protected override int GetCountFast() protected override int GetCountFast()
@ -266,7 +266,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
")}}} ")}}}
break; break;
")}}} ")}}}
if (MaybeUnknown == null) if (MaybeUnknown == null)
{{ {{
ThrowKeyNotFoundException(); ThrowKeyNotFoundException();
}} }}
@ -278,7 +278,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase)) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase)) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
{header.SetBit()}; {header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@" _headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase)) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -372,7 +372,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
_headers = default(HeaderReferences); _headers = default(HeaderReferences);
MaybeUnknown?.Clear(); MaybeUnknown?.Clear();
}} }}
protected override void CopyToFast(KeyValuePair<string, StringValues>[] array, int arrayIndex) protected override void CopyToFast(KeyValuePair<string, StringValues>[] array, int arrayIndex)
{{ {{
if (arrayIndex < 0) if (arrayIndex < 0)
@ -380,7 +380,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
ThrowArgumentException(); ThrowArgumentException();
}} }}
{Each(loop.Headers, header => $@" {Each(loop.Headers, header => $@"
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
if (arrayIndex == array.Length) if (arrayIndex == array.Length)
{{ {{
@ -397,12 +397,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
protected void CopyToFast(ref MemoryPoolIterator output) protected void CopyToFast(ref MemoryPoolIterator output)
{{ {{
{Each(loop.Headers, header => $@" {Each(loop.Headers, header => $@"
if ({header.TestBit()}) if ({header.TestBit()})
{{ {(header.EnhancedSetter == false ? "" : $@" {{ {(header.EnhancedSetter == false ? "" : $@"
if (_headers._raw{header.Identifier} != null) if (_headers._raw{header.Identifier} != null)
{{ {{
output.CopyFrom(_headers._raw{header.Identifier}, 0, _headers._raw{header.Identifier}.Length); output.CopyFrom(_headers._raw{header.Identifier}, 0, _headers._raw{header.Identifier}.Length);
}} }}
else ")} else ")}
foreach (var value in _headers._{header.Identifier}) foreach (var value in _headers._{header.Identifier})
{{ {{
@ -418,17 +418,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{(loop.ClassName == "FrameRequestHeaders" ? $@" {(loop.ClassName == "FrameRequestHeaders" ? $@"
public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value)
{{ {{
fixed (byte* ptr = &keyBytes[keyOffset]) var key = new string('\0', keyLength);
{{ fixed (byte* ptr = &keyBytes[keyOffset])
var pUB = ptr; {{
var pUL = (ulong*)pUB; var pUB = ptr;
var pUI = (uint*)pUB; var pUL = (ulong*)pUB;
var pUI = (uint*)pUB;
var pUS = (ushort*)pUB; var pUS = (ushort*)pUB;
switch (keyLength) switch (keyLength)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if ({header.EqualIgnoreCaseBytes()}) if ({header.EqualIgnoreCaseBytes()})
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -445,8 +446,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
")}}} ")}}}
break; break;
")}}} ")}}}
fixed(char *keyBuffer = key)
{{
if (!AsciiUtilities.TryGetAsciiString(ptr, keyBuffer, keyLength))
{{
throw new BadHttpRequestException(""Invalid characters in header name"");
}}
}}
}} }}
var key = System.Text.Encoding.ASCII.GetString(keyBytes, keyOffset, keyLength);
StringValues existing; StringValues existing;
Unknown.TryGetValue(key, out existing); Unknown.TryGetValue(key, out existing);
Unknown[key] = AppendValue(existing, value); Unknown[key] = AppendValue(existing, value);