Skip to content

Instantly share code, notes, and snippets.

@benaadams
Created April 23, 2020 15:49
Show Gist options
  • Save benaadams/2ac588cc3dd65088db2bb51f9e4a89e1 to your computer and use it in GitHub Desktop.
Save benaadams/2ac588cc3dd65088db2bb51f9e4a89e1 to your computer and use it in GitHub Desktop.
using System;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Primitives;
public class Program
{
static void Main()
{
var connection = HttpParser.ParseConnection(default);
}
}
public class HttpParser
{
[Flags]
public enum ConnectionOptions
{
None = 0,
Close = 1,
KeepAlive = 2,
Upgrade = 4
}
public static ConnectionOptions ParseConnection(StringValues connection)
{
char lowerCaseChar = (char)0x0020;
ulong lowerCaseULong = 0x0020_0020_0020_0020;
uint lowerCaseUInt = 0x0020_0020;
ushort lowerCaseUShort = 0x0020;
// Keep-alive
ulong lowerCaseKeep = 0x0000_0020_0020_0020; // Don't lowercase hyphen
ulong keepChars = 0x002d_0070_0065_0065; // 4 chars "eep-"
ulong alivChars = 0x0076_0069_006c_0061; // 4 chars "aliv"
ushort eChars = 0x0065; // 4 chars "aliv"
// Upgrade
ulong pgraChars = 0x0061_0072_0067_0070; // 4 chars "pgra"
uint deChars = 0x0065_0064; // 2 chars "de"
// Close
ulong loseChars = 0x0065_0073_006f_006c; // 4 chars "lose"
var connectionOptions = ConnectionOptions.None;
var connectionCount = connection.Count;
for (var i = 0; i < connectionCount; i++)
{
var value = connection[i].AsSpan();
while (value.Length > 0)
{
int offset;
char c = '\0';
// Skip any spaces and empty values
for (offset = 0; offset < value.Length; offset++)
{
c = value[offset];
if (c == ' ' || c == ',')
{
continue;
}
break;
}
if (offset == value.Length)
{
// Consumed enitre string, move to next
break;
}
var potentialConnectionOptions = ConnectionOptions.None;
value = value.Slice(offset + 1);
offset = 0;
var byteValue = MemoryMarshal.AsBytes(value);
if ((c | lowerCaseChar) == 'k' && byteValue.Length >= (2 * sizeof(ulong) + sizeof(ushort)))
{
if ((BinaryPrimitives.ReadUInt64LittleEndian(byteValue) | lowerCaseKeep) == keepChars)
{
offset += sizeof(ulong) / 2;
byteValue = byteValue.Slice(sizeof(ulong));
if ((BinaryPrimitives.ReadUInt64LittleEndian(byteValue) | lowerCaseULong) == alivChars)
{
offset += sizeof(ulong) / 2;
byteValue = byteValue.Slice(sizeof(ulong));
if ((BinaryPrimitives.ReadUInt16LittleEndian(byteValue) | lowerCaseUShort) == eChars)
{
offset += sizeof(ushort) / 2;
potentialConnectionOptions = ConnectionOptions.KeepAlive;
}
}
}
}
else if ((c | lowerCaseChar) == 'u' && byteValue.Length >= (sizeof(ulong) + sizeof(uint)))
{
if ((BinaryPrimitives.ReadUInt64LittleEndian(byteValue) | lowerCaseULong) == pgraChars)
{
offset += sizeof(ulong) / 2;
byteValue = byteValue.Slice(sizeof(ulong));
if ((BinaryPrimitives.ReadUInt32LittleEndian(byteValue) | lowerCaseUInt) == deChars)
{
offset += sizeof(uint) / 2;
potentialConnectionOptions = ConnectionOptions.Upgrade;
}
}
}
else if ((c | lowerCaseChar) == 'c' && byteValue.Length >= sizeof(ulong))
{
if ((BinaryPrimitives.ReadUInt64LittleEndian(byteValue) | lowerCaseULong) == loseChars)
{
offset += sizeof(ulong) / 2;
potentialConnectionOptions = ConnectionOptions.Close;
}
}
if (offset == value.Length)
{
// Consumed enitre string, move to next string
connectionOptions |= potentialConnectionOptions;
break;
}
value = value.Slice(offset);
for (offset = 0; offset < value.Length; offset++)
{
c = value[offset];
if (c == ' ')
{
continue;
}
if (c == ',')
{
break;
}
else
{
// Value contains extra chars; this is not the matched one.
potentialConnectionOptions = ConnectionOptions.None;
continue;
}
}
if (offset == value.Length)
{
// Consumed enitre string, move to next string
connectionOptions |= potentialConnectionOptions;
break;
}
else if (c == ',')
{
// Consumed value, move to next value
connectionOptions |= potentialConnectionOptions;
value = value.Slice(offset + 1);
continue;
}
}
}
return connectionOptions;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment