From 423d5432be5206849cd90cc0f524aed0ec8d028b Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 21 Jun 2018 19:57:07 -0700 Subject: [PATCH] Add test for ensuring HPACK lowercase header names - ensure lowercase mask only applied to uppercase letters --- .../Internal/Http2/HPack/HPackEncoder.cs | 2 +- test/Kestrel.Core.Tests/HPackEncoderTests.cs | 115 +++++++++++++----- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/src/Kestrel.Core/Internal/Http2/HPack/HPackEncoder.cs b/src/Kestrel.Core/Internal/Http2/HPack/HPackEncoder.cs index 0c92961acf..b364ec7e49 100644 --- a/src/Kestrel.Core/Internal/Http2/HPack/HPackEncoder.cs +++ b/src/Kestrel.Core/Internal/Http2/HPack/HPackEncoder.cs @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack return false; } - buffer[i++] = (byte)(s[j] | (lowercase ? toLowerMask : 0)); + buffer[i++] = (byte)(s[j] | (lowercase && s[j] >= (byte)'A' && s[j] <= (byte)'Z' ? toLowerMask : 0)); } length = i; diff --git a/test/Kestrel.Core.Tests/HPackEncoderTests.cs b/test/Kestrel.Core.Tests/HPackEncoderTests.cs index 20313c6a90..57ee0ba9a4 100644 --- a/test/Kestrel.Core.Tests/HPackEncoderTests.cs +++ b/test/Kestrel.Core.Tests/HPackEncoderTests.cs @@ -10,37 +10,96 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { public class HPackEncoderTests { - [Fact] - public void EncodesHeadersInSinglePayloadWhenSpaceAvailable() + public static TheoryData[], byte[], int?> SinglePayloadData + { + get + { + var data = new TheoryData[], byte[], int?>(); + + // Lowercase header name letters only + data.Add( + new[] + { + new KeyValuePair("CustomHeader", "CustomValue"), + }, + new byte[] + { + // 0 12 c u s t o m + 0x00, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + // h e a d e r 11 C + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0b, 0x43, + // u s t o m V a l + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x61, 0x6c, + // u e + 0x75, 0x65 + }, + null); + // Lowercase header name letters only + data.Add( + new[] + { + new KeyValuePair("CustomHeader!#$%&'*+-.^_`|~", "CustomValue"), + }, + new byte[] + { + // 0 27 c u s t o m + 0x00, 0x1b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + // h e a d e r ! # + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x21, 0x23, + // $ % & ' * + - . + 0x24, 0x25, 0x26, 0x27, 0x2a, 0x2b, 0x2d, 0x2e, + // ^ _ ` | ~ 11 C u + 0x5e, 0x5f, 0x60, 0x7c, 0x7e, 0x0b, 0x43, 0x75, + // s t o m V a l u + 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x61, 0x6c, 0x75, + // e + 0x65 + }, + null); + // Single Payload + data.Add( + new[] + { + new KeyValuePair("date", "Mon, 24 Jul 2017 19:22:30 GMT"), + new KeyValuePair("content-type", "text/html; charset=utf-8"), + new KeyValuePair("server", "Kestrel") + }, + new byte[] + { + 0x88, 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x1d, + 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x34, 0x20, + 0x4a, 0x75, 0x6c, 0x20, 0x32, 0x30, 0x31, 0x37, + 0x20, 0x31, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x33, + 0x30, 0x20, 0x47, 0x4d, 0x54, 0x00, 0x0c, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, + 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, + 0x74, 0x66, 0x2d, 0x38, 0x00, 0x06, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x07, 0x4b, 0x65, 0x73, + 0x74, 0x72, 0x65, 0x6c + }, + 200); + + return data; + } + } + + [Theory] + [MemberData(nameof(SinglePayloadData))] + public void EncodesHeadersInSinglePayloadWhenSpaceAvailable(KeyValuePair[] headers, byte[] expectedPayload, int? statusCode) { var encoder = new HPackEncoder(); - - var statusCode = 200; - var headers = new [] - { - new KeyValuePair("date", "Mon, 24 Jul 2017 19:22:30 GMT"), - new KeyValuePair("content-type", "text/html; charset=utf-8"), - new KeyValuePair("server", "Kestrel") - }; - - var expectedPayload = new byte[] - { - 0x88, 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x1d, - 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x34, 0x20, - 0x4a, 0x75, 0x6c, 0x20, 0x32, 0x30, 0x31, 0x37, - 0x20, 0x31, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x33, - 0x30, 0x20, 0x47, 0x4d, 0x54, 0x00, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, - 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, - 0x74, 0x66, 0x2d, 0x38, 0x00, 0x06, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x07, 0x4b, 0x65, 0x73, - 0x74, 0x72, 0x65, 0x6c - }; - var payload = new byte[1024]; - Assert.True(encoder.BeginEncode(statusCode, headers, payload, out var length)); + var length = 0; + if (statusCode.HasValue) + { + Assert.True(encoder.BeginEncode(statusCode.Value, headers, payload, out length)); + } + else + { + Assert.True(encoder.BeginEncode(headers, payload, out length)); + } Assert.Equal(expectedPayload.Length, length); for (var i = 0; i < length; i++)