blob: 003c32d79e69916497db8aabff99e7380c288932 [file] [log] [blame]
/** @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.
*/
#include <catch2/catch_test_macros.hpp>
#include <cstdio>
#include "proxy/http3/Http3Frame.h"
#include "proxy/http3/Http3FrameDispatcher.h"
#include "proxy/http3/Http3SettingsHandler.h"
TEST_CASE("Http3Frame Type", "[http3]")
{
CHECK(Http3Frame::type(reinterpret_cast<const uint8_t *>("\x00\x00"), 2) == Http3FrameType::DATA);
// Undefined range
CHECK(Http3Frame::type(reinterpret_cast<const uint8_t *>("\x0f\x00"), 2) == Http3FrameType::UNKNOWN);
CHECK(Http3Frame::type(reinterpret_cast<const uint8_t *>("\xff\xff\xff\xff\xff\xff\xff\x00"), 9) == Http3FrameType::UNKNOWN);
}
TEST_CASE("Load DATA Frame", "[http3]")
{
SECTION("Normal")
{
uint8_t buf1[] = {
0x00, // Type
0x04, // Length
0x11, 0x22, 0x33, 0x44, // Payload
};
MIOBuffer *input = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input->write(buf1, sizeof(buf1));
IOBufferReader *input_reader = input->alloc_reader();
std::shared_ptr<Http3Frame> frame1 = Http3FrameFactory::create(*input_reader);
frame1->update();
CHECK(frame1->type() == Http3FrameType::DATA);
CHECK(frame1->length() == 4);
std::shared_ptr<Http3DataFrame> data_frame = std::dynamic_pointer_cast<Http3DataFrame>(frame1);
CHECK(data_frame);
CHECK(data_frame->payload_length() == 4);
IOBufferReader *data_reader = data_frame->data();
CHECK(data_reader->read_avail() == 4);
CHECK(memcmp(data_reader->start(), "\x11\x22\x33\x44", 4) == 0);
free_MIOBuffer(input);
}
}
TEST_CASE("Store DATA Frame", "[http3]")
{
SECTION("Normal")
{
uint8_t buf[32] = {0};
size_t len;
uint8_t expected1[] = {
0x00, // Type
0x04, // Length
0x11, 0x22, 0x33, 0x44, // Payload
};
uint8_t raw1[] = "\x11\x22\x33\x44";
MIOBuffer *payload1 = new_MIOBuffer(BUFFER_SIZE_INDEX_8K);
payload1->set(raw1, 4);
IOBufferReader *payload1_reader = payload1->alloc_reader();
Http3DataFrame data_frame(*payload1_reader, 4);
free_MIOBuffer(payload1);
CHECK(data_frame.length() == 4);
auto ibb = data_frame.to_io_buffer_block();
IOBufferReader reader;
reader.block = ibb.get();
len = reader.read_avail();
reader.read(buf, sizeof(buf));
CHECK(len == 6);
CHECK(memcmp(buf, expected1, len) == 0);
}
}
TEST_CASE("Store HEADERS Frame", "[http3]")
{
SECTION("Normal")
{
uint8_t buf[32] = {0};
size_t len;
uint8_t expected1[] = {
0x01, // Type
0x04, // Length
0x11, 0x22, 0x33, 0x44, // Payload
};
uint8_t raw1[] = "\x11\x22\x33\x44";
ats_unique_buf header_block = ats_unique_malloc(4);
memcpy(header_block.get(), raw1, 4);
Http3HeadersFrame hdrs_frame(std::move(header_block), 4);
CHECK(hdrs_frame.length() == 4);
auto ibb = hdrs_frame.to_io_buffer_block();
IOBufferReader reader;
reader.block = ibb.get();
len = reader.read_avail();
reader.read(buf, sizeof(buf));
CHECK(len == 6);
CHECK(memcmp(buf, expected1, len) == 0);
}
}
TEST_CASE("Load SETTINGS Frame", "[http3]")
{
SECTION("Normal")
{
uint8_t buf[] = {
0x04, // Type
0x08, // Length
0x06, // Identifier
0x44, 0x00, // Value
0x09, // Identifier
0x0f, // Value
0x4a, 0xba, // Identifier
0x00, // Value
};
MIOBuffer *input = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input->write(buf, sizeof(buf));
IOBufferReader *input_reader = input->alloc_reader();
std::shared_ptr<Http3Frame> frame = Http3FrameFactory::create(*input_reader);
frame->update();
CHECK(frame->type() == Http3FrameType::SETTINGS);
CHECK(frame->length() == sizeof(buf) - 2);
std::shared_ptr<Http3SettingsFrame> settings_frame = std::dynamic_pointer_cast<Http3SettingsFrame>(frame);
CHECK(settings_frame);
CHECK(settings_frame->is_valid());
CHECK(settings_frame->get(Http3SettingsId::MAX_FIELD_SECTION_SIZE) == 0x0400);
CHECK(settings_frame->get(Http3SettingsId::NUM_PLACEHOLDERS) == 0x0f);
free_MIOBuffer(input);
}
}
TEST_CASE("Store SETTINGS Frame", "[http3]")
{
SECTION("Normal")
{
uint8_t expected[] = {
0x04, // Type
0x08, // Length
0x06, // Identifier
0x44, 0x00, // Value
0x09, // Identifier
0x0f, // Value
0x4a, 0x0a, // Identifier
0x00, // Value
};
Http3SettingsFrame settings_frame;
settings_frame.set(Http3SettingsId::MAX_FIELD_SECTION_SIZE, 0x0400);
settings_frame.set(Http3SettingsId::NUM_PLACEHOLDERS, 0x0f);
uint8_t buf[32] = {0};
size_t len;
auto ibb = settings_frame.to_io_buffer_block();
IOBufferReader reader;
reader.block = ibb.get();
len = reader.read_avail();
reader.read(buf, sizeof(buf));
CHECK(len == sizeof(expected));
CHECK(memcmp(buf, expected, len) == 0);
}
SECTION("Normal from Client")
{
uint8_t expected[] = {
0x04, // Type
0x06, // Length
0x06, // Identifier
0x44, 0x00, // Value
0x4a, 0x0a, // Identifier
0x00, // Value
};
Http3SettingsFrame settings_frame;
settings_frame.set(Http3SettingsId::MAX_FIELD_SECTION_SIZE, 0x0400);
uint8_t buf[32] = {0};
size_t len;
auto ibb = settings_frame.to_io_buffer_block();
IOBufferReader reader;
reader.block = ibb.get();
len = reader.read_avail();
reader.read(buf, sizeof(buf));
CHECK(len == sizeof(expected));
CHECK(memcmp(buf, expected, len) == 0);
}
}
TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]")
{
uint8_t buf1[] = {
0x0f, // Type
0x00, // Length
};
MIOBuffer *input = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input->write(buf1, sizeof(buf1));
IOBufferReader *input_reader = input->alloc_reader();
std::shared_ptr<const Http3Frame> frame1 = Http3FrameFactory::create(*input_reader);
CHECK(frame1);
CHECK(frame1->type() == Http3FrameType::UNKNOWN);
CHECK(frame1->length() == 0);
free_MIOBuffer(input);
}
TEST_CASE("Http3FrameFactory Fast Create Frame", "[http3]")
{
Http3FrameFactory factory;
uint8_t buf1[] = {
0x00, // Type
0x04, // Length
0x11, 0x22, 0x33, 0x44, // Payload
};
uint8_t buf2[] = {
0x00, // Type
0x04, // Length
0xaa, 0xbb, 0xcc, 0xdd, // Payload
};
MIOBuffer *input1 = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input1->write(buf1, sizeof(buf1));
IOBufferReader *input_reader1 = input1->alloc_reader();
MIOBuffer *input2 = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input2->write(buf2, sizeof(buf2));
IOBufferReader *input_reader2 = input2->alloc_reader();
std::shared_ptr<const Http3Frame> frame1 = factory.fast_create(*input_reader1);
CHECK(frame1 != nullptr);
std::shared_ptr<const Http3DataFrame> data_frame1 = std::dynamic_pointer_cast<const Http3DataFrame>(frame1);
CHECK(data_frame1 != nullptr);
CHECK(memcmp(data_frame1->data()->start(), buf1 + 2, 4) == 0);
std::shared_ptr<const Http3Frame> frame2 = factory.fast_create(*input_reader2);
CHECK(frame2 != nullptr);
std::shared_ptr<const Http3DataFrame> data_frame2 = std::dynamic_pointer_cast<const Http3DataFrame>(frame2);
CHECK(data_frame2 != nullptr);
CHECK(memcmp(data_frame2->data()->start(), buf2 + 2, 4) == 0);
CHECK(frame1 == frame2);
free_MIOBuffer(input1);
free_MIOBuffer(input2);
}
TEST_CASE("Http3FrameFactory Fast Create Unknown Frame", "[http3]")
{
Http3FrameFactory factory;
uint8_t buf1[] = {
0x0f, // Type
};
MIOBuffer *input = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input->write(buf1, sizeof(buf1));
IOBufferReader *input_reader = input->alloc_reader();
std::shared_ptr<const Http3Frame> frame1 = factory.fast_create(*input_reader);
CHECK(frame1);
CHECK(frame1->type() == Http3FrameType::UNKNOWN);
free_MIOBuffer(input);
}
TEST_CASE("SETTINGS frame handler", "[http3]")
{
uint8_t buf1[] = {
0x04, // Type
0x08, // Length
0x06, // Identifier
0x44, 0x00, // Value
0x09, // Identifier
0x0f, // Value
0x4a, 0x0a, // Identifier
0x00, // Value
};
MIOBuffer *input = new_MIOBuffer(BUFFER_SIZE_INDEX_128);
input->write(buf1, sizeof(buf1));
IOBufferReader *input_reader = input->alloc_reader();
Http3SettingsHandler handler = Http3SettingsHandler(nullptr);
Http3SettingsFrame invalid_frame = Http3SettingsFrame(*input_reader, 1);
Http3ErrorUPtr error = Http3ErrorUPtr(nullptr);
invalid_frame.update();
CHECK(invalid_frame.is_valid() == false);
std::shared_ptr<const Http3Frame> invalid_frame_ptr = std::make_shared<const Http3SettingsFrame>(invalid_frame);
error = handler.handle_frame(invalid_frame_ptr);
REQUIRE(error);
CHECK(error->code == Http3ErrorCode::H3_EXCESSIVE_LOAD);
input->reset();
input->write(buf1, sizeof(buf1));
Http3SettingsFrame valid_frame = Http3SettingsFrame(*input_reader, 3);
CHECK(valid_frame.is_valid() == true);
std::shared_ptr<const Http3Frame> valid_frame_ptr = std::make_shared<const Http3SettingsFrame>(valid_frame);
error = handler.handle_frame(valid_frame_ptr);
CHECK(error == nullptr);
free_MIOBuffer(input);
}