/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 | | }; |