< Summary

Information
Class: System.Net.Http.HPack.DynamicTable
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\Http2\Hpack\DynamicTable.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 70
Coverable lines: 70
Total lines: 135
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Insert(...)100%110%
Insert(...)0%660%
UpdateMaxSize(...)0%220%
EnsureAvailable(...)0%660%

File(s)

D:\runner\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\Http2\Hpack\DynamicTable.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5
 6namespace System.Net.Http.HPack
 7{
 8    internal sealed class DynamicTable
 9    {
 10        private HeaderField[] _buffer;
 11        private int _maxSize;
 12        private int _size;
 13        private int _count;
 14        private int _insertIndex;
 15        private int _removeIndex;
 16
 017        public DynamicTable(int maxSize)
 018        {
 019            _buffer = [];
 020            _maxSize = maxSize;
 021        }
 22
 23        public int Count => _count;
 24
 25        public int Size => _size;
 26
 27        public int MaxSize => _maxSize;
 28
 29        public ref readonly HeaderField this[int index]
 30        {
 31            get
 032            {
 033                if (index >= _count)
 034                {
 35#pragma warning disable CA2201 // Do not raise reserved exception types
 36                    // Helpful to act like static table (array)
 037                    throw new IndexOutOfRangeException();
 38#pragma warning restore CA2201
 39                }
 40
 041                index = _insertIndex - index - 1;
 42
 043                if (index < 0)
 044                {
 45                    // _buffer is circular; wrap the index back around.
 046                    index += _buffer.Length;
 047                }
 48
 049                return ref _buffer[index];
 050            }
 51        }
 52
 53        public void Insert(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
 054        {
 055            Insert(staticTableIndex: null, name, value);
 056        }
 57
 58        public void Insert(int? staticTableIndex, ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
 059        {
 060            int entryLength = HeaderField.GetLength(name.Length, value.Length);
 061            EnsureAvailable(entryLength);
 62
 063            if (entryLength > _maxSize)
 064            {
 65                // http://httpwg.org/specs/rfc7541.html#rfc.section.4.4
 66                // It is not an error to attempt to add an entry that is larger than the maximum size;
 67                // an attempt to add an entry larger than the maximum size causes the table to be emptied
 68                // of all existing entries and results in an empty table.
 069                return;
 70            }
 71
 72            // Ensure that we have at least one slot available.
 073            if (_count == _buffer.Length)
 074            {
 075                int maxCapacity = _maxSize / HeaderField.RfcOverhead;
 076                Debug.Assert(_count + 1 <= maxCapacity);
 77
 78                // Double the size of the current buffer, starting with at least 16 entries.
 079                int newBufferSize = Math.Min(Math.Max(16, _buffer.Length * 2), maxCapacity);
 080                Debug.Assert(newBufferSize > _count);
 81
 082                var newBuffer = new HeaderField[newBufferSize];
 83
 084                int headCount = Math.Min(_buffer.Length - _removeIndex, _count);
 085                int tailCount = _count - headCount;
 86
 087                Array.Copy(_buffer, _removeIndex, newBuffer, 0, headCount);
 088                Array.Copy(_buffer, 0, newBuffer, headCount, tailCount);
 89
 090                _buffer = newBuffer;
 091                _removeIndex = 0;
 092                _insertIndex = _count;
 093            }
 94
 095            var entry = new HeaderField(staticTableIndex, name, value);
 096            _buffer[_insertIndex] = entry;
 97
 098            if (++_insertIndex == _buffer.Length)
 099            {
 0100                _insertIndex = 0;
 0101            }
 102
 0103            _size += entry.Length;
 0104            _count++;
 0105        }
 106
 107        public void UpdateMaxSize(int maxSize)
 0108        {
 0109            int previousMax = _maxSize;
 0110            _maxSize = maxSize;
 111
 0112            if (maxSize < previousMax)
 0113            {
 0114                EnsureAvailable(0);
 0115            }
 0116        }
 117
 118        private void EnsureAvailable(int available)
 0119        {
 0120            while (_count > 0 && _maxSize - _size < available)
 0121            {
 0122                ref HeaderField field = ref _buffer[_removeIndex];
 0123                _size -= field.Length;
 0124                field = default;
 125
 0126                _count--;
 127
 0128                if (++_removeIndex == _buffer.Length)
 0129                {
 0130                    _removeIndex = 0;
 0131                }
 0132            }
 0133        }
 134    }
 135}