示例#1
0
        /// <summary>
        /// Compress the header list.
        /// </summary>
        /// <param name="headers">The headers.</param>
        /// <returns>The compressed headers.</returns>
        public byte[] Compress(HeadersList headers)
        {
            var toSend   = new HeadersList();
            var toDelete = new HeadersList(_remoteRefSet);

            ClearStream(_serializerStream, (int)_serializerStream.Position);

            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 (_remoteHeadersTable.Contains(header) || Constants.StaticTable.Contains(header))
                {
                    CompressIndexed(header);
                }
                else
                {
                    CompressIncremental(header);
                }

                _remoteRefSet.Add(header);
            }

            _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 EvictHeaderTableEntries(HeadersList headersTable, HeadersList refTable)
        {
            /* 07 -> 3.3.2
            Whenever the maximum size for the header table is made smaller,
            entries are evicted from the end of the header table until the size
            of the header table is less than or equal to the maximum size. */
            while (headersTable.StoredHeadersSize >= _maxHeaderByteSize && headersTable.Count > 0)
            {
                var header = headersTable[headersTable.Count - 1];
                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 (refTable.Contains(header))
                    refTable.Remove(header);
            }
        }
示例#3
0
        /// <summary>
        /// Evict header table entry.
        /// </summary>
        /// <param name="headersTable"></param>
        /// <param name="refTable"></param>
        private void EvictHeaderTableEntries(HeadersList headersTable, HeadersList refTable)
        {
            /* 07 -> 3.3.2
             * Whenever the maximum size for the header table is made smaller,
             * entries are evicted from the end of the header table until the size
             * of the header table is less than or equal to the maximum size. */
            while (headersTable.StoredHeadersSize >= _maxHeaderByteSize && headersTable.Count > 0)
            {
                var header = headersTable[headersTable.Count - 1];
                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 (refTable.Contains(header))
                {
                    refTable.Remove(header);
                }
            }
        }
示例#4
0
        /// <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);
        }
        public HeadersList Decompress(byte[] serializedHeaders)
        {
            try
            {
                var workingSet = new HeadersList(_localRefSet);
                var unindexedHeadersList = new HeadersList();
                _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 if (entry.Item3 == IndexationType.WithoutIndexation)
                    {
                        unindexedHeadersList.Add(header);
                    }
                    else
                    {
                        workingSet.Add(header);
                    }
                }

                _localRefSet = new HeadersList(workingSet);

                for (int i = _localRefSet.Count - 1; i >= 0; --i)
                {
                    var header = _localRefSet[i];
                    if (!_localHeaderTable.Contains(header))
                        _localRefSet.RemoveAll(h => h.Equals(header));
                }

                workingSet.AddRange(unindexedHeadersList);
                return workingSet;
            }
            catch (Exception e)
            {
                throw new CompressionError(e);
            }
        }
        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 MakeHeadersTableBeUpToDate(HeadersList headersTable, HeadersList refTable)
        {
            while (headersTable.StoredHeadersSize >= _maxHeaderByteSize && headersTable.Count > 0)
            {

                var header = headersTable[headersTable.Count - 1];
                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 (refTable.Contains(header))
                    refTable.Remove(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);
        }
示例#9
0
        /// <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));
        }