public static (int bytesConsumed, HttpHeaderData) DecodeHeader(ReadOnlySpan <byte> buffer) { switch (BitOperations.LeadingZeroCount(buffer[0]) - 24) // byte 'b' is extended to uint, so will have 24 extra 0s. { case 0: // Indexed Header Field { if ((buffer[0] & 0b0100_0000) == 0) { throw new Exception("QPack dynamic table is not yet supported."); } (int bytesConsumed, int staticIndex) = DecodeInteger(buffer, 0b0011_1111); var staticHeader = s_staticTable[staticIndex]; var header = new HttpHeaderData(staticHeader.Name, staticHeader.Value, raw: buffer.Slice(0, bytesConsumed).ToArray()); return(bytesConsumed, header); } case 1: // Literal Header Field With Name Reference { if ((buffer[0] & 0b0001_0000) == 0) { throw new Exception("QPack dynamic table is not yet supported."); } (int nameLength, int staticIndex) = DecodeInteger(buffer, 0b0000_1111); (int valueLength, string value) = DecodeString(buffer.Slice(nameLength), 0b0111_1111); int headerLength = nameLength + valueLength; var header = new HttpHeaderData(s_staticTable[staticIndex].Name, value, raw: buffer.Slice(0, headerLength).ToArray()); return(headerLength, header); } case 2: // Literal Header Field Without Name Reference { (int nameLength, string name) = DecodeString(buffer, 0b0000_0111); (int valueLength, string value) = DecodeString(buffer.Slice(nameLength), 0b0111_1111); int headerLength = nameLength + valueLength; var header = new HttpHeaderData(name, value, raw: buffer.Slice(0, headerLength).ToArray()); return(headerLength, header); } case 3: // Indexed Header Field With Post-Base Index default: // Literal Header Field With Post-Base Name Reference (at least 4 zeroes, maybe more) throw new Exception("QPack dynamic table is not yet supported."); } }
public static (int bytesConsumed, HttpHeaderData) DecodeHeader(ReadOnlySpan <byte> buffer) { int firstByte = buffer[0]; // Indexed Header Field, dynamic. if ((firstByte & 0b1100_0000) == 0b1000_0000) { throw new Exception("QPack dynamic table is not yet supported."); } // Indexed Header Field, static. if ((firstByte & 0b1100_0000) == 0b1100_0000) { (int bytesConsumed, int staticIndex) = DecodeInteger(buffer, 0b1100_0000); var staticHeader = s_staticTable[staticIndex]; var header = new HttpHeaderData(staticHeader.Name, staticHeader.Value, raw: buffer.Slice(0, bytesConsumed).ToArray()); return(bytesConsumed, header); } // Indexed Header Field With Post-Base Index if ((firstByte & 0b1111_0000) == 0b0001_0000) { throw new Exception("QPack dynamic table is not yet supported."); } // Literal Header Field With Name Reference if ((firstByte & 0b1100_0000) == 0b0100_0000) { if ((firstByte & 0b0001_0000) != 0) { throw new Exception("QPack dynamic table is not yet supported."); } (int nameLength, int staticIndex) = DecodeInteger(buffer, 0b1111_0000); (int valueLength, string value) = DecodeString(buffer.Slice(nameLength), 0b1000_0000); int headerLength = nameLength + valueLength; var header = new HttpHeaderData(s_staticTable[staticIndex].Name, value, raw: buffer.Slice(0, headerLength).ToArray()); return(headerLength, header); } // Literal Header Field With Post-Base Name Reference. if ((firstByte & 0b1111_0000) == 0b0000_0000) { throw new Exception("QPack dynamic table is not yet supported."); } // Literal Header Field Without Name Reference. if ((firstByte & 0b1110_0000) == 0b0010_0000) { (int nameLength, string name) = DecodeString(buffer, 0b1111_1000); (int valueLength, string value) = DecodeString(buffer.Slice(nameLength), 0b1000_0000); int headerLength = nameLength + valueLength; var header = new HttpHeaderData(name, value, raw: buffer.Slice(0, headerLength).ToArray()); return(headerLength, header); } throw new Exception("Invalid QPack."); }