Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
HPackDecoder.cs
Go to the documentation of this file.
2
4
5internal sealed class HPackDecoder
6{
20
21 private readonly int _maxDynamicTableSize;
22
23 private readonly int _maxHeadersLength;
24
25 private readonly DynamicTable _dynamicTable;
26
28
29 private byte[] _stringOctets;
30
31 private byte[] _headerNameOctets;
32
33 private byte[] _headerValueOctets;
34
35 private (int start, int length)? _headerNameRange;
36
37 private (int start, int length)? _headerValueRange;
38
39 private State _state;
40
41 private byte[] _headerName;
42
43 private int _headerStaticIndex;
44
45 private int _stringIndex;
46
47 private int _stringLength;
48
49 private int _headerNameLength;
50
51 private int _headerValueLength;
52
53 private bool _index;
54
55 private bool _huffman;
56
57 private bool _headersObserved;
58
59 public HPackDecoder(int maxDynamicTableSize = 4096, int maxHeadersLength = 65536)
60 : this(maxDynamicTableSize, maxHeadersLength, new DynamicTable(maxDynamicTableSize))
61 {
62 }
63
64 internal HPackDecoder(int maxDynamicTableSize, int maxHeadersLength, DynamicTable dynamicTable)
65 {
66 _maxDynamicTableSize = maxDynamicTableSize;
67 _maxHeadersLength = maxHeadersLength;
68 _dynamicTable = dynamicTable;
69 _stringOctets = new byte[4096];
70 _headerNameOctets = new byte[4096];
71 _headerValueOctets = new byte[4096];
72 }
73
74 public void Decode(ReadOnlySpan<byte> data, bool endHeaders, IHttpHeadersHandler handler)
75 {
76 DecodeInternal(data, handler);
78 }
79
81 {
82 int currentIndex = 0;
83 do
84 {
85 switch (_state)
86 {
87 case State.Ready:
88 Parse(data, ref currentIndex, handler);
89 break;
90 case State.HeaderFieldIndex:
91 ParseHeaderFieldIndex(data, ref currentIndex, handler);
92 break;
93 case State.HeaderNameIndex:
94 ParseHeaderNameIndex(data, ref currentIndex, handler);
95 break;
96 case State.HeaderNameLength:
97 ParseHeaderNameLength(data, ref currentIndex, handler);
98 break;
99 case State.HeaderNameLengthContinue:
100 ParseHeaderNameLengthContinue(data, ref currentIndex, handler);
101 break;
102 case State.HeaderName:
103 ParseHeaderName(data, ref currentIndex, handler);
104 break;
105 case State.HeaderValueLength:
106 ParseHeaderValueLength(data, ref currentIndex, handler);
107 break;
108 case State.HeaderValueLengthContinue:
109 ParseHeaderValueLengthContinue(data, ref currentIndex, handler);
110 break;
111 case State.HeaderValue:
112 ParseHeaderValue(data, ref currentIndex, handler);
113 break;
114 case State.DynamicTableSizeUpdate:
115 ParseDynamicTableSizeUpdate(data, ref currentIndex);
116 break;
117 default:
118 throw new NotImplementedException(_state.ToString());
119 }
120 }
121 while (currentIndex < data.Length);
122 if (_headerNameRange.HasValue)
123 {
126 ReadOnlySpan<byte> readOnlySpan = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length);
127 readOnlySpan.CopyTo(_headerName);
128 _headerNameLength = readOnlySpan.Length;
129 _headerNameRange = null;
130 }
131 }
132
133 private void ParseDynamicTableSizeUpdate(ReadOnlySpan<byte> data, ref int currentIndex)
134 {
135 if (TryDecodeInteger(data, ref currentIndex, out var result))
136 {
138 _state = State.Ready;
139 }
140 }
141
142 private void ParseHeaderValueLength(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
143 {
144 if (currentIndex >= data.Length)
145 {
146 return;
147 }
148 byte b = data[currentIndex++];
150 if (_integerDecoder.BeginTryDecode((byte)(b & 0xFFFFFF7Fu), 7, out var result))
151 {
152 OnStringLength(result, State.HeaderValue);
153 if (result == 0)
154 {
155 OnString(State.Ready);
156 ProcessHeaderValue(data, handler);
157 }
158 else
159 {
160 ParseHeaderValue(data, ref currentIndex, handler);
161 }
162 }
163 else
164 {
165 _state = State.HeaderValueLengthContinue;
166 ParseHeaderValueLengthContinue(data, ref currentIndex, handler);
167 }
168 }
169
170 private void ParseHeaderNameLengthContinue(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
171 {
172 if (TryDecodeInteger(data, ref currentIndex, out var result))
173 {
174 OnStringLength(result, State.HeaderName);
175 ParseHeaderName(data, ref currentIndex, handler);
176 }
177 }
178
179 private void ParseHeaderValueLengthContinue(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
180 {
181 if (TryDecodeInteger(data, ref currentIndex, out var result))
182 {
183 OnStringLength(result, State.HeaderValue);
184 ParseHeaderValue(data, ref currentIndex, handler);
185 }
186 }
187
188 private void ParseHeaderFieldIndex(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
189 {
190 if (TryDecodeInteger(data, ref currentIndex, out var result))
191 {
192 OnIndexedHeaderField(result, handler);
193 }
194 }
195
196 private void ParseHeaderNameIndex(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
197 {
198 if (TryDecodeInteger(data, ref currentIndex, out var result))
199 {
200 OnIndexedHeaderName(result);
201 ParseHeaderValueLength(data, ref currentIndex, handler);
202 }
203 }
204
205 private void ParseHeaderNameLength(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
206 {
207 if (currentIndex >= data.Length)
208 {
209 return;
210 }
211 byte b = data[currentIndex++];
213 if (_integerDecoder.BeginTryDecode((byte)(b & 0xFFFFFF7Fu), 7, out var result))
214 {
215 if (result == 0)
216 {
218 }
219 OnStringLength(result, State.HeaderName);
220 ParseHeaderName(data, ref currentIndex, handler);
221 }
222 else
223 {
224 _state = State.HeaderNameLengthContinue;
225 ParseHeaderNameLengthContinue(data, ref currentIndex, handler);
226 }
227 }
228
229 private void Parse(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
230 {
231 if (currentIndex >= data.Length)
232 {
233 return;
234 }
235 byte b = data[currentIndex++];
237 {
238 case 24:
239 {
240 _headersObserved = true;
241 int num = b & -129;
242 if (_integerDecoder.BeginTryDecode((byte)num, 7, out var result2))
243 {
244 OnIndexedHeaderField(result2, handler);
245 break;
246 }
247 _state = State.HeaderFieldIndex;
248 ParseHeaderFieldIndex(data, ref currentIndex, handler);
249 break;
250 }
251 case 25:
252 ParseLiteralHeaderField(data, ref currentIndex, b, 192, 6, index: true, handler);
253 break;
254 default:
255 ParseLiteralHeaderField(data, ref currentIndex, b, 240, 4, index: false, handler);
256 break;
257 case 27:
258 ParseLiteralHeaderField(data, ref currentIndex, b, 240, 4, index: false, handler);
259 break;
260 case 26:
261 {
263 {
265 }
266 if (_integerDecoder.BeginTryDecode((byte)(b & 0xFFFFFF1Fu), 5, out var result))
267 {
269 break;
270 }
271 _state = State.DynamicTableSizeUpdate;
272 ParseDynamicTableSizeUpdate(data, ref currentIndex);
273 break;
274 }
275 }
276 }
277
278 private void ParseLiteralHeaderField(ReadOnlySpan<byte> data, ref int currentIndex, byte b, byte mask, byte indexPrefix, bool index, IHttpHeadersHandler handler)
279 {
280 _headersObserved = true;
281 _index = index;
282 int num = b & ~mask;
283 int result;
284 if (num == 0)
285 {
286 _state = State.HeaderNameLength;
287 ParseHeaderNameLength(data, ref currentIndex, handler);
288 }
289 else if (_integerDecoder.BeginTryDecode((byte)num, indexPrefix, out result))
290 {
291 OnIndexedHeaderName(result);
292 ParseHeaderValueLength(data, ref currentIndex, handler);
293 }
294 else
295 {
296 _state = State.HeaderNameIndex;
297 ParseHeaderNameIndex(data, ref currentIndex, handler);
298 }
299 }
300
301 private void ParseHeaderName(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
302 {
303 int num = Math.Min(_stringLength - _stringIndex, data.Length - currentIndex);
304 if (num == _stringLength && !_huffman)
305 {
306 _headerNameRange = (currentIndex, num);
307 currentIndex += num;
308 _state = State.HeaderValueLength;
309 return;
310 }
311 data.Slice(currentIndex, num).CopyTo(_stringOctets.AsSpan(_stringIndex));
312 _stringIndex += num;
313 currentIndex += num;
315 {
316 OnString(State.HeaderValueLength);
317 ParseHeaderValueLength(data, ref currentIndex, handler);
318 }
319 }
320
321 private void ParseHeaderValue(ReadOnlySpan<byte> data, ref int currentIndex, IHttpHeadersHandler handler)
322 {
323 int num = Math.Min(_stringLength - _stringIndex, data.Length - currentIndex);
324 if (num == _stringLength && !_huffman)
325 {
326 _headerValueRange = (currentIndex, num);
327 currentIndex += num;
328 _state = State.Ready;
329 ProcessHeaderValue(data, handler);
330 return;
331 }
332 data.Slice(currentIndex, num).CopyTo(_stringOctets.AsSpan(_stringIndex));
333 _stringIndex += num;
334 currentIndex += num;
336 {
337 OnString(State.Ready);
338 ProcessHeaderValue(data, handler);
339 }
340 }
341
342 private void CheckIncompleteHeaderBlock(bool endHeaders)
343 {
344 if (endHeaders)
345 {
346 if (_state != 0)
347 {
349 }
350 _headersObserved = false;
351 }
352 }
353
355 {
356 ReadOnlySpan<byte> value = ((!_headerValueRange.HasValue) ? ((ReadOnlySpan<byte>)_headerValueOctets.AsSpan(0, _headerValueLength)) : data.Slice(_headerValueRange.GetValueOrDefault().start, _headerValueRange.GetValueOrDefault().length));
357 if (_headerStaticIndex > 0)
358 {
360 if (_index)
361 {
363 }
364 }
365 else
366 {
367 ReadOnlySpan<byte> name = ((!_headerNameRange.HasValue) ? ((ReadOnlySpan<byte>)_headerName.AsSpan(0, _headerNameLength)) : data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length));
368 handler.OnHeader(name, value);
369 if (_index)
370 {
372 }
373 }
375 _headerNameRange = null;
376 _headerValueRange = null;
377 }
378
379 public void CompleteDecode()
380 {
381 if (_state != 0)
382 {
384 }
385 }
386
388 {
390 {
392 }
393 else
394 {
395 ref readonly HeaderField dynamicHeader = ref GetDynamicHeader(index);
396 handler.OnHeader(dynamicHeader.Name, dynamicHeader.Value);
397 }
398 _state = State.Ready;
399 }
400
401 private void OnIndexedHeaderName(int index)
402 {
404 {
406 }
407 else
408 {
411 }
412 _state = State.HeaderValueLength;
413 }
414
415 private void OnStringLength(int length, State nextState)
416 {
417 if (length > _stringOctets.Length)
418 {
420 {
422 }
423 _stringOctets = new byte[Math.Max(length, _stringOctets.Length * 2)];
424 }
426 _stringIndex = 0;
427 _state = nextState;
428 }
429
430 private void OnString(State nextState)
431 {
432 try
433 {
434 if (_state == State.HeaderName)
435 {
438 }
439 else
440 {
442 }
443 }
444 catch (HuffmanDecodingException innerException)
445 {
447 }
448 _state = nextState;
449 int Decode(ref byte[] dst)
450 {
451 if (_huffman)
452 {
454 }
455 EnsureStringCapacity(ref dst);
457 return _stringLength;
458 }
459 }
460
461 private void EnsureStringCapacity(ref byte[] dst)
462 {
463 if (dst.Length < _stringLength)
464 {
465 dst = new byte[Math.Max(_stringLength, dst.Length * 2)];
466 }
467 }
468
469 private bool TryDecodeInteger(ReadOnlySpan<byte> data, ref int currentIndex, out int result)
470 {
471 while (currentIndex < data.Length)
472 {
473 if (_integerDecoder.TryDecode(data[currentIndex], out result))
474 {
475 currentIndex++;
476 return true;
477 }
478 currentIndex++;
479 }
480 result = 0;
481 return false;
482 }
483
484 private static bool IsHuffmanEncoded(byte b)
485 {
486 return (b & 0x80) != 0;
487 }
488
489 private ref readonly HeaderField GetDynamicHeader(int index)
490 {
491 try
492 {
493 return ref _dynamicTable[index - H2StaticTable.Count - 1];
494 }
496 {
498 }
499 }
500
509}
static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count)
Definition Buffer.cs:102
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static byte Max(byte val1, byte val2)
Definition Math.cs:738
void Insert(ReadOnlySpan< byte > name, ReadOnlySpan< byte > value)
static ref readonly HeaderField Get(int index)
void OnIndexedHeaderField(int index, IHttpHeadersHandler handler)
void DecodeInternal(ReadOnlySpan< byte > data, IHttpHeadersHandler handler)
readonly DynamicTable _dynamicTable
bool TryDecodeInteger(ReadOnlySpan< byte > data, ref int currentIndex, out int result)
ref readonly HeaderField GetDynamicHeader(int index)
void ParseHeaderValueLength(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void Decode(ReadOnlySpan< byte > data, bool endHeaders, IHttpHeadersHandler handler)
void EnsureStringCapacity(ref byte[] dst)
void ParseHeaderFieldIndex(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
HPackDecoder(int maxDynamicTableSize, int maxHeadersLength, DynamicTable dynamicTable)
HPackDecoder(int maxDynamicTableSize=4096, int maxHeadersLength=65536)
void ParseHeaderNameLength(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void ParseLiteralHeaderField(ReadOnlySpan< byte > data, ref int currentIndex, byte b, byte mask, byte indexPrefix, bool index, IHttpHeadersHandler handler)
static bool IsHuffmanEncoded(byte b)
void OnStringLength(int length, State nextState)
void ParseDynamicTableSizeUpdate(ReadOnlySpan< byte > data, ref int currentIndex)
void ParseHeaderNameLengthContinue(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void ProcessHeaderValue(ReadOnlySpan< byte > data, IHttpHeadersHandler handler)
void ParseHeaderValue(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void Parse(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void ParseHeaderName(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void ParseHeaderValueLengthContinue(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
void CheckIncompleteHeaderBlock(bool endHeaders)
void ParseHeaderNameIndex(ReadOnlySpan< byte > data, ref int currentIndex, IHttpHeadersHandler handler)
static int Decode(ReadOnlySpan< byte > src, ref byte[] dstArray)
Definition Huffman.cs:118
static int LeadingZeroCount(uint value)
static string net_http_hpack_late_dynamic_table_size_update
Definition SR.cs:164
static string net_http_hpack_invalid_index
Definition SR.cs:174
static string net_http_invalid_header_name
Definition SR.cs:180
static string net_http_hpack_huffman_decode_failed
Definition SR.cs:160
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string net_http_headers_exceeded_length
Definition SR.cs:178
static string net_http_hpack_incomplete_header_block
Definition SR.cs:162
static string net_http_hpack_large_table_size_update
Definition SR.cs:170
static string net_http_hpack_unexpected_end
Definition SR.cs:176
Definition SR.cs:7
void OnHeader(ReadOnlySpan< byte > name, ReadOnlySpan< byte > value)
bool BeginTryDecode(byte b, int prefixLength, out int result)
bool TryDecode(byte b, out int result)
void CopyTo(Span< T > destination)
ReadOnlySpan< T > Slice(int start)