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 "QUICApplication.h"
30 #include "Http3Types.h"
31 
32 class Http3Frame
33 {
34 public:
35   constexpr static size_t MAX_FRAM_HEADER_OVERHEAD = 128; ///< Type (i) + Length (i)
36 
Http3Frame()37   Http3Frame() {}
38   Http3Frame(const uint8_t *buf, size_t len);
39   Http3Frame(Http3FrameType type);
~Http3Frame()40   virtual ~Http3Frame() {}
41 
42   uint64_t total_length() const;
43   uint64_t length() const;
44   Http3FrameType type() const;
45   virtual void store(uint8_t *buf, size_t *len) const;
46   virtual void reset(const uint8_t *buf, size_t len);
47   static int length(const uint8_t *buf, size_t buf_len, uint64_t &length);
48   static Http3FrameType type(const uint8_t *buf, size_t buf_len);
49 
50 protected:
51   uint64_t _length       = 0;
52   Http3FrameType _type   = Http3FrameType::UNKNOWN;
53   size_t _payload_offset = 0;
54 };
55 
56 class Http3UnknownFrame : public Http3Frame
57 {
58 public:
Http3UnknownFrame()59   Http3UnknownFrame() : Http3Frame() {}
60   Http3UnknownFrame(const uint8_t *buf, size_t len);
61 
62   void store(uint8_t *buf, size_t *len) const override;
63 
64 protected:
65   const uint8_t *_buf = nullptr;
66   size_t _buf_len     = 0;
67 };
68 
69 //
70 // DATA Frame
71 //
72 
73 class Http3DataFrame : public Http3Frame
74 {
75 public:
Http3DataFrame()76   Http3DataFrame() : Http3Frame() {}
77   Http3DataFrame(const uint8_t *buf, size_t len);
78   Http3DataFrame(ats_unique_buf payload, size_t payload_len);
79 
80   void store(uint8_t *buf, size_t *len) const override;
81   void reset(const uint8_t *buf, size_t len) override;
82 
83   const uint8_t *payload() const;
84   uint64_t payload_length() const;
85 
86 private:
87   const uint8_t *_payload      = nullptr;
88   ats_unique_buf _payload_uptr = {nullptr};
89   size_t _payload_len          = 0;
90 };
91 
92 //
93 // HEADERS Frame
94 //
95 
96 class Http3HeadersFrame : public Http3Frame
97 {
98 public:
Http3HeadersFrame()99   Http3HeadersFrame() : Http3Frame() {}
100   Http3HeadersFrame(const uint8_t *buf, size_t len);
101   Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len);
102 
103   void store(uint8_t *buf, size_t *len) const override;
104   void reset(const uint8_t *buf, size_t len) override;
105 
106   const uint8_t *header_block() const;
107   uint64_t header_block_length() const;
108 
109 private:
110   const uint8_t *_header_block      = nullptr;
111   ats_unique_buf _header_block_uptr = {nullptr};
112   size_t _header_block_len          = 0;
113 };
114 
115 //
116 // SETTINGS Frame
117 //
118 
119 class Http3SettingsFrame : public Http3Frame
120 {
121 public:
Http3SettingsFrame()122   Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {}
123   Http3SettingsFrame(const uint8_t *buf, size_t len, uint32_t max_settings = 0);
124 
125   static constexpr size_t MAX_PAYLOAD_SIZE = 60;
126   static constexpr std::array<Http3SettingsId, 4> VALID_SETTINGS_IDS{
127     Http3SettingsId::HEADER_TABLE_SIZE,
128     Http3SettingsId::MAX_HEADER_LIST_SIZE,
129     Http3SettingsId::QPACK_BLOCKED_STREAMS,
130     Http3SettingsId::NUM_PLACEHOLDERS,
131   };
132 
133   void store(uint8_t *buf, size_t *len) const override;
134   void reset(const uint8_t *buf, size_t len) override;
135 
136   bool is_valid() const;
137   Http3ErrorUPtr get_error() const;
138 
139   bool contains(Http3SettingsId id) const;
140   uint64_t get(Http3SettingsId id) const;
141   void set(Http3SettingsId id, uint64_t value);
142 
143 private:
144   std::map<Http3SettingsId, uint64_t> _settings;
145   // TODO: make connection error with HTTP_MALFORMED_FRAME
146   bool _valid = false;
147   Http3ErrorCode _error_code;
148   const char *_error_reason = nullptr;
149 };
150 
151 using Http3FrameDeleterFunc  = void (*)(Http3Frame *p);
152 using Http3FrameUPtr         = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
153 using Http3DataFrameUPtr     = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
154 using Http3HeadersFrameUPtr  = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
155 using Http3SettingsFrameUPtr = std::unique_ptr<Http3SettingsFrame, Http3FrameDeleterFunc>;
156 
157 using Http3FrameDeleterFunc = void (*)(Http3Frame *p);
158 using Http3FrameUPtr        = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
159 using Http3DataFrameUPtr    = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
160 using Http3HeadersFrameUPtr = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
161 
162 extern ClassAllocator<Http3Frame> http3FrameAllocator;
163 extern ClassAllocator<Http3DataFrame> http3DataFrameAllocator;
164 extern ClassAllocator<Http3HeadersFrame> http3HeadersFrameAllocator;
165 extern ClassAllocator<Http3SettingsFrame> http3SettingsFrameAllocator;
166 
167 class Http3FrameDeleter
168 {
169 public:
170   static void
delete_null_frame(Http3Frame * frame)171   delete_null_frame(Http3Frame *frame)
172   {
173     ink_assert(frame == nullptr);
174   }
175 
176   static void
delete_frame(Http3Frame * frame)177   delete_frame(Http3Frame *frame)
178   {
179     frame->~Http3Frame();
180     http3FrameAllocator.free(static_cast<Http3Frame *>(frame));
181   }
182 
183   static void
delete_data_frame(Http3Frame * frame)184   delete_data_frame(Http3Frame *frame)
185   {
186     frame->~Http3Frame();
187     http3DataFrameAllocator.free(static_cast<Http3DataFrame *>(frame));
188   }
189 
190   static void
delete_headers_frame(Http3Frame * frame)191   delete_headers_frame(Http3Frame *frame)
192   {
193     frame->~Http3Frame();
194     http3HeadersFrameAllocator.free(static_cast<Http3HeadersFrame *>(frame));
195   }
196 
197   static void
delete_settings_frame(Http3Frame * frame)198   delete_settings_frame(Http3Frame *frame)
199   {
200     frame->~Http3Frame();
201     http3SettingsFrameAllocator.free(static_cast<Http3SettingsFrame *>(frame));
202   }
203 };
204 
205 //
206 // Http3FrameFactory
207 //
208 class Http3FrameFactory
209 {
210 public:
211   /*
212    * This is for an empty Http3FrameUPtr.
213    * Empty frames are used for variable initialization and return value of frame creation failure
214    */
215   static Http3FrameUPtr create_null_frame();
216 
217   /*
218    * This is used for creating a Http3Frame object based on received data.
219    */
220   static Http3FrameUPtr create(const uint8_t *buf, size_t len);
221 
222   /*
223    * This works almost the same as create() but it reuses created objects for performance.
224    * If you create a frame object which has the same frame type that you created before, the object will be reset by new data.
225    */
226   std::shared_ptr<const Http3Frame> fast_create(QUICStreamIO &stream_io, size_t frame_len);
227   std::shared_ptr<const Http3Frame> fast_create(const uint8_t *buf, size_t len);
228 
229   /*
230    * Creates a HEADERS frame.
231    */
232   static Http3HeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len);
233   static Http3HeadersFrameUPtr create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len);
234 
235   /*
236    * Creates a DATA frame.
237    */
238   static Http3DataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len);
239   static Http3DataFrameUPtr create_data_frame(IOBufferReader *reader, size_t data_len);
240 
241 private:
242   std::shared_ptr<Http3Frame> _unknown_frame        = nullptr;
243   std::shared_ptr<Http3Frame> _reusable_frames[256] = {nullptr};
244 };
245