xref: /trafficserver/proxy/http3/Http3Frame.cc (revision 88909bcf)
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);
245     len += id_len;
246 
247     size_t value_len = QUICVariableInt::size(buf + len);
248     uint64_t value   = QUICIntUtil::read_QUICVariableInt(buf + 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