Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.

Commit

Permalink
Handle multiple tokens in Connection header (#1170).
Browse files Browse the repository at this point in the history
  • Loading branch information
Cesar Blum Silveira committed Oct 24, 2016
1 parent 610601c commit 45173dd
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,58 @@ private void ConsumedBytes(int count)
OnConsumedBytes(count);
}

internal static unsafe void ParseConnection(string connection, out bool isKeepAlive, out bool isUpgrade)
{
isKeepAlive = false;
isUpgrade = false;

fixed (char* ptr = connection)
{
var ch = ptr;
var end = ch + connection.Length;

while (ch < end)
{
if ((*ch | 0x20) == 'k' && (end - ch) >= 9)
{
if ((*++ch | 0x20) == 'e' &&
(*++ch | 0x20) == 'e' &&
(*++ch | 0x20) == 'p' &&
*++ch == '-' &&
(*++ch | 0x20) == 'a' &&
(*++ch | 0x20) == 'l' &&
(*++ch | 0x20) == 'i' &&
(*++ch | 0x20) == 'v' &&
(*++ch | 0x20) == 'e')
{
isKeepAlive = true;
ch++;
}
}
else if ((*ch | 0x20) == 'u' && (end - ch) >= 7)
{
if ((*++ch | 0x20) == 'p' &&
(*++ch | 0x20) == 'g' &&
(*++ch | 0x20) == 'r' &&
(*++ch | 0x20) == 'a' &&
(*++ch | 0x20) == 'd' &&
(*++ch | 0x20) == 'e')
{
isUpgrade = true;
ch++;
}
}

while (ch < end && *ch++ != ',') ;

while (ch < end && *ch == ' ')
{
ch++;
}
}
}
}

protected abstract ValueTask<ArraySegment<byte>> PeekAsync(CancellationToken cancellationToken);

protected virtual void OnConsumedBytes(int count)
Expand All @@ -234,12 +286,13 @@ public static MessageBody For(
var connection = headers.HeaderConnection.ToString();
if (connection.Length > 0)
{
if (connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase))
bool upgrade;
ParseConnection(connection, out keepAlive, out upgrade);

if (upgrade)
{
return new ForRemainingData(context);
}

keepAlive = connection.Equals("keep-alive", StringComparison.OrdinalIgnoreCase);
}

var transferEncoding = headers.HeaderTransferEncoding.ToString();
Expand Down
76 changes: 76 additions & 0 deletions test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,82 @@ public async Task CopyToAsyncAdvancesRequestStreamWhenDestinationWriteAsyncThrow
}
}

[Theory]
[InlineData("keep-alive, upgrade")]
[InlineData("Keep-Alive, Upgrade")]
[InlineData("upgrade, keep-alive")]
[InlineData("Upgrade, Keep-Alive")]
public void ConnectionUpgradeKeepAlive(string headerConnection)
{
using (var input = new TestInput())
{
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders { HeaderConnection = headerConnection }, input.FrameContext);
var stream = new FrameRequestStream();
stream.StartAcceptingReads(body);

input.Add("Hello", true);

var buffer = new byte[1024];
Assert.Equal(5, stream.Read(buffer, 0, 1024));
AssertASCII("Hello", new ArraySegment<byte>(buffer, 0, 5));
}
}

[Theory]
[InlineData("keep-alive", true, false)]
[InlineData("keep-alive, upgrade", true, true)]
[InlineData("keep-alive,upgrade", true, true)]
[InlineData("upgrade, keep-alive", true, true)]
[InlineData("upgrade,keep-alive", true, true)]
[InlineData("upgrade,,keep-alive", true, true)]
[InlineData("keep-alive,", true, false)]
[InlineData("keep-alive,,", true, false)]
[InlineData(",keep-alive", true, false)]
[InlineData(",,keep-alive", true, false)]
[InlineData("keep-alive, ", true, false)]
[InlineData("keep-alive, ,", true, false)]
[InlineData("keep-alive, , ", true, false)]
[InlineData("keep-alive ,", true, false)]
[InlineData(",keep-alive", true, false)]
[InlineData(", keep-alive", true, false)]
[InlineData(",,keep-alive", true, false)]
[InlineData(", ,keep-alive", true, false)]
[InlineData(",, keep-alive", true, false)]
[InlineData(", , keep-alive", true, false)]
[InlineData("upgrade,", false, true)]
[InlineData("upgrade,,", false, true)]
[InlineData(",upgrade", false, true)]
[InlineData(",,upgrade", false, true)]
[InlineData("upgrade, ", false, true)]
[InlineData("upgrade, ,", false, true)]
[InlineData("upgrade, , ", false, true)]
[InlineData("upgrade ,", false, true)]
[InlineData(",upgrade", false, true)]
[InlineData(", upgrade", false, true)]
[InlineData(",,upgrade", false, true)]
[InlineData(", ,upgrade", false, true)]
[InlineData(",, upgrade", false, true)]
[InlineData(", , upgrade", false, true)]
[InlineData("kupgrade", false, false)]
[InlineData("keupgrade", false, false)]
[InlineData("ukeep-alive", false, false)]
[InlineData("upkeep-alive", false, false)]
[InlineData("k,upgrade", false, true)]
[InlineData("u,keep-alive", true, false)]
[InlineData("ke,upgrade", false, true)]
[InlineData("up,keep-alive", true, false)]
[InlineData("close", false, false)]
[InlineData("upgrade,close", false, true)]
[InlineData("close,upgrade", false, true)]
public void TestParseConnection(string connection, bool expectedKeepAlive, bool expectedUpgrade)
{
bool keepAlive, upgrade;
MessageBody.ParseConnection(connection, out keepAlive, out upgrade);

Assert.Equal(expectedKeepAlive, keepAlive);
Assert.Equal(expectedUpgrade, upgrade);
}

private void AssertASCII(string expected, ArraySegment<byte> actual)
{
var encoding = Encoding.ASCII;
Expand Down

0 comments on commit 45173dd

Please sign in to comment.