Coverage Report

Created: 2026-10-31 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/proxy/http3/Http3Frame.h
Line
Count
Source
1
/** @file
2
 *
3
 *  A brief file description
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/Allocator.h"
27
#include "tscore/ink_memory.h"
28
#include "tscore/ink_assert.h"
29
#include "iocore/net/quic/QUICApplication.h"
30
#include "proxy/http3/Http3Types.h"
31
32
class Http3Frame
33
{
34
public:
35
  constexpr static size_t MAX_FRAM_HEADER_OVERHEAD = 128; ///< Type (i) + Length (i)
36
37
157
  Http3Frame() {}
38
  Http3Frame(IOBufferReader &reader);
39
  Http3Frame(Http3FrameType type);
40
  virtual ~Http3Frame();
41
42
  bool                       is_valid() const;
43
  uint64_t                   total_length() const;
44
  uint64_t                   length() const;
45
  Http3FrameType             type() const;
46
  bool                       update();
47
  virtual Ptr<IOBufferBlock> to_io_buffer_block() const;
48
  virtual void               reset(IOBufferReader &reader);
49
  static int                 length(const uint8_t *buf, size_t buf_len, uint64_t &length);
50
  static Http3FrameType      type(const uint8_t *buf, size_t buf_len);
51
52
protected:
53
  IOBufferReader *_reader           = nullptr;
54
  bool            _finished_reading = false;
55
  uint64_t        _length           = 0;
56
  Http3FrameType  _type             = Http3FrameType::UNKNOWN;
57
  size_t          _payload_offset   = 0;
58
  bool            _is_valid         = true;
59
60
  virtual bool _parse();
61
62
private:
63
  bool _is_ready = false;
64
};
65
66
//
67
// DATA Frame
68
//
69
70
class Http3DataFrame : public Http3Frame
71
{
72
public:
73
18
  Http3DataFrame() : Http3Frame() {}
74
  Http3DataFrame(IOBufferReader &reader);
75
  Http3DataFrame(IOBufferReader &reader, size_t payload_len);
76
77
  Ptr<IOBufferBlock> to_io_buffer_block() const override;
78
  void               reset(IOBufferReader &reader) override;
79
80
  uint64_t payload_length() const;
81
82
  IOBufferReader *data() const;
83
84
private:
85
  // Head of IOBufferBlock chain to send
86
  Ptr<IOBufferBlock> _whole_frame;
87
  uint64_t           _payload_len = 0;
88
89
protected:
90
  bool _parse() override;
91
};
92
93
//
94
// HEADERS Frame
95
//
96
97
class Http3HeadersFrame : public Http3Frame
98
{
99
public:
100
1
  Http3HeadersFrame() : Http3Frame() {}
101
  Http3HeadersFrame(IOBufferReader &reader);
102
  // Shares the caller's buffer via a cloned reader instead of copying header_block_len bytes.
103
  // Safe as long as the source MIOBuffer outlives this frame, which holds for the qmux/quic
104
  // write path: the frame is created, serialized via to_io_buffer_block(), and destroyed, all
105
  // synchronously, well within the lifetime of the Http3HeaderFramer that owns the source buffer.
106
  Http3HeadersFrame(IOBufferReader &header_block_reader, size_t header_block_len);
107
  ~Http3HeadersFrame();
108
109
  Ptr<IOBufferBlock> to_io_buffer_block() const override;
110
  void               reset(IOBufferReader &reader) override;
111
112
  const uint8_t *header_block() const;
113
  uint64_t       header_block_length() const;
114
115
protected:
116
  bool _parse() override;
117
118
private:
119
  uint8_t        *_header_block        = nullptr;
120
  size_t          _header_block_len    = 0;
121
  IOBufferReader *_header_block_reader = nullptr;
122
};
123
124
//
125
// SETTINGS Frame
126
//
127
128
class Http3SettingsFrame : public Http3Frame
129
{
130
public:
131
3
  Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {}
132
  Http3SettingsFrame(IOBufferReader &reader, uint32_t max_settings = 0);
133
134
  static constexpr size_t                         MAX_PAYLOAD_SIZE = 60;
135
  static constexpr std::array<Http3SettingsId, 4> VALID_SETTINGS_IDS{
136
    Http3SettingsId::HEADER_TABLE_SIZE,
137
    Http3SettingsId::MAX_FIELD_SECTION_SIZE,
138
    Http3SettingsId::QPACK_BLOCKED_STREAMS,
139
    Http3SettingsId::NUM_PLACEHOLDERS,
140
  };
141
142
  Ptr<IOBufferBlock> to_io_buffer_block() const override;
143
  void               reset(IOBufferReader &reader) override;
144
145
  Http3ErrorUPtr get_error() const;
146
147
  bool     contains(Http3SettingsId id) const;
148
  uint64_t get(Http3SettingsId id) const;
149
  void     set(Http3SettingsId id, uint64_t value);
150
151
protected:
152
  bool _parse() override;
153
154
private:
155
  uint32_t                            _max_settings = 0;
156
  std::map<Http3SettingsId, uint64_t> _settings;
157
  Http3ErrorCode                      _error_code;
158
  const char                         *_error_reason = nullptr;
159
};
160
161
using Http3FrameDeleterFunc  = void (*)(Http3Frame *p);
162
using Http3FrameUPtr         = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
163
using Http3DataFrameUPtr     = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
164
using Http3HeadersFrameUPtr  = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
165
using Http3SettingsFrameUPtr = std::unique_ptr<Http3SettingsFrame, Http3FrameDeleterFunc>;
166
167
using Http3FrameDeleterFunc = void (*)(Http3Frame *p);
168
using Http3FrameUPtr        = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
169
using Http3DataFrameUPtr    = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
170
using Http3HeadersFrameUPtr = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
171
172
extern ClassAllocator<Http3Frame, false>         http3FrameAllocator;
173
extern ClassAllocator<Http3DataFrame, false>     http3DataFrameAllocator;
174
extern ClassAllocator<Http3HeadersFrame, false>  http3HeadersFrameAllocator;
175
extern ClassAllocator<Http3SettingsFrame, false> http3SettingsFrameAllocator;
176
177
class Http3FrameDeleter
178
{
179
public:
180
  static void
181
  delete_null_frame(Http3Frame *frame)
182
0
  {
183
0
    ink_assert(frame == nullptr);
184
0
  }
185
186
  static void
187
  delete_frame(Http3Frame *frame)
188
138
  {
189
138
    frame->~Http3Frame();
190
138
    http3FrameAllocator.free(static_cast<Http3Frame *>(frame));
191
138
  }
192
193
  static void
194
  delete_data_frame(Http3Frame *frame)
195
18
  {
196
18
    frame->~Http3Frame();
197
18
    http3DataFrameAllocator.free(static_cast<Http3DataFrame *>(frame));
198
18
  }
199
200
  static void
201
  delete_headers_frame(Http3Frame *frame)
202
1
  {
203
1
    frame->~Http3Frame();
204
1
    http3HeadersFrameAllocator.free(static_cast<Http3HeadersFrame *>(frame));
205
1
  }
206
207
  static void
208
  delete_settings_frame(Http3Frame *frame)
209
3
  {
210
3
    frame->~Http3Frame();
211
3
    http3SettingsFrameAllocator.free(static_cast<Http3SettingsFrame *>(frame));
212
3
  }
213
};
214
215
//
216
// Http3FrameFactory
217
//
218
class Http3FrameFactory
219
{
220
public:
221
  /*
222
   * This is for an empty Http3FrameUPtr.
223
   * Empty frames are used for variable initialization and return value of frame creation failure
224
   */
225
  static Http3FrameUPtr create_null_frame();
226
227
  /*
228
   * This is used for creating a Http3Frame object based on received data.
229
   */
230
  static Http3FrameUPtr create(IOBufferReader &reader);
231
232
  /*
233
   * This works almost the same as create() but it reuses created objects for performance.
234
   * If you create a frame object which has the same frame type that you created before, the object will be reset by new data.
235
   */
236
  std::shared_ptr<Http3Frame> fast_create(IOBufferReader &reader);
237
238
  /*
239
   * Creates a HEADERS frame.
240
   */
241
  static Http3HeadersFrameUPtr create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len);
242
243
  /*
244
   * Creates a DATA frame.
245
   */
246
  static Http3DataFrameUPtr create_data_frame(IOBufferReader *reader, size_t data_len);
247
248
private:
249
  std::shared_ptr<Http3Frame> _unknown_frame        = nullptr;
250
  std::shared_ptr<Http3Frame> _reusable_frames[256] = {nullptr};
251
};