1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package io.netty5.handler.codec.http2;
33
34 import static io.netty5.handler.codec.http2.Http2CodecUtil.MAX_HEADER_TABLE_SIZE;
35 import static io.netty5.handler.codec.http2.Http2CodecUtil.MIN_HEADER_TABLE_SIZE;
36
37 final class HpackDynamicTable {
38
39
40 HpackHeaderField[] hpackHeaderFields;
41 int head;
42 int tail;
43 private long size;
44 private long capacity = -1;
45
46
47
48
49 HpackDynamicTable(long initialCapacity) {
50 setCapacity(initialCapacity);
51 }
52
53
54
55
56 public int length() {
57 int length;
58 if (head < tail) {
59 length = hpackHeaderFields.length - tail + head;
60 } else {
61 length = head - tail;
62 }
63 return length;
64 }
65
66
67
68
69 public long size() {
70 return size;
71 }
72
73
74
75
76 public long capacity() {
77 return capacity;
78 }
79
80
81
82
83
84 public HpackHeaderField getEntry(int index) {
85 if (index <= 0 || index > length()) {
86 throw new IndexOutOfBoundsException("Index " + index + " out of bounds for length " + length());
87 }
88 int i = head - index;
89 if (i < 0) {
90 return hpackHeaderFields[i + hpackHeaderFields.length];
91 } else {
92 return hpackHeaderFields[i];
93 }
94 }
95
96
97
98
99
100
101
102 public void add(HpackHeaderField header) {
103 int headerSize = header.size();
104 if (headerSize > capacity) {
105 clear();
106 return;
107 }
108 while (capacity - size < headerSize) {
109 remove();
110 }
111 hpackHeaderFields[head++] = header;
112 size += headerSize;
113 if (head == hpackHeaderFields.length) {
114 head = 0;
115 }
116 }
117
118
119
120
121 public HpackHeaderField remove() {
122 HpackHeaderField removed = hpackHeaderFields[tail];
123 if (removed == null) {
124 return null;
125 }
126 size -= removed.size();
127 hpackHeaderFields[tail++] = null;
128 if (tail == hpackHeaderFields.length) {
129 tail = 0;
130 }
131 return removed;
132 }
133
134
135
136
137 public void clear() {
138 while (tail != head) {
139 hpackHeaderFields[tail++] = null;
140 if (tail == hpackHeaderFields.length) {
141 tail = 0;
142 }
143 }
144 head = 0;
145 tail = 0;
146 size = 0;
147 }
148
149
150
151
152
153 public void setCapacity(long capacity) {
154 if (capacity < MIN_HEADER_TABLE_SIZE || capacity > MAX_HEADER_TABLE_SIZE) {
155 throw new IllegalArgumentException("capacity is invalid: " + capacity);
156 }
157
158 if (this.capacity == capacity) {
159 return;
160 }
161 this.capacity = capacity;
162
163 if (capacity == 0) {
164 clear();
165 } else {
166
167 while (size > capacity) {
168 remove();
169 }
170 }
171
172 int maxEntries = (int) (capacity / HpackHeaderField.HEADER_ENTRY_OVERHEAD);
173 if (capacity % HpackHeaderField.HEADER_ENTRY_OVERHEAD != 0) {
174 maxEntries++;
175 }
176
177
178 if (hpackHeaderFields != null && hpackHeaderFields.length == maxEntries) {
179 return;
180 }
181
182 HpackHeaderField[] tmp = new HpackHeaderField[maxEntries];
183
184
185 int len = length();
186 if (hpackHeaderFields != null) {
187 int cursor = tail;
188 for (int i = 0; i < len; i++) {
189 HpackHeaderField entry = hpackHeaderFields[cursor++];
190 tmp[i] = entry;
191 if (cursor == hpackHeaderFields.length) {
192 cursor = 0;
193 }
194 }
195 }
196
197 tail = 0;
198 head = tail + len;
199 hpackHeaderFields = tmp;
200 }
201 }