1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
/** @file
*
* A brief file description
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "tscore/Allocator.h"
#include "tscore/ink_memory.h"
#include "tscore/ink_assert.h"
#include "QUICApplication.h"
#include "Http3Types.h"
class Http3Frame
{
public:
constexpr static size_t MAX_FRAM_HEADER_OVERHEAD = 128; ///< Type (i) + Length (i)
Http3Frame() {}
Http3Frame(const uint8_t *buf, size_t len);
Http3Frame(Http3FrameType type);
virtual ~Http3Frame() {}
uint64_t total_length() const;
uint64_t length() const;
Http3FrameType type() const;
virtual Ptr<IOBufferBlock> to_io_buffer_block() const;
virtual void reset(const uint8_t *buf, size_t len);
static int length(const uint8_t *buf, size_t buf_len, uint64_t &length);
static Http3FrameType type(const uint8_t *buf, size_t buf_len);
protected:
uint64_t _length = 0;
Http3FrameType _type = Http3FrameType::UNKNOWN;
size_t _payload_offset = 0;
};
class Http3UnknownFrame : public Http3Frame
{
public:
Http3UnknownFrame() : Http3Frame() {}
Http3UnknownFrame(const uint8_t *buf, size_t len);
Ptr<IOBufferBlock> to_io_buffer_block() const override;
protected:
const uint8_t *_buf = nullptr;
size_t _buf_len = 0;
};
//
// DATA Frame
//
class Http3DataFrame : public Http3Frame
{
public:
Http3DataFrame() : Http3Frame() {}
Http3DataFrame(const uint8_t *buf, size_t len);
Http3DataFrame(ats_unique_buf payload, size_t payload_len);
Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
const uint8_t *payload() const;
uint64_t payload_length() const;
private:
const uint8_t *_payload = nullptr;
ats_unique_buf _payload_uptr = {nullptr};
size_t _payload_len = 0;
};
//
// HEADERS Frame
//
class Http3HeadersFrame : public Http3Frame
{
public:
Http3HeadersFrame() : Http3Frame() {}
Http3HeadersFrame(const uint8_t *buf, size_t len);
Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len);
Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
const uint8_t *header_block() const;
uint64_t header_block_length() const;
private:
const uint8_t *_header_block = nullptr;
ats_unique_buf _header_block_uptr = {nullptr};
size_t _header_block_len = 0;
};
//
// SETTINGS Frame
//
class Http3SettingsFrame : public Http3Frame
{
public:
Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {}
Http3SettingsFrame(const uint8_t *buf, size_t len, uint32_t max_settings = 0);
static constexpr size_t MAX_PAYLOAD_SIZE = 60;
static constexpr std::array<Http3SettingsId, 4> VALID_SETTINGS_IDS{
Http3SettingsId::HEADER_TABLE_SIZE,
Http3SettingsId::MAX_HEADER_LIST_SIZE,
Http3SettingsId::QPACK_BLOCKED_STREAMS,
Http3SettingsId::NUM_PLACEHOLDERS,
};
Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
bool is_valid() const;
Http3ErrorUPtr get_error() const;
bool contains(Http3SettingsId id) const;
uint64_t get(Http3SettingsId id) const;
void set(Http3SettingsId id, uint64_t value);
private:
std::map<Http3SettingsId, uint64_t> _settings;
// TODO: make connection error with HTTP_MALFORMED_FRAME
bool _valid = false;
Http3ErrorCode _error_code;
const char *_error_reason = nullptr;
};
using Http3FrameDeleterFunc = void (*)(Http3Frame *p);
using Http3FrameUPtr = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
using Http3DataFrameUPtr = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
using Http3HeadersFrameUPtr = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
using Http3SettingsFrameUPtr = std::unique_ptr<Http3SettingsFrame, Http3FrameDeleterFunc>;
using Http3FrameDeleterFunc = void (*)(Http3Frame *p);
using Http3FrameUPtr = std::unique_ptr<Http3Frame, Http3FrameDeleterFunc>;
using Http3DataFrameUPtr = std::unique_ptr<Http3DataFrame, Http3FrameDeleterFunc>;
using Http3HeadersFrameUPtr = std::unique_ptr<Http3HeadersFrame, Http3FrameDeleterFunc>;
extern ClassAllocator<Http3Frame> http3FrameAllocator;
extern ClassAllocator<Http3DataFrame> http3DataFrameAllocator;
extern ClassAllocator<Http3HeadersFrame> http3HeadersFrameAllocator;
extern ClassAllocator<Http3SettingsFrame> http3SettingsFrameAllocator;
class Http3FrameDeleter
{
public:
static void
delete_null_frame(Http3Frame *frame)
{
ink_assert(frame == nullptr);
}
static void
delete_frame(Http3Frame *frame)
{
frame->~Http3Frame();
http3FrameAllocator.free(static_cast<Http3Frame *>(frame));
}
static void
delete_data_frame(Http3Frame *frame)
{
frame->~Http3Frame();
http3DataFrameAllocator.free(static_cast<Http3DataFrame *>(frame));
}
static void
delete_headers_frame(Http3Frame *frame)
{
frame->~Http3Frame();
http3HeadersFrameAllocator.free(static_cast<Http3HeadersFrame *>(frame));
}
static void
delete_settings_frame(Http3Frame *frame)
{
frame->~Http3Frame();
http3SettingsFrameAllocator.free(static_cast<Http3SettingsFrame *>(frame));
}
};
//
// Http3FrameFactory
//
class Http3FrameFactory
{
public:
/*
* This is for an empty Http3FrameUPtr.
* Empty frames are used for variable initialization and return value of frame creation failure
*/
static Http3FrameUPtr create_null_frame();
/*
* This is used for creating a Http3Frame object based on received data.
*/
static Http3FrameUPtr create(const uint8_t *buf, size_t len);
/*
* This works almost the same as create() but it reuses created objects for performance.
* If you create a frame object which has the same frame type that you created before, the object will be reset by new data.
*/
std::shared_ptr<const Http3Frame> fast_create(IOBufferReader &reader, size_t frame_len);
std::shared_ptr<const Http3Frame> fast_create(const uint8_t *buf, size_t len);
/*
* Creates a HEADERS frame.
*/
static Http3HeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len);
static Http3HeadersFrameUPtr create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len);
/*
* Creates a DATA frame.
*/
static Http3DataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len);
static Http3DataFrameUPtr create_data_frame(IOBufferReader *reader, size_t data_len);
private:
std::shared_ptr<Http3Frame> _unknown_frame = nullptr;
std::shared_ptr<Http3Frame> _reusable_frames[256] = {nullptr};
};
|