/// <summary> /// Insert to headers table. /// </summary> /// <param name="header">The header.</param> /// <param name="refSet">The refernced header list.</param> /// <param name="headersTable">The header list.</param> private void InsertToHeadersTable(KeyValuePair <string, string> header, HeadersList refSet, HeadersList headersTable) { /* 07 -> 3.3.1 * The size of an entry is the sum of its name's length in octets (as * defined in Section 4.1.2), of its value's length in octets * (Section 4.1.2) and of 32 octets. */ int headerLen = header.Key.Length + header.Value.Length + 32; /* 07 -> 3.3.2 * Whenever a new entry is to be added to the table, any name referenced * by the representation of this new entry is cached, and then entries * are evicted from the end of the header table until the size of the * header table is less than or equal to (maximum size - new entry * size), or until the table is empty. * * If the size of the new entry is less than or equal to the maximum * size, that entry is added to the table. It is not an error to * attempt to add an entry that is larger than the maximum size. */ while (headersTable.StoredHeadersSize + headerLen >= _maxHeaderByteSize && headersTable.Count > 0) { headersTable.RemoveAt(headersTable.Count - 1); /* 07 -> 3.3.2 * Whenever an entry is evicted from the header table, any reference to * that entry contained by the reference set is removed. */ if (refSet.Contains(header)) { refSet.Remove(header); } } /* 07 -> 3.2.1 * We should always insert into * begin of the headers table. */ headersTable.Insert(0, header); }
/// <summary> /// Modifies the table. /// </summary> /// <param name="headerName">Name of the header.</param> /// <param name="headerValue">The header value.</param> /// <param name="headerType">Type of the header.</param> /// <param name="useHeadersTable">The use headers table.</param> /// <param name="index">The index.</param> private void ModifyTable(string headerName, string headerValue, IndexationType headerType, HeadersList useHeadersTable, int index) { int headerLen = headerName.Length + headerValue.Length + sizeof(Int32); //spec 04: 3.2.3. Header Table Management // The header table can be modified by either adding a new entry to it //or by replacing an existing one. Before doing such a modification, //it has to be ensured that the header table size will stay lower than //or equal to the SETTINGS_MAX_BUFFER_SIZE limit (see Section 5). To //achieve this, repeatedly, the first entry of the header table is //removed, until enough space is available for the modification. //A consequence of removing one or more entries at the beginning of the //header table is that the remaining entries are renumbered. The first //entry of the header table is always associated to the index 0. //When the modification of the header table is the replacement of an //existing entry, the replaced entry is the one indicated in the //literal representation before any entry is removed from the header //table. If the entry to be replaced is removed from the header table //when performing the size adjustment, the replacement entry is //inserted at the beginning of the header table. //The addition of a new entry with a size greater than the //SETTINGS_MAX_BUFFER_SIZE limit causes all the entries from the header //table to be dropped and the new entry not to be added to the header //table. The replacement of an existing entry with a new entry with a //size greater than the SETTINGS_MAX_BUFFER_SIZE has the same //consequences. switch (headerType) { case IndexationType.Incremental: while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize && useHeadersTable.Count > 0) { useHeadersTable.RemoveAt(0); } useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue)); break; case IndexationType.Substitution: if (index != -1) { var header = useHeadersTable[index]; int substHeaderLen = header.Key.Length + header.Value.Length + sizeof(Int32); int deletedHeadersCounter = 0; while (useHeadersTable.StoredHeadersSize + headerLen - substHeaderLen > MaxHeaderByteSize) { if (useHeadersTable.Count > 0) { useHeadersTable.RemoveAt(0); deletedHeadersCounter++; } } if (index >= deletedHeadersCounter) { useHeadersTable[index - deletedHeadersCounter] = new KeyValuePair<string, string>(headerName, headerValue); } else { useHeadersTable.Insert(0, new KeyValuePair<string, string>(headerName, headerValue)); } } //If header wasn't found then add it to the table else { while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize && useHeadersTable.Count > 0) { useHeadersTable.RemoveAt(0); } useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue)); } break; default: return; } }
private void InsertToHeadersTable(KeyValuePair<string, string> header, HeadersList refSet, HeadersList headersTable) { /* 07 -> 3.3.1 The size of an entry is the sum of its name's length in octets (as defined in Section 4.1.2), of its value's length in octets (Section 4.1.2) and of 32 octets. */ int headerLen = header.Key.Length + header.Value.Length + 32; /* 07 -> 3.3.2 Whenever a new entry is to be added to the table, any name referenced by the representation of this new entry is cached, and then entries are evicted from the end of the header table until the size of the header table is less than or equal to (maximum size - new entry size), or until the table is empty. If the size of the new entry is less than or equal to the maximum size, that entry is added to the table. It is not an error to attempt to add an entry that is larger than the maximum size. */ while (headersTable.StoredHeadersSize + headerLen >= _maxHeaderByteSize && headersTable.Count > 0) { headersTable.RemoveAt(headersTable.Count - 1); /* 07 -> 3.3.2 Whenever an entry is evicted from the header table, any reference to that entry contained by the reference set is removed. */ if (refSet.Contains(header)) refSet.Remove(header); } /* 07 -> 3.2.1 We should always insert into begin of the headers table. */ headersTable.Insert(0, header); }
private void InsertToHeadersTable(KeyValuePair<string, string> header, HeadersList refSet, HeadersList headersTable) { //spec 05 // The size of an entry is the sum of its name's length in octets (as //defined in Section 4.1.2), of its value's length in octets //(Section 4.1.2) and of 32 octets. int headerLen = header.Key.Length + header.Value.Length + 32; //spec 05 //3.3.3. Entry Eviction when Adding New Entries //Whenever a new entry is to be added to the table, any name referenced //by the representation of this new entry is cached, and then entries //are evicted from the end of the header table until the size of the //header table is less than or equal to SETTINGS_HEADER_TABLE_SIZE - //new entry size, or until the table is empty. //If the size of the new entry is less than or equal to //SETTINGS_HEADER_TABLE_SIZE, that entry is added to the table. It is //not an error to attempt to add an entry that is larger than //SETTINGS_HEADER_TABLE_SIZE. while (headersTable.StoredHeadersSize + headerLen >= _maxHeaderByteSize && headersTable.Count > 0) { headersTable.RemoveAt(headersTable.Count - 1); //spec 05 //3.3.2. Entry Eviction When Header Table Size Changes //Whenever an entry is evicted from the header table, any reference to //that entry contained by the reference set is removed. if (refSet.Contains(header)) refSet.Remove(header); } //spec 05 //We should always insert into begin of the headers table. //See 3.2.1. Header Field Representation Processing headersTable.Insert(0, header); }
/// <summary> /// Process indexed. /// </summary> /// <param name="index">The index.</param> /// <returns>The indexation.</returns> private Tuple <string, string, IndexationType> ProcessIndexed(int index) { /* 07 -> 4.2 * The index value of 0 is not used. It MUST be treated as a decoding * error if found in an indexed header field representation. */ if (index == 0) { throw new Exception("indexed representation with zero value"); } var header = default(KeyValuePair <string, string>); bool isInStatic = index > _localHeadersTable.Count & index <= _localHeadersTable.Count + Constants.StaticTable.Count; bool isInHeaders = index <= _localHeadersTable.Count; if (isInStatic) { header = Constants.StaticTable[index - _localHeadersTable.Count - 1]; } else if (isInHeaders) { header = _localHeadersTable[index - 1]; } else { throw new IndexOutOfRangeException("no such index nor in static neither in headers tables"); } /* 07 -> 3.2.1 * An _indexed representation_ corresponding to an entry _present_ in * the reference set entails the following actions: * * o The entry is removed from the reference set. */ if (_localRefSet.Contains(header)) { _localRefSet.Remove(header); return(null); } /* 07 -> 3.2.1 * An _indexed representation_ corresponding to an entry _not present_ * in the reference set entails the following actions: * * o If referencing an element of the static table: * * The header field corresponding to the referenced entry is * emitted. * * The referenced static entry is inserted at the beginning of the * header table. * * A reference to this new header table entry is added to the * reference set, except if this new entry didn't fit in the * header table. * * o If referencing an element of the header table: * * The header field corresponding to the referenced entry is * emitted. * * The referenced header table entry is added to the reference * set. */ if (isInStatic) { _localHeadersTable.Insert(0, header); } _localRefSet.Add(header); return(new Tuple <string, string, IndexationType>(header.Key, header.Value, IndexationType.Indexed)); }
/// <summary> /// Compressed indexed. /// </summary> /// <param name="header">The header.</param> private void CompressIndexed(KeyValuePair <string, string> header) { /* 07 -> 3.2.1 * An _indexed representation_ corresponding to an entry _not present_ * in the reference set entails the following actions: * * o If referencing an element of the static table: * * The header field corresponding to the referenced entry is * emitted. * * The referenced static entry is inserted at the beginning of the * header table. * * A reference to this new header table entry is added to the * reference set, except if this new entry didn't fit in the * header table. */ int index = _remoteHeadersTable.FindIndex(kv => kv.Key.Equals(header.Key) && kv.Value.Equals(header.Value)); bool isFound = index != -1; /* 07 -> 3.1.4 * <---------- Index Address Space ----------> * <-- Header Table --> <-- Static Table --> +---+-----------+---+ +---+-----------+---+ | 1 | ... | k | |k+1| ... | n | +---+-----------+---+ +---+-----------+---+ | ^ | | V | Insertion Point Drop Point */ if (!isFound) { index = Constants.StaticTable.FindIndex(kv => kv.Key.Equals(header.Key, StringComparison.OrdinalIgnoreCase) && kv.Value.Equals(header.Value, StringComparison.OrdinalIgnoreCase)); isFound = index != -1; if (isFound) { index += _remoteHeadersTable.Count; /* 07 -> 3.2.1 * The referenced static entry is inserted at the beginning of the * header table. */ _remoteHeadersTable.Insert(0, header); } } if (!isFound) { throw new Exception("cant compress indexed header. Index not found."); } const byte prefix = (byte)UVarIntPrefix.Indexed; var bytes = (index + 1).ToUVarInt(prefix); // Set indexed type bytes[0] |= (byte)IndexationType.Indexed; WriteToOutput(bytes, 0, bytes.Length); }