/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 | 144 | 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 | | class Http3UnknownFrame : public Http3Frame |
67 | | { |
68 | | public: |
69 | 0 | Http3UnknownFrame() : Http3Frame() {} |
70 | | Http3UnknownFrame(IOBufferReader &reader); |
71 | | |
72 | | Ptr<IOBufferBlock> to_io_buffer_block() const override; |
73 | | |
74 | | protected: |
75 | | const uint8_t *_buf = nullptr; |
76 | | size_t _buf_len = 0; |
77 | | }; |
78 | | |
79 | | // |
80 | | // DATA Frame |
81 | | // |
82 | | |
83 | | class Http3DataFrame : public Http3Frame |
84 | | { |
85 | | public: |
86 | 10 | Http3DataFrame() : Http3Frame() {} |
87 | | Http3DataFrame(IOBufferReader &reader); |
88 | | Http3DataFrame(IOBufferReader &reader, size_t payload_len); |
89 | | |
90 | | Ptr<IOBufferBlock> to_io_buffer_block() const override; |
91 | | void reset(IOBufferReader &reader) override; |
92 | | |
93 | | uint64_t payload_length() const; |
94 | | |
95 | | IOBufferReader *data() const; |
96 | | |
97 | | private: |
98 | | // Head of IOBufferBlock chain to send |
99 | | Ptr<IOBufferBlock> _whole_frame; |
100 | | uint64_t _payload_len = 0; |
101 | | }; |
102 | | |
103 | | // |
104 | | // HEADERS Frame |
105 | | // |
106 | | |
107 | | class Http3HeadersFrame : public Http3Frame |
108 | | { |
109 | | public: |
110 | 5 | Http3HeadersFrame() : Http3Frame() {} |
111 | | Http3HeadersFrame(IOBufferReader &reader); |
112 | | Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len); |
113 | | ~Http3HeadersFrame(); |
114 | | |
115 | | Ptr<IOBufferBlock> to_io_buffer_block() const override; |
116 | | void reset(IOBufferReader &reader) override; |
117 | | |
118 | | const uint8_t *header_block() const; |
119 | | uint64_t header_block_length() const; |
120 | | |
121 | | protected: |
122 | | bool _parse() override; |
123 | | |
124 | | private: |
125 | | uint8_t *_header_block = nullptr; |
126 | | ats_unique_buf _header_block_uptr = {nullptr}; |
127 | | size_t _header_block_len = 0; |
128 | | }; |
129 | | |
130 | | // |
131 | | // SETTINGS Frame |
132 | | // |
133 | | |
134 | | class Http3SettingsFrame : public Http3Frame |
135 | | { |
136 | | public: |
137 | 5 | Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {} |
138 | | Http3SettingsFrame(IOBufferReader &reader, uint32_t max_settings = 0); |
139 | | |
140 | | static constexpr size_t MAX_PAYLOAD_SIZE = 60; |
141 | | static constexpr std::array<Http3SettingsId, 4> VALID_SETTINGS_IDS{ |
142 | | Http3SettingsId::HEADER_TABLE_SIZE, |
143 | | Http3SettingsId::MAX_FIELD_SECTION_SIZE, |
144 | | Http3SettingsId::QPACK_BLOCKED_STREAMS, |
145 | | Http3SettingsId::NUM_PLACEHOLDERS, |
146 | | }; |
147 | | |
148 | | Ptr<IOBufferBlock> to_io_buffer_block() const override; |
149 | | void reset(IOBufferReader &reader) override; |
150 | | |
151 | | Http3ErrorUPtr get_error() const; |
152 | | |
153 | | bool contains(Http3SettingsId id) const; |
154 | | uint64_t get(Http3SettingsId id) const; |
155 | | void set(Http3SettingsId id, uint64_t value); |
156 | | |
157 | | protected: |
158 | | bool _parse() override; |
159 | | |
160 | | private: |
161 | | uint32_t _max_settings = 0; |
162 | | std::map<Http3SettingsId, uint64_t> _settings; |
163 | | Http3ErrorCode _error_code; |
164 | | const char *_error_reason = nullptr; |
165 | | }; |
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 | | using Http3SettingsFrameUPtr = std::unique_ptr<Http3SettingsFrame, Http3FrameDeleterFunc>; |
172 | | |
173 | | using Http3FrameDeleterFunc = void (*)(Http3Frame *p); |
174 | | using Http3FrameUPtr = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>; |
175 | | using Http3DataFrameUPtr = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>; |
176 | | using Http3HeadersFrameUPtr = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>; |
177 | | |
178 | | extern ClassAllocator<Http3Frame, false> http3FrameAllocator; |
179 | | extern ClassAllocator<Http3DataFrame, false> http3DataFrameAllocator; |
180 | | extern ClassAllocator<Http3HeadersFrame, false> http3HeadersFrameAllocator; |
181 | | extern ClassAllocator<Http3SettingsFrame, false> http3SettingsFrameAllocator; |
182 | | |
183 | | class Http3FrameDeleter |
184 | | { |
185 | | public: |
186 | | static void |
187 | | delete_null_frame(Http3Frame *frame) |
188 | 0 | { |
189 | 0 | ink_assert(frame == nullptr); |
190 | 0 | } |
191 | | |
192 | | static void |
193 | | delete_frame(Http3Frame *frame) |
194 | 129 | { |
195 | 129 | frame->~Http3Frame(); |
196 | 129 | http3FrameAllocator.free(static_cast<Http3Frame *>(frame)); |
197 | 129 | } |
198 | | |
199 | | static void |
200 | | delete_data_frame(Http3Frame *frame) |
201 | 10 | { |
202 | 10 | frame->~Http3Frame(); |
203 | 10 | http3DataFrameAllocator.free(static_cast<Http3DataFrame *>(frame)); |
204 | 10 | } |
205 | | |
206 | | static void |
207 | | delete_headers_frame(Http3Frame *frame) |
208 | 5 | { |
209 | 5 | frame->~Http3Frame(); |
210 | 5 | http3HeadersFrameAllocator.free(static_cast<Http3HeadersFrame *>(frame)); |
211 | 5 | } |
212 | | |
213 | | static void |
214 | | delete_settings_frame(Http3Frame *frame) |
215 | 5 | { |
216 | 5 | frame->~Http3Frame(); |
217 | 5 | http3SettingsFrameAllocator.free(static_cast<Http3SettingsFrame *>(frame)); |
218 | 5 | } |
219 | | }; |
220 | | |
221 | | // |
222 | | // Http3FrameFactory |
223 | | // |
224 | | class Http3FrameFactory |
225 | | { |
226 | | public: |
227 | | /* |
228 | | * This is for an empty Http3FrameUPtr. |
229 | | * Empty frames are used for variable initialization and return value of frame creation failure |
230 | | */ |
231 | | static Http3FrameUPtr create_null_frame(); |
232 | | |
233 | | /* |
234 | | * This is used for creating a Http3Frame object based on received data. |
235 | | */ |
236 | | static Http3FrameUPtr create(IOBufferReader &reader); |
237 | | |
238 | | /* |
239 | | * This works almost the same as create() but it reuses created objects for performance. |
240 | | * If you create a frame object which has the same frame type that you created before, the object will be reset by new data. |
241 | | */ |
242 | | std::shared_ptr<Http3Frame> fast_create(IOBufferReader &reader); |
243 | | |
244 | | /* |
245 | | * Creates a HEADERS frame. |
246 | | */ |
247 | | static Http3HeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len); |
248 | | static Http3HeadersFrameUPtr create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len); |
249 | | |
250 | | /* |
251 | | * Creates a DATA frame. |
252 | | */ |
253 | | static Http3DataFrameUPtr create_data_frame(IOBufferReader *reader, size_t data_len); |
254 | | |
255 | | private: |
256 | | std::shared_ptr<Http3Frame> _unknown_frame = nullptr; |
257 | | std::shared_ptr<Http3Frame> _reusable_frames[256] = {nullptr}; |
258 | | }; |