/// <summary> /// Encode literal header field according to Section 6.2. /// </summary> /// <param name="output">Output.</param> /// <param name="name">Name.</param> /// <param name="value">Value.</param> /// <param name="indexType">Index type.</param> /// <param name="nameIndex">Name index.</param> private void EncodeLiteral(BinaryWriter output, byte[] name, byte[] value, HPackUtil.IndexType indexType, int nameIndex) { int mask; int prefixBits; switch (indexType) { case HPackUtil.IndexType.INCREMENTAL: mask = 0x40; prefixBits = 6; break; case HPackUtil.IndexType.NONE: mask = 0x00; prefixBits = 4; break; case HPackUtil.IndexType.NEVER: mask = 0x10; prefixBits = 4; break; default: throw new Exception("should not reach here"); } Encoder.EncodeInteger(output, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex); if (nameIndex == -1) { this.EncodeStringLiteral(output, name); } this.EncodeStringLiteral(output, value); }
/// <summary> /// Set the maximum table size. /// </summary> /// <param name="output">Output.</param> /// <param name="maxHeaderTableSize">Max header table size.</param> public void SetMaxHeaderTableSize(BinaryWriter output, int maxHeaderTableSize) { if (maxHeaderTableSize < 0) { throw new ArgumentException("Illegal Capacity: " + maxHeaderTableSize); } if (this.capacity == maxHeaderTableSize) { return; } this.capacity = maxHeaderTableSize; this.EnsureCapacity(0); Encoder.EncodeInteger(output, 0x20, 5, maxHeaderTableSize); }
/// <summary> /// Encode string literal according to Section 5.2. /// </summary> /// <param name="output">Output.</param> /// <param name="stringLiteral">String literal.</param> private void EncodeStringLiteral(BinaryWriter output, byte[] stringLiteral) { int huffmanLength = Huffman.ENCODER.GetEncodedLength(stringLiteral); if ((huffmanLength < stringLiteral.Length && !forceHuffmanOff) || forceHuffmanOn) { Encoder.EncodeInteger(output, 0x80, 7, huffmanLength); Huffman.ENCODER.Encode(output, stringLiteral); } else { Encoder.EncodeInteger(output, 0x00, 7, stringLiteral.Length); output.Write(stringLiteral, 0, stringLiteral.Length); } }
/// <summary> /// Encode the header field into the header block. /// </summary> /// <param name="output">Output.</param> /// <param name="name">Name.</param> /// <param name="value">Value.</param> /// <param name="sensitive">If set to <c>true</c> sensitive.</param> public void EncodeHeader(BinaryWriter output, byte[] name, byte[] value, bool sensitive) { // If the header value is sensitive then it must never be indexed if (sensitive) { int nameIndex = this.GetNameIndex(name); this.EncodeLiteral(output, name, value, HPackUtil.IndexType.NEVER, nameIndex); return; } // If the peer will only use the static table if (this.capacity == 0) { int staticTableIndex = StaticTable.GetIndex(name, value); if (staticTableIndex == -1) { int nameIndex = StaticTable.GetIndex(name); this.EncodeLiteral(output, name, value, HPackUtil.IndexType.NONE, nameIndex); } else { Encoder.EncodeInteger(output, 0x80, 7, staticTableIndex); } return; } int headerSize = HeaderField.SizeOf(name, value); // If the headerSize is greater than the max table size then it must be encoded literally if (headerSize > this.capacity) { int nameIndex = this.GetNameIndex(name); this.EncodeLiteral(output, name, value, HPackUtil.IndexType.NONE, nameIndex); return; } HeaderEntry headerField = this.GetEntry(name, value); if (headerField != null) { int index = this.GetIndex(headerField.Index) + StaticTable.Length; // Section 6.1. Indexed Header Field Representation Encoder.EncodeInteger(output, 0x80, 7, index); } else { int staticTableIndex = StaticTable.GetIndex(name, value); if (staticTableIndex != -1) { // Section 6.1. Indexed Header Field Representation Encoder.EncodeInteger(output, 0x80, 7, staticTableIndex); } else { int nameIndex = this.GetNameIndex(name); if (useIndexing) { this.EnsureCapacity(headerSize); } var indexType = useIndexing ? HPackUtil.IndexType.INCREMENTAL : HPackUtil.IndexType.NONE; this.EncodeLiteral(output, name, value, indexType, nameIndex); if (useIndexing) { this.Add(name, value); } } } }