public CompressionProcessor() { _requestHeadersStorage = CompressionInitialHeaders.RequestInitialHeaders; _responseHeadersStorage = CompressionInitialHeaders.ResponseInitialHeaders; InitCompressor(); InitDecompressor(); }
public CompressionProcessor(ConnectionEnd end) { if (end == ConnectionEnd.Client) { _localHeaderTable = CompressionInitialHeaders.ResponseInitialHeaders; _remoteHeaderTable = CompressionInitialHeaders.RequestInitialHeaders; } else { _localHeaderTable = CompressionInitialHeaders.RequestInitialHeaders; _remoteHeaderTable = CompressionInitialHeaders.ResponseInitialHeaders; } _localRefSet = new SizedHeadersList(); _remoteRefSet = new SizedHeadersList(); InitCompressor(); InitDecompressor(); }
//Method retypes as many headers as it can to be Indexed //and checks if headers marked as indexed are present in the headers table /*private void OptimizeInputAndSendOptimized(List<KeyValuePair<string, string>> headers) { for (int i = 0; i < headers.Count; i++ ) { var headerKv = new KeyValuePair<string, string>(headers[i].Item1, headers[i].Item2); IndexationType headerType = (headers[i].Item3 as Indexation).Type; int index = _remoteHeaderTable.IndexOf(headerKv); //case headerType == IndexationType.Incremental //must not be considered because headers table can contain duplicates if (index != -1 && headerType == IndexationType.Substitution) { CompressIndexed(headerKv); headers.Remove(headers[i--]); } //If header marked as indexed, but not found in the table, compress it as incremental. if (index == -1 && headerType == IndexationType.Indexed) { CompressNonIndexed(headerKv.Key, headerKv.Value, IndexationType.Incremental, 5); headers.Remove(headers[i--]); } } }*/ public byte[] Compress(HeadersList headers) { var toSend = new SizedHeadersList(); var toDelete = new SizedHeadersList(_remoteRefSet); ClearStream(_serializerStream, (int) _serializerStream.Position); //OptimizeInputAndSendOptimized(headersCopy); - dont need this? foreach (var header in headers) { if (header.Key == null || header.Value == null) { throw new InvalidHeaderException(header); } if (!_remoteRefSet.Contains(header)) { //Not there, Will send toSend.Add(header); } else { //Already there, don't delete toDelete.Remove(header); } } foreach (var header in toDelete) { //Anything left in toDelete, should send, so it is deleted from ref set. CompressIndexed(header); _remoteRefSet.Remove(header); //Update our copy } foreach (var header in toSend) { //Send whatever was left in headersCopy if (_remoteHeaderTable.Contains(header)) { CompressIndexed(header); } else { CompressHeader(header, new Indexation(IndexationType.Incremental)); } _remoteRefSet.Add(header); //Update our copy } _serializerStream.Flush(); var result = new byte[_serializerStream.Position]; var streamBuffer = _serializerStream.GetBuffer(); Buffer.BlockCopy(streamBuffer, 0, result, 0, (int)_serializerStream.Position); return result; }
private void ModifyTable(string headerName, string headerValue, IndexationType headerType, SizedHeadersList useHeadersTable, int index) { int headerLen = headerName.Length + headerValue.Length; switch (headerType) { case IndexationType.Incremental: if (useHeadersTable.Count > HeadersLimit - 1) { useHeadersTable.RemoveAt(0); } while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize) { useHeadersTable.RemoveAt(0); } useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue)); break; case IndexationType.Substitution: if (index != -1) { useHeadersTable[index] = new KeyValuePair<string, string>(headerName, headerValue); } else { if (useHeadersTable.Count > HeadersLimit - 1) { useHeadersTable.RemoveAt(0); } while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize) { useHeadersTable.RemoveAt(0); } //If header wasn't found then add it to the table useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue)); } break; default: return; } }
public HeadersList Decompress(byte[] serializedHeaders) { try { var workingSet = new SizedHeadersList(_localRefSet); _currentOffset = 0; while (_currentOffset != serializedHeaders.Length) { var entry = ParseHeader(serializedHeaders); var header = new KeyValuePair<string, string>(entry.Item1, entry.Item2); if (entry.Item3 == IndexationType.Indexed) { if (workingSet.Contains(header)) workingSet.RemoveAll(h => h.Equals(header)); else workingSet.Add(header); } else { workingSet.Add(header); } } _localRefSet = new SizedHeadersList(workingSet); for (int i = _localRefSet.Count - 1; i >= 0; --i) { var header = _localRefSet[i]; if (!_localHeaderTable.Contains(header)) _localRefSet.RemoveAll(h => h.Equals(header)); } return workingSet; } catch (Exception e) { throw new CompressionError(e); } }
private void CompressHeader(Tuple<string, string, IAdditionalHeaderInfo> header, SizedHeadersList useHeadersTable) { byte prefix = 0; var headerName = header.Item1; var headerValue = header.Item2; var headerType = (header.Item3 as Indexation).Type; switch (headerType) { case IndexationType.WithoutIndexation: case IndexationType.Incremental: prefix = 5; break; case IndexationType.Substitution: prefix = 6; break; case IndexationType.Indexed: CompressIndexed(new KeyValuePair<string, string>(headerName, headerValue), useHeadersTable); return; } CompressNonIndexed(headerName, headerValue, headerType, prefix, useHeadersTable); }
private Tuple<string, string, IAdditionalHeaderInfo> ParseHeader(byte[] bytes, SizedHeadersList useHeadersTable) { var type = GetHeaderType(bytes); int index = GetIndex(bytes, type); string name; string value; byte valueLen; byte nameLen; switch (type) { case IndexationType.Indexed: var kv = useHeadersTable[index]; return new Tuple<string, string, IAdditionalHeaderInfo>(kv.Key, kv.Value, new Indexation(type)); case IndexationType.Incremental: case IndexationType.WithoutIndexation: case IndexationType.Substitution: //get replaced entry index. It's equal with the found index in our case if (type == IndexationType.Substitution) { index = GetIndex(bytes, type); } if (index == 0) { nameLen = bytes[_currentOffset++]; name = Encoding.UTF8.GetString(bytes, _currentOffset, nameLen); _currentOffset += nameLen; } else { //Index increased by 1 was sent name = useHeadersTable[index - 1].Key; } valueLen = bytes[_currentOffset++]; value = Encoding.UTF8.GetString(bytes, _currentOffset, valueLen); _currentOffset += valueLen; ModifyTable(name, value, type, useHeadersTable, index - 1); return new Tuple<string, string, IAdditionalHeaderInfo>(name, value, new Indexation(type)); } return default(Tuple<string, string, IAdditionalHeaderInfo>); }
//Method retypes as many headers as it can to be Indexed //and checks if headers marked as indexed are present in the headers table private void OptimizeInputAndSendOptimized(List<Tuple<string, string, IAdditionalHeaderInfo>> headers, SizedHeadersList useHeadersTable) { for (int i = 0; i < headers.Count; i++ ) { var headerKv = new KeyValuePair<string, string>(headers[i].Item1, headers[i].Item2); IndexationType headerType = (headers[i].Item3 as Indexation).Type; int index = useHeadersTable.IndexOf(headerKv); //case headerType == IndexationType.Incremental //must not be considered because headers table can contain duplicates if (index != -1 && headerType == IndexationType.Substitution) { CompressIndexed(headerKv, useHeadersTable); headers.Remove(headers[i--]); } //If header marked as indexed, but not found in the table, compress it as incremental. if (index == -1 && headerType == IndexationType.Indexed) { CompressNonIndexed(headerKv.Key, headerKv.Value, IndexationType.Incremental, 5, useHeadersTable); headers.Remove(headers[i--]); } } }
private void CompressNonIndexed(string headerName, string headerValue, IndexationType headerType, byte prefix, SizedHeadersList useHeadersTable) { int index = useHeadersTable.FindIndex(kv => kv.Key == headerName); byte nameLenBinary = 0; // headers cant be more then 255 characters length byte[] nameBinary = new byte[0]; //It's necessary to form result array because partial writeToOutput stream can cause problems because of multithreading using (var stream = new MemoryStream(64)) { byte[] indexBinary; byte valueLenBinary; byte[] valueBinary; if (index != -1) { indexBinary = (index + 1).ToUVarInt(prefix); } else { indexBinary = 0.ToUVarInt(prefix); nameBinary = Encoding.UTF8.GetBytes(headerName); nameLenBinary = (byte)nameBinary.Length; } //Set without index type indexBinary[0] |= (byte)headerType; valueBinary = Encoding.UTF8.GetBytes(headerValue); valueLenBinary = (byte)valueBinary.Length; stream.Write(indexBinary, 0, indexBinary.Length); //write replaced index. It's equal with the found index in our case if (headerType == IndexationType.Substitution) { stream.Write(indexBinary, 0, indexBinary.Length); } if (index == -1) { stream.WriteByte(nameLenBinary); stream.Write(nameBinary, 0, nameBinary.Length); } stream.WriteByte(valueLenBinary); stream.Write(valueBinary, 0, valueBinary.Length); WriteToOutput(stream.GetBuffer(), 0, (int)stream.Position); } ModifyTable(headerName, headerValue, headerType, useHeadersTable, index); }
private void CompressIndexed(KeyValuePair<string, string> header, SizedHeadersList useHeadersTable) { int index = useHeadersTable.FindIndex(kv => kv.Key == header.Key && kv.Value == header.Value); const byte prefix = 7; var bytes = index.ToUVarInt(prefix); //Set indexed type bytes[0] |= (byte) IndexationType.Indexed; WriteToOutput(bytes, 0, bytes.Length); }