Coverage Report

Created: 2026-03-28 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/proxy/http2/HPACK.h
Line
Count
Source
1
/** @file
2
3
  [RFC 7541] HPACK: Header Compression for HTTP/2
4
5
  @section license License
6
7
  Licensed to the Apache Software Foundation (ASF) under one
8
  or more contributor license agreements.  See the NOTICE file
9
  distributed with this work for additional information
10
  regarding copyright ownership.  The ASF licenses this file
11
  to you under the Apache License, Version 2.0 (the
12
  "License"); you may not use this file except in compliance
13
  with the License.  You may obtain a copy of the License at
14
15
      http://www.apache.org/licenses/LICENSE-2.0
16
17
  Unless required by applicable law or agreed to in writing, software
18
  distributed under the License is distributed on an "AS IS" BASIS,
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
  See the License for the specific language governing permissions and
21
  limitations under the License.
22
 */
23
24
#pragma once
25
26
#include "tscore/ink_platform.h"
27
#include "tscore/Diags.h"
28
#include "proxy/hdrs/HTTP.h"
29
#include "proxy/hdrs/XPACK.h"
30
31
#include <deque>
32
#include <string_view>
33
34
// It means that any header field can be compressed/decompressed by ATS
35
const static int HPACK_ERROR_COMPRESSION_ERROR   = -1;
36
const static int HPACK_ERROR_SIZE_EXCEEDED_ERROR = -2;
37
38
enum class HpackField {
39
  INDEX,              // [RFC 7541] 6.1. Indexed Header Field Representation
40
  INDEXED_LITERAL,    // [RFC 7541] 6.2.1. Literal Header Field with Incremental Indexing
41
  NOINDEX_LITERAL,    // [RFC 7541] 6.2.2. Literal Header Field without Indexing
42
  NEVERINDEX_LITERAL, // [RFC 7541] 6.2.3. Literal Header Field never Indexed
43
  TABLESIZE_UPDATE,   // [RFC 7541] 6.3. Dynamic Table Size Update
44
};
45
46
enum class HpackIndex {
47
  NONE,
48
  STATIC,
49
  DYNAMIC,
50
};
51
52
enum class HpackMatch {
53
  NONE,
54
  NAME,
55
  EXACT,
56
};
57
58
// Result of looking for a header field in IndexingTable
59
struct HpackLookupResult {
60
  uint32_t   index      = 0;
61
  HpackIndex index_type = HpackIndex::NONE;
62
  HpackMatch match_type = HpackMatch::NONE;
63
};
64
65
struct HpackHeaderField {
66
  std::string_view name;
67
  std::string_view value;
68
};
69
70
class MIMEFieldWrapper
71
{
72
public:
73
0
  MIMEFieldWrapper(MIMEField *f, HdrHeap *hh, MIMEHdrImpl *impl) : _field(f), _heap(hh), _mh(impl) {}
74
  void
75
  name_set(const char *name, int name_len)
76
0
  {
77
0
    _field->name_set(_heap, _mh, std::string_view{name, static_cast<std::string_view::size_type>(name_len)});
78
0
  }
79
80
  void
81
  value_set(const char *value, int value_len)
82
0
  {
83
0
    _field->value_set(_heap, _mh, std::string_view{value, static_cast<std::string_view::size_type>(value_len)});
84
0
  }
85
86
  std::string_view
87
  name_get() const
88
0
  {
89
0
    return _field->name_get();
90
0
  }
91
92
  std::string_view
93
  value_get() const
94
0
  {
95
0
    return _field->value_get();
96
0
  }
97
98
  const MIMEField *
99
  field_get() const
100
0
  {
101
0
    return _field;
102
0
  }
103
104
private:
105
  MIMEField   *_field;
106
  HdrHeap     *_heap;
107
  MIMEHdrImpl *_mh;
108
};
109
110
// [RFC 7541] 2.3. Indexing Table
111
class HpackIndexingTable
112
{
113
public:
114
0
  explicit HpackIndexingTable(uint32_t size) : _dynamic_table(size){};
115
0
  ~HpackIndexingTable() {}
116
117
  // noncopyable
118
  HpackIndexingTable(HpackIndexingTable &)                  = delete;
119
  HpackIndexingTable &operator=(const HpackIndexingTable &) = delete;
120
121
  HpackLookupResult lookup(const HpackHeaderField &header) const;
122
  int               get_header_field(uint32_t index, MIMEFieldWrapper &header_field) const;
123
124
  void     add_header_field(const HpackHeaderField &header);
125
  uint32_t maximum_size() const;
126
  uint32_t size() const;
127
  void     update_maximum_size(uint32_t new_size);
128
129
  // Temporal buffer for internal use but it has to be public because many functions are not members of this class.
130
  Arena arena;
131
132
private:
133
  XpackDynamicTable _dynamic_table;
134
};
135
136
// Low level interfaces
137
int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index);
138
int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t *buf_end, const HpackHeaderField &header,
139
                                                      uint32_t index, HpackIndexingTable &indexing_table, HpackField type);
140
int64_t encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf_end, const HpackHeaderField &header,
141
                                                  HpackIndexingTable &indexing_table, HpackField type);
142
143
int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
144
                                    HpackIndexingTable &indexing_table);
145
int64_t decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
146
                                    HpackIndexingTable &indexing_table);
147
int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, HpackIndexingTable &indexing_table,
148
                                  uint32_t maximum_table_size);
149
150
// High level interfaces
151
using HpackHandle = HpackIndexingTable;
152
int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len,
153
                                  uint32_t max_header_size, uint32_t maximum_table_size);
154
int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr,
155
                                  int32_t maximum_table_size = -1);
156
int32_t hpack_get_maximum_table_size(HpackHandle &handle);