Properly handle headers with empty values

This commit is contained in:
Stephen Halter 2015-10-21 12:49:37 -07:00
parent 52f4fa91e3
commit 094b8efbf8
2 changed files with 51 additions and 7 deletions

View File

@ -157,7 +157,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput))
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
@ -654,7 +654,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return Encoding.UTF8.GetString(range.Array, range.Offset + startIndex, endIndex - startIndex);
}
private bool TakeMessageHeaders(SocketInput input)
public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders)
{
var scan = input.ConsumingStart();
var consumed = scan;
@ -692,6 +692,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
chSecond == '\r' ||
chSecond == '\n')
{
if (chSecond == '\r')
{
var scanAhead = scan;
var chAhead = scanAhead.Take();
if (chAhead == '\n')
{
chAhead = scanAhead.Take();
// If the "\r\n" isn't part of "linear whitespace",
// then this header has no value.
if (chAhead != ' ' && chAhead != '\t')
{
break;
}
}
}
beginValue = scan;
chSecond = scan.Take();
}
@ -729,9 +745,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
var name = beginName.GetArraySegment(endName);
#if DEBUG
var nameString = beginName.GetString(endName);
#endif
var value = beginValue.GetString(endValue);
if (wrapping)
{
@ -739,7 +752,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
consumed = scan;
_requestHeaders.Append(name.Array, name.Offset, name.Count, value);
requestHeaders.Append(name.Array, name.Offset, name.Count, value);
break;
}
}

View File

@ -1,9 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Server.Kestrel.Http;
using System;
using System.Linq;
using System.Text;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Xunit;
namespace Microsoft.AspNet.Server.KestrelTests
@ -34,5 +36,34 @@ namespace Microsoft.AspNet.Server.KestrelTests
Assert.Equal(Encoding.ASCII.GetBytes(expected), beginChunkBytes.ToArray());
}
[Theory]
[InlineData("Cookie: \r\n\r\n", 1)]
[InlineData("Cookie:\r\n\r\n", 1)]
[InlineData("Cookie:\r\n value\r\n\r\n", 1)]
[InlineData("Cookie\r\n", 0)]
[InlineData("Cookie: \r\nConnection: close\r\n\r\n", 2)]
[InlineData("Connection: close\r\nCookie: \r\n\r\n", 2)]
[InlineData("Connection: close\r\nCookie \r\n", 1)]
[InlineData("Connection:\r\n \r\nCookie \r\n", 1)]
public void EmptyHeaderValuesCanBeParsed(string rawHeaders, int numHeaders)
{
var socketInput = new SocketInput(new MemoryPool2());
var headerCollection = new FrameRequestHeaders();
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
var inputBuffer = socketInput.IncomingStart(headerArray.Length);
Buffer.BlockCopy(headerArray, 0, inputBuffer.Data.Array, inputBuffer.Data.Offset, headerArray.Length);
socketInput.IncomingComplete(headerArray.Length, null);
var success = Frame.TakeMessageHeaders(socketInput, headerCollection);
Assert.True(success);
Assert.Equal(numHeaders, headerCollection.Count());
// Assert TakeMessageHeaders consumed all the input
var scan = socketInput.ConsumingStart();
Assert.True(scan.IsEnd);
}
}
}