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 #include "tscore/Diags.h"
25 #include "quic/QUICIntUtil.h"
26 #include "Http3Frame.h"
27 #include "Http3Config.h"
28
29 ClassAllocator<Http3Frame> http3FrameAllocator("http3FrameAllocator");
30 ClassAllocator<Http3DataFrame> http3DataFrameAllocator("http3DataFrameAllocator");
31 ClassAllocator<Http3HeadersFrame> http3HeadersFrameAllocator("http3HeadersFrameAllocator");
32 ClassAllocator<Http3SettingsFrame> http3SettingsFrameAllocator("http3SettingsFrameAllocator");
33
34 //
35 // Static functions
36 //
37
38 int
length(const uint8_t * buf,size_t buf_len,uint64_t & length)39 Http3Frame::length(const uint8_t *buf, size_t buf_len, uint64_t &length)
40 {
41 size_t length_field_length = 0;
42 return QUICVariableInt::decode(length, length_field_length, buf, buf_len);
43 }
44
45 Http3FrameType
type(const uint8_t * buf,size_t buf_len)46 Http3Frame::type(const uint8_t *buf, size_t buf_len)
47 {
48 uint64_t type = 0;
49 size_t type_field_length = 0;
50 int ret = QUICVariableInt::decode(type, type_field_length, buf, buf_len);
51 ink_assert(ret != 1);
52 if (type <= static_cast<uint64_t>(Http3FrameType::X_MAX_DEFINED)) {
53 return static_cast<Http3FrameType>(type);
54 } else {
55 return Http3FrameType::UNKNOWN;
56 }
57 }
58
59 //
60 // Generic Frame
61 //
62
Http3Frame(const uint8_t * buf,size_t buf_len)63 Http3Frame::Http3Frame(const uint8_t *buf, size_t buf_len)
64 {
65 // Type
66 size_t type_field_length = 0;
67 int ret = QUICVariableInt::decode(reinterpret_cast<uint64_t &>(this->_type), type_field_length, buf, buf_len);
68 ink_assert(ret != 1);
69
70 // Length
71 size_t length_field_length = 0;
72 ret = QUICVariableInt::decode(this->_length, length_field_length, buf + type_field_length, buf_len - type_field_length);
73 ink_assert(ret != 1);
74
75 // Payload offset
76 this->_payload_offset = type_field_length + length_field_length;
77 }
78
Http3Frame(Http3FrameType type)79 Http3Frame::Http3Frame(Http3FrameType type) : _type(type) {}
80
81 uint64_t
total_length() const82 Http3Frame::total_length() const
83 {
84 return this->_payload_offset + this->length();
85 }
86
87 uint64_t
length() const88 Http3Frame::length() const
89 {
90 return this->_length;
91 }
92
93 Http3FrameType
type() const94 Http3Frame::type() const
95 {
96 if (static_cast<uint64_t>(this->_type) <= static_cast<uint64_t>(Http3FrameType::X_MAX_DEFINED)) {
97 return this->_type;
98 } else {
99 return Http3FrameType::UNKNOWN;
100 }
101 }
102
103 void
store(uint8_t * buf,size_t * len) const104 Http3Frame::store(uint8_t *buf, size_t *len) const
105 {
106 // If you really need this, you should keep the data passed to its constructor
107 ink_assert(!"Not supported");
108 }
109
110 void
reset(const uint8_t * buf,size_t len)111 Http3Frame::reset(const uint8_t *buf, size_t len)
112 {
113 this->~Http3Frame();
114 new (this) Http3Frame(buf, len);
115 }
116
117 //
118 // UNKNOWN Frame
119 //
Http3UnknownFrame(const uint8_t * buf,size_t buf_len)120 Http3UnknownFrame::Http3UnknownFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len), _buf(buf), _buf_len(buf_len) {}
121
122 void
store(uint8_t * buf,size_t * len) const123 Http3UnknownFrame::store(uint8_t *buf, size_t *len) const
124 {
125 memcpy(buf, this->_buf, this->_buf_len);
126 *len = this->_buf_len;
127 }
128
129 //
130 // DATA Frame
131 //
Http3DataFrame(const uint8_t * buf,size_t buf_len)132 Http3DataFrame::Http3DataFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len)
133 {
134 this->_payload = buf + this->_payload_offset;
135 this->_payload_len = buf_len - this->_payload_offset;
136 }
137
Http3DataFrame(ats_unique_buf payload,size_t payload_len)138 Http3DataFrame::Http3DataFrame(ats_unique_buf payload, size_t payload_len)
139 : Http3Frame(Http3FrameType::DATA), _payload_uptr(std::move(payload)), _payload_len(payload_len)
140 {
141 this->_length = this->_payload_len;
142 this->_payload = this->_payload_uptr.get();
143 }
144
145 void
store(uint8_t * buf,size_t * len) const146 Http3DataFrame::store(uint8_t *buf, size_t *len) const
147 {
148 size_t written = 0;
149 size_t n;
150 QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
151 written += n;
152 QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length);
153 written += n;
154 memcpy(buf + written, this->_payload, this->_payload_len);
155 written += this->_payload_len;
156 *len = written;
157 }
158
159 void
reset(const uint8_t * buf,size_t len)160 Http3DataFrame::reset(const uint8_t *buf, size_t len)
161 {
162 this->~Http3DataFrame();
163 new (this) Http3DataFrame(buf, len);
164 }
165
166 const uint8_t *
payload() const167 Http3DataFrame::payload() const
168 {
169 return this->_payload;
170 }
171
172 uint64_t
payload_length() const173 Http3DataFrame::payload_length() const
174 {
175 return this->_payload_len;
176 }
177
178 //
179 // HEADERS Frame
180 //
Http3HeadersFrame(const uint8_t * buf,size_t buf_len)181 Http3HeadersFrame::Http3HeadersFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len)
182 {
183 this->_header_block = buf + this->_payload_offset;
184 this->_header_block_len = buf_len - this->_payload_offset;
185 }
186
Http3HeadersFrame(ats_unique_buf header_block,size_t header_block_len)187 Http3HeadersFrame::Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len)
188 : Http3Frame(Http3FrameType::HEADERS), _header_block_uptr(std::move(header_block)), _header_block_len(header_block_len)
189 {
190 this->_length = header_block_len;
191 this->_header_block = this->_header_block_uptr.get();
192 }
193
194 void
store(uint8_t * buf,size_t * len) const195 Http3HeadersFrame::store(uint8_t *buf, size_t *len) const
196 {
197 size_t written = 0;
198 size_t n;
199 QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
200 written += n;
201 QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length);
202 written += n;
203 memcpy(buf + written, this->_header_block, this->_header_block_len);
204 written += this->_header_block_len;
205 *len = written;
206 }
207
208 void
reset(const uint8_t * buf,size_t len)209 Http3HeadersFrame::reset(const uint8_t *buf, size_t len)
210 {
211 this->~Http3HeadersFrame();
212 new (this) Http3HeadersFrame(buf, len);
213 }
214
215 const uint8_t *
header_block() const216 Http3HeadersFrame::header_block() const
217 {
218 return this->_header_block;
219 }
220
221 uint64_t
header_block_length() const222 Http3HeadersFrame::header_block_length() const
223 {
224 return this->_header_block_len;
225 }
226
227 //
228 // SETTINGS Frame
229 //
230
Http3SettingsFrame(const uint8_t * buf,size_t buf_len,uint32_t max_settings)231 Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len, uint32_t max_settings) : Http3Frame(buf, buf_len)
232 {
233 size_t len = this->_payload_offset;
234 uint32_t nsettings = 0;
235
236 while (len < buf_len) {
237 if (nsettings >= max_settings) {
238 this->_error_code = Http3ErrorCode::EXCESSIVE_LOAD;
239 this->_error_reason = reinterpret_cast<const char *>("too many settings");
240 break;
241 }
242
243 size_t id_len = QUICVariableInt::size(buf + len);
244 uint16_t id = QUICIntUtil::read_QUICVariableInt(buf + len, buf_len - len);
245 len += id_len;
246
247 size_t value_len = QUICVariableInt::size(buf + len);
248 uint64_t value = QUICIntUtil::read_QUICVariableInt(buf + len, buf_len - len);
249 len += value_len;
250
251 // Ignore any SETTINGS identifier it does not understand.
252 bool ignore = true;
253 for (const auto &known_id : Http3SettingsFrame::VALID_SETTINGS_IDS) {
254 if (id == static_cast<uint64_t>(known_id)) {
255 ignore = false;
256 break;
257 }
258 }
259
260 if (ignore) {
261 continue;
262 }
263
264 this->_settings.insert(std::make_pair(static_cast<Http3SettingsId>(id), value));
265 ++nsettings;
266 }
267
268 if (len == buf_len) {
269 this->_valid = true;
270 }
271 }
272
273 void
store(uint8_t * buf,size_t * len) const274 Http3SettingsFrame::store(uint8_t *buf, size_t *len) const
275 {
276 uint8_t payload[Http3SettingsFrame::MAX_PAYLOAD_SIZE] = {0};
277 uint8_t *p = payload;
278 size_t l = 0;
279
280 for (auto &it : this->_settings) {
281 QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(it.first), p, &l);
282 p += l;
283 QUICIntUtil::write_QUICVariableInt(it.second, p, &l);
284 p += l;
285 }
286
287 // Exercise the requirement that unknown identifiers be ignored. - 4.2.5.1.
288 QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(Http3SettingsId::UNKNOWN), p, &l);
289 p += l;
290 QUICIntUtil::write_QUICVariableInt(0, p, &l);
291 p += l;
292
293 size_t written = 0;
294 size_t payload_len = p - payload;
295
296 size_t n;
297 QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
298 written += n;
299 QUICVariableInt::encode(buf + written, UINT64_MAX, n, payload_len);
300 written += n;
301
302 // Payload
303 memcpy(buf + written, payload, payload_len);
304 written += payload_len;
305
306 *len = written;
307 }
308
309 void
reset(const uint8_t * buf,size_t len)310 Http3SettingsFrame::reset(const uint8_t *buf, size_t len)
311 {
312 this->~Http3SettingsFrame();
313 new (this) Http3SettingsFrame(buf, len);
314 }
315
316 bool
is_valid() const317 Http3SettingsFrame::is_valid() const
318 {
319 return this->_valid;
320 }
321
322 Http3ErrorUPtr
get_error() const323 Http3SettingsFrame::get_error() const
324 {
325 return std::make_unique<Http3ConnectionError>(this->_error_code, this->_error_reason);
326 }
327
328 bool
contains(Http3SettingsId id) const329 Http3SettingsFrame::contains(Http3SettingsId id) const
330 {
331 auto p = this->_settings.find(id);
332 return (p != this->_settings.end());
333 }
334
335 uint64_t
get(Http3SettingsId id) const336 Http3SettingsFrame::get(Http3SettingsId id) const
337 {
338 auto p = this->_settings.find(id);
339 if (p != this->_settings.end()) {
340 return p->second;
341 }
342
343 return 0;
344 }
345
346 void
set(Http3SettingsId id,uint64_t value)347 Http3SettingsFrame::set(Http3SettingsId id, uint64_t value)
348 {
349 this->_settings[id] = value;
350 }
351
352 //
353 // Http3FrameFactory
354 //
355 Http3FrameUPtr
create_null_frame()356 Http3FrameFactory::create_null_frame()
357 {
358 return {nullptr, &Http3FrameDeleter::delete_null_frame};
359 }
360
361 Http3FrameUPtr
create(const uint8_t * buf,size_t len)362 Http3FrameFactory::create(const uint8_t *buf, size_t len)
363 {
364 Http3Config::scoped_config params;
365 Http3Frame *frame = nullptr;
366 Http3FrameType type = Http3Frame::type(buf, len);
367
368 switch (type) {
369 case Http3FrameType::HEADERS:
370 frame = http3HeadersFrameAllocator.alloc();
371 new (frame) Http3HeadersFrame(buf, len);
372 return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame);
373 case Http3FrameType::DATA:
374 frame = http3DataFrameAllocator.alloc();
375 new (frame) Http3DataFrame(buf, len);
376 return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_data_frame);
377 case Http3FrameType::SETTINGS:
378 frame = http3SettingsFrameAllocator.alloc();
379 new (frame) Http3SettingsFrame(buf, len, params->max_settings());
380 return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame);
381 default:
382 // Unknown frame
383 Debug("http3_frame_factory", "Unknown frame type %hhx", static_cast<uint8_t>(type));
384 frame = http3FrameAllocator.alloc();
385 new (frame) Http3Frame(buf, len);
386 return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_frame);
387 }
388 }
389
390 std::shared_ptr<const Http3Frame>
fast_create(const uint8_t * buf,size_t len)391 Http3FrameFactory::fast_create(const uint8_t *buf, size_t len)
392 {
393 Http3FrameType type = Http3Frame::type(buf, len);
394 if (type == Http3FrameType::UNKNOWN) {
395 if (!this->_unknown_frame) {
396 this->_unknown_frame = Http3FrameFactory::create(buf, len);
397 } else {
398 this->_unknown_frame->reset(buf, len);
399 }
400 return this->_unknown_frame;
401 }
402
403 std::shared_ptr<Http3Frame> frame = this->_reusable_frames[static_cast<uint8_t>(type)];
404
405 if (frame == nullptr) {
406 frame = Http3FrameFactory::create(buf, len);
407 if (frame != nullptr) {
408 this->_reusable_frames[static_cast<uint8_t>(type)] = frame;
409 }
410 } else {
411 frame->reset(buf, len);
412 }
413
414 return frame;
415 }
416
417 std::shared_ptr<const Http3Frame>
fast_create(QUICStreamIO & stream_io,size_t frame_len)418 Http3FrameFactory::fast_create(QUICStreamIO &stream_io, size_t frame_len)
419 {
420 uint8_t buf[65536];
421
422 // FIXME DATA frames can be giga bytes
423 ink_assert(sizeof(buf) > frame_len);
424
425 if (stream_io.peek(buf, frame_len) < static_cast<int64_t>(frame_len)) {
426 // Return if whole frame data is not available
427 return nullptr;
428 }
429 return this->fast_create(buf, frame_len);
430 }
431
432 Http3HeadersFrameUPtr
create_headers_frame(const uint8_t * header_block,size_t header_block_len)433 Http3FrameFactory::create_headers_frame(const uint8_t *header_block, size_t header_block_len)
434 {
435 ats_unique_buf buf = ats_unique_malloc(header_block_len);
436 memcpy(buf.get(), header_block, header_block_len);
437
438 Http3HeadersFrame *frame = http3HeadersFrameAllocator.alloc();
439 new (frame) Http3HeadersFrame(std::move(buf), header_block_len);
440 return Http3HeadersFrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame);
441 }
442
443 Http3HeadersFrameUPtr
create_headers_frame(IOBufferReader * header_block_reader,size_t header_block_len)444 Http3FrameFactory::create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len)
445 {
446 ats_unique_buf buf = ats_unique_malloc(header_block_len);
447
448 int64_t nread;
449 while ((nread = header_block_reader->read(buf.get(), header_block_len)) > 0) {
450 ;
451 }
452
453 Http3HeadersFrame *frame = http3HeadersFrameAllocator.alloc();
454 new (frame) Http3HeadersFrame(std::move(buf), header_block_len);
455 return Http3HeadersFrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame);
456 }
457
458 Http3DataFrameUPtr
create_data_frame(const uint8_t * payload,size_t payload_len)459 Http3FrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len)
460 {
461 ats_unique_buf buf = ats_unique_malloc(payload_len);
462 memcpy(buf.get(), payload, payload_len);
463
464 Http3DataFrame *frame = http3DataFrameAllocator.alloc();
465 new (frame) Http3DataFrame(std::move(buf), payload_len);
466 return Http3DataFrameUPtr(frame, &Http3FrameDeleter::delete_data_frame);
467 }
468
469 // TODO: This should clone IOBufferBlock chain to avoid memcpy
470 Http3DataFrameUPtr
create_data_frame(IOBufferReader * reader,size_t payload_len)471 Http3FrameFactory::create_data_frame(IOBufferReader *reader, size_t payload_len)
472 {
473 ats_unique_buf buf = ats_unique_malloc(payload_len);
474 size_t written = 0;
475
476 while (written < payload_len) {
477 int64_t len = reader->block_read_avail();
478
479 if (written + len > payload_len) {
480 len = payload_len - written;
481 }
482
483 memcpy(buf.get() + written, reinterpret_cast<uint8_t *>(reader->start()), len);
484 reader->consume(len);
485 written += len;
486 }
487
488 ink_assert(written == payload_len);
489
490 Http3DataFrame *frame = http3DataFrameAllocator.alloc();
491 new (frame) Http3DataFrame(std::move(buf), payload_len);
492
493 return Http3DataFrameUPtr(frame, &Http3FrameDeleter::delete_data_frame);
494 }
495